{
  "$comment": "The CoRelayer error catalogue. Generated from docosaurus/scripts/lib/error-catalogue.ts and checked against components.schemas.ErrorCode in the OpenAPI document on every build.",
  "documentation": "https://docs.co-relayer.com/errors",
  "errors": [
    {
      "code": "MALFORMED_REQUEST",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/malformed-request",
      "summary": "The request body did not match the schema of the endpoint.",
      "hint": "Read `details.field`, fix the request and send it again. Validate against `/openapi.yaml` before retrying in a loop.",
      "details": [
        "field"
      ]
    },
    {
      "code": "VARIANTS_NOT_SUPPORTED",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/variants-not-supported",
      "summary": "The request carried several signed variants of the same transaction.",
      "hint": "Call the assign endpoint, put the relayer it returns into the transaction, sign once, and relay that one transaction."
    },
    {
      "code": "RELAYER_SIGNATURE_PRESENT",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/relayer-signature-present",
      "summary": "The transaction already had a `relayerSignature`.",
      "hint": "Remove `relayerSignature` and send the transaction with only the sender (and guardian) signature."
    },
    {
      "code": "CHAIN_ID_MISMATCH",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/chain-id-mismatch",
      "summary": "The transaction was signed for a different network than this host serves.",
      "hint": "Rebuild the transaction with the chain id from `GET /v1/network` on the host you are calling, and sign it again."
    },
    {
      "code": "TX_VERSION_UNSUPPORTED",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/tx-version-unsupported",
      "summary": "The transaction `version` is not one CoRelayer relays.",
      "hint": "Rebuild the transaction with a supported version and sign it again."
    },
    {
      "code": "TX_OPTIONS_UNSUPPORTED",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/tx-options-unsupported",
      "summary": "The transaction `options` field has a bit CoRelayer does not relay.",
      "hint": "Clear the unsupported bits, rebuild and sign again."
    },
    {
      "code": "LEASE_MISSING",
      "status": 400,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/lease-missing",
      "summary": "The relay request arrived without the lease returned by the assign call.",
      "hint": "Call the assign endpoint first and send the lease it returns with the transaction."
    },
    {
      "code": "LEASE_INVALID",
      "status": 403,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/lease-invalid",
      "summary": "The lease did not verify.",
      "hint": "Request a fresh assignment. Never edit a lease; it is opaque."
    },
    {
      "code": "LEASE_MISMATCH",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/lease-mismatch",
      "summary": "The lease does not belong to this transaction.",
      "hint": "Assign again for the sender you are actually relaying, then sign that transaction."
    },
    {
      "code": "LEASE_EXPIRED",
      "status": 409,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/lease-expired",
      "summary": "The lease was older than its validity window when the transaction arrived.",
      "hint": "If `details.renewable` is true, renew the lease and resend the same signed bytes. Otherwise assign again and sign once more.",
      "details": [
        "renewable"
      ]
    },
    {
      "code": "NONCE_PIN_MISMATCH",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/nonce-pin-mismatch",
      "summary": "The transaction nonce is not the nonce the assignment pinned.",
      "hint": "Discard this signature. Assign again, use `assignment.pinNonce`, and sign that transaction."
    },
    {
      "code": "RESIGN_REQUIRED",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NEW_SIGNATURE_SAME_NONCE",
      "type": "https://docs.co-relayer.com/errors/resign-required",
      "summary": "The assigned relayer can no longer be used, so the transaction must be signed once more.",
      "hint": "Take the new relayer from the `assignment` member, rebuild the transaction with the same nonce, and have the user sign it — once.",
      "details": [
        "assignment"
      ]
    },
    {
      "code": "RESIGN_SAME_NONCE",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NEW_SIGNATURE_SAME_NONCE",
      "type": "https://docs.co-relayer.com/errors/resign-same-nonce",
      "summary": "A replacement for the same nonce is needed, at a higher gas price.",
      "hint": "Rebuild with the same nonce and at least `details.minGasPrice`, then sign once.",
      "details": [
        "assignment",
        "minGasPrice"
      ]
    },
    {
      "code": "REPLACEMENT_UNDERPRICED",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/replacement-underpriced",
      "summary": "The replacement transaction does not pay enough to displace the one in the pool.",
      "hint": "Sign a replacement with at least `details.minGasPrice`, or wait for the pending one to execute.",
      "details": [
        "minGasPrice"
      ]
    },
    {
      "code": "INTENT_ALREADY_EXECUTED",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/intent-already-executed",
      "summary": "That nonce has already executed on chain.",
      "hint": "Read `intent.txHash` and treat the work as done. Do not sign again.",
      "details": [
        "intent.txHash"
      ]
    },
    {
      "code": "NOTHING_TO_CANCEL",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/nothing-to-cancel",
      "summary": "There is no in-flight intent to cancel.",
      "hint": "Read the current state with the intent status endpoint before cancelling."
    },
    {
      "code": "NONCE_TOO_LOW",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/nonce-too-low",
      "summary": "The transaction nonce is below the account nonce on chain.",
      "hint": "Read `details.expectedNonce`, rebuild with it, sign once.",
      "details": [
        "onchainNonce",
        "poolLastNonce",
        "expectedNonce"
      ]
    },
    {
      "code": "NONCE_IN_FLIGHT",
      "status": 409,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/nonce-in-flight",
      "summary": "Another intent already holds this nonce.",
      "hint": "If `resign` is `SAME_BYTES`, resend the identical bytes — that is safe. Otherwise wait for the in-flight intent to settle, or cancel it.",
      "details": [
        "occupiedBy",
        "pinnedNonce"
      ]
    },
    {
      "code": "NONCE_GAP",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/nonce-gap",
      "summary": "The nonce skips ahead of the account nonce and the pool.",
      "hint": "Fill the gap first, or rebuild at the next usable nonce and sign once."
    },
    {
      "code": "TOO_MANY_IN_FLIGHT",
      "status": 429,
      "group": "relay",
      "retryable": true,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/too-many-in-flight",
      "summary": "This sender has as many unsettled intents as it may have at once.",
      "hint": "Wait for an intent to reach a terminal state, then send the next one."
    },
    {
      "code": "RELAYER_UNKNOWN",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/relayer-unknown",
      "summary": "The `relayer` address in the transaction is not one of ours.",
      "hint": "Call the assign endpoint and use the relayer it returns."
    },
    {
      "code": "RELAYER_SHARD_MISMATCH",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/relayer-shard-mismatch",
      "summary": "The relayer is not in the sender’s shard.",
      "hint": "Assign again for this sender; assignment always picks a relayer in the right shard."
    },
    {
      "code": "RELAYER_RETIRED",
      "status": 410,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/relayer-retired",
      "summary": "The relayer in the transaction has been retired.",
      "hint": "Assign again and sign the new transaction once. On the native path this normally arrives as `RESIGN_REQUIRED` instead."
    },
    {
      "code": "GAS_PRICE_OUT_OF_RANGE",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/gas-price-out-of-range",
      "summary": "The gas price is below the network minimum or above the cap CoRelayer relays.",
      "hint": "Read `details.bound` (`min` or `max`) and `details.limit`, rebuild inside the range, sign once.",
      "details": [
        "limit",
        "actual",
        "bound"
      ]
    },
    {
      "code": "GAS_LIMIT_TOO_LOW",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/gas-limit-too-low",
      "summary": "The gas limit is below the movement gas of the transaction.",
      "hint": "Raise `gasLimit` to at least `details.limit` and sign once.",
      "details": [
        "limit",
        "actual"
      ]
    },
    {
      "code": "GAS_LIMIT_TOO_HIGH",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/gas-limit-too-high",
      "summary": "The gas limit is above the ceiling of your rate class.",
      "hint": "Lower `gasLimit` below `details.limit`, or move to a tier whose rate class allows more.",
      "details": [
        "limit",
        "actual"
      ]
    },
    {
      "code": "GAS_OVERPROVISIONED",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/gas-overprovisioned",
      "summary": "The gas limit is far above what simulation says the transaction needs.",
      "hint": "Set `gasLimit` close to the simulated cost — the endpoint accepts up to 1.9× the simulated processing gas above movement gas.",
      "details": [
        "limit",
        "actual"
      ]
    },
    {
      "code": "DATA_TOO_LARGE",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/data-too-large",
      "summary": "The transaction data field is larger than self-serve accounts may send.",
      "hint": "Shrink the payload. Larger payloads and contract deployments need an account allow-list entry — contact support.",
      "details": [
        "limit",
        "actual"
      ]
    },
    {
      "code": "RECEIVER_NOT_ALLOWED",
      "status": 403,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/receiver-not-allowed",
      "summary": "The receiver of the transaction is not allowed on this path.",
      "hint": "Relay it on a paid path, or send it to an allowed receiver. For a sponsor key, add the contract to the key's receiver list; an NFT, SFT, Meta-ESDT or multi-token transfer has to be paid by the sender's own plan or a plan that names the sender."
    },
    {
      "code": "SENDER_SIGNATURE_INVALID",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/sender-signature-invalid",
      "summary": "The sender signature does not verify against the transaction bytes.",
      "hint": "Rebuild the transaction, sign it once, and send exactly the bytes that were signed."
    },
    {
      "code": "GUARDIAN_SIGNATURE_INVALID",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/guardian-signature-invalid",
      "summary": "The guardian signature does not verify.",
      "hint": "Have the guardian sign the final bytes, then relay."
    },
    {
      "code": "GUARDIAN_REQUIRED",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/guardian-required",
      "summary": "The sender is guarded but the transaction is not.",
      "hint": "Rebuild as a guarded transaction, collect the guardian signature, then relay."
    },
    {
      "code": "GUARDIAN_MISMATCH",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/guardian-mismatch",
      "summary": "The guardian in the transaction is not the sender’s active guardian.",
      "hint": "Read the account’s active guardian from the network and rebuild."
    },
    {
      "code": "GUARDIAN_IS_RELAYER",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/guardian-is-relayer",
      "summary": "The guardian and the relayer are the same address.",
      "hint": "Assign a different relayer and sign once."
    },
    {
      "code": "INSUFFICIENT_SENDER_BALANCE",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/insufficient-sender-balance",
      "summary": "The sender cannot cover the `value` it is trying to move.",
      "hint": "Fund the sender, or lower `value`, then relay."
    },
    {
      "code": "SIMULATION_FAILED",
      "status": 422,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/simulation-failed",
      "summary": "Pre-flight simulation says the transaction would fail on chain.",
      "hint": "Read `details.returnMessage`, fix the call, and sign a corrected transaction.",
      "details": [
        "returnMessage"
      ]
    },
    {
      "code": "SWAP_VENUE_PAUSED",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/swap-venue-paused",
      "summary": "The exchange venue used to convert USDC is paused.",
      "hint": "Retry later with the same bytes. Nothing was charged. This never affects relaying an existing plan."
    },
    {
      "code": "CONTRACT_PAUSED",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/contract-paused",
      "summary": "The CoRelayer contract is paused for this kind of call.",
      "hint": "Retry later with the same bytes. An existing plan keeps working; nothing was charged.",
      "details": [
        "scope"
      ]
    },
    {
      "code": "ASSIGN_PROOF_REQUIRED",
      "status": 401,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/assign-proof-required",
      "summary": "The assign call needs a proof that the sender is present.",
      "hint": "Sign the presence message with the sender key and call assign again.",
      "details": [
        "serverTimeMs"
      ]
    },
    {
      "code": "ASSIGN_PROOF_INVALID",
      "status": 401,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/assign-proof-invalid",
      "summary": "The presence proof did not verify.",
      "hint": "Sign the bytes of the message directly with the sender key (sdk-core `UserSigner.sign`), read `details.serverTimeMs`, rebuild the proof for this host’s chain id, and call assign again.",
      "details": [
        "serverTimeMs"
      ]
    },
    {
      "code": "FREE_FLOW_BUSY",
      "status": 409,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/free-flow-busy",
      "summary": "This sender already has a free transaction in flight.",
      "hint": "Wait for the free intent to settle, then send the next one.",
      "details": [
        "reason"
      ]
    },
    {
      "code": "FREE_FLOW_BARRED",
      "status": 403,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/free-flow-barred",
      "summary": "This sender is temporarily barred from the free flow.",
      "hint": "Wait until `details.untilMs`, or pay the gas yourself for this transaction.",
      "details": [
        "untilMs"
      ]
    },
    {
      "code": "FREE_FLOW_UNAVAILABLE",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/free-flow-unavailable",
      "summary": "The free-transaction budget for this period is spent.",
      "hint": "Pay the gas yourself for this one, or retry later. Paid relaying is unaffected."
    },
    {
      "code": "INTENT_ALREADY_SUBMITTED",
      "status": 409,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/intent-already-submitted",
      "summary": "This idempotency key was already used.",
      "hint": "Read the `intent` member: it is the first submission. Track that one.",
      "details": [
        "intent"
      ]
    },
    {
      "code": "HOURLY_BURN_EXCEEDED",
      "status": 429,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/hourly-burn-exceeded",
      "summary": "The account passed the Relay Units per hour of its rate class.",
      "hint": "Honour `Retry-After` and send the same bytes again afterwards."
    },
    {
      "code": "SIGNER_TIMEOUT",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/signer-timeout",
      "summary": "The signer did not commit before the deadline.",
      "hint": "Retry with the same bytes."
    },
    {
      "code": "NO_ENTITLEMENT",
      "status": 402,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/no-entitlement",
      "summary": "The account has no plan that can pay for this transaction.",
      "hint": "Buy or renew a plan, then relay. The response carries a `PAYMENT-REQUIRED` header for x402 clients that pay for their own address. A server relaying with a sponsor key ignores that header: it is built for the transaction’s sender, not for the key’s account. If that server’s plan is active and the answer says `NO_ACCOUNT`, the key never reached `POST /v1/relay` (a stripped header, a key sent as `Authorization: Bearer`, a client built without it), so the relay billed the sender, who has no plan: send it as `X-Api-Key`. A sponsored answer carries `billing.authMode: \"api_key\"`. Otherwise renew the plan in the dashboard.",
      "details": [
        "reason"
      ]
    },
    {
      "code": "SENDER_NOT_AUTHORIZED",
      "status": 403,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/sender-not-authorized",
      "summary": "This sender is not authorised to spend the paying account’s plan.",
      "hint": "List the sender on that account as a named wallet, or leave `account` out. To pay for users you do not list, relay through your server with a sponsor key (`X-Api-Key`, Builder and up): the key decides who pays, whatever `account` says.",
      "details": [
        "reason",
        "account"
      ]
    },
    {
      "code": "QUOTA_EXHAUSTED",
      "status": 429,
      "group": "relay",
      "retryable": false,
      "resign": "NONE",
      "type": "https://docs.co-relayer.com/errors/quota-exhausted",
      "summary": "The plan’s included Relay Units are used up.",
      "hint": "Turn on pay-as-you-go, top up its escrow, upgrade the tier, or wait for the next period. There is no `Retry-After`: time alone does not fix this.",
      "details": [
        "reason"
      ]
    },
    {
      "code": "RATE_LIMITED",
      "status": 429,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/rate-limited",
      "summary": "You are sending faster than your rate class allows.",
      "hint": "Honour `Retry-After` / `details.retryAfterMs` and resend the same bytes.",
      "details": [
        "retryAfterMs",
        "scope"
      ]
    },
    {
      "code": "GAS_BUDGET_EXCEEDED",
      "status": 429,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/gas-budget-exceeded",
      "summary": "The gas-per-second budget of your rate class in this shard is spent.",
      "hint": "Honour `Retry-After` and resend, or spread heavy transactions out.",
      "details": [
        "retryAfterMs"
      ]
    },
    {
      "code": "NO_RELAYER_AVAILABLE",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/no-relayer-available",
      "summary": "No healthy relayer can be assigned in that shard right now.",
      "hint": "Retry shortly. If you already hold a signed transaction, resend the same bytes."
    },
    {
      "code": "UPSTREAM_UNAVAILABLE",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/upstream-unavailable",
      "summary": "A dependency (chain gateway, node) was unavailable before anything was committed.",
      "hint": "Retry with the same bytes."
    },
    {
      "code": "SIGNER_UNAVAILABLE",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/signer-unavailable",
      "summary": "The signer process could not be reached.",
      "hint": "Retry with the same bytes."
    },
    {
      "code": "SIGNER_FENCED",
      "status": 503,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/signer-fenced",
      "summary": "The signer fenced itself and refuses to sign.",
      "hint": "Retry with the same bytes; another host takes over."
    },
    {
      "code": "INTERNAL",
      "status": 500,
      "group": "relay",
      "retryable": true,
      "resign": "SAME_BYTES",
      "type": "https://docs.co-relayer.com/errors/internal",
      "summary": "An unexpected failure before the commit point.",
      "hint": "Retry with the same bytes. If it repeats, send `instance` (the request id) to support."
    },
    {
      "code": "PRICE_ABOVE_MAX",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/price-above-max",
      "summary": "The price at execution time is above the maximum you signed for.",
      "hint": "Re-quote and sign a purchase with a current `max_price`."
    },
    {
      "code": "TIER_NOT_PURCHASABLE",
      "status": 422,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/tier-not-purchasable",
      "summary": "That tier cannot be bought right now.",
      "hint": "Read `GET /v1/pricing` and pick a tier whose `available` is true."
    },
    {
      "code": "QUEUED_BLOCK_EXISTS",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/queued-block-exists",
      "summary": "A plan is already queued to start after the current one.",
      "hint": "Wait for the queued block to start, or buy a more expensive tier: an upgrade takes effect now and credits the queued block back to your account."
    },
    {
      "code": "DOWNGRADE_NOT_IMMEDIATE",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/downgrade-not-immediate",
      "summary": "A plan without a period cannot start while a period plan is running.",
      "hint": "Let the current plan end — turn auto-renew off, or leave it off — and buy the no-period tier after `endMs`; or keep the period plan and renew it with `setAutoRenew(true, months, maxPrice)`."
    },
    {
      "code": "INSUFFICIENT_CREDITS",
      "status": 402,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/insufficient-credits",
      "summary": "The account does not hold enough credits for this purchase.",
      "hint": "Deposit USDC first, or buy in one call with `depositAndSubscribe`."
    },
    {
      "code": "DEPOSIT_BELOW_MIN",
      "status": 422,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/deposit-below-min",
      "summary": "The deposit is below the minimum the contract accepts.",
      "hint": "Read `deposit.minMicroUsdc` from `GET /v1/pricing` and deposit at least that."
    },
    {
      "code": "DEPOSIT_ABOVE_MAX",
      "status": 422,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/deposit-above-max",
      "summary": "The deposit is above the configured maximum.",
      "hint": "Read `deposit.maxMicroUsdc` from `GET /v1/pricing` (0 means unlimited) and split the deposit below it."
    },
    {
      "code": "SWAP_BUDGET_EXHAUSTED",
      "status": 503,
      "group": "purchase",
      "retryable": true,
      "type": "https://docs.co-relayer.com/errors/swap-budget-exhausted",
      "summary": "The rolling swap budget for deposits is used up.",
      "hint": "Retry after `details.retryAfterMs`.",
      "details": [
        "retryAfterMs"
      ]
    },
    {
      "code": "PAYG_PRICE_ABOVE_MAX",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/payg-price-above-max",
      "summary": "The pay-as-you-go price is above the maximum this account accepts.",
      "hint": "Raise `max_payg_price` on the account, or wait for the price to come back under it."
    },
    {
      "code": "DEPLOY_NOT_ALLOWED",
      "status": 403,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/deploy-not-allowed",
      "summary": "Contract deployments and upgrades are not relayed for this account.",
      "hint": "Ask support to allow-list the account, or deploy with your own gas."
    },
    {
      "code": "UNSUPPORTED_TX_FIELD",
      "status": 422,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/unsupported-tx-field",
      "summary": "The transaction carries a fee-relevant field this Relay-Unit schedule does not price.",
      "hint": "Remove the field, or wait for the schedule version announced in the changelog."
    },
    {
      "code": "QUOTE_EXPIRED",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/quote-expired",
      "summary": "The quote presented with the payment has expired.",
      "hint": "Request a fresh quote and pay against that one."
    },
    {
      "code": "RENEW_NOT_APPLICABLE",
      "status": 409,
      "group": "purchase",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/renew-not-applicable",
      "summary": "“Renew now” would do nothing.",
      "hint": "Read `details.predictedOutcome` and act on that instead.",
      "details": [
        "predictedOutcome"
      ]
    },
    {
      "code": "UNAUTHENTICATED",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/unauthenticated",
      "summary": "The endpoint needs credentials and none were presented.",
      "hint": "Authenticate and repeat the request."
    },
    {
      "code": "TOKEN_INVALID",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/token-invalid",
      "summary": "The token did not verify.",
      "hint": "Obtain a fresh token for this host and retry."
    },
    {
      "code": "TOKEN_EXPIRED",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/token-expired",
      "summary": "The token is past its validity.",
      "hint": "Refresh the token and retry."
    },
    {
      "code": "ORIGIN_NOT_ALLOWED",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/origin-not-allowed",
      "summary": "The browser origin is not allowed for this route.",
      "hint": "Call the API from an allowed origin, or use a token instead of a cookie."
    },
    {
      "code": "CHALLENGE_INVALID",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/challenge-invalid",
      "summary": "The signed challenge did not verify.",
      "hint": "Request a new challenge and sign that one."
    },
    {
      "code": "API_KEY_INVALID",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/api-key-invalid",
      "summary": "The API key is unknown, revoked, or from another environment.",
      "hint": "Use a key issued for this host, or create a new one in the dashboard."
    },
    {
      "code": "API_KEY_SCOPE",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/api-key-scope",
      "summary": "The API key is valid but not allowed to do this.",
      "hint": "Use a key with the right scope, move to a plan that can sponsor, or widen the key’s allow-lists in the dashboard."
    },
    {
      "code": "STREAM_TICKET_INVALID",
      "status": 401,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/stream-ticket-invalid",
      "summary": "The ticket presented to the event stream did not verify.",
      "hint": "Request a new ticket and reconnect."
    },
    {
      "code": "FORBIDDEN",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/forbidden",
      "summary": "Authenticated, but not permitted to do this.",
      "hint": "Use a credential that does, or ask the account owner for access."
    },
    {
      "code": "ADMIN_ONLY",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/admin-only",
      "summary": "This route is not available to your wallet.",
      "hint": "Nothing to do: this route is not part of the public API."
    },
    {
      "code": "ACTION_SIGNATURE_INVALID",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/action-signature-invalid",
      "summary": "A required per-action signature did not verify.",
      "hint": "Sign the action payload again and retry."
    },
    {
      "code": "ACCOUNT_SUSPENDED",
      "status": 403,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/account-suspended",
      "summary": "The account is suspended.",
      "hint": "Contact support@co-relayer.com. Credits are not lost by a suspension."
    },
    {
      "code": "NOT_FOUND",
      "status": 404,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/not-found",
      "summary": "No such resource.",
      "hint": "Check the identifier and the host you are calling."
    },
    {
      "code": "PAYLOAD_TOO_LARGE",
      "status": 413,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/payload-too-large",
      "summary": "The request body is larger than the endpoint accepts.",
      "hint": "Send less in one request; page or batch instead."
    },
    {
      "code": "CURSOR_INVALID",
      "status": 400,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/cursor-invalid",
      "summary": "The pagination cursor is malformed or no longer valid.",
      "hint": "Start the listing again without a cursor."
    },
    {
      "code": "IDEMPOTENCY_KEY_REUSED",
      "status": 422,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/idempotency-key-reused",
      "summary": "That idempotency key was used for a different request body.",
      "hint": "Use a new key, or resend the original body."
    },
    {
      "code": "IDEMPOTENCY_IN_PROGRESS",
      "status": 409,
      "group": "platform",
      "retryable": true,
      "type": "https://docs.co-relayer.com/errors/idempotency-in-progress",
      "summary": "The first request with this key is still running.",
      "hint": "Wait briefly and retry with the same key — you will get the first request’s result."
    },
    {
      "code": "LIMIT_REACHED",
      "status": 409,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/limit-reached",
      "summary": "A per-account limit is full.",
      "hint": "Remove an existing entry, or move to a tier with a higher limit."
    },
    {
      "code": "WEBHOOK_URL_NOT_ALLOWED",
      "status": 422,
      "group": "platform",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/webhook-url-not-allowed",
      "summary": "That webhook URL cannot be registered.",
      "hint": "Register a public HTTPS endpoint."
    },
    {
      "code": "PAYMENT_REQUIRED",
      "status": 402,
      "group": "x402",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/payment-required",
      "summary": "The resource needs payment; the response describes how.",
      "hint": "Pay against one of the `accepts` entries and repeat the request with the payment header."
    },
    {
      "code": "PAYMENT_INVALID",
      "status": 402,
      "group": "x402",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/payment-invalid",
      "summary": "The payment presented did not verify.",
      "hint": "Compare your payment against the challenge you were served, fix it, and retry."
    },
    {
      "code": "PAYMENT_FAILED",
      "status": 402,
      "group": "x402",
      "retryable": false,
      "type": "https://docs.co-relayer.com/errors/payment-failed",
      "summary": "The payment verified but could not be settled.",
      "hint": "Request a fresh challenge and pay again. Read the changelog and status page if it repeats."
    }
  ]
}
