Quickstart#
From nothing to a checkout an agent can pay, in about five minutes. Everything below runs in test mode, so no real money moves until you decide it should.
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",
"status": "open",
"test_mode": true
}
That URL is the product. Share it anywhere.
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": "105000",
"payTo": "0x234fE2A1D1df93fD9B907F0e1ad0c8b94E81FB5c",
"extra": { "providerAmount": "100000", "feeAmount": "5000" }
}],
"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.
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#
Two changes:
- Mint a live key —
c402 keys create --mode live - Drop
test_modewhen creating the checkout
Everything else is identical. The same code path settles real USDC on Base, splits the fee on-chain, and writes a receipt.
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