# Build an unsigned swap transaction

`POST https://api.getchord.xyz/v1/swap`

Source: https://getchord.xyz/docs/api-reference/operations/buildswap/

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 (JSON)

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| `quoteResponse` | yes | object |  |
| `userPublicKey` | yes | string | Wallet that signs and receives the output. |
| `chain` | no | `5042` · `4663` · `143` · `43114` · `8453` · `56` · `42161` · `1` | Must match the quote. |
| `slippageBps` | no | integer | Optional consistency check — same value the quote was requested with. |
| `feeAccount` | no | string | Referrer credited with the referral share of the protocol fee. |
| `wrapUnwrapMON` | no | boolean | Wrap / unwrap the native unit around the swap where the chain has a wrapped native (not Arc). |
| `usePermit2` | no | boolean |  |
| `batch` | no | `7702` |  |

```json
{
  "quoteResponse": {
    "…": "the /v1/quote body"
  },
  "userPublicKey": "0xb145400da27a2497d9fc2cd5621f2bfd37617af4",
  "chain": 5042
}
```

## Response 200

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

Example (captured from the live API):

```json
{
  "transaction": {
    "to": "0x1b1fee89a381e595fe6536b99ba91f3e16e9601a",
    "data": "0xdc72a437…",
    "value": "0",
    "gasLimit": "1500000",
    "chainId": 5042
  },
  "lastValidBlockHeight": 21808340
}
```

- **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`).
