x402 Payments
Bound an agent's x402 payments with its grant and budget, and keep each payment on the signed receipt of its call.
On this page
An agent that buys HTTP resources over x402 spends only what its grant allows. The kernel checks the grant and holds the budget before the payment is authorized, then signs one receipt that carries both the decision and the money outcome.
x402 plugs in as an optional payment module behind the kernel's PaymentAdapter port. You run a governed prepayment locally first, with no key, chain, or facilitator, then point the adapter at the facilitator you operate.
The kernel holds the budget before x402 moves money
The kernel decides whether the agent may spend, calls the payment adapter for one external authorization, and signs the receipt. The agent then sends the paid request to the x402 endpoint itself.
Holds and caps prevent spend before dispatch
The kernel checks the grant and records the hold against its budget and caps, then asks the configured adapter to authorize up to the quoted amount. A payment on the rail never authorizes a call by itself: the grant and the hold do. PaymentAdapter lifecycle.
PaymentAdapter lifecycle. Holds and caps prevent spend before dispatch; what the rail does is observed and recorded. The modules are off in default builds; custody and the facilitator service are left out.Settlement railsBefore dispatch, the kernel checks the grant, records the hold against the budget and caps, and calls authorize on the adapter for up to the quoted amount. The grant and the hold admit the call; a payment on the rail never authorizes one by itself. When a governed intent carries MustPrepay and no adapter is configured, the kernel refuses before dispatch.
After the call, the rail reports a RailSettlementStatus that folds into the receipt's SettlementStatus (NotApplicable, Pending, Settled, or Failed) beside the payment_reference. The kernel observes and records that outcome. The x402 HTTP exchange runs between the agent and the endpoint, and no Chio component terminates it.
Read more in Settlement rails.
The grant names the paying tool and caps what it spends
An agent pays only through a tool its capability grants. Each grant names a server_id, a tool_name, and a list of operations (invoke for a payment call), with the optional ceilings max_invocations, max_cost_per_invocation, and max_total_cost. The tool grant is the whole scope, with no dotted permission namespace beside it.
- Budgets. The kernel evaluates the upcoming payment against per-call and cumulative budgets, and refuses a call over a limit before any payment is sent.
- Revocation. Once a revocation is visible at the enforcement point, the kernel refuses new governed payment dispatches, even while the agent still holds the token. Revocation does not reverse a payment an external service already completed.
- Cross-currency pricing. When the settlement currency differs from the budget currency, the kernel prices the call through Chainlink or Pyth, applies the configured FX margin, and attaches the oracle evidence to the receipt.
- One record. The receipt that records the verdict carries the money outcome on
metadata.financial, so a receipt log ties each payment to the capability that permitted it without a join.
Route payment traffic through the kernel, and set host egress controls so the agent reaches the facilitator only through that path.
Read more in Capabilities and Budgets and metering.
1. Run a governed prepayment with no key or chain
Install the chio CLI, then put one governed call that mandates prepayment (MustPrepay) through an ephemeral kernel. The command wires the deterministic no-broadcast sim adapter and writes the signed receipt to --out.
curl -fsSL https://chio.computer/install.sh | sh$ chio mcp governed-sim \
--payment-adapter sim \
--governed-mustprepay \
--out ./receipt.jsonYou should see the command exit 0 with no output and one receipt in receipt.json. CI runs this same no-key call through examples/governed-x402-sim/smoke.sh.
2. Read the payment on the call's receipt
Print the decision and the financial metadata from the receipt.
$ jq '{id, decision, receipt_kind, financial: .metadata.financial}' ./receipt.json{
"id": "05cb8d13de28bf96c7220d74f45c1563f4d9f36fc8b0ac672f8d7c7ff9337a25",
"decision": {
"verdict": "allow"
},
"receipt_kind": "mediated_decision",
"financial": {
"budget_remaining": 900,
"budget_total": 1000,
"cost_breakdown": {
"payment": {
"adapter_metadata": {
"adapter": "sim",
"commerce": null,
"governed": {
"approvalTokenId": "governed-sim-approval-1",
"intentHash": "1ee415c06b0bb092d5c3fec07097fb41d192ee06d43649f404b543d31dd22f18",
"intentId": "governed-sim-intent-1",
"purpose": "no-key CI smoke",
"serverId": "governed-sim-srv",
"toolName": "compute"
},
"mode": "prepaid_no_broadcast"
},
"authorization_id": "sim-268afdc9129342029708eb795c87da08",
"preauthorized_units": 100,
"recorded_units": 100
}
},
"cost_charged": 100,
"currency": "USD",
"delegation_depth": 0,
"grant_index": 0,
"payment_reference": "sim-268afdc9129342029708eb795c87da08",
"root_budget_holder": "66c2cd97052842de29bda51688fcb33c87f6a74bd90a6c4546fe03b7479271b5",
"settlement_status": "settled"
}
}You should see allow and a settlement_status of settled. The payment is a branch of the receipt's cost breakdown, metadata.financial.cost_breakdown.payment, carrying the adapter that moved the money, the authorization_id it returned, and the governed intent the approval was bound to. Beside it sit cost_charged, budget_remaining, and settlement_status.
The sim adapter is deterministic, so authorization_id repeats across runs. The kernel keypair is ephemeral, so id, intentHash, and root_budget_holder change on every run.
3. Remove the adapter, and the kernel refuses before dispatch
A call that mandates prepayment never falls back to running unpaid. Run the identical intent with --payment-adapter none.
$ chio mcp governed-sim \
--payment-adapter none \
--governed-mustprepay \
--out ./deny.jsonerror[CHIO-ECONOMY-PREPAYMENT-REQUIRED]: the governed intent requires prepayment (settlement_mode=MustPrepay) and no payment adapter is configured help: pass --payment-adapter sim for a local run, or --payment-adapter http-x402 with a facilitator URL code: urn:chio:error:economy:prepayment-required docs: https://chio.computer/docs/reference/errors#error-economy-prepayment-required
You should see exit status 1 and the kernel's reason: the intent mandates prepayment and no payment adapter is configured. The refusal still writes --out, and the record is a signed receipt.
$ jq '{id, decision, financial: .metadata.financial}' ./deny.json{
"id": "fa761f9eb9d61ede8b6a3e320471e50c9d1eb4e4e234ede0ffd0079ae291e67d",
"decision": {
"verdict": "deny",
"reason": "governed transaction denied: governed intent mandates prepayment (settlement_mode=MustPrepay) but no payment adapter is configured",
"guard": "kernel"
},
"financial": {
"attempted_cost": 100,
"budget_remaining": 1000,
"budget_total": 1000,
"cost_charged": 0,
"currency": "USD",
"delegation_depth": 0,
"grant_index": 0,
"root_budget_holder": "d982de219319344a1f643e7fa1eda75e91cb47f1324ae9b4e45a7c1cf0eb23db",
"settlement_status": "not_applicable"
}
}The receipt records what the call would have cost on attempted_cost and 0 on cost_charged, and budget_remaining still equals budget_total. It carries no cost_breakdown, because no adapter ran, and settlement_status reads not_applicable.
4. Point the adapter at your x402 facilitator
Select the http-x402 mode at kernel-host configuration, with the facilitator's base_url and an optional bearer token. You supply the facilitator service, its custody, and the payment account.
pub struct X402PaymentAdapter {
base_url: String,
authorize_path: String,
bearer_token: Option<String>,
http: ureq::Agent,
}X402PaymentAdapter makes one remote call, the authorization, posted to the facilitator's /authorize endpoint. x402 completes final prepayment there (PrepaidFinal), so capture, release, and refund synthesize their results locally as prepaid bookkeeping and send no HTTP. A lower measured cost triggers no remote refund by itself.
The http-x402 mode is a payment-rail module that runs outside the kernel. With it enabled, the receipt keeps the shape you read in step 2, with the facilitator's authorization in place of the simulated one.
Each adapter mode makes a different number of remote calls
The host selects one adapter at configuration. Simulation is the default; the two HTTP modes delegate money movement to a facilitator you configure.
| Mode | Adapter | Remote calls per payment | Settlement |
|---|---|---|---|
sim | SimPaymentAdapter | None; no key or broadcast | Prepaid, deterministic |
http-x402 | X402PaymentAdapter | One: authorize | PrepaidFinal, per-request stablecoin |
http-acp | AcpPaymentAdapter | One per operation | ReversibleHold, shared payment token |
Choose http-acp when an external facilitator must confirm every transition: its adapter carries a path for authorize, capture, release, refund, and settlement state.
x402 protocol and interop reference
Try PAYMENT-SIGNATURE, source_protocol_version, or Eip3009NonceStore.
HTTP 402 exchange
The server uses HTTP 402 to request payment. In x402 V2, PAYMENT-REQUIRED carries the requirements, PAYMENT-SIGNATURE carries the retry's payment payload, and PAYMENT-RESPONSE carries the settlement response. The values are Base64-encoded JSON. The exchange below is illustrative, with symbolic payloads; the x402 HTTP documentation defines their schemas.
GET /v1/quote?sku=sku-301 HTTP/1.1
Host: pricing.larkfield.example
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <Base64 PaymentRequired JSON>
GET /v1/quote?sku=sku-301 HTTP/1.1
Host: pricing.larkfield.example
PAYMENT-SIGNATURE: <Base64 PaymentPayload JSON>
HTTP/1.1 200 OK
PAYMENT-RESPONSE: <Base64 SettlementResponse JSON>
Content-Type: application/json
{ "sku": "sku-301", "price": "140.00", "currency": "USD" }V1 used X-PAYMENT and X-PAYMENT-RESPONSE, with x402Version: 1; V2 uses x402Version: 2. The protocol migration guide covers the change. These public wire versions are distinct from the source-version literal that Chio's offline claim validator accepts.
Inbound payment claims
For the receiving direction, Chio ships an offline claim validator; it parses no payment headers and builds no 402 Payment Required response. It checks an external.x402.payment.v1 subject inside a proof envelope for a matching source version, four SHA-256 digests, a transaction passport reference that matches the envelope, an order id, network, asset, a non-zero amount, a status of authorized or settled, and a payment receipt reference bound into the envelope.
The validator accepts the source-version literal 0.5. A bound x402 claim whose source_protocol_version is any other value is rejected as an unsupported source version, and a claim carrying a refunded status is a hard claim failure.
Governed interoperability API
x402 has no crate of its own. It is one of four bounded payment-interop capabilities in chio-settle, each built on governed dispatch and settlement truth, with signed receipts staying the record:
- x402 payment-requirement projection.
build_x402_payment_requirementsturns one governed settlement dispatch into an x402 payment-requirement object, bound to a facilitator URL, a resource identifier, and an explicit accepted-token list. - EIP-3009 gasless transfer.
prepare_transfer_with_authorizationprepares onetransferWithAuthorizationdigest for review, and anEip3009NonceStorekeeps each nonce single-use. - Circle nanopayment evaluation.
evaluate_circle_nanopaymentevaluates one nanopayment candidate, only when operator-managed custody is declared explicitly. - ERC-4337 paymaster compatibility.
prepare_paymaster_compatibilityevaluates one paymaster compatibility record, bounded by explicit reimbursement ceilings.
Each function projects, prepares, or evaluates one record for an external system. The layer runs no payment-facilitator marketplace, takes no implicit custody handoff, and offers no universal gas sponsorship. Off-protocol facilitator state never changes a signed Chio receipt.
Where the payment code lives
The caller never assembles a payment envelope. Authorization, budget reservation, adapter dispatch, and receipt signing happen inside the kernel, so the caller uses the same capability, intent, and verdict as any other tool call. The payment-specific parts live in the four chio-settle::payments functions above and in chio-kernel::payment::X402PaymentAdapter. The ACP adapter carries one path per operation:
pub struct AcpPaymentAdapter {
base_url: String,
authorize_path: String,
capture_path: String,
release_path: String,
refund_path: String,
settlement_state_path: String,
bearer_token: Option<String>,
http: ureq::Agent,
}