By · Founder, Stacktree · Last updated
blog · build guide

Adding x402 to a real API, step by step.

Our publish endpoint has accepted autonomous stablecoin payments since June, and the numbers are public. This is the other half: what we actually built to get there, in the order we would build it again, including the parts that failed on mainnet first.

Get started free

What does it take to accept x402 payments?

Five things: an endpoint that answers unpaid requests with HTTP 402 and machine-readable payment requirements; a facilitator to verify and settle the signed USDC payment; an idempotent grant so retries cannot double-charge or double-mint; pricing that cannot bleed you (time-box anything with ongoing cost); and a discovery listing so agents can find you. We run all five in production on a Cloudflare Worker with no SDK. Days of work, plus a week of gotchas.

Step 1: price the thing honestly

Before any code: decide what a one-time payment buys, because an anonymous $1 payment that grants a perpetual obligation is a slow leak. Our model: $1 provisions a persistent API key at free-tier limits; individual unlocks are purchasable on top; and anything with ongoing cost to us (custom domains, elevated limits) is time-boxed at $5 per 30 days, renewed via a fresh 402. Bounded things are one-time, unbounded things expire. This rule shaped everything downstream.

Step 2: return a real 402, both versions

The protocol is HTTP with one twist: an unpaid request gets status 402 plus payment requirements (asset, network, amount, receiver). The twist inside the twist is versioning: x402 v2 carries requirements in a PAYMENT-REQUIRED header, v1 carries them in the body, and real wallets are split across both. We shipped v2-only first and watched a funded Coinbase wallet fail to pay us because it only spoke v1. Serve both. The client retries with a signed payment header; that is the whole dance. Our 402 requirements look like this (v2 shape; see the x402 docs for the full schema):

{
  "x402Version": 2,
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",            // Base mainnet
    "asset": "0x8335...2913",            // USDC contract
    "maxAmountRequired": "1000000",      // $1.00, 6 decimals
    "payTo": "0xcc98...4333",
    "resource": "https://api.stacktr.ee/provision",
    "extra": { "name": "USD Coin", "version": "2" }  // EIP-712 domain, see gotchas
  }]
}

Step 3: verify and settle via a facilitator

You do not need chain infrastructure. A facilitator exposes verify and settle endpoints: you POST the payment header, it checks the EIP-3009 signature, executes the on-chain USDC transfer, and pays the gas. We use Coinbase's CDP facilitator on Base mainnet, called with plain fetch; the auth is a per-request Ed25519 JWT we build with crypto.subtle, no SDK. Keep the facilitator URL configurable: it is the one dependency worth being able to swap. The two calls (CDP facilitator docs):

POST {facilitator}/verify  { paymentPayload, paymentRequirements }  // signature + funds check
POST {facilitator}/settle  { paymentPayload, paymentRequirements }  // executes transferWithAuthorization

The payment itself is an EIP-3009 transferWithAuthorization signed by the payer, so the facilitator can submit it and pay gas without ever holding funds.

Step 4: mint idempotently

Settlements retry, headers replay, networks flake. Every grant we issue is recorded with a unique constraint on (protocol, settlement reference), so a replayed settlement returns the original grant instead of minting twice:

CREATE TABLE payment_grants (
  id            TEXT PRIMARY KEY,
  protocol      TEXT NOT NULL,        -- 'x402' | 'mpp' | 'stripe' | 'credit'
  external_ref  TEXT NOT NULL,        -- settlement tx / session id
  payer         TEXT, amount TEXT, currency TEXT,
  api_key_id    TEXT NOT NULL,
  UNIQUE (protocol, external_ref)     -- the whole idempotency story
);

This one table is also your ledger, and it will disagree with the block explorer: our month-one numbers show why you should log every 402, verify, settle, and mint so you can reconcile the two.

Step 5: get discovered

