x402 Machine Payments

HTTP 402 as a payment rail — software pays USDC for what it uses, at nanopayments scale.

Most of the internet's customers are software. x402 makes HTTP-native payments real: a machine requests a paid resource, the server answers 402 Payment Required with machine-readable terms, the client pays and retries, and gets its data. No accounts, no API keys, no invoices.

The 402 challenge

Call POST /api/quote identifying as an external agent (x-corridor-client: external-agent) without paying:

curl -s -X POST https://transvia.xyz/api/quote \
  -H "content-type: application/json" \
  -H "x-corridor-client: external-agent" \
  -d '{"corridor":"USD-EUR","amountUsdc":100}'

The response is 402 Payment Required with the terms:

{
  "x402Version": 1,
  "error": "X-PAYMENT header is required for agent access",
  "accepts": [
    {
      "scheme": "exact",
      "network": "arc-testnet",
      "maxAmountRequired": "10000",
      "resource": "https://transvia.xyz/api/quote",
      "description": "Transvia FX quote (60s TTL)",
      "mimeType": "application/json",
      "payTo": "0x…treasury",
      "asset": "USDC",
      "maxTimeoutSeconds": 30,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ]
}

Price: 0.01 USDC per quote on Arc Testnet. maxAmountRequired is in 6-decimal USDC units — "10000" is 0.01 USDC.

The whole protocol as a UML sequence diagram:

     UML sequence diagram — the x402 handshake (402 → pay → 200)

  Agent                                    Resource (Transvia API)
    │                                             │
    │──GET /api/quote (no payment)───────────────▶│
    │                                             │  402 challenge:
    │◀────────────────────────────────────────────│  scheme exact · arc-testnet
    │                                             │  maxAmountRequired 10000
    │  signs EIP-3009 TransferWithAuthorization   │
    │  (offchain signature — no tx, no gas)       │
    │                                             │
    │──retry with x-payment header───────────────▶│
    │                                             │  verify: recover EIP-712
    │                                             │  signer, match payer
    │◀────────────────────────────────────────────│  200 OK + quote body

The paid retry

Build the payment: an EIP-3009 TransferWithAuthorization — the USDC holder signs "pay up to 0.01 USDC to the treasury" offchain — JSON-encoded, base64-wrapped, and sent as the x-payment header. Retry the same request with the header. The x402 verifier recovers the EIP-712 signer, matches it to the declared payer, and returns 200 with the quote. Verification is cryptographic on both the simulated and live rails — a single flipped byte in the signature is rejected.

Honesty note: the signature is fully verified on every request; settling that authorization onchain via a USDC transferWithAuthorization call is the documented next step (a facilitator service). Transvia never claims funds moved onchain for machine quote payments.

Nanopayments scale

x402 is not only for agents buying quotes for themselves. Transvia's own automation agent runs on the same rail — and its economics only work because payments can be tiny:

What the agent buysCost
FX feed refresh while transfers are in flight$0.000001
Fee-split batch booking at settlement$0.000001

A million FX feed updates cost one dollar. That is the point: resources get metered per call, and software buys exactly what it needs. How these purchases are decided and logged is in Automation Agents.

Replay the handshake live

POST /api/x402/demo replays the protocol steps against the live API — the real 402 challenge from the quote endpoint, a real EIP-3009 signature built by the rail's internal agent wallet, and the paid retry:

curl -s -X POST https://transvia.xyz/api/x402/demo
{
  "steps": [
    { "step": 1, "label": "Agent → Transvia /api/quote (no payment)", "status": 402 },
    { "step": 2, "label": "Agent builds X-PAYMENT header (real EIP-3009 signature)", "status": "local" },
    { "step": 3, "label": "Agent retries with X-PAYMENT → /api/quote", "status": 200 }
  ],
  "ok": true
}

Each step also carries the full response bodies (trimmed here). ok: false with a skipped step 3 means no operator key is configured — the demo says so instead of fabricating a payer. Every payment the API verifies lands in the machine-economy ledger at GET /api/agent/payments.

A full agent handshake snippet is in Examples.