We've wired up the digital storefront so an AI agent can run the whole purchase loop itself: discover a product, receive a payment challenge, pay in USDC on Base mainnet, and get the product delivered — no Stripe session, no facilitator, no human approving the transfer. It's the x402 protocol implemented as a self-custody machine-payment path beside the existing agent commerce layer, and it runs on a Cloudflare Worker that is read-only against the chain.
This post walks the actual implementation: the four-step challenge → pay → verify → deliver flow, then the engineering decisions that make on-chain payments safe without a trusted third party — per-order derived recipient addresses, strict exact-amount verification, a second-RPC cross-check, and fail-closed invariants.
The flow: challenge → pay → verify → deliver
x402 is an HTTP-native payment protocol: a merchant answers a request with 402 Payment Required and a machine-readable challenge, the agent pays, the merchant verifies on-chain, and the agent gets its content. Datanest's implementation lives at GET /api/x402/products/{id} on the agent-MCP Worker.
1. Challenge. The agent requests a product with no proof. The Worker mints a 128-bit secret order id, derives a per-order recipient address, computes the exact price, and durably writes the order — if that write fails, it returns 503 rather than handing out a challenge whose record isn't durable. The response is a 402 with a base64 PAYMENT-REQUIRED header describing the accepted payment (scheme exact-transfer, network eip155:8453, the USDC asset, the exact amount, and the derived payTo address), plus the secret order id in an X402-Order-Id header. The order expires after X402_ORDER_TTL_SECONDS (default 900 seconds).
2. Pay. The agent transfers exactly the price in USDC to that order's payTo address. Because the recipient address is unique per order, the exact amount is the only constraint — no nonce, no overcharge.
3. Verify. The agent retries the same URL, now carrying PAYMENT-SIGNATURE: <tx-hash> and X402-Order-Id. The Worker fetches the receipt, requires a successful transaction (status === 0x1) at valid block heights with at least X402_MIN_CONFIRMATIONS confirmations (default 5), and decodes a strict 3-topic + 1-word ERC-20 Transfer event to the order's address for exactly the price — exact ===, never >=.
4. Deliver. On success the order is marked paid (with the payer's from address recorded) and the product zip streams from R2 with a PAYMENT-RESPONSE header. Re-downloading a paid order is idempotent.
Why the tricky parts matter
The unglamorous part of machine payments is replay protection. A tx hash is public, so it is never trusted alone: delivery requires both the secret order id (only ever handed to the payer, never written on-chain) and a transfer to that order's own derived address.
The derived address is a non-hardened child of the merchant master public key:
tweak = keccak256("x402-order-v1" ‖ orderId ‖ productId ‖ network) mod n
child_pub = master_pub + tweak·G
address = last 20 bytes of keccak256(uncompressed child_pub)
Because the tweak is seeded by the 128-bit order id, a paid transaction for one order can never satisfy another — address collision is on the order of 2¹²⁸. This replaced an earlier amount-binding scheme (price + 4-digit nonce) that had only 10⁴ entropy and was forceable via a few thousand free challenges. The merchant sweeps a child offline with child_sk = (master_sk + tweak) mod n, so funds sent to any derived address remain recoverable — without the Worker ever holding a signing key. It holds only the master public key and address; the private key lives offline and is used solely to sweep the master and derived addresses.
Verification also distrusts a single RPC provider. If X402_RPC_URL_VERIFY is configured, the Worker re-fetches the receipt from a second independent provider and requires agreement on status, block, and the decoded transfer — disagreement fails closed. The fail-closed list also covers a missing or invalid X402_MASTER_PUB (x402 disables itself rather than issuing weakly-bound challenges), an invalid cross-check URL, and any order-write failure. The default verification path additionally retries its primary RPC twice and fails over across a list of public endpoints.
Two smaller details worth stealing: optional payer binding — if the agent declared an X402-Payer header at challenge time, the verified transfer's from must match it or delivery is rejected with a payer_mismatch; and no full order ids ever reach the logs, only a prefix.
Current state, honestly: the x402 routes are live on Base mainnet and the challenge path is reliable. Verification is code-correct but depends on RPC reachability — production-grade reads want an API-keyed RPC endpoint and the second-provider cross-check wired in as operator config. Until then the code fails closed instead of issuing weakly-bound challenges.
What this unlocks
The interesting bit is less "crypto checkout" and more "autonomous buyer." The same Worker already exposes an MCP server at https://datanest-stores.com/mcp with tools to search the catalogue, inspect products, compare them, and prepare Stripe checkout links. x402 adds the self-custody leg: an agent with a funded wallet can complete the whole loop — browse, choose, pay, download — with no card rails and no human in the loop.
The full public catalogue is available at https://datanest-stores.com/catalog.json, and the MCP server (plus its REST API under /api/agent/v1) lives at https://datanest-stores.com/mcp. If you're building agents that buy things, that's a live storefront to point them at.
Top comments (0)