Qiguard API docs

API reference

Built from the OpenAPI 3.1.0 document of the Qiguard API, version 1.0.0. Download it as openapi.yaml or openapi.json.

Base URL https://api.qiguard.com. Keyed endpoints need the headers qg-api-key and qg-version: v1; keyless endpoints need no header. Every response carries the header qg-zid and the body field zid.

Endpoints

MethodPathKeySummary
GET/swap/allowance-holder/priceyesIndicative price for an allowance-holder swap
GET/swap/allowance-holder/quoteyesFirm quote with the transaction to send
GET/gasless/priceyesIndicative price for a gasless swap
GET/gasless/quoteyesGasless quote with the Permit2 witness message to sign
POST/gasless/submityesSubmit a signed gasless trade
GET/gasless/status/{tradeHash}yesStatus of a submitted gasless trade
GET/swap/chainsnoChains supported by the Swap endpoints
GET/gasless/chainsnoChains supported by the Gasless endpoints
GET/sourcesnoLiquidity sources of a chain (names usable in excludedSources)
GET/tokensnoTokens and anchors supported on a chain
GET/statusnoLive state of every chain (contract pause flag, RPC, swap and gasless availability)

GET /swap/allowance-holder/price

Indicative price for an allowance-holder swap.

Parameters of GET /swap/allowance-holder/price

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
chainIdqueryyesinteger, one of 1, 56, 137, 8453
sellTokenqueryyesAddress
buyTokenqueryyesAddress
sellAmountqueryyesUintAmount of sellToken in base units.
buyAmountquerynoUintExact-out is not supported in v1; sending it gives 400 EXACT_OUT_NOT_SUPPORTED. (not used in v1)
takerquerynoAddressThe wallet that holds sellToken. When present, issues are filled and the wallet's on-chain fee rate is used.
recipientquerynoAddressMust be absent or equal to taker; otherwise 400 RECIPIENT_NOT_SUPPORTED (the contract pays the taker).
slippageBpsquerynointeger, 10 to 1000, default 100Default 100, allowed 10-1000. Mutually exclusive with slippagePpm. minBuyAmount = floor(buyAmount * (10000 - slippageBps) / 10000).
slippagePpmquerynointeger, 1000 to 100000Slippage in parts per million, rounded down to whole bps (warning slippage_ppm_rounded). Same limits as slippageBps.
deadlineSecondsquerynointeger, 30 to 600, default 120Seconds until the calldata deadline (expiresAt). Default 120, allowed 30-600.
excludedSourcesquerynostringComma-separated names from /sources. Unknown names are listed in issues.invalidSourcesPassed.
gasPricequerynoUintGas price in wei for the estimate. Default is the chain's current gas price.
swapFeeRecipientquerynostringYour fee wallet, or up to 3 wallets separated by commas. Sent together with swapFeeBps; the router pays each wallet its share on chain in the same transaction.
swapFeeBpsquerynostringThe fee of each swapFeeRecipient in basis points, in the same order (for example 30 or 20,10). The total is at most 300.
swapFeePpmquerynostringNot accepted (400 INPUT_INVALID); use swapFeeBps. (not used in v1)
swapFeeTokenquerynoAddressThe token the integrator fee is taken in, sellToken or buyToken. Default buyToken.
tradeSurplusRecipientquerynostringAccepted and ignored (warning trade_surplus_ignored); the whole output always goes to the taker. (not used in v1)
tradeSurplusMaxBpsquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
tradeSurplusMaxPpmquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
txOriginquerynoAddressAccepted and ignored (warning tx_origin_ignored). The contract pays msg.sender, so a contract taker must call the contract itself. (not used in v1)
sellEntireBalancequerynostring, one of true, falsefalse is accepted; true gives 400 INPUT_INVALID (reason not_supported).
wrapUnwrapModequerynostring, one of direct, settlerdirect is accepted and ignored; settler gives 400 INPUT_INVALID. Wrap and unwrap pairs give TOKEN_PAIR_NOT_SUPPORTED.

Responses of GET /swap/allowance-holder/price

StatusMeaningBody
200A price, or liquidityAvailable false when no route exists.SwapPrice or NoLiquidity
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
503SETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.Error
curl -s "https://api.qiguard.com/swap/allowance-holder/price?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"

GET /swap/allowance-holder/quote

Firm quote with the transaction to send.

Same parameters as the price endpoint; taker is required. transaction.data calls marketSwap, marketSwapNativeToToken or marketSwapTokenToNative on the settlement contract, followed by the 18-byte Qiguard tag (qiguard.tag). Approve issues.allowance.spender for the exact sellAmount, wait for the approval receipt, then quote again: transaction expires at expiresAt.

