---
title: "Cross-chain swap plan"
method: POST
path: "/xswap/plan"
tags: ["Bridge"]
---

# Cross-chain swap plan

`POST /xswap/plan`

## Request

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

Quotes a token on one chain into a token on another two ways at once — **composed** (Chord's router on the origin → USDC/USDG rail → Chord's router on the destination) and **direct** (Relay end to end) — and names the one that lands more. Long-tail tokens on Arc / Monad / Robinhood only route on the composed path. Fees come back as three lines (protocol · bridge · network) and `gas` says who pays on each side. `MIN_SIZE` below 10 USD of the bridged stable.

## Request body

- object
  - `user` string, required: EVM address, hex, case-insensitive.
  - `chainIn` 143 | 4663 | 5042, required
  - `chainOut` 143 | 4663 | 5042, required
  - `tokenIn` string, required: EVM address, hex, case-insensitive.
  - `tokenOut` string, required: EVM address, hex, case-insensitive.
  - `amount` string, required: Amount in the token's smallest unit, as a decimal string. Never a float.
  - `slippageBps` integer
  - `recipient` string: EVM address, hex, case-insensitive.
  - `rail` 'auto' | 'relay' | 'cctp': Force a rail; `auto` applies the corridor rules (Robinhood → Relay; Monad ↔ Arc → CCTP when the mint relayer is funded; else Relay).

## Response `200`

- object
  - `best` 'composed' | 'direct'
  - `composed` object, nullable
    - `chainIn` integer
    - `chainOut` integer
    - `tokenIn` string: EVM address, hex, case-insensitive.
    - `tokenOut` string: EVM address, hex, case-insensitive.
    - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `legs` union[]
      - union
        - object
          - `kind` 'swap'
          - `chainId` integer
          - `tokenIn` string: EVM address, hex, case-insensitive.
          - `tokenOut` string: EVM address, hex, case-insensitive.
          - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `priceImpactPct` number
          - `feeBps` integer: Our tier fee on this leg's output.
          - `dexIds` string[]
        - object
          - `kind` 'bridge'
          - `rail` 'relay' | 'cctp'
          - `chainIdIn` integer
          - `chainIdOut` integer
          - `tokenIn` string: EVM address, hex, case-insensitive.
          - `tokenOut` string: EVM address, hex, case-insensitive.
          - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `timeEstimateSec` number
          - `requestId` string: Relay intent id; empty on CCTP until the burn is sent.
          - `srcDomain` integer: CCTP only.
          - `dstDomain` integer: CCTP only.
          - `feeBps` number: Circle's fast-transfer fee, CCTP only.
    - `timeEstimateSec` number
    - `rail` 'relay' | 'cctp'
    - `railReason` string: Why this rail.
    - `fees` object
      - `protocol` object: Our on-chain tier fee per swap leg.
        - `originBps` integer
        - `destBps` integer
        - `usd` number
      - `bridge` object: The bridge's own cut.
        - `rail` string
        - `usd` number
        - `bps` number
        - `appFeeBps` integer: App fee added on Relay.
      - `network` object: Gas we front on the destination.
        - `usd` number: Flat per relayer-paid transaction.
        - `covered` boolean: true = we eat it (Arc mint).
        - `mode` 'user' | 'usdc-gas' | 'gasless' | 'solver' | 'none'
      - `totalUsd` number
    - `gas` object: Who pays gas on each side.
      - `origin` string
      - `dest` string
    - `minAnchorUnits` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `bridge` object: Rail-shaped: `{ rail, requestId, checkEndpoint, steps[], fees, details }` — sign `steps` in order on the origin chain (an `approval` item may be skipped when the allowance covers it).
  - `direct` object, nullable
    - `chainIn` integer
    - `chainOut` integer
    - `tokenIn` string: EVM address, hex, case-insensitive.
    - `tokenOut` string: EVM address, hex, case-insensitive.
    - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `legs` union[]
      - union
        - object
          - `kind` 'swap'
          - `chainId` integer
          - `tokenIn` string: EVM address, hex, case-insensitive.
          - `tokenOut` string: EVM address, hex, case-insensitive.
          - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `priceImpactPct` number
          - `feeBps` integer: Our tier fee on this leg's output.
          - `dexIds` string[]
        - object
          - `kind` 'bridge'
          - `rail` 'relay' | 'cctp'
          - `chainIdIn` integer
          - `chainIdOut` integer
          - `tokenIn` string: EVM address, hex, case-insensitive.
          - `tokenOut` string: EVM address, hex, case-insensitive.
          - `amountIn` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `amountOut` string: Amount in the token's smallest unit, as a decimal string. Never a float.
          - `timeEstimateSec` number
          - `requestId` string: Relay intent id; empty on CCTP until the burn is sent.
          - `srcDomain` integer: CCTP only.
          - `dstDomain` integer: CCTP only.
          - `feeBps` number: Circle's fast-transfer fee, CCTP only.
    - `timeEstimateSec` number
    - `rail` 'relay' | 'cctp'
    - `railReason` string: Why this rail.
    - `fees` object
      - `protocol` object: Our on-chain tier fee per swap leg.
        - `originBps` integer
        - `destBps` integer
        - `usd` number
      - `bridge` object: The bridge's own cut.
        - `rail` string
        - `usd` number
        - `bps` number
        - `appFeeBps` integer: App fee added on Relay.
      - `network` object: Gas we front on the destination.
        - `usd` number: Flat per relayer-paid transaction.
        - `covered` boolean: true = we eat it (Arc mint).
        - `mode` 'user' | 'usdc-gas' | 'gasless' | 'solver' | 'none'
      - `totalUsd` number
    - `gas` object: Who pays gas on each side.
      - `origin` string
      - `dest` string
    - `minAnchorUnits` string: Amount in the token's smallest unit, as a decimal string. Never a float.
    - `bridge` object: Rail-shaped: `{ rail, requestId, checkEndpoint, steps[], fees, details }` — sign `steps` in order on the origin chain (an `approval` item may be skipped when the allowance covers it).
  - `errors` object: Per-path failure `{ code, message }` when a path could not be quoted.

## Other responses

- `400`: Invalid parameters — `error` names the check that failed (`INVALID_PARAMS`, `BAD_ADDRESS`, `BAD_LIMIT`, `BAD_HOURS`, …).
- `404`: Nothing at this identity (`NOT_FOUND`, `UNKNOWN_TOKEN`, `NO_ROUTE`).
- `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`).
- `503`: 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.

---

[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)
