Unsigned transaction on any chain: Chord first, a fallback only when it fails
const url = 'https://api.getchord.xyz/v1/meta/swap';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"chain":8453,"tokenIn":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","tokenOut":"0x4200000000000000000000000000000000000006","amount":"10000000","slippageBps":50,"taker":"0x00000000000000000000000000000000000c0ffe"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.getchord.xyz/v1/meta/swap \ --header 'Content-Type: application/json' \ --data '{ "chain": 8453, "tokenIn": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "tokenOut": "0x4200000000000000000000000000000000000006", "amount": "10000000", "slippageBps": 50, "taker": "0x00000000000000000000000000000000000c0ffe" }'The same answer as /meta/quote with a taker required: an UNSIGNED transaction, simulated as the taker. Chord never signs and never holds funds.
Send the pair and amount, or the quoteId of a /meta/quote answer from the last 2 minutes. The policy runs again at the current state, so provider can differ from the quote’s: compare before you sign.
Before signing
approvalnot null: sendtoken.approve(spender, amount)first.spenderistx.to. Withapproval.resetFirst: true(USDT on Ethereum, a left-over allowance) sendapprove(spender, 0)before it.- When
provideris notchord,tx.tois that aggregator’s router. Show the user which provider it is.
Policy
- Chord’s own router is always asked first, with its normal budget.
- A fallback is asked only when Chord fails: the engine timed out, errored or is down; there is no route; Chord refuses the route itself (value guard, taxed token, stale bonding-curve route); the chain’s router is not live; or the built transaction fails simulation. A better price elsewhere is not a reason. A user error (unknown token, bad amount) never falls back.
- Fallbacks are tried in the chain’s order (
GET /meta/providers); the first answer that passes every check wins. Per provider 4 s, whole request 9 s, a circuit breaker per provider and chain.
Safety, on every fallback answer
- The transaction target and the approval spender must be on Chord’s allowlist for that provider and chain, and deployed there.
minAmountOutcomes from your slippage; a provider minimum below it is refused.- The value guard of
/quoteapplies: an output worth 30 % less than the input at Chord’s prices is refused. An unpriced token gets a security scan (safety); a honeypot is refused. - With
taker, the transaction is simulated as that wallet and must deliver at leastminAmountOut. A fallback transaction that cannot be simulated is never returned. - Without
taker, a fallback price is shown only after the provider BUILT the route and it was simulated for a placeholder wallet (PRICE_CHECKED); a provider that prices a size but will not build it is skipped. The placeholder’s transaction is never returned. - An input the simulation cannot supply (a balance that is not a plain storage mapping, e.g. rebasing shares) while the taker does not hold it: HTTP 422
INPUT_NOT_SIMULATABLE— hold the input and ask again.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Chain id or key.
EVM address, hex, case-insensitive.
EVM address, hex, case-insensitive.
Amount in the token’s smallest unit, as a decimal string. Never a float.
The wallet that signs and receives.
Instead of chain / tokens / amount: the id of a /meta/quote answer (valid 2 minutes).
Example
{ "chain": 8453, "tokenIn": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "tokenOut": "0x4200000000000000000000000000000000000006", "amount": "10000000", "slippageBps": 50, "taker": "0x00000000000000000000000000000000000c0ffe"}Responses
Section titled “ Responses ”Sign tx with any wallet library and submit it to the chain in tx.chainId.
The same shape whichever provider answered.
object
Chain id.
EVM address, hex, case-insensitive.
EVM address, hex, case-insensitive.
Amount in the token’s smallest unit, as a decimal string. Never a float.
The wallet the transaction was built and simulated for; null on a price-only quote.
The slippage minAmountOut reflects.
Who answered: chord (Chord’s own router), kyberswap, monorail, lifi, relay. null = no provider has a route.
null when Chord answered. Otherwise why it did not: no_route, insufficient_liquidity, engine_error, engine_timeout, engine_down, value_guard, taxed_token, route_stale, chain_not_live, build_failed, simulation_failed.
Every provider asked, in order.
One provider that was asked, in order.
object
chord, kyberswap, monorail, lifi or relay.
ok, or why this provider did not produce the answer: no_route, timeout, http_error, rate_limited, invalid_response, not_allowlisted, calldata_mismatch, min_out_too_low, value_gap, unsafe_token, simulation_failed, unverified, breaker_open, skipped; for Chord also engine_error, engine_timeout, engine_down, route_refused, build_failed, chain_not_live.
Time spent on this provider.
Short reason from a fixed vocabulary, never provider text.
What the taker receives after every fee, smallest unit of tokenOut. (/quote’s outputAmount is before Chord’s fee; this is after.)
The minimum the transaction enforces, from the slippage you asked for.
Percent, when the provider states one.
Output value against input value at Chord’s own prices, percent (negative = worth more). null when Chord has no reliable price for a side: see safety and warnings.
Chord path: Chord’s protocol fee on the output. Fallback: the integrator fee Chord added (0 today); the provider’s own fees are already inside amountOut.
EVM address, hex, case-insensitive.
object
Venue names.
The UNSIGNED transaction. null without taker. to is the Chord router when provider is chord, the provider’s own router otherwise.
object
EVM address, hex, case-insensitive.
Calldata.
Amount in the token’s smallest unit, as a decimal string. Never a float.
Gas limit to sign with.
The approval to send first. null for a native input or when the taker’s allowance already covers the amount.
object
EVM address, hex, case-insensitive.
EVM address, hex, case-insensitive.
Amount in the token’s smallest unit, as a decimal string. Never a float.
Present only for a token that reverts approve(x > 0) while its allowance is non-zero (USDT on Ethereum). true = the taker has a left-over allowance: send approve(spender, 0) first, then this approval.
The transaction run as the taker (with the input supplied when the taker does not hold it), measuring the taker’s own balance change. null without taker.
object
true = ran and delivered at least minAmountOut; null = no verdict (only ever returned on the Chord path).
Amount in the token’s smallest unit, as a decimal string. Never a float.
A security scan of the unknown token, present when the value check could not run on a fallback answer.
object
goplus
EVM address, hex, case-insensitive.
none, low, medium, high.
INSUFFICIENT_BALANCE, UNPRICED, OUTPUT_WRAPPED, NO_ROUTE, and on a price-only fallback PRICE_CHECKED (built and simulated for a placeholder wallet) or UNVERIFIED_PRICE (built, not simulatable) — each followed by a sentence.
Pass to POST /meta/swap within 2 minutes.
Unix time, seconds, UTC.
Example
{ "chain": 8453, "tokenIn": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "tokenOut": "0x4200000000000000000000000000000000000006", "amountIn": "10000000", "taker": "0x00000000000000000000000000000000000c0ffe", "slippageBps": 50, "provider": "chord", "fallbackReason": null, "attempts": [ { "provider": "chord", "status": "ok", "ms": 222, "error": null } ], "amountOut": "3727897844407334", "minAmountOut": "3709258355185298", "priceImpactPct": "0.0000", "valueLossPct": -0.02, "feeBps": 0, "feeRecipient": "0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834", "route": { "venues": [ "aerodrome_slipstream_3" ] }, "tx": { "to": "0x1b1fee89a381e595fe6536b99ba91f3e16e9601a", "data": "0xdc72a437…", "value": "0", "gas": "1000000", "chainId": 8453 }, "approval": { "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "spender": "0x1b1fee89a381e595fe6536b99ba91f3e16e9601a", "amount": "10000000" }, "simulation": { "ok": true, "amountOut": "3727897844407334", "gasUsed": 456590 }, "safety": null, "warnings": [ "INSUFFICIENT_BALANCE: the taker holds less than the input amount; the transaction was simulated with the input supplied." ], "quoteId": "8f722080-92a4-493d-aa16-a06f468a581e", "expiresAt": 1791055797}Invalid parameters — error names the check that failed (INVALID_PARAMS, BAD_ADDRESS, BAD_LIMIT, BAD_HOURS, …).
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}No provider has a route for this pair and size (NO_ROUTE); the body carries fallbackReason and attempts.
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}Unknown or expired quoteId (QUOTE_EXPIRED). Send the full params.
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}The request is valid but cannot be served as asked (INPUT_NOT_SIMULATABLE on /meta/*: a route exists, but the input token cannot be supplied in a simulation and the taker does not hold it — hold the input and ask again).
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}Over the per-minute limit (RATE_LIMIT_EXCEEDED). Read X-RateLimit-Reset and back off.
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}The lane behind this endpoint is not ready or not enabled here (NOT_READY, CHAIN_NOT_ENABLED, NOT_ENABLED, *_UNAVAILABLE). Retry later; do not treat it as an empty answer.
Every non-2xx body.
object
Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.
For humans.
HTTP status, when included.
Example
{ "error": "INVALID_PARAMS", "message": "amount must be an integer string in the token's smallest unit"}