Parameters of GET /swap/allowance-holder/quote

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
chainIdqueryyesinteger, one of 1, 56, 137, 8453
sellTokenqueryyesAddress
buyTokenqueryyesAddress
sellAmountqueryyesUintAmount of sellToken in base units.
buyAmountquerynoUintExact-out is not supported in v1; sending it gives 400 EXACT_OUT_NOT_SUPPORTED. (not used in v1)
takerqueryyesAddressThe wallet that holds sellToken and sends (or signs) the trade.
recipientquerynoAddressMust be absent or equal to taker; otherwise 400 RECIPIENT_NOT_SUPPORTED (the contract pays the taker).
slippageBpsquerynointeger, 10 to 1000, default 100Default 100, allowed 10-1000. Mutually exclusive with slippagePpm. minBuyAmount = floor(buyAmount * (10000 - slippageBps) / 10000).
slippagePpmquerynointeger, 1000 to 100000Slippage in parts per million, rounded down to whole bps (warning slippage_ppm_rounded). Same limits as slippageBps.
deadlineSecondsquerynointeger, 30 to 600, default 120Seconds until the calldata deadline (expiresAt). Default 120, allowed 30-600.
excludedSourcesquerynostringComma-separated names from /sources. Unknown names are listed in issues.invalidSourcesPassed.
gasPricequerynoUintGas price in wei for the estimate. Default is the chain's current gas price.
swapFeeRecipientquerynostringYour fee wallet, or up to 3 wallets separated by commas. Sent together with swapFeeBps; the router pays each wallet its share on chain in the same transaction.
swapFeeBpsquerynostringThe fee of each swapFeeRecipient in basis points, in the same order (for example 30 or 20,10). The total is at most 300.
swapFeePpmquerynostringNot accepted (400 INPUT_INVALID); use swapFeeBps. (not used in v1)
swapFeeTokenquerynoAddressThe token the integrator fee is taken in, sellToken or buyToken. Default buyToken.
tradeSurplusRecipientquerynostringAccepted and ignored (warning trade_surplus_ignored); the whole output always goes to the taker. (not used in v1)
tradeSurplusMaxBpsquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
tradeSurplusMaxPpmquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
txOriginquerynoAddressAccepted and ignored (warning tx_origin_ignored). The contract pays msg.sender, so a contract taker must call the contract itself. (not used in v1)
sellEntireBalancequerynostring, one of true, falsefalse is accepted; true gives 400 INPUT_INVALID (reason not_supported).
wrapUnwrapModequerynostring, one of direct, settlerdirect is accepted and ignored; settler gives 400 INPUT_INVALID. Wrap and unwrap pairs give TOKEN_PAIR_NOT_SUPPORTED.

Responses of GET /swap/allowance-holder/quote

StatusMeaningBody
200A quote, or liquidityAvailable false when no route exists.SwapQuote or NoLiquidity
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
503SETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.Error
curl -s "https://api.qiguard.com/swap/allowance-holder/quote?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000&taker=0x1111111111111111111111111111111111111111" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"

The example taker 0x1111111111111111111111111111111111111111 is a placeholder: replace it with your wallet address.

GET /gasless/price

Indicative price for a gasless swap.

ERC-20 to ERC-20 only (the wrapped native token is allowed, the native coin is not). On a chain listed by /gasless/chains with enabled: false the price is still returned, with the warning gasless_not_enabled. With a taker whose balance is below sellAmount, the price is still returned and issues.balance shows the shortfall; only /gasless/quote answers 400 INSUFFICIENT_BALANCE.

Parameters of GET /gasless/price

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
chainIdqueryyesinteger, one of 56, 8453Gasless chains are BSC (56) and Base (8453). Other values give 400 CHAIN_NOT_SUPPORTED.
sellTokenqueryyesAddress
buyTokenqueryyesAddress
sellAmountqueryyesUintAmount of sellToken in base units.
buyAmountquerynoUintExact-out is not supported in v1; sending it gives 400 EXACT_OUT_NOT_SUPPORTED. (not used in v1)
takerquerynoAddressThe wallet that holds sellToken. When present, issues are filled and the wallet's on-chain fee rate is used.
recipientquerynoAddressMust be absent or equal to taker; otherwise 400 RECIPIENT_NOT_SUPPORTED (the contract pays the taker).
slippageBpsquerynointeger, 10 to 300, default 50Default 50, allowed 10-300. Mutually exclusive with slippagePpm.
slippagePpmquerynointeger, 1000 to 100000Slippage in parts per million, rounded down to whole bps (warning slippage_ppm_rounded). Same limits as slippageBps.
deadlineSecondsquerynointeger, 60 to 600, default 180Seconds until the signed deadline. Default 180, allowed 60-600.
excludedSourcesquerynostringComma-separated names from /sources. Unknown names are listed in issues.invalidSourcesPassed.
swapFeeRecipientquerynostringYour fee wallet, or up to 3 wallets separated by commas. Sent together with swapFeeBps; the router pays each wallet its share on chain in the same transaction.
swapFeeBpsquerynostringThe fee of each swapFeeRecipient in basis points, in the same order (for example 30 or 20,10). The total is at most 300.
swapFeePpmquerynostringNot accepted (400 INPUT_INVALID); use swapFeeBps. (not used in v1)
swapFeeTokenquerynoAddressThe token the integrator fee is taken in, sellToken or buyToken. Default buyToken.
tradeSurplusRecipientquerynostringAccepted and ignored (warning trade_surplus_ignored); the whole output always goes to the taker. (not used in v1)
tradeSurplusMaxBpsquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
tradeSurplusMaxPpmquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)

