When a paid request lacks a valid X-PAYMENT header, the API responds with HTTP 402 and a JSON payment requirement using scheme exact_split.
Example 402 response
{
"error": "payment_required",
"x402Version": 1,
"scheme": "exact_split",
"resource": "POST /p/demo/summarize",
"description": "Summarize text endpoint",
"expiresAt": "2026-06-23T12:00:00.000Z",
"nonce": "<random>",
"requestHash": "<sha256>",
"paymentRequirementId": "<convex id>",
"accepts": [
{
"chain": "sui",
"network": "mainnet",
"asset": "USDC",
"totalAmount": "0.002",
"decimals": 6,
"coinType": "0x...::usdc::USDC",
"splits": [
{ "recipientType": "provider", "payTo": "0xprovider...", "amount": "0.0019" },
{ "recipientType": "platform", "payTo": "0xplatform...", "amount": "0.0001" }
]
},
{
"chain": "solana",
"network": "mainnet",
"asset": "USDC",
"totalAmount": "0.002",
"decimals": 6,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"splits": [
{ "recipientType": "provider", "payTo": "ProviderSolana...", "amount": "0.0019" },
{ "recipientType": "platform", "payTo": "PlatformSolana...", "amount": "0.0001" }
]
}
],
"cost": {
"inference": { "amount": "0.002", "asset": "USDC" },
"total": { "amount": "0.002", "asset": "USDC" },
"pricingSourceVersion": "2026-06-20"
}
}
Important fields
| Field | Purpose |
|---|---|
scheme |
Always exact_split — atomic multi-leg USDC payment |
accepts |
Payment options per chain; SDK selects one matching your chain config |
accepts[].splits[] |
Provider and platform legs (recipientType, payTo, amount) |
accepts[].totalAmount |
Sum of all split legs |
paymentRequirementId |
Convex ID binding proof to stored requirement |
nonce |
Single-use identifier; must appear in payment proof |
requestHash |
Binds payment to this exact request — must match on retry |
expiresAt |
Requirement expiry — pay before this timestamp |
cost |
Optional breakdown (endpoint price, platform fee) |
Free endpoints (price = 0) may have a single platform split (provider amount 0).
X-PAYMENT header
On retry, the SDK sends a base64-encoded JSON proof:
{
"x402Version": 1,
"scheme": "exact_split",
"chain": "sui",
"network": "mainnet",
"asset": "USDC",
"payer": "<user address>",
"txHashOrDigest": "<on-chain id>",
"paymentRequirementId": "<from 402>",
"nonce": "<from 402>",
"requestHash": "<from 402>",
"expiresAt": "<from 402>"
}
Use encodePaymentProof() and decodePaymentProof() from the SDK if building custom integrations. Use buildPaymentProof() to construct proofs consistently.
Request hash binding
The requestHash binds payment to:
- HTTP method and route path
- Request body hash (SHA-256 of JSON body)
- Endpoint price and resolved platform fee
- Split recipients and amounts
- Nonce and expiry
This prevents reusing payment on a different route, body, or pricing mode.
SDK selection
The SDK calls selectPaymentOption(requirement, chain) to pick the matching accept option. If your chain is not in accepts, you get unsupported_chain.
Your wallet adapter's pay() must send one atomic transaction covering all split legs.