Before you debug
Four things resolve most reports, and they are faster to check than to read about:- Which environment.
CdpX402ClientandcreateX402Serverdefault to"production", which means mainnet and real funds. Omitting the option is not the same as running in development. - Which network. The CAIP-2 identifier has to match on both sides. A client registered for
eip155:8453cannot pay a route that only acceptseip155:84532. - The balance. Confirm the payer holds the token the route asks for, on that network.
- The credentials.
CDP_API_KEY_ID,CDP_API_KEY_SECRET, andCDP_WALLET_SECRETall need to be set, unless you are a seller receiving to an address you already control.
error field in the server’s JSON response before anything else. It usually names the
failure directly, and the codes are explained under
Error code reference.
Payment fails or the 402 persists
The endpoint still returns 402 after I attach a payment
The endpoint still returns 402 after I attach a payment
The server rejected the payment rather than ignoring it, so the reason is in the response body.
The usual causes, in rough order of frequency:
- The payer’s balance is too low, or holds the right token on the wrong network.
- The client and the route have no network and scheme in common.
CdpX402Clientregistersexactanduptoon Base only, so paying a route on Polygon, Arbitrum, World, or Solana requires adding that network throughnetworkSchemes. - The amount does not match. The
exactscheme requires equality on EVM, so neither underpayment nor overpayment settles. - The authorization expired before it reached the facilitator.
- The payer was declined by compliance screening. See A payment was declined by screening.
No scheme registered
No scheme registered
The client or the server never registered a handler for the scheme and network combination the
payment needs.On TypeScript this is rare, because
CdpX402Client and createX402Server register schemes for
you. When it does happen, it is because the route accepts a network outside the client’s
defaults: add it through networkSchemes on the client. On Python there are no defaults, so
every scheme is registered by hand, and this error means one was missed. It also appears when a
plain network name is passed where a CAIP-2 identifier is expected, since base and
eip155:8453 do not match as strings.invalid_payload or a schema validation failure
invalid_payload or a schema validation failure
The payload reached the facilitator but did not match the expected shape. Check, in order:
- Protocol version. A v1 client against a v2 server produces exactly this error. The
giveaway is
X-PAYMENTin the request instead ofPAYMENT-SIGNATURE. - Mixed package versions. The
@x402packages release in lockstep, so a stale@x402/evmagainst a current@x402/corecan send a payload the server rejects. Upgrade them together. - Price format. Route prices are strings such as
"$0.01", not numbers. - The signature itself. A wrong chain ID or an expired
validBeforefails validation rather than producing a signature error.
Signing fails in Python
Signing fails in Python
ExactEvmScheme expects an x402 signer, and an eth_account object declares sign_typed_data
differently. The scheme wraps an eth_account object in EthAccountSigner for you, so a
signing failure here usually means the object you passed is neither — a raw key, a viem-style
account, or a custom class. Pass a CDP account through EvmLocalAccount first. The working
setup is in step 2 of the buyer quickstart.It works on testnet but fails on mainnet
Four things change when you move, and any one of them produces a failure that looks like a broken integration:- The environment flag.
"production"is the default, so an integration that worked on testnet hadenvironment: "development"set explicitly somewhere. Removing it is what moves you to mainnet, and forgetting to remove it is what keeps you on testnet. - The network identifiers. Base is
eip155:8453, noteip155:84532. On Python, where there is no environment switch, every registration has to be updated by hand. - The balance. Testnet USDC does not exist on mainnet. Fund the payer with real USDC on the network the route accepts.
- The client’s networks.
CdpX402Clientregisters Base mainnet in production and Base Sepolia in development. If your route accepts Polygon, Arbitrum, World, or Solana, buyers have to add that network throughnetworkSchemeson either environment.
Settlement problems
Settlement timed out. Should I retry?
Settlement timed out. Should I retry?
Yes. A timed-out settle can still have landed onchain, but retrying the same authorization
cannot charge the buyer a second time: the
exact scheme’s authorization nonce is single-use, so
the facilitator rejects the replay with invalid_payload. Every scheme has an equivalent
protection.That reply is ambiguous on its own, though, because it looks the same whether the first attempt
settled or the payload was bad to begin with. To learn what actually happened, take the
transaction reference from the timed-out response and look it up on the network with
eth_getTransactionReceipt or the Solana equivalent. A confirmed transaction is a completed
payment, and no transaction reference means nothing was broadcast.A payment was declined by screening
A payment was declined by screening
The CDP Facilitator screens every payment against sanctions lists and Know Your Transaction risk
signals, checking the payer and the recipient. A declined payment returns
kyt_risk_detected
with a 403, so nothing moves onchain and the buyer keeps their funds. Screening runs at both
verification and settlement.This is not retryable. An address was declined rather than a request, so the same buyer is
declined again until they pay from a different account. If you believe an address was declined
incorrectly, raise it in Discord.A buyer may have been charged twice
A buyer may have been charged twice
A single authorization cannot settle twice on Base or Solana, so start by working out which of
two different things happened.If the payment payloads were identical across the requests, the likely story is that the first
settlement failed and the retry succeeded, which is one charge rather than two. If the payloads
differed, the buyer signed twice, and the usual reason is a client paying again to regain access
to a resource it had already paid for.That second case is a design problem rather than a bug, and there are two extensions that fix
it.
payment-identifier gives the client an idempotency key, so a repeated request returns the
original response instead of asking for payment again. sign-in-with-x gives the caller a
provable identity that persists across requests, so your server can recognize a returning buyer
and serve what they already bought. Neither is prescribed by the CDP SDK, so you configure them
by hand.Discovery problems
My endpoint is missing from the Bazaar
My endpoint is missing from the Bazaar
Run the validation endpoint first. It
identifies the missing requirement faster than working through the checklist by hand.An endpoint has to be served over public HTTPS, return valid Bazaar metadata on a
402, and
have settled at least one payment through the CDP Facilitator. Endpoints on localhost, behind
an authenticating proxy, or reachable only over plain HTTP are not indexed.If all of that holds, give it time. Indexing runs after the settled payment and takes up to 15
minutes.How do I read the validation response?
How do I read the validation response?
valid is the summary, and the fields under it explain how it was reached.preflightlists what was checked before any simulated payment. It separates failures, which block indexing, from advisory recommendations, which do not.bazaarExtensionreports whether your discovery metadata was found and parsed.simulation.outcomeis the result of a simulated payment.acceptedis the success signal.
valid: true and advisory recommendations will be indexed, but agents may
struggle to call it. Recommendations are usually about missing input schemas.EXTENSION-RESPONSES header, route consolidation,
ranking refresh timing, and removal for inactivity, see
Troubleshooting discovery.
Error code reference
The facilitator returns a reason string on every rejection:invalidReason when verification fails,
errorReason when settlement fails. The codes below are the ones the CDP Facilitator returns in
practice, which is a smaller set than the x402 specification defines.
Any payment
invalid_payload is the catch-all, so it covers more than a malformed body. A reused authorization
nonce, a failed onchain simulation, and a recipient that does not match the route all arrive as
invalid_payload.
EVM exact payments
Tokens that settle through Permit2 add a parallel family prefixed
invalid_exact_evm_permit2_payload_, covering signature, amount, deadline, recipient,
spender, valid_after, and allowance_required. allowance_required is the one to know: it means
the one-time Permit2 approval has not been granted yet.
Solana exact payments
Solana rejections are prefixed invalid_exact_svm_payload_transaction, with about twenty variants
that name the specific instruction or account at fault. The ones that come up most are
invalid_exact_svm_payload_transaction_simulation_failed,
invalid_exact_svm_payload_transaction_sender_ata_not_found when the payer has no associated token
account for the asset, and invalid_exact_svm_payload_transaction_amount_mismatch.
Settlement only
The last three are the ones worth handling deliberately, because the payment may or may not have
landed. Resolve them by confirming the transaction rather than by retrying.
Other schemes carry their own codes.
batch-settlement defines a large family prefixed
invalid_batch_settlement_evm_, while upto has no dedicated codes and surfaces its failures
through invalid_payload. The exhaustive list is in the
verify endpoint reference.
Getting help
For product and integration questions rather than errors, start with the FAQ. For anything else, the CDP Discord and the protocol and SDK issue trackers are listed under Community and developer resources. When you report a payment failure, include the CAIP-2 network, the scheme, theerror field from
the response, and the transaction reference if one exists. Without those, the first reply will ask
for them.