Responses of GET /gasless/price

StatusMeaningBody
200A gasless price, or liquidityAvailable false.GaslessPrice or NoLiquidity
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
503SETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.Error
curl -s "https://api.qiguard.com/gasless/price?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"

GET /gasless/quote

Gasless quote with the Permit2 witness message to sign.

taker is required. Sign trade.eip712 with eth_signTypedData_v4 and send it to POST /gasless/submit. approval is always null in v1: a taker without a Permit2 allowance must first send one normal approve(Permit2, amount) transaction and pay its gas (issues.allowance shows it). A taker balance below sellAmount gives 400 INSUFFICIENT_BALANCE. Before signing, check that domain.verifyingContract is Permit2, message.spender is the settlement contract of the chain and witness.recipient is the taker (the SDK's assertGaslessTrade does this).

Parameters of GET /gasless/quote

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
chainIdqueryyesinteger, one of 56, 8453Gasless chains are BSC (56) and Base (8453). Other values give 400 CHAIN_NOT_SUPPORTED.
sellTokenqueryyesAddress
buyTokenqueryyesAddress
sellAmountqueryyesUintAmount of sellToken in base units.
buyAmountquerynoUintExact-out is not supported in v1; sending it gives 400 EXACT_OUT_NOT_SUPPORTED. (not used in v1)
takerqueryyesAddressThe wallet that holds sellToken and sends (or signs) the trade.
recipientquerynoAddressMust be absent or equal to taker; otherwise 400 RECIPIENT_NOT_SUPPORTED (the contract pays the taker).
slippageBpsquerynointeger, 10 to 300, default 50Default 50, allowed 10-300. Mutually exclusive with slippagePpm.
slippagePpmquerynointeger, 1000 to 100000Slippage in parts per million, rounded down to whole bps (warning slippage_ppm_rounded). Same limits as slippageBps.
deadlineSecondsquerynointeger, 60 to 600, default 180Seconds until the signed deadline. Default 180, allowed 60-600.
excludedSourcesquerynostringComma-separated names from /sources. Unknown names are listed in issues.invalidSourcesPassed.
swapFeeRecipientquerynostringYour fee wallet, or up to 3 wallets separated by commas. Sent together with swapFeeBps; the router pays each wallet its share on chain in the same transaction.
swapFeeBpsquerynostringThe fee of each swapFeeRecipient in basis points, in the same order (for example 30 or 20,10). The total is at most 300.
swapFeePpmquerynostringNot accepted (400 INPUT_INVALID); use swapFeeBps. (not used in v1)
swapFeeTokenquerynoAddressThe token the integrator fee is taken in, sellToken or buyToken. Default buyToken.
tradeSurplusRecipientquerynostringAccepted and ignored (warning trade_surplus_ignored); the whole output always goes to the taker. (not used in v1)
tradeSurplusMaxBpsquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)
tradeSurplusMaxPpmquerynostringAccepted and ignored (warning trade_surplus_ignored). (not used in v1)

Responses of GET /gasless/quote

StatusMeaningBody
200A gasless quote, or liquidityAvailable false.GaslessQuote or NoLiquidity
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
503SETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.Error
curl -s "https://api.qiguard.com/gasless/quote?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000&taker=0x1111111111111111111111111111111111111111" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"

The example taker 0x1111111111111111111111111111111111111111 is a placeholder: replace it with your wallet address.

POST /gasless/submit

Submit a signed gasless trade.

Idempotent by tradeHash (the EIP-712 digest): the same trade from the same app returns 200 with the same body; from another app it returns 400 TRADE_ALREADY_SUBMITTED. An optional Idempotency-Key header is also honoured for 24 hours. Until gasless is enabled on the chain (relayer funded and switched on), this endpoint returns 503 GASLESS_NOT_ENABLED with data.reason = "gasless_not_enabled". A 503 RELAYER_UNAVAILABLE with data.reason relayer_timeout or relayer_unreachable carries data.tradeHash: the trade may still have been accepted, so read GET /gasless/status/{tradeHash} (404 means it was not) before quoting and signing again; sending the same body again returns the earlier answer.

Parameters of POST /gasless/submit

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
Idempotency-Keyheadernostring, pattern ^[\x21-\x7e]{1,64}$, length 1 to 641-64 visible ASCII characters. Same key and same body within 24 h returns the stored response; same key with another body gives 400 IDEMPOTENCY_KEY_REUSED.

Request body of POST /gasless/submit

JSON, required: GaslessSubmitRequest.

Responses of POST /gasless/submit

StatusMeaningBody
200Accepted (status pending), or the earlier result of the same trade.GaslessSubmitResponse
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
413PAYLOAD_TOO_LARGE (body above 256 KB).Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
503SETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.Error
curl -s -X POST "https://api.qiguard.com/gasless/submit" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1" \
  -H "content-type: application/json" --data @body.json

body.json is a GaslessSubmitRequest: chainId, and the trade object of your gasless quote unchanged with the signature split into v, r, s.