Nobody types your API into a wallet. Agents find paid endpoints through scanners, so we self-host the discovery feed paths x402 scanners probe and appear on x402scan. That listing alone produced a buyer every two to three days, all month, with zero announcement. Config gotchas: your OpenAPI spec needs x-payment-info on paid routes (an empty security array means "free" to the scanner), and each route needs an input schema or the listing is rejected.

We implemented this twice, on purpose

Everything above describes the hand-rolled integration on api.stacktr.ee: our worker owns the 402, the facilitator calls, and the grants table. But there is a second, much faster mode, and we run that too: agents.stacktr.ee fronts the same product through agentcash's router, which handles the payment negotiation for us and is what carries the MPP-on-Tempo rail. Build-it-yourself buys you control, your own ledger, and no dependency; the router buys you extra rails in an afternoon. If you just want to charge agents for an API, start with a router and graduate to owning the 402 when the volume justifies it.

The gotchas that cost us live transactions

  • Base mainnet USDC signs as "USD Coin". The EIP-712 domain name is USD Coin (version 2); testnet uses USDC. Wrong name means an on-chain revert at settlement. Two live attempts died here; make the asset name configurable.
  • v1-only wallets are common. Including, at the time, Coinbase's own tooling. Dual-serve or lose payers silently.
  • Some agent payment clients cannot pay v2 endpoints at all. Check the client ecosystem's issue trackers before assuming a failed payment is your bug.
  • Never advertise rails that are not live. Our MPP, ACP, and AP2 code paths exist but gate off unless configured, and the scaffolded ones fail closed. A discovery badge that lies gets found out by an agent with money.

The human fallback

The dominant real-world case is still a human driving an agent in a terminal. So the 402 also advertises a fallback: the agent requests a pay session, prints a QR code, the human scans and pays by card via ordinary Stripe Checkout, and the agent polls to collect its key. Overpay and the surplus becomes a credit balance the agent draws down silently on later purchases, no 402 round-trip. Same grants table, different rail. Building this doubled the audience for the whole system.

FAQ

Frequent questions

How long does it take to add x402 to an API? +
The core loop (402 with requirements, verify and settle via a facilitator, grant on settlement) was days of work, not weeks, on a Cloudflare Worker with no SDK, just fetch. The long tail was gotchas: EIP-712 domain names, protocol version splits, and discovery-listing schemas. Budget a week to be honest.
Do you need your own crypto infrastructure? +
No. A facilitator (we use Coinbase's CDP facilitator; the endpoint is configurable) does on-chain verification and settlement, and even pays the gas. You need a wallet address to receive USDC and an off-ramp when it matters. What you must own is the application side: idempotent grants and honest SKUs.
What should you charge over x402? +
Small, flat, and honest to your costs. We charge $1 to provision a persistent API key and $1 to $5 for feature unlocks. The rule that matters: anything with ONGOING cost (a custom domain, elevated limits) is time-boxed and renews via a fresh 402; one-time payments only buy bounded things. A $1 payment that buys a perpetual obligation is a slow leak.
How do agents find an x402 endpoint? +
Discovery listings. We self-host the x402 discovery feed paths that scanners probe, and the listing on x402scan has generated a steady drip of real buyers (roughly one every two to three days) with zero announcement. Listing config gotcha: paid routes need x-payment-info in your OpenAPI spec; marking them with an empty security array means "free" to the scanner.
Does x402 replace Stripe? +
Not for us. Every subscription we have still arrives through ordinary Stripe Checkout; x402 serves a different buyer (agents and their operators, no signup, pay-per-action). We also accept MPP on Tempo over the same 402 flow (set up with agentcash's tooling, which is what unlocked the MPP rails for a UK entity), and built a QR scan-to-pay card fallback for the common case where a human is driving the agent. Treat x402 as a new front door, not a checkout replacement.
Keep reading

Related guides

References

Sources and further reading

See the flow live.

The endpoint this guide describes is in production: a 402, a $1 settlement, a persistent key. No signup on either side.

Sign up free →