x402 — Pay-per-request micropayments
x402 — Pay-per-request access
Section titled “x402 — Pay-per-request access”TCG API speaks x402, the HTTP 402 micropayment protocol built for AI agents. No account, no registration, no subscription — an agent that can hold USDC on Base or Solana can call every paid endpoint by attaching a signed payment to each request.
All existing X-API-Key auth keeps working unchanged. x402 is additive.
Quick map
Section titled “Quick map”- Discovery: /.well-known/x402.json
- Live endpoint / price map:
https://api.tcgapi.dev/v1/x402/info - Networks: Base mainnet and Solana mainnet — both settle in USDC (6 decimals).
- Facilitator: Coinbase CDP —
api.cdp.coinbase.com/platform/v2/x402— serves both chains. - Spec: github.com/coinbase/x402
The flow in three requests
Section titled “The flow in three requests”1. First request without payment → 402
Section titled “1. First request without payment → 402”curl -i https://api.tcgapi.dev/v1/cards/123Response:
HTTP/2 402content-type: application/jsoncache-control: no-storevary: X-PAYMENT{ "x402Version": 1, "error": "X-PAYMENT header is required", "accepts": [ { "scheme": "exact", "network": "base", "maxAmountRequired": "5000", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "payTo": "0x908B2Cc89A2387F754ba3C80aedb06F3457436Aa", "resource": "https://api.tcgapi.dev/v1/cards/123", "description": "Single card details", "maxTimeoutSeconds": 60, "extra": { "name": "USD Coin", "version": "2" } }, { "scheme": "exact", "network": "solana", "maxAmountRequired": "5000", "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "payTo": "AHk5DFmmdvPMjf6tZFrMPbHGhEBUDhUmcqmWkYANYthg", "resource": "https://api.tcgapi.dev/v1/cards/123", "description": "Single card details", "maxTimeoutSeconds": 60, "extra": { "feePayer": "BENrLoUbndxoNMUS5JXApGMtNykLjFXXixMtpDwDR9SP" } } ]}Pick whichever chain your agent already holds USDC on and sign against that entry.
2. Sign a payment payload
Section titled “2. Sign a payment payload”Base (EVM): Use the x402-fetch Node client — it picks the EVM entry from accepts[], EIP-712-signs a TransferWithAuthorization, and retries automatically.
import { wrapFetchWithPayment } from "x402-fetch";import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);const fetchWithPayment = wrapFetchWithPayment(fetch, account);
const res = await fetchWithPayment("https://api.tcgapi.dev/v1/cards/123");const data = await res.json();const txHash = res.headers.get("X-Payment-Response"); // base64-encoded settlementSolana: Use @x402/svm with a Solana keypair. The payload carries a pre-signed SPL TransferChecked instruction instead of an EIP-712 authorization; the outer envelope (scheme, network, base64 payload in X-PAYMENT) is identical.
import { ExactSvmSchemeV1 } from "@x402/svm/v1";import { toClientSvmSigner } from "@x402/svm";import { createKeyPairSignerFromBytes } from "@solana/kit";import { base58 } from "@scure/base";
const keypair = await createKeyPairSignerFromBytes(base58.decode(process.env.SOLANA_PRIVATE_KEY!));const client = new ExactSvmSchemeV1(toClientSvmSigner(keypair));
// Pick the solana entry from the 402 body, then:const payload = await client.createPaymentPayload(1, svmRequirement);const xPayment = Buffer.from(JSON.stringify({ ...payload, x402Version: 1 })).toString("base64");const res = await fetch("https://api.tcgapi.dev/v1/cards/123", { headers: { "X-PAYMENT": xPayment } });By hand: base64-encode {x402Version, scheme, network, payload} and retry with X-PAYMENT: <base64>. The payload shape differs per chain (EVM: signed authorization; SVM: { transaction: <base64 pre-signed tx> }).
3. Paid response
Section titled “3. Paid response”HTTP/2 200content-type: application/jsonx-payment-response: <base64(SettlementResponse)>cache-control: no-storevary: X-PAYMENT{ "data": { "id": 123, "name": "...", "tcgplayer_id": 456 }, "meta": {}, "payment": { "method": "x402", "tx_hash": "0x...", "amount_usdc": "5000" } }Price map
Section titled “Price map”All prices are atomic USDC (6 decimals on Base) per request.
| Endpoints | Atomic | USD |
|---|---|---|
/v1/cards/{id}, /v1/cards/{id}/prices, /v1/cards/tcgplayer/{id}, /v1/cards/{id}/prices/cardmarket, /v1/cardmarket/coverage | 5000 | $0.005 |
/v1/sets, /v1/sets/{id}, /v1/sets/{id}/cards, /v1/sets/{id}/prices, /v1/sets/{id}/prices/cardmarket | 5000 | $0.005 |
/v1/search, /v1/prices/top-movers, /v1/cards/{id}/history | 5000 | $0.005 |
/v1/cards/{id}/history/detailed | 20000 | $0.020 |
/v1/bulk/prices, /v1/bulk/cards, /v1/bulk/history | 50000 | $0.050 |
/v1/export/set/{id} | 250000 | $0.250 |
Not x402-enabled: /v1/bulk/resolve/tcgplayer and /v1/bulk/resolve/name (subscription-only — they use per-item credit accounting that doesn’t map to a single x402 charge).
Public endpoints (/v1/games, /v1/games/{slug}, /v1/games/{slug}/sets, /v1/auth/*) never require payment.
Operational notes
Section titled “Operational notes”- No double-charge on retries. Each EIP-3009 nonce is recorded server-side. Replaying the same
X-PAYMENTreturns 402. - No CDN caching of paid responses. Both 402 and paid 200 responses set
Cache-Control: no-storeandVary: X-PAYMENT. - Preflight is always free.
OPTIONSrequests return 204 and never trigger payment. - Rate limits don’t apply. x402 requests bypass the subscription daily-request quota (the payment is the rate limit).
Why x402?
Section titled “Why x402?”- No signup for your agents. Give an agent a USDC balance and it works.
- Settlement is on-chain. Nothing to reconcile; the tx hash is the receipt.
- Cheap. $0.005 is the floor for most read endpoints — cheaper than building and managing an API key for a one-off agent task.
- Backward compatible. Your existing
X-API-Keyintegrations don’t change.