Errors
Every error, on every path, has the same JSON body and the header qg-zid:
{
"name": "INPUT_INVALID",
"message": "sellAmount must be a positive integer string",
"data": {
"zid": "0x7d1e0c55a9b2f4e83c61d0aa",
"details": [ { "field": "sellAmount", "reason": "not an integer" } ]
}
}
nameis the stable code;messageis text for people and can change.data.zididentifies the request.data.details[]appears only withINPUT_INVALIDandORIGIN_NOT_ALLOWED. Other context is indata(reason,token,chainId,minSellAmount,status,tradeHash).- The API answers JSON only, 404s included.
400
| Name | Where | Extra data | What to do |
|---|---|---|---|
INPUT_INVALID | any | details[], reason | Fix the field named in details |
HTTPS_REQUIRED | any, plain HTTP | - | Use https://. The key sent over plain HTTP is revoked: create a new one |
API_VERSION_MISSING | keyed | - | Send qg-version: v1 |
CHAIN_NOT_SUPPORTED | chain-bound | chainId | Use a chain from /swap/chains or /gasless/chains |
TOKEN_NOT_SUPPORTED | price, quote, submit | token, reason (transfer_tax) | Use a token from /tokens |
TOKEN_PAIR_NOT_SUPPORTED | price, quote, submit | reason (no_anchor, wrap_unwrap, native_not_supported) | Put an anchor on one side; no wrap or unwrap; no native coin on gasless |
RECIPIENT_NOT_SUPPORTED | price, quote | - | Leave recipient out or set it to taker |
SELL_AMOUNT_TOO_SMALL | price, quote, submit | minSellAmount | Sell at least minSellAmount |
INSUFFICIENT_BALANCE | gasless quote with taker (the gasless price answers 200 with issues.balance instead) | token, actual, expected | The taker needs more of the sell token |
SWAP_VALIDATION_FAILED | swap quote simulation | reason (slippage, adapter_not_allowed), revert | Quote again; raise slippageBps for volatile pairs |
UNABLE_TO_CALCULATE_GAS_FEE | gasless price and quote | - | Retry shortly |
SMART_WALLET_NOT_SUPPORTED | gasless with taker | - | Use the swap endpoints for contract wallets |
INTEGRATOR_FEE_NOT_SUPPORTED | price, quote | - | Remove the swapFee* parameters |
EXACT_OUT_NOT_SUPPORTED | price, quote | - | Send sellAmount instead of buyAmount |
IDEMPOTENCY_KEY_REUSED | submit | - | Use a new Idempotency-Key for a different body |
INSUFFICIENT_BALANCE_OR_ALLOWANCE | submit | taker, sellToken, sellAmount, minBalanceOrAllowance | Top up the balance or approve Permit2 |
INVALID_APPROVAL | submit | - | Send approval as null or leave it out |
INVALID_SIGNATURE | submit | - | Sign trade.eip712 again with eth_signTypedData_v4 |
INVALID_SIGNER | submit | - | The signer must be the taker (witness.recipient) |
META_TRANSACTION_EXPIRY_TOO_SOON | submit | - | Quote and sign again |
META_TRANSACTION_INVALID | submit | reason (price_moved, simulation_failed, gas_too_high, ...), revert | Send the typed data unchanged; on price_moved, quote and sign again |
PENDING_TRADES_ALREADY_EXIST | submit | - | Wait for the taker's pending trade on this chain |
TRADE_ALREADY_SUBMITTED | submit | reason (permit_nonce_used) | Another app sent this trade, or the Permit2 nonce is used: quote again |
401, 403, 404, 405
| HTTP | Name | Where | Extra data | What to do |
|---|---|---|---|---|
| 401 | API_KEY_MISSING | keyed | - | Send qg-api-key (message: "No API key found in request") |
| 401 | API_KEY_INVALID | keyed | - | The key is unknown, malformed or revoked: use an active key |
| 403 | APP_NOT_APPROVED | keyed | status (pending, suspended) | Wait for approval, or see the app in the dashboard |
| 403 | PRODUCT_NOT_ENABLED | keyed | reason (product_not_enabled, chain_not_enabled) | Enable the product or chain in the app settings |
| 403 | ORIGIN_NOT_ALLOWED | keyed | details | Call from a server; a proxy must strip Origin and Sec-Fetch-* |
| 403 | TAKER_NOT_AUTHORIZED_FOR_TRADE | taker-bound | reason (denied, gasless_blocked) | The taker cannot trade through this endpoint |
| 404 | NOT_FOUND | any | - | Check the path |
| 404 | META_TRANSACTION_STATUS_NOT_FOUND | status | - | Use the tradeHash and chainId of a trade your app submitted |
| 405 | METHOD_NOT_ALLOWED | any | - | Use the method in the Allow header |
413, 414, 429
| HTTP | Name | Where | Extra data | What to do |
|---|---|---|---|---|
| 413 | PAYLOAD_TOO_LARGE | submit | - | The body limit is 256 KB |
| 414 | URI_TOO_LONG | any | - | The URL limit is 8,192 characters |
| 429 | RATE_LIMITED | keyed, and the gasless per-taker hourly limit | reason | Wait Retry-After seconds (10 for the app limit) |
| 429 | QUOTA_EXCEEDED | daily request cap, gasless submits per day | reason | Wait until 00:00 UTC (Retry-After) |
| 429 | GAS_BUDGET_EXCEEDED | gasless | reason (app_daily, chain_daily, free_tier_daily) | The sponsored-gas budget is used up for the day |
500, 503
| HTTP | Name | Where | Extra data | What to do |
|---|---|---|---|---|
| 500 | INTERNAL_SERVER_ERROR | any | - | Retry; keep the zid |
| 500 | UNCATEGORIZED | any | - | Retry; keep the zid |
| 503 | SETTLEMENT_PAUSED | chain-bound | chainId | The settlement contract of the chain is paused; GET /status shows when it is back |
| 503 | SWAP_NOT_ENABLED | swap | chainId, reason (switched_off) | Swap is switched off on this chain for now |
| 503 | GASLESS_NOT_ENABLED | gasless submit | reason (gasless_not_enabled), chainId | Gasless is not switched on for this chain yet; use the swap endpoints |
| 503 | RELAYER_UNAVAILABLE | gasless submit | reason (relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout, relayer_unreachable); tradeHash with relayer_timeout and relayer_unreachable | Retry later; Retry-After: 3 when busy or timed out. With tradeHash, first read GET /gasless/status/{tradeHash}: the trade may have been accepted (404 means it was not) |
| 503 | RPC_UNAVAILABLE | price, quote, submit, status | - | The chain's RPC operators did not agree or answer; retry |
Retrying
429 RATE_LIMITED: retry afterRetry-After.500and503: retry with a growing delay.400,401,403,404: change the request first; the same request gets the same answer.- A gasless submit can be repeated: the same trade from the same app returns the earlier answer (Idempotency). Do not quote and sign a new trade while an earlier one may still be accepted: after a timeout, read its status first.
This page as Markdown: errors.md. All pages for tools: llms.txt.