> For the complete documentation index, see [llms.txt](https://docs.metric.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.metric.xyz/reference/api/find-best-route.md).

# Find best route

`POST /public/v1/evm/{chain_id}/route`

Find and price the best execution across direct and one-intermediate-hop paths for an **exact-input or exact-output** swap. Returns one or more routes. For exact-input, the input is split across multiple routes only when the configured thresholds show it reduces price impact and the split returns more total output. For exact-output, the output target is split instead, and a split is kept only if it needs less total input.

This is a public endpoint. A Trading API key is optional; sending one raises your rate limit:

```http
Authorization: Bearer <your_trading_api_key>
```

A key you send must be valid: an unknown key returns `401`. Leave the header out if you don't have one.

### Path parameters

| Name       | Type    | Description           |
| ---------- | ------- | --------------------- |
| `chain_id` | integer | Numeric EVM chain id. |

### Request body

| Field         | Type    | Required        | Description                                                                                                                                          |
| ------------- | ------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenIn`     | string  | yes             | Input token address. Must differ from `tokenOut`, non-zero.                                                                                          |
| `tokenOut`    | string  | yes             | Output token address.                                                                                                                                |
| `tradeType`   | string  | no              | `exact_in` or `exact_out`. Inferred when omitted: `amountIn` alone ⇒ `exact_in`, `amountOut` alone ⇒ `exact_out`. Required if you send both amounts. |
| `amountIn`    | string  | for `exact_in`  | Exact input, raw units (base-10, positive).                                                                                                          |
| `amountOut`   | string  | for `exact_out` | Exact output target, raw units.                                                                                                                      |
| `maxRoutes`   | integer | no              | Cap on routes in the plan, from `1` to `4`; `0` is treated as `1` and larger values as `4`. `1` = single best route (no split); omitted = `4`.       |
| `poolAddress` | string  | no              | Restrict routing to this one Metric pool. Its tokens must match `tokenIn`/`tokenOut`; a success returns one direct route through it.                 |

### Request

```bash
# Route (exact-in) - single & split, one endpoint
curl -X POST "https://api.metric.xyz/public/v1/evm/1/route" \
  -H "Content-Type: application/json" \
  -d '{
    "tokenIn":  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "tradeType": "exact_in",
    "amountIn": "50000000000000000",
    "maxRoutes": 4
  }'
