Parse and format the three MPP protocol headers.
Headers
WWW-Authenticate: Payment— challenge header using RFC 9110 auth-param syntaxAuthorization: Payment— credential header (scheme + base64url JSON blob)Payment-Receipt— receipt header (bare base64url JSON blob)Accept-Payment— client preference header (method/intent[;q=value])
Usage
# Server: format a 402 challenge response header
header_value = MPP.Headers.format_challenge(challenge)
# → ~s(Payment id="x7Tg...", realm="api.example.com", method="stripe", ...)
# Client: parse a 402 challenge from response
{:ok, challenge} = MPP.Headers.parse_challenge(header_value)
# Client: format credential for request
header_value = MPP.Headers.format_credential(credential)
# → "Payment eyJjaGFsbGVuZ2..."
# Server: parse credential from request
{:ok, credential} = MPP.Headers.parse_credential(header_value)
# Server: format receipt for response
header_value = MPP.Headers.format_receipt(receipt)
# Client: parse receipt from response
{:ok, receipt} = MPP.Headers.parse_receipt(header_value)API Functions
| Function | Arity | Description | Param Kinds |
|---|---|---|---|
rank_by_accept_payment | 3 | Reorder server offers by client Accept-Payment preferences. Excludes q=0 matches. | offers: value, preferences: value, method_intent: value |
format_accept_payment | 1 | Format preference entries into an Accept-Payment header value. | entries: value |
apply_accept_payment_header | 3 | Filter and reorder server offers using a request Accept-Payment header. Malformed or no-match headers are a no-op. | offers: value, header: value, method_intent: value |
parse_accept_payment | 1 | Parse an Accept-Payment header into client preference entries. Malformed input returns [] (spec MAY-ignore). | header: value |
parse_receipt | 1 | Parse a Payment-Receipt header value into a receipt struct. | header: value |
format_receipt | 1 | Format a receipt as a Payment-Receipt header value (bare base64url JSON, no scheme prefix). | receipt: value |
parse_credential | 1 | Parse an Authorization: Payment header value into a credential struct. | header: value |
format_credential | 1 | Format a credential as an Authorization: Payment header value. | credential: value |
parse_challenges | 1 | Parse a WWW-Authenticate header containing one or more Payment challenges. Splits on scheme boundaries, skips non-Payment schemes. Partial failures are tolerated: if some challenges parse and others fail, only the successful ones are returned (matching mppx deserializeList semantics). | header: value |
parse_challenge | 1 | Parse a WWW-Authenticate: Payment header value into a challenge struct. | header: value |
format_challenge | 1 | Format a challenge as a WWW-Authenticate: Payment header value with RFC 9110 auth-param syntax. | challenge: value |
Summary
Functions
Filter and reorder server offers using an Accept-Payment header.
Format preference entries into an Accept-Payment header value.
Format a challenge as a WWW-Authenticate: Payment header value with RFC 9110 auth-param syntax.
Format a credential as an Authorization: Payment header value.
Format a receipt as a Payment-Receipt header value (bare base64url JSON, no scheme prefix).
Parse an Accept-Payment header value into preference entries.
Parse a WWW-Authenticate: Payment header value into a challenge struct.
Parse a WWW-Authenticate header containing one or more Payment challenges. Splits on scheme boundaries, skips non-Payment schemes. Partial failures are tolerated: if some challenges parse and others fail, only the successful ones are returned (matching mppx deserializeList semantics).
Parse an Authorization: Payment header value into a credential struct.
Parse a Payment-Receipt header value into a receipt struct.
Reorder server offers by client Accept-Payment preferences.
Types
Functions
@spec apply_accept_payment_header([term()], String.t() | nil, (term() -> {String.t(), String.t()})) :: [ term() ]
Filter and reorder server offers using an Accept-Payment header.
Returns offers unchanged when header is nil, malformed, or matches no
offers (spec MAY-ignore).
@spec format_accept_payment([accept_payment_entry() | map()]) :: String.t()
Format preference entries into an Accept-Payment header value.
Omits ;q= when q is 1.0. Entries may be {method, intent, q} tuples
or maps with :method, :intent, and :q keys.
@spec format_challenge(MPP.Challenge.t()) :: String.t()
Format a challenge as a WWW-Authenticate: Payment header value with RFC 9110 auth-param syntax.
Parameters
challenge- Challenge struct to format (value)
Returns
Header value string with quoted auth-params (string)
Composes With
parse_challenge
# descripex:contract
%{
params: %{
challenge: %{description: "Challenge struct to format", kind: :value}
},
returns: %{
type: :string,
description: "Header value string with quoted auth-params"
},
composes_with: [:parse_challenge]
}
@spec format_credential(MPP.Credential.t()) :: String.t()
Format a credential as an Authorization: Payment header value.
Parameters
credential- Credential struct to format (value)
Returns
Header value with Payment scheme prefix and base64url JSON blob (string)
Composes With
parse_credential
# descripex:contract
%{
params: %{
credential: %{description: "Credential struct to format", kind: :value}
},
returns: %{
type: :string,
description: "Header value with Payment scheme prefix and base64url JSON blob"
},
composes_with: [:parse_credential]
}
@spec format_receipt(MPP.Receipt.t()) :: String.t()
Format a receipt as a Payment-Receipt header value (bare base64url JSON, no scheme prefix).
Parameters
receipt- Receipt struct to format (value)
Returns
Base64url-encoded JSON string (string)
Composes With
parse_receipt
# descripex:contract
%{
params: %{receipt: %{description: "Receipt struct to format", kind: :value}},
returns: %{type: :string, description: "Base64url-encoded JSON string"},
composes_with: [:parse_receipt]
}
@spec parse_accept_payment(String.t()) :: [accept_payment_entry()]
Parse an Accept-Payment header value into preference entries.
Each entry is {method, intent, q} where method and intent are lowercase
tokens or *, and q is 0.0..1.0 (default 1.0).
Returns [] for empty, whitespace-only, or malformed input (spec MAY-ignore).
@spec parse_challenge(String.t()) :: {:ok, MPP.Challenge.t()} | {:error, atom()}
Parse a WWW-Authenticate: Payment header value into a challenge struct.
Parameters
header- Raw WWW-Authenticate header value string (value)
Returns
{:ok, challenge} on success, {:error, reason} on failure (tagged_tuple)
Errors
:invalid_scheme:missing_required_params:duplicate_param:invalid_auth_params:request_too_large
Composes With
format_challenge
# descripex:contract
%{
params: %{
header: %{
description: "Raw WWW-Authenticate header value string",
kind: :value
}
},
errors: [:invalid_scheme, :missing_required_params, :duplicate_param,
:invalid_auth_params, :request_too_large],
returns: %{
type: :tagged_tuple,
description: "`{:ok, challenge}` on success, `{:error, reason}` on failure"
},
composes_with: [:format_challenge]
}
@spec parse_challenges(String.t()) :: {:ok, [MPP.Challenge.t()]} | {:error, atom()}
Parse a WWW-Authenticate header containing one or more Payment challenges. Splits on scheme boundaries, skips non-Payment schemes. Partial failures are tolerated: if some challenges parse and others fail, only the successful ones are returned (matching mppx deserializeList semantics).
Parameters
header- Raw WWW-Authenticate header value, possibly containing multiple challenges (value)
Returns
{:ok, [challenge]} on success, {:error, reason} if no Payment challenges found or all fail to parse (tagged_tuple)
Errors
:no_payment_challenges:invalid_scheme:missing_required_params:duplicate_param:invalid_auth_params:request_too_large
Composes With
parse_challengeformat_challenge
# descripex:contract
%{
params: %{
header: %{
description: "Raw WWW-Authenticate header value, possibly containing multiple challenges",
kind: :value
}
},
errors: [:no_payment_challenges, :invalid_scheme, :missing_required_params,
:duplicate_param, :invalid_auth_params, :request_too_large],
returns: %{
type: :tagged_tuple,
description: "`{:ok, [challenge]}` on success, `{:error, reason}` if no Payment challenges found or all fail to parse"
},
composes_with: [:parse_challenge, :format_challenge]
}
@spec parse_credential(String.t()) :: {:ok, MPP.Credential.t()} | {:error, atom()}
Parse an Authorization: Payment header value into a credential struct.
Parameters
header- Raw Authorization header value string (value)
Returns
{:ok, credential} on success, {:error, reason} on failure (tagged_tuple)
Errors
:invalid_scheme:invalid_base64:invalid_json:missing_required_fields:token_too_large
Composes With
format_credential
# descripex:contract
%{
params: %{
header: %{
description: "Raw Authorization header value string",
kind: :value
}
},
errors: [:invalid_scheme, :invalid_base64, :invalid_json,
:missing_required_fields, :token_too_large],
returns: %{
type: :tagged_tuple,
description: "`{:ok, credential}` on success, `{:error, reason}` on failure"
},
composes_with: [:format_credential]
}
@spec parse_receipt(String.t()) :: {:ok, MPP.Receipt.t()} | {:error, atom()}
Parse a Payment-Receipt header value into a receipt struct.
Parameters
header- Raw Payment-Receipt header value (bare base64url JSON) (value)
Returns
{:ok, receipt} on success, {:error, reason} on failure (tagged_tuple)
Errors
:invalid_base64:invalid_json:missing_required_fields:token_too_large
Composes With
format_receipt
# descripex:contract
%{
params: %{
header: %{
description: "Raw Payment-Receipt header value (bare base64url JSON)",
kind: :value
}
},
errors: [:invalid_base64, :invalid_json, :missing_required_fields,
:token_too_large],
returns: %{
type: :tagged_tuple,
description: "`{:ok, receipt}` on success, `{:error, reason}` on failure"
},
composes_with: [:format_receipt]
}
@spec rank_by_accept_payment([term()], [accept_payment_entry() | map()], (term() -> {String.t(), String.t()})) :: [term()]
Reorder server offers by client Accept-Payment preferences.
Offers with no matching preference or only q=0 matches are excluded.
Sorting matches mpp-rs / mppx: highest effective q, then original offer order.
method_intent extracts {method, intent} from each offer (defaults to
challenge fields when omitted).