Skip to content

Unsigned transaction on any chain: Chord first, a fallback only when it fails

POST
/meta/swap
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

  • approval not null: send token.approve(spender, amount) first. spender is tx.to. With approval.resetFirst: true (USDT on Ethereum, a left-over allowance) send approve(spender, 0) before it.
  • When provider is not chord, tx.to is that aggregator’s router. Show the user which provider it is.

Policy

  1. Chord’s own router is always asked first, with its normal budget.
  2. 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.
  3. 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.
  • minAmountOut comes from your slippage; a provider minimum below it is refused.
  • The value guard of /quote applies: 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 least minAmountOut. 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.
Media typeapplication/json
object
chain

Chain id or key.

string
tokenIn

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
tokenOut

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
amount

Amount in the token’s smallest unit, as a decimal string. Never a float.

string
/^\d+$/
slippageBps
integer
default: 50 >= 1 <= 5000
taker
required

The wallet that signs and receives.

string
/^0x[a-fA-F0-9]{40}$/
quoteId

Instead of chain / tokens / amount: the id of a /meta/quote answer (valid 2 minutes).

string
Example
{
"chain": 8453,
"tokenIn": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"tokenOut": "0x4200000000000000000000000000000000000006",
"amount": "10000000",
"slippageBps": 50,
"taker": "0x00000000000000000000000000000000000c0ffe"
}

Sign tx with any wallet library and submit it to the chain in tx.chainId.

Media typeapplication/json

The same shape whichever provider answered.

object
chain

Chain id.

integer
tokenIn

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
tokenOut

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
amountIn

Amount in the token’s smallest unit, as a decimal string. Never a float.

string
/^\d+$/
taker

The wallet the transaction was built and simulated for; null on a price-only quote.

string | null
/^0x[a-fA-F0-9]{40}$/
slippageBps

The slippage minAmountOut reflects.

integer
provider

Who answered: chord (Chord’s own router), kyberswap, monorail, lifi, relay. null = no provider has a route.

string | null
fallbackReason

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.

string | null
attempts

Every provider asked, in order.

Array<object>

One provider that was asked, in order.

object
provider

chord, kyberswap, monorail, lifi or relay.

string
status

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.

string
ms

Time spent on this provider.

integer
error

Short reason from a fixed vocabulary, never provider text.

string | null
amountOut

What the taker receives after every fee, smallest unit of tokenOut. (/quote’s outputAmount is before Chord’s fee; this is after.)

string
/^\d+$/
minAmountOut

The minimum the transaction enforces, from the slippage you asked for.

string
/^\d+$/
priceImpactPct

Percent, when the provider states one.

string | null
valueLossPct

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.

number | null
feeBps

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.

integer
feeRecipient

EVM address, hex, case-insensitive.

string | null
/^0x[a-fA-F0-9]{40}$/
route
object
venues

Venue names.

Array<string>
tx

The UNSIGNED transaction. null without taker. to is the Chord router when provider is chord, the provider’s own router otherwise.

object
to

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
data

Calldata.

string
value

Amount in the token’s smallest unit, as a decimal string. Never a float.

string
/^\d+$/
gas

Gas limit to sign with.

string | null
chainId
integer
approval

The approval to send first. null for a native input or when the taker’s allowance already covers the amount.

object
token

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
spender

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
amount

Amount in the token’s smallest unit, as a decimal string. Never a float.

string
/^\d+$/
resetFirst

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.

boolean
simulation

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
ok

true = ran and delivered at least minAmountOut; null = no verdict (only ever returned on the Chord path).

boolean | null
amountOut

Amount in the token’s smallest unit, as a decimal string. Never a float.

string
/^\d+$/
gasUsed
integer
revert
string
reason
string
safety

A security scan of the unknown token, present when the value check could not run on a fallback answer.

object
source

goplus

string
token

EVM address, hex, case-insensitive.

string
/^0x[a-fA-F0-9]{40}$/
worstFlag

none, low, medium, high.

string
honeypot
boolean | null
buyTaxPct
number | null
sellTaxPct
number | null
risks
Array<string>
warnings

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.

Array<string>
quoteId

Pass to POST /meta/swap within 2 minutes.

string
expiresAt

Unix time, seconds, UTC.

integer
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, …).

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
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.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
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.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
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).

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
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.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
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.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
Example
{
"error": "INVALID_PARAMS",
"message": "amount must be an integer string in the token's smallest unit"
}