> 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/integrate/integrate-metric-liquidity.md).

# Integrate Metric liquidity

For aggregators and solvers

## Integration Overview

Connect Metric liquidity in an aggregator, solver or trading application.

Integrate through the Metric API or directly through its contracts.

### Option 1: API integration (recommended)

Use the Metric API for pool metadata, quotes, depth and routes. Quote and route endpoints are public; a Trading API key raises their rate limits. See [Via API](/integrate/integrate-metric-liquidity/via-api.md).

### Option 2: smart contract or SDK integration

Call Metric's contracts directly: quote offchain with `MetricOmmSwapQuoter` (via `eth_call`), then swap through the router or the pool. A contract cannot get a live quote from inside a transaction for a pool priced by Chainlink or Pyth. See [Via smart contracts](/integrate/integrate-metric-liquidity/via-smart-contracts.md).

Compressed oracle feeds have public reads. Chainlink and Pyth reads are restricted to registered pools during swaps, approved integrators, and offchain `eth_call`s made without a `from` address. See [Oracles](/how-pools-work/oracles.md).

### Executing a swap

Before routing, read pool metadata and route only to pools whose `priceProviderStatus` is `healthy` and whose `pauseLevel` is `0`. Route legs return the no-limit `priceLimitX64`, so set your own protection: `amountOutMinimum` for exact input, `amountInMaximum` for exact output.

A successful quote does not guarantee execution. Before sending, simulate the actual transaction with your real `from` address.

### Why a swap reverts

| Cause                                                                                      | Error                                                                                                                                                 | Check before sending                                                                                               |
| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Price data too old or missing, or the provider halted                                      | Swap: `PriceProviderFailed(reason)`, where `reason` holds the provider's error (e.g. `FeedStalled()`). Quote: the provider's error itself, unwrapped. | Metadata `priceProviderStatus` is not `healthy`                                                                    |
| Pool not registered with its oracle                                                        | `PriceProviderFailed(reason)`, where `reason` holds the oracle's `NotRegistered(feedId, pool)`                                                        | Quotes still succeed, because offchain reads skip the access check. Simulate the transaction with your real `from` |
| Provider quote failed the pool's price checks                                              | `BidAskRefAsymmetryOutOfBounds`, `BidGreaterThanAsk`, `ReferencePriceOutOfRange`, `BidIsZero`                                                         | A Live quote reverts with the same error, wrapped                                                                  |
| Pool paused                                                                                | `PoolPaused`                                                                                                                                          | Metadata `pauseLevel` above 0. A Live quote reverts with the quoter's `PoolPaused(pool, pauseLevel)`, unwrapped    |
| StopLoss: the swap would leave a bin's per-share value further below its peak than allowed | `OracleStopLossTriggered(binIdx, isToken0Metric, currentMetric, threshold)`                                                                           | A quote runs extensions and reverts with the same error, wrapped                                                   |
| Velocity Guard: the reference price moved faster than allowed                              | `PriceVelocityExceeded(actualDeltaSqE36, allowedDeltaSqE36)`                                                                                          | A quote runs extensions and reverts with the same error, wrapped                                                   |
| Sender not on the pool's swap allowlist                                                    | `NotAllowedToSwap`                                                                                                                                    | Quote with the real `sender` (the router, for router swaps)                                                        |
| Trading hours or another custom extension                                                  | The extension's own error                                                                                                                             | Quote with the real `sender`, `recipient` and `extensionData`                                                      |
| Pool not from the current factory                                                          | `InvalidPool` (router)                                                                                                                                | Use only pools listed by `/metadata`                                                                               |
| Output below your minimum, or input above your maximum                                     | `InsufficientOutput`, `InputTooHigh`                                                                                                                  | Your own limits                                                                                                    |
| Exact output not reached (price limit or thin depth)                                       | `InvalidOutputAmount`                                                                                                                                 | Quote the exact output first                                                                                       |
| A multihop leg filled only partially                                                       | `InvalidInputAmountAtHop`, `InvalidOutputAmountAtHop`                                                                                                 | A quote reverts with the quoter's own errors of the same name, which have different selectors                      |
| Deadline passed                                                                            | `TransactionExpired`                                                                                                                                  | —                                                                                                                  |
| Nothing to fill on that side                                                               | `FinalAmountIsZero`                                                                                                                                   | A quote reverts with the same error, wrapped                                                                       |
| Direct pool swap: callback underpaid                                                       | `IncorrectDelta`                                                                                                                                      | Only when calling the pool directly                                                                                |

In a quote, "wrapped" means the quoter reverts `WrappedError(pool, selector, reason)`; decode `reason` for the error in the table.

On a swap, extension errors reach you unwrapped: the pool re-throws the extension's revert data unchanged.
