---
title: "Build an unsigned swap transaction"
method: POST
path: "/swap"
tags: ["Quote and swap"]
---

# Build an unsigned swap transaction

`POST /swap`

## Request

- Base URL: `https://api.getchord.xyz/v1`
- URL: `https://api.getchord.xyz/v1/swap`
- Auth: none declared

Turns a quote into a transaction against the Chord router. You sign it and broadcast it; Chord never sees a key and never holds funds.

**Notes**
- Send the `/quote` body back unmodified. `chain` must match the quote.
- For an ERC-20 input, approve the router (`transaction.to`) for at least `inputAmount` first — or run `/swap/simulate` and let it tell you.
- `slippageBps` is a consistency check only: the signed minimum output is the quote's `otherAmountThreshold`. A different value is refused with `SLIPPAGE_MISMATCH` — re-quote at the slippage you want.
- On Arc the native sentinel aliases to the USDC predeploy: a "native" input is pulled by `transferFrom`, a "native" output is delivered as the predeploy, and `value` is always 0.
- `batch: "7702"` is Monad-only (EIP-7702 one-signature approve+swap); it is ignored on every other chain.

## Request body

- object
  - `quoteResponse` QuoteResponse, required
    - `inputMint` string: EVM address, hex, case-insensitive.
    - `outputMint` string: EVM address, hex, case-insensitive.
    - `inputAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `outputAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `otherAmountThreshold` string: Minimum output after fee and slippage — the number the transaction enforces.
    - `slippageBps` integer
    - `priceImpactPct` string: Percent, as a string, against the spot rate of the same route.
    - `routePlan` RouteLeg[]: Empty with `outputAmount` "0" = no route (an honest answer, never a fabricated price).
      - `percent` integer: Share of the input this leg carries.
      - `swapInfo` object
        - `dex` string: Venue id (see Resources → Venue ids).
        - `pool` string: Pool address, or the 32-byte pool id on Uniswap V4.
        - `inputMint` string: EVM address, hex, case-insensitive.
        - `outputMint` string: EVM address, hex, case-insensitive.
        - `inputAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
        - `outputAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
        - `adapter` string: The router adapter that executes this leg — from the engine, never hardcode.
        - `extraData` string: Adapter-specific calldata for the leg.
        - `feeAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
        - `feeMint` string: EVM address, hex, case-insensitive.
    - `noRouteReason` string: Only when `routePlan` is empty: `INSUFFICIENT_LIQUIDITY` (try a smaller amount) or `NO_POOLS`.
    - `gasEstimate` string: Gas units, from the venue quoter or the RPC.
    - `gasCostUSD` string
    - `blockNumber` integer
    - `timeTaken` number: Engine seconds.
    - `feeBps` integer: Protocol fee on the output token, per token on-chain (`FeeCollector.feeBpsFor`): 5 bps by default on every chain, 0 on the stablecoins and majors a chain exempts (USDC / EURC on Arc, WETH / USDG and stocks on Robinhood Chain), capped at 100.
    - `feeAmount` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `feeMint` string: EVM address, hex, case-insensitive.
    - `feeTier` string: `major` · `stable` · `standard` · `meme` · `new`.
    - `preliminary` boolean: Present only on `fast=1` answers: single-hop, ~400 ms, replace it with the full quote.
  - `userPublicKey` string, required: Wallet that signs and receives the output.
  - `chain` 5042 | 4663 | 143 | 43114 | 8453 | 56 | 42161 | 1: Must match the quote.
  - `slippageBps` integer: Optional consistency check — same value the quote was requested with.
  - `feeAccount` string: Referrer credited with the referral share of the protocol fee.
  - `wrapUnwrapMON` boolean: Wrap / unwrap the native unit around the swap where the chain has a wrapped native (not Arc).
  - `usePermit2` boolean
  - `batch` '7702'

## Response `200`

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

- object
  - `transaction` SwapTx: Unsigned transaction against the router.
    - `to` string: EVM address, hex, case-insensitive.
    - `data` string: Calldata.
    - `value` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `gasLimit` string
    - `chainId` integer
  - `lastValidBlockHeight` integer: Block after which the quote should be considered stale.
  - `batch7702` object: Monad only — the one-signature approve+swap plan.

## Other responses

- `400`: Invalid parameters — `error` names the check that failed (`INVALID_PARAMS`, `BAD_ADDRESS`, `BAD_LIMIT`, `BAD_HOURS`, …).
- `429`: Over the per-minute limit (`RATE_LIMIT_EXCEEDED`). Read `X-RateLimit-Reset` and back off.
- `502`: The routing engine or an upstream did not answer (`ENGINE_ERROR`, `ROUTE_ERROR`).

---

[API](https://skmtc.dev/getchord/apis/chord-api.md) · [All operations](https://skmtc.dev/getchord/apis/chord-api/llms.txt) · [OpenAPI document](https://skmtc.dev/getchord/apis/chord-api/revisions/d3bc4640fea0?raw)