GET /gasless/status/{tradeHash}

Status of a submitted gasless trade.

Only the app that submitted the trade can read it. confirmed means 5 confirmations on BSC and 3 on Base.

Parameters of GET /gasless/status/{tradeHash}

NameInRequiredTypeDescription
qg-versionheaderyesstring, one of v1API version. Missing gives 400 API_VERSION_MISSING; another value gives 400 INPUT_INVALID.
tradeHashpathyesBytes32
chainIdqueryyesinteger, one of 56, 8453Gasless chains are BSC (56) and Base (8453). Other values give 400 CHAIN_NOT_SUPPORTED.

Responses of GET /gasless/status/{tradeHash}

StatusMeaningBody
200Current status.GaslessStatus
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
401API_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).Error
403APP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).Error
404META_TRANSACTION_STATUS_NOT_FOUND, or NOT_FOUND for an unknown path.Error
429RATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/gasless/status/0xa80ae1ca92ebcfd14acb76387a103bd132a66ae86d4292e38550b1d2529e9b10?chainId=8453" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"

The example tradeHash is the test-vector digest; use the tradeHash of your own submit.

GET /swap/chains

Chains supported by the Swap endpoints.

Responses of GET /swap/chains

StatusMeaningBody
200Supported chains.ChainsResponse
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/swap/chains"

Example answer:

{
  "chains": [
    {
      "chainId": 56,
      "chainName": "BSC"
    },
    {
      "chainId": 1,
      "chainName": "Ethereum"
    },
    {
      "chainId": 8453,
      "chainName": "Base"
    },
    {
      "chainId": 137,
      "chainName": "Polygon"
    }
  ],
  "zid": "0x0b7a51f2e9c4d3a8812e6f40"
}

GET /gasless/chains

Chains supported by the Gasless endpoints.

enabled: false means price and quote work but submit returns 503 GASLESS_NOT_ENABLED.

Responses of GET /gasless/chains

StatusMeaningBody
200Gasless chains.GaslessChainsResponse
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/gasless/chains"

Example answer:

{
  "chains": [
    {
      "chainId": 56,
      "chainName": "BSC",
      "enabled": false
    },
    {
      "chainId": 8453,
      "chainName": "Base",
      "enabled": false
    }
  ],
  "zid": "0x0b7a51f2e9c4d3a8812e6f40"
}

GET /sources

Liquidity sources of a chain (names usable in excludedSources).

Parameters of GET /sources

NameInRequiredTypeDescription
chainIdqueryyesinteger, one of 1, 56, 137, 8453

Responses of GET /sources

StatusMeaningBody
200Source names.SourcesResponse
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/sources?chainId=56"

Example answer:

{
  "sources": [
    "PancakeSwap_V2",
    "PancakeSwap_V3"
  ],
  "zid": "0x0b7a51f2e9c4d3a8812e6f40"
}

GET /tokens

Tokens and anchors supported on a chain.

Parameters of GET /tokens

NameInRequiredTypeDescription
chainIdqueryyesinteger, one of 1, 56, 137, 8453

Responses of GET /tokens

StatusMeaningBody
200Token list.TokensResponse
400INPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.Error
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/tokens?chainId=8453"

GET /status

Live state of every chain (contract pause flag, RPC, swap and gasless availability).

Responses of GET /status

StatusMeaningBody
200Status, cached for 15 seconds.StatusResponse
500INTERNAL_SERVER_ERROR or UNCATEGORIZED.Error
curl -s "https://api.qiguard.com/status"

Response headers

HeaderDescription
qg-zidRequest id, the same value as the body zid.
RateLimit-PolicyThe app burst limit, for example "burst";q=50;w=10 (5 requests per second counted over 10 seconds). A "daily" part is added only when the app has a daily cap.
Retry-AfterSeconds to wait before retrying.
qg-quota-remainingApproximate requests left today; sent only when the app has a daily cap.
qg-quota-resetSeconds until 00:00 UTC; sent only when the app has a daily cap.

Error responses

Every error has the body Error. The full list of names, with the extra data fields, is on the errors page.

