> 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/retrieve-current-bid-and-ask.md).

# Retrieve pool bid and ask

`GET /public/v1/evm/{chain_id}/{pool_address}/bid_ask`

Returns the pool's adjusted bid and ask with per-bin depth. These are not the raw provider quote: they already include the pool's spread and fees. See [Liquidity and bins](/how-pools-work/liquidity-and-bins.md) for pool pricing.

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.

The `pool_address` is the unique identifier used throughout the API.

To quote many pools at once, use [Retrieve batch bid and ask](/reference/api/retrieve-batch-bid-and-ask.md) (up to 100 per request).

### Path parameters

| Name           | Type    | Description                                                                             |
| -------------- | ------- | --------------------------------------------------------------------------------------- |
| `chain_id`     | integer | EVM chain ID, e.g. `1`. Must be one of the chains returned by `GET /public/v1/chains`.  |
| `pool_address` | address | Pool address as returned by `GET /public/v1/evm/{chain_id}/metadata`. Case-insensitive. |

### Query parameters

All optional.

| Name    | Type    | Default | Description                                                                                                                                       |
| ------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `depth` | boolean | `true`  | `false` returns `"depth": null` and skips the one-sided check (see [Unavailable prices](#unavailable-prices)). Must be exactly `true` or `false`. |

### Request

```bash
curl "https://api.metric.xyz/public/v1/evm/1/0xF85AfbADeCC7F23Dd173ed706f07d9C7e2473e24/bid_ask"
```

### Response

`200 OK`. Depth is trimmed to two levels per side here.

```json
{
  "pair": "WETH/USDC",
  "poolAddress": "0xF85AfbADeCC7F23Dd173ed706f07d9C7e2473e24",
  "priceProviderStatus": "healthy",
  "bidAdj": "49940417631045696435290",
  "askAdj": "49945012360825322506424",
  "totalToken0Available": "24503618827789131821",
  "totalToken1Available": "49785157539",
  "serverTs": 1790508850,
  "depth": {
    "bids": [
      {
        "binIdx": -1,
        "price": "49937913286041055521250",
        "cumulativeVolume": "7430706558",
        "cumulativeInputVolume": "2744786401520641763",
        "priceImpactE6": "51"
      },
      {
        "binIdx": -2,
        "price": "49932918995283375647711",
        "cumulativeVolume": "21731301391",
        "cumulativeInputVolume": "8027598362225637937",
        "priceImpactE6": "151"
      }
    ],
    "asks": [
      {
        "binIdx": -1,
        "price": "49947502535663908680680",
        "cumulativeVolume": "2727338310371559766",
        "cumulativeInputVolume": "7384519505",
        "priceImpactE6": "49"
      },
      {
        "binIdx": 0,
        "price": "49952497285917475071548",
        "cumulativeVolume": "8169278436813730931",
        "cumulativeInputVolume": "22120177339",
        "priceImpactE6": "149"
      }
    ]
  }
}
```

Here `bidAdj / 2^64 = 2707.28` and `askAdj / 2^64 = 2707.52` USDC per WETH. The first bid level fills 2.74 WETH in for 7,430.71 USDC out.

### Response fields

| Field                  | Type           | Description                                                                                                                                                                    |
| ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `pair`                 | string         | Display pair, `token0Symbol/token1Symbol` (same as `/metadata`).                                                                                                               |
| `poolAddress`          | address        | The pool.                                                                                                                                                                      |
| `priceProviderStatus`  | string         | `healthy`, `feed_down`, `pool_refused`, `pool_paused`, `internal_error` or `unknown`. Check this before using any price (see [Unavailable prices](#unavailable-prices) below). |
| `bidAdj`               | string         | Best price for selling token0, Q64.64: token1 per whole token0 = `bidAdj / 2^64`.                                                                                              |
| `askAdj`               | string         | Best price for buying token0, same format.                                                                                                                                     |
| `totalToken0Available` | string \| null | The pool's token0 balance, raw token0 units. Includes fees not yet collected, so slightly more than LPs' liquidity.                                                            |
| `totalToken1Available` | string \| null | The pool's token1 balance, raw token1 units. Includes fees not yet collected, so slightly more than LPs' liquidity.                                                            |
| `serverTs`             | integer        | Server time of the snapshot, Unix seconds.                                                                                                                                     |
| `depth`                | object \| null | Per-bin depth: `bids` (you sell token0) and `asks` (you buy token0). `null` when `depth=false`.                                                                                |

All prices and amounts are decimal strings. Parse them as BigInt, not Number.

#### Depth levels

Each entry in `bids[]` / `asks[]` is one pool bin, ordered outward from the current price.

| Field                   | Type    | Description                                                                                                                                                                                                                                                      |
| ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `binIdx`                | integer | The pool's own bin index, not a level number. Both sides start at the current bin, which is partly consumed. Bids walk down (−1, −2, …) and asks walk up (−1, 0, 1, …).                                                                                          |
| `price`                 | string  | Marginal price at the far edge of this bin, Q64.64 (same format as `bidAdj`).                                                                                                                                                                                    |
| `cumulativeVolume`      | string  | Total **output** you receive by walking through the end of this bin, in raw native units. Bids output token1; asks output token0.                                                                                                                                |
| `cumulativeInputVolume` | string  | Total **input** you pay to walk through the end of this bin, in raw native units. Bids take token0; asks take token1.                                                                                                                                            |
| `priceImpactE6`         | string  | Distance of `price` from `bidAdj` (bids) or `askAdj` (asks), in millionths, unsigned. `49` ≈ 0.005%. This is the marginal price at the bin's far edge, not the average price of an order that reaches it. For that, see [Estimating a fill](#estimating-a-fill). |

| Side   | You         | Input token | Output token |
| ------ | ----------- | ----------- | ------------ |
| `bids` | sell token0 | token0      | token1       |
| `asks` | buy token0  | token1      | token0       |

The last level's `cumulativeVolume` approaches the side's total: `totalToken1Available` for bids, `totalToken0Available` for asks, unless a guard cuts that side short.

How the list ends:

* **Bins past the pool's liquidity** repeat the previous cumulative values and add no volume. Ignore them.
* **A guard such as StopLoss** can stop a side early, at the first bin the pool won't fully fill. If the pool still fills part of that bin, the side ends with one extra level for it: its cumulative values include only the part that fills, and its `price` is where that partial fill stops, not the bin's far edge. If nothing in that bin fills, the side ends at the previous level.

### Estimating a fill

Use the cumulative columns to estimate how much an order of size `X` fills for. [Find best route](/reference/api/find-best-route.md) runs this same calculation on the same depth to score routes, so your estimate matches its output for that snapshot.

Pick the side from the direction: **bids** to sell token0, **asks** to buy token0. Then walk its levels in order, turning the cumulative columns into per-bin amounts:

```
// Exact input: X is what you pay. Returns what you receive.
remaining = X;  received = 0
prevIn = 0;  prevOut = 0
for level in side:
    if level.cumulativeInputVolume <= prevIn: continue   // adds no input: skip
    binIn  = level.cumulativeInputVolume - prevIn
    binOut = level.cumulativeVolume      - prevOut
    prevIn = level.cumulativeInputVolume;  prevOut = level.cumulativeVolume
    if binOut == 0: continue                              // nothing to receive here
    used = min(remaining, binIn)
    received  += floor(binOut * used / binIn)
    remaining -= used
    if remaining == 0: return received
// out of levels: the order is larger than this side's depth
```

For **exact output** (`X` is what you receive), swap the roles: take `used = min(remaining, binOut)` from each bin, add `ceil(binIn * used / binOut)` to what you pay, and stop when `remaining` reaches 0.

Use BigInt throughout and multiply before dividing: the products can exceed 2^128.

The average fill price is `received / X` (exact input) or `X / paid` (exact output), in raw units. Inside a bin, the walk takes a proportional share of the bin's input and output.

**Example:** selling 5 WETH (`X = 5000000000000000000`) into the bids above.

1. The first bin takes all `2744786401520641763` of its input and returns `7430706558` USDC.
2. The remaining `2255213598479358237` fills inside the second bin. That bin has `5282811960704996174` input and `14300594833` output, so it returns `floor(14300594833 × 2255213598479358237 / 5282811960704996174) = 6104872967`.
3. In total you receive `13535579525` (13,535.58 USDC), an average of 2,707.12 USDC per WETH.

Depth is a snapshot for estimation. For an exact amount, quote with `MetricOmmSwapQuoter` before executing.

### Unavailable prices

When the pool can't be quoted, the endpoint still returns `200` with sentinel values:

```json
{
  "priceProviderStatus": "feed_down",
  "bidAdj": "0",
  "askAdj": "340282366920938463463374607431768211455",
  "depth": { "bids": [], "asks": [] }
}
```

`bidAdj = 0`, `askAdj = 2^128 − 1` and empty depth mean the pool is not quotable. `priceProviderStatus` says why:

| Value            | Meaning                                                                                                        |
| ---------------- | -------------------------------------------------------------------------------------------------------------- |
| `healthy`        | The pool is quotable (but see the one-sided case below).                                                       |
| `feed_down`      | The feed has no valid price right now.                                                                         |
| `pool_refused`   | The feed quoted, but the pool refuses to trade on that quote, on both sides.                                   |
| `pool_paused`    | The pool is paused.                                                                                            |
| `internal_error` | Metric failed to read the price on its own side; this does not mean the pool's feed is unhealthy. Retry later. |
| `unknown`        | No status could be determined.                                                                                 |

Treat any `priceProviderStatus` other than `healthy` as "do not trade".

One side can be closed while the status stays `healthy`. For some pools the pool refuses trades in one direction only; that side then gets its sentinel (`bidAdj = "0"` or `askAdj = "340282366920938463463374607431768211455"`) while the other side keeps a real price. Check each side's value, not only the status. This check only runs when `depth=true`: with `depth=false`, a side the pool refuses can still show a real price next to `healthy`, so request depth if you rely on it.

### Errors

| Status | Error                                   | When                                                                                                                                                                                                                                  |
| ------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `Invalid pool address format`           | `pool_address` is not a valid address. An address without the `0x` prefix returns `pool_address is not a valid EVM address`.                                                                                                          |
| `400`  | `Failed to deserialize query string: …` | `depth` is not `true` or `false`. This body is plain text, not JSON.                                                                                                                                                                  |
| `401`  | `Invalid API key`                       | An `Authorization` header was sent with an unknown or revoked key.                                                                                                                                                                    |
| `404`  | `Unknown chainId: <id>`                 | The chain is not served by the API.                                                                                                                                                                                                   |
| `404`  | `Pair metadata not found for <pool>`    | The pool isn't served on this chain: wrong chain, unknown address, a pool delisted by Metric, or a pool on a disabled contract release. A listed pool with no liquidity returns `200`; its depth levels show zero `cumulativeVolume`. |
| `429`  | Rate limited                            | Too many requests. A valid key gets a higher limit. Wait for the time in `Retry-After`.                                                                                                                                               |
| `500`  | `Internal server error`                 | Metric couldn't read the pool onchain. Retry.                                                                                                                                                                                         |
| `503`  | `Service temporarily unavailable`       | A concurrent request for the same pool timed out, or on Ethereum Metric's price service was too busy or slow to answer in time. Retry shortly.                                                                                        |

New API keys work within seconds of being issued.