```

### Response

`200 OK`

```json
{
  "tokenIn": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "tokenOut": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  "tradeType": "exact_in",
  "amountIn": "50000000000000000",
  "amountOut": "136120897",
  "effectivePriceX64": "50219747000",
  "priceImpactBestRoute": "0.000082",
  "candidatesConsidered": 8,
  "routes": [
    {
      "tradeType": "exact_in",
      "routeType": "direct",
      "amountIn": "50000000000000000",
      "amountOut": "136120897",
      "effectivePriceX64": "50219747000",
      "priceImpactE6": "82",
      "legs": [
        {
          "tradeType": "exact_in",
          "poolAddress": "0xF85AfbADeCC7F23Dd173ed706f07d9C7e2473e24",
          "pair": "WETH/USDC",
          "zeroForOne": true,
          "tokenIn": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
          "tokenOut": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "amountIn": "50000000000000000",
          "amountOut": "136120897",
          "effectivePriceX64": "50219747000",
          "priceImpactE6": "82",
          "priceLimitX64": "0"
        }
      ]
    }
  ]
}
```

| Field                  | Type    | Description                                                                                                |
| ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------- |
| `tokenIn` / `tokenOut` | string  | Echoed endpoints (lowercased).                                                                             |
| `tradeType`            | string  | Echoed; tells you which side was fixed.                                                                    |
| `amountIn`             | string  | For `exact_in`, the request; for `exact_out`, the computed required input.                                 |
| `amountOut`            | string  | For `exact_in`, total computed output; for `exact_out`, ≈ the requested target.                            |
| `effectivePriceX64`    | string  | Blended execution price for the whole plan: `amountOut × 2^64 / amountIn`, in raw token units (see below). |
| `priceImpactBestRoute` | string  | Best single route's price impact as a **decimal fraction** (`"0.0135"` = 1.35%).                           |
| `candidatesConsidered` | integer | Number of candidate paths scored.                                                                          |
| `routes`               | array   | One entry per allocated route (≥1; multiple ⇒ split).                                                      |

`effectivePriceX64` is output per input, in the trade's direction (`tokenOut` per `tokenIn`), scaled by 2^64. It is **not** decimal-normalized, unlike `bidAdj`/`askAdj`. To get a human-readable price, compute `effectivePriceX64 / 2^64 × 10^(tokenIn decimals − tokenOut decimals)`. In the example, `50219747000 / 2^64 ≈ 2.72e-9` USDC base units per wei, so `× 10^(18 − 6)` gives ≈ 2,722 USDC per WETH.

### Response fields

#### Each `routes[]` entry

| Field                    | Type   | Description                                                             |
| ------------------------ | ------ | ----------------------------------------------------------------------- |
| `tradeType`              | string | Echoed.                                                                 |
| `routeType`              | string | `direct` or `one_hop`.                                                  |
| `amountIn` / `amountOut` | string | Amounts allocated to this route (raw units).                            |
| `effectivePriceX64`      | string | This route's execution price, same format.                              |
| `priceImpactE6`          | string | The largest `priceImpactE6` among this route's legs, E6 (`10000` = 1%). |
| `legs`                   | array  | Per-leg execution params.                                               |

#### Each leg

| Field                    | Type    | Description                                                                                                                                                                    |
| ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `tradeType`              | string  | Echoed.                                                                                                                                                                        |
| `poolAddress`            | string  | Pool to swap against.                                                                                                                                                          |
| `pair`                   | string  | Pool pair label.                                                                                                                                                               |
| `zeroForOne`             | boolean | Swap direction for this leg.                                                                                                                                                   |
| `tokenIn` / `tokenOut`   | string  | Leg tokens. For one-hop, leg 2 `amountIn` = leg 1 `amountOut`.                                                                                                                 |
| `amountIn` / `amountOut` | string  | Leg amounts (raw units).                                                                                                                                                       |
| `effectivePriceX64`      | string  | Leg execution price, same format.                                                                                                                                              |
| `priceImpactE6`          | string  | Leg price impact, E6: the depth level's `priceImpactE6` at the far edge of the last bin the leg reaches, not the leg's average price. Use `effectivePriceX64` for the average. |
| `priceLimitX64`          | string  | No-limit sentinel for the onchain swap: `0` when `zeroForOne`, `2^128−1` otherwise.                                                                                            |

### Routing and splitting

These details are internal and not returned in the response.

1. Enumerate direct + one-hop candidates; score each by walking `bid_ask` depth bins for the requested amount, as described in [Estimating a fill](/reference/api/retrieve-current-bid-and-ask.md#estimating-a-fill).
2. Pick the best single route (baseline). If its price impact is below `split_threshold_bps`, return just that.
3. Otherwise greedily allocate across routes by marginal price, subject to `min_improvement_bps`, `min_leg_fraction_bps`, and `maxRoutes`.
4. A split is returned only if it beats the baseline: more total output for exact-in, less total input for exact-out. The chosen `reason` (`below_split_threshold` / `single_route_after_allocation` / `not_better_than_baseline` / `split_applied`) and `splitApplied` are recorded in **logs/traces only**, not the response.

### Errors

| Status | Meaning                                                                                                                                                                 |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Invalid body, `tokenIn == tokenOut`, zero address, non-positive amount, missing `amountIn`/`amountOut` for the `tradeType`, or both amounts sent without a `tradeType`. |
| `401`  | `Invalid API key`: an `Authorization` header was sent with an unknown key.                                                                                              |
| `404`  | `Unknown chainId: <id>`: the chain is not served by the API.                                                                                                            |
| `422`  | `no_route` (no eligible direct/one-hop path) or `insufficient_liquidity` (no candidate had enough depth).                                                               |
| `429`  | Rate limited. A valid key gets a higher limit. Wait for the time in `Retry-After`.                                                                                      |
| `500`  | Internal error loading pool data. Retry.                                                                                                                                |
| `502`  | An upstream data source failed. Retry.                                                                                                                                  |
| `503`  | Routing exceeded the 5s deadline.                                                                                                                                       |

A `422` body carries a machine-readable `code`:

```json
{
  "code": "insufficient_liquidity",
  "error": "no candidate route had enough depth to fill the requested amount"
}
```