ResponseNames
BadRequestINPUT_INVALID, HTTPS_REQUIRED, API_VERSION_MISSING, CHAIN_NOT_SUPPORTED, TOKEN_NOT_SUPPORTED, TOKEN_PAIR_NOT_SUPPORTED, RECIPIENT_NOT_SUPPORTED, SELL_AMOUNT_TOO_SMALL, INSUFFICIENT_BALANCE (gasless quote only), SWAP_VALIDATION_FAILED, UNABLE_TO_CALCULATE_GAS_FEE, SMART_WALLET_NOT_SUPPORTED, INTEGRATOR_FEE_NOT_SUPPORTED, EXACT_OUT_NOT_SUPPORTED, IDEMPOTENCY_KEY_REUSED; on submit also INSUFFICIENT_BALANCE_OR_ALLOWANCE, INVALID_APPROVAL, INVALID_SIGNATURE, INVALID_SIGNER, META_TRANSACTION_EXPIRY_TOO_SOON, META_TRANSACTION_INVALID, PENDING_TRADES_ALREADY_EXIST, TRADE_ALREADY_SUBMITTED.
UnauthorizedAPI_KEY_MISSING (message "No API key found in request") or API_KEY_INVALID (unknown, malformed or revoked key).
ForbiddenAPP_NOT_APPROVED (data.status pending or suspended), PRODUCT_NOT_ENABLED (data.reason product_not_enabled or chain_not_enabled), ORIGIN_NOT_ALLOWED, TAKER_NOT_AUTHORIZED_FOR_TRADE (data.reason denied or gasless_blocked).
NotFoundMETA_TRANSACTION_STATUS_NOT_FOUND, or NOT_FOUND for an unknown path.
PayloadTooLargePAYLOAD_TOO_LARGE (body above 256 KB).
TooManyRequestsRATE_LIMITED (Retry-After 10), QUOTA_EXCEEDED (daily request cap or gasless submits per day; Retry-After = seconds to 00:00 UTC), GAS_BUDGET_EXCEEDED (sponsored-gas budget of the app, the chain or the free tier).
InternalErrorINTERNAL_SERVER_ERROR or UNCATEGORIZED.
UnavailableSETTLEMENT_PAUSED (contract paused), SWAP_NOT_ENABLED (swap switched off for the chain), GASLESS_NOT_ENABLED (data.reason gasless_not_enabled: relayer not set up or funded yet, or switched off), RELAYER_UNAVAILABLE (data.reason relayer_low_balance, relayer_busy, relayer_stalled, gas_price_above_cap, relayer_timeout or relayer_unreachable; Retry-After when busy or timed out; relayer_timeout and relayer_unreachable add data.tradeHash: read the status of that trade before quoting again), RPC_UNAVAILABLE.

Schemas

Schema Address

Type: string, pattern ^0x[0-9a-fA-F]{40}$.

Schema Uint

Unsigned integer as a decimal string.

Type: string, pattern ^[0-9]{1,78}$.

Schema Hex

Type: string, pattern ^0x([0-9a-fA-F]{2})*$.

Schema Bytes32

Type: string, pattern ^0x[0-9a-fA-F]{64}$.

Schema Zid

Request id, 0x + 12 random bytes.

Type: string, pattern ^0x[0-9a-f]{24}$.

Schema Error

FieldTypeRequiredDescription
namestringyesError code, see the error table in the docs.
messagestringyes
dataobjectyes
data.zidZidyes
data.detailsarray of objectno
data.details[].fieldstringyes
data.details[].reasonstringyes
data.reasonstringnoShort machine-readable sub-reason, for example gasless_not_enabled, gasless_blocked, price_moved.
{
  "name": "INPUT_INVALID",
  "message": "sellAmount must be a positive integer string",
  "data": {
    "zid": "0x7d1e0c55a9b2f4e83c61d0aa",
    "details": [
      {
        "field": "sellAmount",
        "reason": "not an integer"
      }
    ]
  }
}

Schema Warning

FieldTypeRequiredDescription
codestring, one of trade_surplus_ignored, tx_origin_ignored, wrap_unwrap_mode_ignored, slippage_ppm_rounded, secret_key_origin_header, gasless_not_enabledyes
messagestringyes

Schema NoLiquidity

FieldTypeRequiredDescription
liquidityAvailableboolean, always falseyes
zidZidyes

Schema QiguardFee

The Qiguard fee of the app's plan (Free 25 bps, paid plans 0), taken on chain from the gross output in the buy token. On a chain without a router it is the settlement fee (USDT-input trades pay it from the sell amount in USDT).

FieldTypeRequiredDescription
amountUintyes
tokenAddressyes
typestring, always "volume"yes
bpsinteger, 0 to 100yes
takenFromstring, one of sell, buyyes

Schema IntegratorFee

One integrator fee (swapFeeRecipient / swapFeeBps), paid on chain to the recipient in the same transaction.

FieldTypeRequiredDescription
amountUintyes
tokenAddressyes
typestring, always "volume"yes
recipientAddressyes
bpsinteger, 1 to 300yes

Schema GasFee

Gasless only. In v1 the gas is sponsored, so amount is always "0".

FieldTypeRequiredDescription
amountUintyes
tokenAddressyes
typestring, always "gas"yes
sponsoredbooleanyes
estimatedCostUsdstringnoEstimated gas cost in USD, decimal string.

Schema Fees

FieldTypeRequiredDescription
integratorFeeIntegratorFee or nullyesThe first integrator fee, or null.
integratorFeesarray of IntegratorFeeyes
qiguardFeeQiguardFeeyes
gasFeeGasFee or nullyes

Schema Issues

FieldTypeRequiredDescription
allowanceobject or nullyes
allowance.actualUintyes
allowance.spenderAddressyes
allowance.resetRequiredbooleannoTrue for Ethereum USDT with a non-zero allowance below sellAmount; approve 0 first.
balanceobject or nullyes
balance.tokenAddressyes
balance.actualUintyes
balance.expectedUintyes
simulationIncompletebooleanyes
invalidSourcesPassedarray of stringyes

