← all guides
tutorialPublished 2026-04-22 · updated 2026-05-02

How AI agents pay for resources with x402 — a working example

TL;DRAn AI agent that needs an SMS OTP number sends a normal HTTP request to /v1/sms/otp. The server replies 402 with an x402 manifest specifying $0.10 in USDC on Base, payTo, and a quote. The agent's wallet signs the transfer, the agent replays the request with an X-Payment header, and the server returns a real US phone number plus a polling URL. The whole round-trip takes under one second.

What you will build

A Python script that buys a one-time SMS OTP number from Agent402 Stock for $0.10 in USDC on Base. The script does not register, does not hold an API key, and does not need a credit card. It uses an existing Coinbase AgentKit wallet to sign the on-chain payment.

The script makes two HTTP calls. The first returns 402 and tells you how to pay. The second includes the signature and returns the number.

Step 1 — make the unpaid request

Start with a plain GET request. No headers, no body. The server responds with HTTP 402 and a JSON manifest.

import requests

resp = requests.get("https://api.agent402stock.xyz/v1/sms/otp")
print(resp.status_code)        # 402
print(resp.json()["accepts"])  # payment options

The accepts array lists each payment option the server will admit. For Agent402 Stock the default is USDC on Base, $0.10 (100 000 base units), with the payTo address you can also see in the published x402 manifest at /.well-known/x402.json.

Step 2 — sign the USDC transfer

An x402 wallet builds an EIP-712 typed payload that describes the intended USDC transfer. AgentKit, Crossmint, and Privy all expose a signX402 helper that takes the accepts entry and returns a base64-encoded signed payload.

from coinbase_agentkit import Wallet

wallet = Wallet.load("agent.json")
payment = wallet.sign_x402(resp.json()["accepts"][0])
# payment is a base64 string ready for the X-Payment header

If you do not want to use a wallet SDK, the canonical signing rules are documented in the x402 spec and amount to a deterministic EIP-712 hash plus an ECDSA signature with your wallet's private key.

Step 3 — replay the request with X-Payment

Send the same request again with the signed payload in the X-Payment header. The server submits the transfer, waits for inclusion in a Base block, and returns the resource.

resp2 = requests.get(
    "https://api.agent402stock.xyz/v1/sms/otp",
    headers={"X-Payment": payment},
)
data = resp2.json()
# {"phone": "+1...", "poll_url": "https://api.agent402stock.xyz/v1/sms/otp/<id>"}

The poll_url is the agent's read endpoint for incoming SMS. Polling is free for the lifetime of the OTP number — the agent only paid the one-shot $0.10 reservation fee.

What can go wrong

If the signature is malformed the server returns 402 again with an error field. If the wallet has insufficient USDC the chain rejects the transfer and the server responds 402 with reason "insufficient_balance". Both are recoverable — refresh the wallet, fix the signature, retry.

If the resource is no longer available the server returns 410 Gone instead of 402. Agents should treat 410 as terminal and not retry.

Frequently asked

Do I need to register before I can use Agent402 Stock?

No. There is no signup, no API key, no dashboard. The agent's wallet is the identity. The first 402 response you receive includes everything needed to pay.

Which wallets work with Agent402 Stock?

Any wallet that can sign an EIP-712 USDC transfer on Base. Tested with Coinbase AgentKit, Crossmint, Privy, and raw viem/ethers + a private key.

What if the SMS never arrives?

Agent402 Stock guarantees at least one inbound SMS within ten minutes or the payment is refunded automatically to the same wallet. The refund hits within five minutes of the timeout.

Related