Skip to content

The x402 protocol

x402 is an open protocol for paying per HTTP request. It repurposes the underused HTTP 402 status code into a real payment challenge.

Stoka implements x402 v2 over Stellar USDC. Other deployments can target Ethereum, Base, Polygon — the protocol is chain-agnostic.

Anatomy of a paid request

1. Unpaid request

http
POST /v1/store HTTP/1.1
Host: api.stoka.space
X-Stoka-Key: note.txt
Content-Type: application/octet-stream
Content-Length: 42

<bytes>

2. Server returns 402 with payment requirements

http
HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "stellar:pubnet",
      "asset":  "CBIE…",
      "payTo":  "GAX4…",
      "maxAmountRequired": "1170",
      "maxTimeoutSeconds": 120,
      "extra": { "areFeesSponsored": true }
    }
  ]
}

maxAmountRequired is in the asset's smallest unit (1 USDC = 10,000,000). extra.areFeesSponsored: true means the facilitator will pay the Stellar network fees — the payer only needs USDC.

3. Client signs + retries

http
POST /v1/store HTTP/1.1
Host: api.stoka.space
X-Stoka-Key: note.txt
X-PAYMENT: base64(json({x402Version, accepted, payload:{transaction: XDR}}))
Content-Type: application/octet-stream

<bytes>

The signed payload is a Soroban transaction containing a SorobanAuthorizationEntry for the USDC contract's transfer function. The payer signs the entry's preimage with the wallet's Ed25519 key; a facilitator (third party) fee-bumps and submits to the network.

4. Server charges exactly maxAmountRequired and completes

http
HTTP/1.1 201 Created
Content-Type: application/json

{
  "owner_pubkey": "GBVY…",
  "key": "note.txt",
  "expires_at": "2026-05-16T18:00:00Z",
  "ttl_seconds": 2592000,
  "charged_atomic": 1170
}

If the facilitator returns an error (insufficient funds, missing trustline, rate-limited) the server returns another 402 so the client can decide whether to re-prompt or abort.

The x402 model has three properties session cookies don't:

  1. Stateless on both sides. No DB row for a login session.
  2. Receipts are on-chain. Auditing who paid how much doesn't require trusting the server's internal log — you can verify against the Stellar ledger.
  3. Priced precisely. The server quotes the exact cost for the exact payload; there's no overage risk.

The tradeoff is latency: the first paid call has a Soroban RPC simulate round-trip (~2 seconds on testnet). Subsequent calls pay that cost again. For agents that send a few requests per minute this is acceptable; for chatty ~100 rps workloads it is not.

References

MIT Licensed.