Schema RouteFill

FieldTypeRequiredDescription
fromAddressyes
toAddressyes
sourcestringyes
proportionBpsstring, always "10000"yes
feeTierintegernoV3 pool fee in hundredths of a bip; absent on V2 legs.

Schema Route

One fill per hop. Phase 1 routes use one source for the whole trade, at most 2 hops.

FieldTypeRequiredDescription
fillsarray of RouteFillyes
tokensarray of objectyes
tokens[].addressAddressyes
tokens[].symbolstringyes

Schema TaxBps

Not measured in v1 (null). Taxed tokens fail simulation and return TOKEN_NOT_SUPPORTED.

FieldTypeRequiredDescription
buyTaxBpsstring or nullyes
sellTaxBpsstring or nullyes
transferTaxBpsstring or nullyes

Schema TokenMetadata

FieldTypeRequiredDescription
buyTokenTaxBpsyes
sellTokenTaxBpsyes

Schema Transaction

FieldTypeRequiredDescription
toAddressyes
dataHexyes
gasUintyes
gasPriceUintyes
valueUintyes

Schema Protection

FieldTypeRequiredDescription
settlementPausedbooleanyesLive paused() of the settlement contract (cached 15 s). While true, price and quote return 503 SETTLEMENT_PAUSED.
simulationstring, one of passed, not_run, skipped_allowance, skipped_balance, at_submityesSwap quote: eth_call of the exact transaction from the taker (passed), or skipped because the allowance or balance is short. Swap price: not_run. Gasless price and quote: at_submit (the relayer simulates before sending).
quoteIntegrityobjectyes
quoteIntegrity.rpcAgreementintegeryesNumber of independent RPC operators that agreed (1 on price, 2 on quote).
quoteIntegrity.maxDeviationBpsinteger or nullno
quoteIntegrity.blockintegeryesBlock the quote was read at.
minBuyAmountEnforcedOnchainboolean, always trueyes
priceBandobjectyes
priceBand.onchainEnforcedbooleanyespriceBandEnabled() of the contract.
priceBand.priceImpactBpsinteger or nullyesExecution price against a small reference trade on the same route; quote only, null on price.
mevobjectyes
mev.submissionstring, one of taker_submits, private, sequenceryes
mev.channelsarray of stringno
routeBoundBySignaturebooleannoGasless only; false in v1, the signed message does not fix the route.
signatureExposurearray of stringnoGasless only; who sees the signed message before inclusion. qiguard includes the private (keyed) RPC endpoint the relayer uses to simulate the transaction; no public RPC receives it.

Schema QiguardCall

FieldTypeRequiredDescription
functionstring, one of marketSwap, marketSwapNativeToToken, marketSwapTokenToNativeyes
selectorstring, one of 0xb5019436, 0x6f1190c5, 0x1f60a2c7yes
adapterAddressyes
deadlineintegeryes
tagstring, pattern ^0x71673031[0-9a-f]{28}$ or nullyes

Schema SwapPrice

FieldTypeRequiredDescription
liquidityAvailableboolean, always trueyes
blockNumberUintyes
sellTokenAddressyes
buyTokenAddressyes
sellAmountUintyes
buyAmountUintyesNet amount the taker receives.
minBuyAmountUintyes
allowanceTargetAddress or nullyesThe settlement contract; null when selling the native coin.
feesFeesyes
issuesIssuesyes
warningsarray of Warningyes
routeRouteyes
tokenMetadataTokenMetadatayes
totalNetworkFeeUintyesgas x gasPrice, plus the L1 data fee on Base.
gasUintyes
gasPriceUintyes
protectionProtectionyes
modestring, always "exact-in"yes
zidZidyes

Schema SwapQuote

