X402.Client.Finch (X402 v0.6.0)

Copy Markdown View Source

Finch-backed payer client with an automatic 402 → sign → retry flow.

request/3 performs an HTTP request; when the server answers 402 with a PAYMENT-REQUIRED header, it decodes the payment requirements, builds and signs a payment via X402.Client.build_payment/3, and retries the request once with the PAYMENT-SIGNATURE header. A request is never paid twice: at most one payment retry is made, and requests that already carry a payment-signature header are refused.

Requires the optional finch dependency; without it every call returns {:error, :missing_dependency}. Start your own Finch pool (with TLS peer verification — see X402.Facilitator.HTTP.secure_pool_opts/0) and pass its name.

Example

{:ok, signer} = X402.Signer.LocalKey.new(System.fetch_env!("PAYER_KEY"))

{:ok, %{status: 200, body: body, payment_response: receipt}} =
  X402.Client.Finch.request(MyApp.Finch, "https://api.example.com/paid",
    signer: signer,
    max_amount: "10000",
    on_payment_required: fn payment_required ->
      IO.inspect(payment_required["accepts"], label: "about to pay")
      :ok
    end
  )

Security

Like the facilitator client, URLs must use https:// — payment authorizations must never travel in plaintext. Loopback hosts (localhost, 127.0.0.1, ::1) are exempt for local development.

Summary

Types

A Finch pool name or pid.

A completed HTTP response.

Functions

Performs an HTTP request, paying for the resource if it requires payment.

Types

finch_name()

@type finch_name() :: atom() | pid() | {:via, module(), term()}

A Finch pool name or pid.

request_error()

@type request_error() ::
  :missing_dependency
  | :insecure_url
  | :payment_cancelled
  | :payment_already_attempted
  | {:transport_error, term()}
  | {:invalid_payment_required, term()}
  | X402.Client.build_error()

response()

@type response() :: %{
  status: non_neg_integer(),
  headers: [{String.t(), String.t()}],
  body: binary(),
  payment_response: map() | nil
}

A completed HTTP response.

:payment_response holds the decoded PAYMENT-RESPONSE header (the settlement receipt) when the server sent a valid one, otherwise nil.

Functions

request(finch_name, url, opts)

(since 0.6.0)
@spec request(finch_name(), String.t(), keyword()) ::
  {:ok, response()} | {:error, request_error()}

Performs an HTTP request, paying for the resource if it requires payment.

Flow:

  1. Perform the request. Anything other than a 402 with a PAYMENT-REQUIRED header is returned as-is.
  2. Decode the PAYMENT-REQUIRED header (X402.PaymentRequired.decode/1).
  3. Invoke the :on_payment_required hook, which may cancel.
  4. Build and sign a payment (X402.Client.build_payment/3) and retry the request once with the PAYMENT-SIGNATURE header.
  5. Return the retried response with the decoded PAYMENT-RESPONSE settlement receipt, when present. A second 402 is returned as-is — the payment is never re-signed or re-sent.

Options

  • :signer - Required. A struct implementing X402.Signer, used to sign the payment.

  • :method - HTTP request method. The default value is :get.

  • :headers - Additional {name, value} request headers. The default value is [].

  • :body - Request body. The default value is nil.

  • :receive_timeout_ms (non_neg_integer/0) - Finch receive timeout per attempt, in milliseconds. The default value is 5000.

  • :network (String.t/0) - Payment selection filter — see X402.Client.select_requirements/2.

  • :scheme (String.t/0) - Payment selection filter — see X402.Client.select_requirements/2.

  • :asset (String.t/0) - Payment selection filter — see X402.Client.select_requirements/2.

  • :max_amount - Maximum amount (atomic units) this client will pay — the budget guard for automated payers. Requirements above it are never selected.

  • :valid_after_buffer (non_neg_integer/0) - Clock-skew buffer for the authorization's validAfter, in seconds. The default value is 60.

  • :extensions (list of function of arity 2) - Client extension enrichers forwarded to X402.Client.build_payment/3 — see its :extensions option. The default value is [].

  • :schemes - Additional X402.Scheme modules forwarded to X402.Client.build_payment/3 — see its :schemes option. The default value is [].

  • :on_payment_required - Budget/consent hook invoked with the decoded PaymentRequired map before any payment is signed. Return :cancel to abort with {:error, :payment_cancelled}; any other return value continues. The default value is nil.