checkout402_
Get started

Quickstart#

From nothing to a checkout an agent can pay, in about five minutes. Everything below creates an unarmed checkout — it rehearses with simulated settlement, so no real money moves until you arm it.

1. Get a key#

c402 login --wallet $AGENT_PRIVATE_KEY   # signs a challenge, no email needed
c402 keys create --name quickstart --mode test
# Sign in at https://checkout402.com/login, then from the browser session:
curl -X POST https://api.checkout402.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"name": "quickstart", "mode": "test"}'

The key is shown once. Store it now.

2. Create a checkout#

c402 checkouts create \
  --title "Swiss company financials" \
  --description "Latest filed financials for a Swiss registered company." \
  --price 0.10 \
  --pay-to 0xYourPayoutWallet \
  --payload '{"company_name": "Example AG", "revenue": 12500000}' \
  --test
curl -X POST https://api.checkout402.com/v1/checkouts \
  -H "Authorization: Bearer $C402_KEY" \
  -H "content-type: application/json" \
  -d '{
    "title": "Swiss company financials",
    "description": "Latest filed financials for a Swiss registered company.",
    "price_usd": "0.10",
    "pay_to": "0xYourPayoutWallet",
    "payload": {"company_name": "Example AG", "revenue": 12500000},
    "test_mode": true
  }'
import httpx

r = httpx.post(
    "https://api.checkout402.com/v1/checkouts",
    headers={"Authorization": f"Bearer {KEY}"},
    json={
        "title": "Swiss company financials",
        "price_usd": "0.10",
        "pay_to": "0xYourPayoutWallet",
        "payload": {"company_name": "Example AG", "revenue": 12500000},
        "test_mode": True,
    },
)
print(r.json()["url"])

You get back a URL:

{
  "id": "chk_aiQQt5DHCTZMSIul",
  "url": "https://api.checkout402.com/c/chk_aiQQt5DHCTZMSIul",
  "test_url": "https://api.checkout402.com/c/chk_aiQQt5DHCTZMSIul/test",
  "status": "open",
  "test_mode": true
}

That URL is the product. Share it anywhere. test_mode: true means it is not armed yet: payments rehearse — same flow, simulated settlement, no funds — until you go live in step 5. test_url is the rehearsal address it keeps forever, even after arming.

3. See both faces#

Open it in a browser and you get a pay page. Ask for JSON and you get the machine face:

curl https://api.checkout402.com/c/chk_aiQQt5DHCTZMSIul
{
  "x402Version": 1,
  "accepts": [{
    "network": "eip155:8453",
    "maxAmountRequired": "110500",
    "payTo": "0x234fE2A1D1df93fD9B907F0e1ad0c8b94E81FB5c",
    "extra": { "providerAmount": "100000", "feeAmount": "10500" }
  }],
  "endpoint": {
    "title": "Swiss company financials",
    "description": "Latest filed financials for a Swiss registered company."
  }
}

HTTP status is 402. An agent can read the price, the fee, and what it's buying — before spending anything. The seller asked $0.10 and keeps $0.10; the $0.0105 fee (0.5% plus a fixed $0.01) is added on top, so the buyer pays $0.1105.

4. Pay it#

from pay402 import pay

goods = pay(
    "https://api.checkout402.com/c/chk_aiQQt5DHCTZMSIul",
    private_key=os.environ["BUYER_KEY"],
    max_usd="1.00",          # required for live payments
)
print(goods.payload)          # {'company_name': 'Example AG', 'revenue': 12500000}
print(goods.receipt.url)      # https://api.checkout402.com/r/pay_...

That one call does the whole loop: request, read the 402, sign an authorization, retry with X-PAYMENT, and hand back the goods plus a receipt.

max_usd is not optional for live payments

An agent looping on a paid endpoint with no ceiling is the failure that matters. pay() refuses a live payment without max_usd rather than defaulting to permissive.

5. Go live#

One command:

c402 checkouts go-live chk_aiQQt5DHCTZMSIul

That arms the checkout in place — same id, same URL, idempotent. The link you already shared is the one that now settles real USDC on Base, splits the fee on-chain, and writes a receipt. Rehearsal doesn't stop: the /test face keeps settling with no money, forever, and can never be armed — point your scripts there, share the bare URL.

(A live key — c402 keys create --mode live — creates checkouts that are born armed, for when you no longer want the rehearsal step.)

Check your payout address before you go live

pay_to is where the money lands, and on-chain payments are irreversible. Verify it character by character — a wrong-but-valid address sends funds somewhere unrecoverable.

Or verify it once: set a payout wallet on your account and you can drop pay_to from every request above. No wallet yet? c402 wallets new generates one on your machine.

What next#

  • Concepts — the object model, in one page
  • Sell an API — relay fulfilment, so buyers hit your real endpoint
  • Payout wallets — set where you get paid once, per chain
  • Connect Claude — let an agent create checkouts across your whole API