FieldTypeRequiredDescription
liquidityAvailableboolean, always trueyes
blockNumberUintyes
expiresAtintegeryesUnix seconds; the deadline inside transaction.data.
sellTokenAddressyes
buyTokenAddressyes
sellAmountUintyes
buyAmountUintyes
minBuyAmountUintyes
allowanceTargetAddress or nullyes
feesFeesyes
issuesIssuesyes
warningsarray of Warningyes
routeRouteyes
tokenMetadataTokenMetadatayes
totalNetworkFeeUintyes
transactionTransactionyes
protectionProtectionyes
qiguardQiguardCallyes
modestring, always "exact-in"yes
zidZidyes
{
  "liquidityAvailable": true,
  "blockNumber": "129508144",
  "expiresAt": 1793000120,
  "sellToken": "0x55d398326f99059fF775485246999027B3197955",
  "buyToken": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  "sellAmount": "100000000000000000000",
  "buyAmount": "158640000000000000",
  "minBuyAmount": "157053600000000000",
  "allowanceTarget": "0x79A76e54f354AC7567f97d979EC1b785c15e37d8",
  "fees": {
    "integratorFee": null,
    "integratorFees": [],
    "qiguardFee": {
      "amount": "500000000000000000",
      "token": "0x55d398326f99059fF775485246999027B3197955",
      "type": "volume",
      "bps": 50,
      "takenFrom": "sell"
    },
    "gasFee": null
  },
  "issues": {
    "allowance": {
      "actual": "0",
      "spender": "0x79A76e54f354AC7567f97d979EC1b785c15e37d8"
    },
    "balance": null,
    "simulationIncomplete": true,
    "invalidSourcesPassed": []
  },
  "warnings": [],
  "route": {
    "fills": [
      {
        "from": "0x55d398326f99059fF775485246999027B3197955",
        "to": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
        "source": "PancakeSwap_V3",
        "proportionBps": "10000",
        "feeTier": 100
      }
    ],
    "tokens": [
      {
        "address": "0x55d398326f99059fF775485246999027B3197955",
        "symbol": "USDT"
      },
      {
        "address": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
        "symbol": "WBNB"
      }
    ]
  },
  "tokenMetadata": {
    "buyToken": {
      "buyTaxBps": null,
      "sellTaxBps": null,
      "transferTaxBps": null
    },
    "sellToken": {
      "buyTaxBps": null,
      "sellTaxBps": null,
      "transferTaxBps": null
    }
  },
  "totalNetworkFee": "26000000000000",
  "transaction": {
    "to": "0x79A76e54f354AC7567f97d979EC1b785c15e37d8",
    "data": "0x1f60a2c7...71673031a4c2e09b5d7f1e335f1c9a7e2b44",
    "gas": "260000",
    "gasPrice": "100000000",
    "value": "0"
  },
  "protection": {
    "settlementPaused": false,
    "simulation": "skipped_allowance",
    "quoteIntegrity": {
      "rpcAgreement": 2,
      "maxDeviationBps": 4,
      "block": 129508144
    },
    "minBuyAmountEnforcedOnchain": true,
    "priceBand": {
      "onchainEnforced": false,
      "priceImpactBps": 3
    },
    "mev": {
      "submission": "taker_submits"
    }
  },
  "qiguard": {
    "function": "marketSwapTokenToNative",
    "selector": "0x1f60a2c7",
    "adapter": "0xb8dfc084c3912B71662044092722fdDA40b15Ab3",
    "deadline": 1793000120,
    "tag": "0x71673031a4c2e09b5d7f1e335f1c9a7e2b44"
  },
  "mode": "exact-in",
  "zid": "0x5f1c9a7e2b44d0c3a1e8f6b2"
}

Schema PermitWitnessMessage

FieldTypeRequiredDescription
permittedobjectyes
permitted.tokenAddressyes
permitted.amountUintyes
spenderAddressyesThe settlement contract of the chain.
nonceUintyesRandom unordered Permit2 nonce.
deadlineUintyes
witnessobjectyes
witness.tokenOutAddressyes
witness.minAmountOutUintyes
witness.recipientAddressyesMust be the taker (the signer).
witness.adapterAddressyes
witness.deadlineUintyesEqual to the outer deadline.

Schema PermitWitnessTypedData

Must be sent back exactly as returned by /gasless/quote: any change to types, primaryType or domain gives META_TRANSACTION_INVALID. The digest of this object is the tradeHash.

FieldTypeRequiredDescription
typesobjectyes
types.EIP712DomainEip712Fieldsyes
types.PermitWitnessTransferFromEip712Fieldsyes
types.TokenPermissionsEip712Fieldsyes
types.OrderWitnessEip712Fieldsyes
primaryTypestring, always "PermitWitnessTransferFrom"yes
domainobjectyes
domain.namestring, always "Permit2"yes
domain.chainIdinteger, one of 56, 8453yes
domain.verifyingContractstring, always "0x000000000022D473030F116dDEE9F6B43aC78BA3"yes
messagePermitWitnessMessageyes
{
  "types": {
    "EIP712Domain": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "chainId",
        "type": "uint256"
      },
      {
        "name": "verifyingContract",
        "type": "address"
      }
    ],
    "PermitWitnessTransferFrom": [
      {
        "name": "permitted",
        "type": "TokenPermissions"
      },
      {
        "name": "spender",
        "type": "address"
      },
      {
        "name": "nonce",
        "type": "uint256"
      },
      {
        "name": "deadline",
        "type": "uint256"
      },
      {
        "name": "witness",
        "type": "OrderWitness"
      }
    ],
    "TokenPermissions": [
      {
        "name": "token",
        "type": "address"
      },
      {
        "name": "amount",
        "type": "uint256"
      }
    ],
    "OrderWitness": [
      {
        "name": "tokenOut",
        "type": "address"
      },
      {
        "name": "minAmountOut",
        "type": "uint256"
      },
      {
        "name": "recipient",
        "type": "address"
      },
      {
        "name": "adapter",
        "type": "address"
      },
      {
        "name": "deadline",
        "type": "uint256"
      }
    ]
  },
  "primaryType": "PermitWitnessTransferFrom",
  "domain": {
    "name": "Permit2",
    "chainId": 8453,
    "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
  },
  "message": {
    "permitted": {
      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "25000000"
    },
    "spender": "0x67433187Db1e57f66E88880b6Be833f6759362b1",
    "nonce": "123456789012345678901234567890",
    "deadline": "1793000120",
    "witness": {
      "tokenOut": "0x4200000000000000000000000000000000000006",
      "minAmountOut": "5981940000000000",
      "recipient": "0x1111111111111111111111111111111111111111",
      "adapter": "0xB47011d787B432ccF7A53284a74432a0De4397a3",
      "deadline": "1793000120"
    }
  }
}

