Every API failure throws AgentApiError with three pieces of information you can act on:
import { AgentApiError } from ' @0xgasless/agent ' ;
await client . x402 . pay ({ agentId, to, value: ' 6000000 ' });
if (err instanceof AgentApiError ) {
console . log (err . status ); // 403
console . log (err . message ); // 'per_tx_cap_exceeded'
console . log (err . code ); // 'per_tx_cap_exceeded'
console . log (err . body ); // { requestedUSD: '6.000000', perTxCapUSD: '5' }
Field Description statusHTTP status from the platform — 400, 401, 403, 404, 500, 502. messageShort human-readable message. Safe to log. codeApp-level identifier when present (e.g. per_tx_cap_exceeded). Use this for branching logic, not message. bodyRaw JSON body the server returned, including any extra context (requestedUSD, allowedChains, etc.).
You sent something the platform can’t process. Fix the request and retry.
message / codeCause Fix agentId is requiredMissing required field Provide an agentId. agentId must be alphanumeric, _ or -, max 64 charsInvalid agentId shape Match ^[A-Za-z0-9_-]{1,64}$. value must be a positive integer stringvalue was empty, negative, or not a stringSend atomic units as a string, e.g. '500000'. validBefore window cannot exceed 3600s (anti-replay)Asked for >1h validity Keep validBefore within 1 hour of now. validAfter must be before validBeforeInverted window Send validAfter < validBefore. nonce must be 0x + 64 hex chars (32 bytes)Bad nonce Let the SDK generate it (default), or pass 32 valid bytes. Chain "X" not allowed for free tierTier doesn’t allow that chain Use an allowed chain or upgrade your tier. Token X not supported on YToken not registered for that chain See Supported Chains . Unsupported chainThe chain wasn’t registered with the facilitator Use a supported chain .
messageCause Fix Unauthorized — missing project contextMissing or malformed Authorization header Confirm your API key is set in apiKey. (any) — from npm install on a private package Old / wrong API key Regenerate the key in the dashboard.
The request was valid but the platform refused. Most policy violations land here.
codeBody extras Meaning per_tx_cap_exceededrequestedUSD, perTxCapUSDvalue exceeds the agent’s per-call cap.per_day_cap_exceededrequestedUSD, perDayCapUSDToday’s running total + the requested value would breach the per-day cap. Resets at UTC midnight. Chain X not in agent policyallowedChainsThe agent’s allowedChains doesn’t include the requested chain. Update with client.policy.setAgent(). Token X not in agent policyallowedTokensSame idea, for tokens. Agent X is revoked — cannot sign— Agent is permanently revoked. Create a new agent. Agent X is paused — cannot sign— Agent is paused. Reactivate via the dashboard. Agent limit reached. <Tier> plan allows N agents.tier, limit, current, upgradeUrlYou’ve hit your tier’s agent cap. Revoke unused agents or upgrade. x402 is not enabled for this projectx402Enabled: falseCall client.policy.enableX402() once.
messageCause Fix Agent X not found in project YThe agent doesn’t exist (yet) Call client.agents.create(). Project Y not foundThe API key is somehow orphaned (rare) Generate a new key in the dashboard.
The platform reached an unexpected state or an upstream dependency failed.
messageCause Fix Signing failed: ...KMS or HD derivation failed Retry; if persistent, contact support. Spend tracking error: ...DynamoDB write failed Retry. Facilitator: ... (502)The facilitator returned a non-2xx Inspect err.body — usually a contract revert reason. Facilitator: transaction execution revertedOn-chain settlement reverted Common causes: agent holds none of the payment token (USDC/XSGD) on the chain; nonce reuse; agentURI too long (for identity); XSGD only — token paused or a party blacklisted by the issuer. Retry with a fresh nonce after fixing the cause. Facilitator unreachable: ...Network issue Retry with backoff.
async function payWithRetry ( input : PayInput , attempts = 3 ) {
for ( let i = 0 ; i < attempts; i ++ ) {
return await client . x402 . pay (input);
if ( ! (err instanceof AgentApiError )) throw err;
// 4xx is a client problem — don't retry
if (err . status >= 400 && err . status < 500 ) throw err;
// 5xx is transient — backoff and retry
await new Promise ( ( r ) => setTimeout (r , 500 * 2 ** i));
throw new Error ( ` Gave up after ${ attempts } attempts ` );
await client . x402 . pay ({ agentId, to, value });
if (err instanceof AgentApiError && err . status === 403 ) {
case ' per_tx_cap_exceeded ' :
// Maybe break the payment into smaller chunks
case ' per_day_cap_exceeded ' :
// Wait for UTC midnight or fall back to a different agent
function describeError ( err : unknown ) : string {
if (err instanceof AgentApiError ) {
if (err . code === ' per_tx_cap_exceeded ' ) {
return ` This payment is too large. Per-call cap is $ ${ err . body ?. perTxCapUSD } . ` ;
if (err . code === ' per_day_cap_exceeded ' ) {
return ` Daily spending cap reached. Resets at UTC midnight. ` ;
Payments — full list of policy checks that produce 403s.
Policy — how to widen agent caps.