Behaviour for lifecycle hooks around client payment creation.
X402.Client.build_payment/3 runs the callbacks in this order:
before_payment/2— after a requirements entry has been selected and before anything is signed. Continue with{:cont, context}(the context's:requirementsmay be replaced, for example to pin a differentacceptsentry) or abort with{:halt, reason}, which surfaces as{:error, {:hook_halted, :before_payment, reason}}.after_payment/2— once thePaymentPayloadhas been signed, assembled and enriched. Continue with{:cont, context}; the context's:payloadmay be replaced and becomes the returned payload.on_payment_failure/2— when signing or enrichment fails afterbefore_payment/2has run. Continue with{:cont, context}(the context's:errormay be replaced) or recover with{:recover, payload}, which returns{:ok, payload}instead.
These mirror the onBeforePaymentCreation, onAfterPaymentCreation, and
onPaymentCreationFailure hooks of the reference TypeScript client.
Selection failures (:no_acceptable_requirements) happen before any hook
runs and never reach on_payment_failure/2.
A callback that raises or exits yields
{:error, {:hook_callback_failed, callback, reason}}; one that returns
anything outside its contract yields
{:error, {:hook_invalid_return, callback, value}}.
Hooks are invoked in the process that calls X402.Client.build_payment/3
(through X402.Client.Finch.request/3 or X402.MCP.Client.call/3, the
request process). X402.Client.Hooks.Default is the no-op implementation
used when no :hooks option is given.
Example
defmodule MyApp.PaymentHooks do
@behaviour X402.Client.Hooks
@impl true
def before_payment(context, _metadata) do
case context.requirements["amount"] do
amount when amount > "1000000" -> {:halt, :too_expensive}
_amount -> {:cont, context}
end
end
@impl true
def after_payment(context, _metadata) do
Logger.info("paying #{context.requirements["amount"]}")
{:cont, context}
end
@impl true
def on_payment_failure(context, _metadata), do: {:cont, context}
end
Summary
Types
Return type for after_payment/2.
Return type for before_payment/2.
Hook callback identifier.
Hook execution errors returned by X402.Client.build_payment/3.
Lifecycle callback metadata passed to hooks.
Return type for on_payment_failure/2.
Callbacks
Runs after the payment payload has been built.
Runs after requirements selection and before the payment is signed.
Runs when building the payment payload fails.
Functions
Validates that a value is a module implementing X402.Client.Hooks.
Types
@type after_result() :: {:cont, X402.Client.Hooks.Context.t()}
Return type for after_payment/2.
@type before_result() :: {:cont, X402.Client.Hooks.Context.t()} | {:halt, term()}
Return type for before_payment/2.
@type callback_name() :: :before_payment | :after_payment | :on_payment_failure
Hook callback identifier.
@type hook_error() :: {:hook_halted, callback_name(), term()} | {:hook_callback_failed, callback_name(), term()} | {:hook_invalid_return, callback_name(), term()}
Hook execution errors returned by X402.Client.build_payment/3.
@type metadata() :: %{ operation: :build_payment, hook_module: module(), scheme: String.t() | nil, network: String.t() | nil }
Lifecycle callback metadata passed to hooks.
@type on_failure_result() :: {:cont, X402.Client.Hooks.Context.t()} | {:recover, map()}
Return type for on_payment_failure/2.
Callbacks
@callback after_payment(X402.Client.Hooks.Context.t(), metadata()) :: after_result()
Runs after the payment payload has been built.
@callback before_payment(X402.Client.Hooks.Context.t(), metadata()) :: before_result()
Runs after requirements selection and before the payment is signed.
@callback on_payment_failure(X402.Client.Hooks.Context.t(), metadata()) :: on_failure_result()
Runs when building the payment payload fails.
Functions
Validates that a value is a module implementing X402.Client.Hooks.
Designed for NimbleOptions custom validation.
Examples
iex> X402.Client.Hooks.validate_module(X402.Client.Hooks.Default)
{:ok, X402.Client.Hooks.Default}
iex> X402.Client.Hooks.validate_module(Enum)
{:error, "expected a module implementing X402.Client.Hooks"}