Schema Eip712Fields

Type: array of object, items with name, type.

Schema GaslessTrade

FieldTypeRequiredDescription
typestring, always "qiguard_permit2_witness"yes
hashBytes32yesEIP-712 digest of eip712; equals the tradeHash returned by submit.
eip712PermitWitnessTypedDatayes

Schema GaslessPrice

FieldTypeRequiredDescription
liquidityAvailableboolean, always trueyes
blockNumberUintyes
sellTokenAddressyes
buyTokenAddressyes
sellAmountUintyes
buyAmountUintyes
minBuyAmountUintyes
targetAddressyesThe settlement contract (the Permit2 spender).
feesFeesyes
issuesIssuesyes
warningsarray of Warningyes
routeRouteyes
tokenMetadataTokenMetadatayes
protectionProtectionyes
zidZidyes

Schema GaslessQuote

FieldTypeRequiredDescription
liquidityAvailableboolean, always trueyes
blockNumberUintyes
expiresAtintegeryesThe signed deadline (unix seconds).
sellTokenAddressyes
buyTokenAddressyes
sellAmountUintyes
buyAmountUintyes
minBuyAmountUintyes
targetAddressyes
approvalnullyesAlways null in v1.
tradeGaslessTradeyes
feesFeesyes
issuesIssuesyes
warningsarray of Warningyes
routeRouteyes
tokenMetadataTokenMetadatayes
protectionProtectionyes
zidZidyes

Schema Signature

FieldTypeRequiredDescription
signatureTypeinteger, always 2yes2 = EIP-712 ECDSA signature of an EOA.
vinteger, one of 27, 28yes
rBytes32yes
sBytes32yes

Schema GaslessSubmitRequest

FieldTypeRequiredDescription
chainIdinteger, one of 56, 8453yes
tradeobjectyes
trade.typestring, always "qiguard_permit2_witness"yes
trade.eip712PermitWitnessTypedDatayes
trade.signatureSignatureyes
approvalnullnoMust be absent or null in v1; anything else gives INVALID_APPROVAL.

Schema GaslessSubmitResponse

FieldTypeRequiredDescription
tradeHashBytes32yes
typestring, always "qiguard_permit2_witness"yes
zidZidyes

Schema GaslessStatus

FieldTypeRequiredDescription
statusstring, one of pending, submitted, succeeded, confirmed, failedyes
transactionsarray of objectyesEvery hash broadcast for this trade (rebroadcasts and replacements included).
transactions[].hashBytes32yes
transactions[].timestampintegeryes
approvalTransactionsarray of any, always emptyyes
reasonstring, one of transaction_simulation_failed, order_expired, transaction_reverted, insufficient_allowance, insufficient_balance, internal_errornoPresent when status is failed.
detailstringnoOptional extra detail, for example slippage or permit_consumed_by_other_tx.
zidZidyes

Schema ChainsResponse

FieldTypeRequiredDescription
chainsarray of objectyes
chains[].chainIdintegeryes
chains[].chainNamestringyes
zidZidyes

Schema GaslessChainsResponse

FieldTypeRequiredDescription
chainsarray of objectyes
chains[].chainIdintegeryes
chains[].chainNamestringyes
chains[].enabledbooleanyesFalse until the relayer is funded and gasless is switched on for the chain.
zidZidyes

Schema SourcesResponse

FieldTypeRequiredDescription
sourcesarray of stringyes
zidZidyes

Schema TokensResponse

FieldTypeRequiredDescription
tokensarray of objectyes
tokens[].addressAddressyes
tokens[].symbolstringyes
tokens[].decimalsintegeryes
tokens[].anchorbooleanyesUSDT, USDC, the native coin or the wrapped native token. Every pair needs an anchor on one side.
tokens[].gaslessbooleanyesUsable on the gasless endpoints of this chain (ERC-20 on a gasless chain).
zidZidyes

Schema StatusResponse

FieldTypeRequiredDescription
versionstringyes
timestring, format date-timeyes
chainsarray of objectyes
chains[].chainIdintegeryes
chains[].chainNamestringyes
chains[].settlementAddressyes
chains[].pausedbooleanyes
chains[].priceBandEnforcedbooleanyes
chains[].feeRecipientAddressyes
chains[].headBlockintegeryes
chains[].rpcstring, one of ok, degraded, downyes
chains[].swapstring, one of operational, paused, switched_off, degradedyes
chains[].gaslessobjectyes
chains[].gasless.statestring, one of not_listed, not_enabled, operational, switched_off, relayer_low, relayer_busy, relayer_stalled, paused, degradedyes
chains[].gasless.relayerstring, one of ok, low, empty, unknownno
chains[].gasless.queuedintegerno
zidZidyes