X402.PaymentSignature (X402 v0.4.1)

Copy Markdown View Source

Decodes and validates x402 PAYMENT-SIGNATURE header values.

The header value is Base64-encoded JSON. This module supports both the legacy v1 signature fields and the v2 PaymentPayload envelope.

For v2, accepted must be a complete X402.PaymentRequirements object and payload must contain the scheme-specific signed data. When requirements are passed to validate/2, every core field is matched and advertised extra values must be preserved.

Summary

Header Encoding

Decodes a Base64 PAYMENT-SIGNATURE value to a map.

Returns the canonical x402 header name.

Payment Verification

Decodes and validates a PAYMENT-SIGNATURE header in one step.

Decodes and validates a PAYMENT-SIGNATURE header against requirements.

Validates a decoded v1 or v2 PAYMENT-SIGNATURE payload.

Validates a decoded PAYMENT-SIGNATURE payload against payment requirements.

Header Encoding

decode(value)

(since 0.1.0)
@spec decode(String.t()) :: {:ok, map()} | {:error, decode_error()}

Decodes a Base64 PAYMENT-SIGNATURE value to a map.

Examples

iex> payload = %{"x402Version" => 2, "accepted" => %{"scheme" => "exact"}, "payload" => %{}}
iex> value = payload |> Jason.encode!() |> Base.encode64()
iex> X402.PaymentSignature.decode(value)
{:ok, payload}

iex> X402.PaymentSignature.decode("not-base64")
{:error, :invalid_base64}

header_name()

(since 0.1.0)
@spec header_name() :: String.t()

Returns the canonical x402 header name.

Examples

iex> X402.PaymentSignature.header_name()
"PAYMENT-SIGNATURE"

Payment Verification

decode_and_validate(value)

(since 0.1.0)
@spec decode_and_validate(String.t()) ::
  {:ok, map()} | {:error, decode_and_validate_error()}

Decodes and validates a PAYMENT-SIGNATURE header in one step.

Examples

iex> payload = %{"x402Version" => 2, "accepted" => %{"scheme" => "exact", "network" => "eip155:8453", "amount" => "1", "asset" => "asset", "payTo" => "receiver", "maxTimeoutSeconds" => 60, "extra" => %{}}, "payload" => %{}}
iex> value = payload |> Jason.encode!() |> Base.encode64()
iex> X402.PaymentSignature.decode_and_validate(value)
{:ok, payload}

decode_and_validate(value, requirements)

(since 0.1.0)
@spec decode_and_validate(String.t(), map()) ::
  {:ok, map()} | {:error, decode_and_validate_error()}

Decodes and validates a PAYMENT-SIGNATURE header against requirements.

validate(payload)

(since 0.1.0)
@spec validate(map()) :: {:ok, map()} | {:error, validate_error()}

Validates a decoded v1 or v2 PAYMENT-SIGNATURE payload.

Payloads with x402Version: 2 are validated against the v2 PaymentPayload structure. Payloads with version 1, or without an explicit version, retain the legacy field validation used by x402 v1.

Examples

iex> payload = %{
...>   "x402Version" => 2,
...>   "accepted" => %{
...>     "scheme" => "exact",
...>     "network" => "eip155:8453",
...>     "amount" => "10000",
...>     "asset" => "0xasset",
...>     "payTo" => "0xreceiver",
...>     "maxTimeoutSeconds" => 60,
...>     "extra" => %{}
...>   },
...>   "payload" => %{"signature" => "0xsignature"}
...> }
iex> X402.PaymentSignature.validate(payload)
{:ok, payload}

iex> X402.PaymentSignature.validate(%{"x402Version" => 2})
{:error, :invalid_payload}

validate(payload, requirements)

(since 0.1.0)
@spec validate(map(), map()) :: {:ok, map()} | {:error, validate_error()}

Validates a decoded PAYMENT-SIGNATURE payload against payment requirements.

For v2, this matches the complete accepted object. For the "upto" scheme, it also ensures the signed maximum does not exceed the advertised amount.

Types

decode_and_validate_error()

@type decode_and_validate_error() :: decode_error() | validate_error()

decode_error()

@type decode_error() :: :invalid_base64 | :invalid_json | :payload_too_large

upto_validation_error()

@type upto_validation_error() ::
  :missing_max_price
  | :missing_payment_value
  | :invalid_max_price
  | :invalid_payment_value
  | :payment_value_exceeds_max_price

validate_error()

@type validate_error() ::
  :invalid_payload
  | :invalid_payment_requirements
  | :invalid_x402_version
  | :no_matching_requirements
  | {:missing_fields, [String.t()]}
  | {:invalid_fields, [String.t()]}
  | {:invalid_upto_payment, upto_validation_error()}
  | {:invalid_format, [{field :: String.t(), reason :: atom()}]}