# Migrate to v2

> Map each v1 endpoint to v2, the behaviour that changes, and what v2 does not cover yet.

> API v1 is deprecated. It stays supported, but new integrations should use the [Khalani API](/). See [Migrate to v2](/v1/migrate/).

v2 is a different API, not a new version of the same calls. Where v1 asks several routes for a price and stores the quote, v2 asks solvers for one price, stores nothing until the build, and needs an API key. The order lifecycle, the error bodies and the fees change too. Plan the move as a new integration, and keep v1 for anything on the [not on v2 yet](#not-on-v2-yet) list.

Read these v2 pages first: the [Quickstart](/quickstart/), [Conventions](/guides/conventions/), the [Order lifecycle](/guides/order-lifecycle/) and [Build and deposit](/guides/build-and-deposit/). Every v2 field is in the [API reference](/api/).

## Endpoint mapping

| v1 | v2 | What changes |
|---|---|---|
| `POST /v1/quotes`, with or without `?mode=stream` | `GET /v2/quote` (API key) | One solver price instead of an aggregation of routes. Nothing is stored: the quote returns a `build` object whose signed `terms` are valid for five minutes. `mode` is `exact_input` or `exact_output`. No streaming. |
| `POST /v1/deposit/build` | `POST /v2/build` (API key) | The build creates the order and returns its `orderId`. EVM sources get `approveTxs[]` and one `depositTx`; a TRON source gets `depositAddress`, `expectedAmount` and `deadline`. Not idempotent: every successful call creates a new order. |
| `PUT /v1/deposit/submit` | None | v2 detects the deposit on-chain. There is no submit step and no server-side broadcast. |
| `GET /v1/orders/{address}` | `GET /v2/orders` (API key) | Scoped to your integrator. Filters: `depositor`, `from`, `to`, `state`. Keyset cursor; `limit` up to 200. |
| `GET /v1/orders/by-id/{orderId}` | `GET /v2/orders/{orderId}` (no key) | Eight states instead of seven, with partial fills. |
| `GET /v1/tokens`, `/v1/tokens/search`, `/v1/tokens/balances/{address}`, `/v1/tokens/autocomplete/{keyword}` | `GET /v2/params` (API key), its `tokens` list | No search, balances or autocomplete. |
| `GET /v1/chains`, `GET /v1/chain/{chainId}/icon` | None | v2 gives only the chain id of each token in `GET /v2/params`. |
| None | `POST /v2/orders/{orderId}/cancel` | New: the depositor signs a cancel, and your backend relays it. |

## Behaviour that changes

| | v1 | v2 |
|---|---|---|
| Access | No key. `X-Integrator-Id` is optional and only selects fee configuration. | `X-API-Key` on every call except `GET /v2/orders/{orderId}` and `GET /v2/health`. |
| Price | Several routes are asked; the native route wins whenever it quotes. | One solver-backed price. A `200` means that size can be filled now. |
| Order id | Returned by submit, after the deposit. | Returned by build, before the deposit. Persist it before the wallet signs. |
| Deposit | The wallet runs the actions; you submit the hash. | The wallet sends `depositTx` from `depositor`; v2 finds it on-chain. |
| States | `created` → `deposited` → `published` → `filled`, or `refund_pending` → `refunded`, or `failed`. | Eight states. Polling stops at `delivered` or `delivery_failed`; keep polling through `withdrawn_on_hub`. |
| Partial fills | No. An order fills or refunds. | Yes. Settlement pays out the filled part and refunds the rest in one step. |
| Errors | `{ message, name, details? }` | Route errors are `{ error, detail? }`. Validation, malformed JSON and maintenance bodies keep the v1 shapes. |
| Rate limits | Build: 60 per minute per wallet, 300 per IP. Quotes unlimited. | Quote: 120 per minute per integrator, 600 per IP. Build: 60 and 300. |
| Your fee | `referrer` and `referrerFeeBps` on the quote, plus the integrator configuration that `X-Integrator-Id` selects. | A commission set in the on-chain integrator registry, read when the order publishes. |

Do not map the states one to one. A v2 order can be partly filled, and it settles once: the payout and the refund happen together, so there is no `filled` versus `refunded` split to mirror. Rewrite your status handling against the eight states in the [Order lifecycle](/guides/order-lifecycle/).

## Migrate step by step

1. **Get an API key**, and send it as `X-API-Key` on every v2 call. The [Quickstart](/quickstart/) covers access.
2. **Replace the quote.** Call `GET /v2/quote` with `fromChainId`, `from`, `toChainId`, `to` and `srcAmount` (or `mode=exact_output` with `outcomeAmount`). Show the user `spend.amount` and `receive.amount`, which include every fee.
3. **Replace the build.** Send the quote's `build` object back unchanged, `terms` included, plus `depositor`. Store the returned `orderId` before anything else. Do not retry a build that returned one.
4. **Drop the submit.** Have the wallet send the approvals and then `depositTx`, once, from `depositor`. A deposit from any other account does not create an order.
5. **Replace tracking.** Poll `GET /v2/orders/{orderId}` until `delivered` or `delivery_failed`, with a local timeout. `withdrawn_on_hub` confirms settlement but not delivery.
6. **Replace error handling.** Log `error ?? message` and keep the `x-request-id`. See [Conventions](/guides/conventions/).

## Not on v2 yet

These work on v1 and have no v2 equivalent today. If your product depends on one, keep that flow on v1.

- Volatile tokens. v2 trades a short list of tokens; volatile tokens are planned.
- Fifteen chains: Optimism, Avalanche, Linea, 0G, BNB Smart Chain, Unichain, Monad, Berachain, Mantle, Katana, ZKsync Era, Abstract, Jovay, Solana and Bitcoin.
- External routes: Across, deBridge and Glacis.
- Solana as a source or destination.
- Bitcoin as a source or destination.
- Deposit addresses on EVM sources. v2 gives a deposit address only for a TRON source.
- Server-side broadcast of a signed transaction.
- Streaming quotes.
- Token search, balances and autocomplete.
- Chain metadata: names, native currencies, RPC and explorer URLs, icons.
