# Integration guide (v1)

> The v1 flow end to end. Routes, deposit methods, quotes with and without a wallet, fees, and production rules.

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

v1 is non-custodial. The user signs and sends the deposit from their own wallet. Your integration requests quotes, runs the wallet actions the API returns, and tracks the order until it is final.

It suits wallets and apps that offer cross-chain swaps, aggregators that want another route source, and backends that coordinate quoting, deposits and status for a UI.

## The flow

1. **Quote.** `POST /v1/quotes` returns a `quoteId` and `routes[]`.
2. **Build.** `POST /v1/deposit/build` with `{ from, quoteId, routeId }` returns the deposit plan: wallet actions in `approvals[]`, or a deposit address.
3. **Execute.** The user's wallet runs `approvals[]` in order. See [Wallet execution](/v1/wallet-execution/).
4. **Submit.** `PUT /v1/deposit/submit` with `{ txHash, quoteId, routeId }` returns the `orderId`.
5. **Track.** Poll `GET /v1/orders/by-id/{orderId}` until the status is `filled`, `refunded` or `failed`.

```mermaid
sequenceDiagram
    participant B as Your app
    participant W as User's wallet
    participant K as API v1
    B->>K: POST /v1/quotes
    K-->>B: quoteId + routes[]
    B->>K: POST /v1/deposit/build
    K-->>B: approvals[]
    B->>W: switch chain, approve, deposit
    W-->>B: deposit txHash
    B->>K: PUT /v1/deposit/submit
    K-->>B: orderId
    B->>K: GET /v1/orders/by-id/{orderId}
```

## Routes

A route is one way of executing the order. Route ids are literal and case-sensitive.

| `routeId` | `type` | Covers |
|---|---|---|
| `Hyperstream` | `native-filler` | The native route: the order settles through Khalani. |
| `HyperstreamUTXO` | `liquidity-router` | The native route for trades with TRON or Bitcoin on either side. |
| `Across` | `external-intent-router` | Across. |
| `DeBridge` | `external-intent-router` | deBridge. |
| `Glacis` | `external-intent-router` | Glacis. Exact-output quotes are found by searching for the matching input (`exactOutMethod: "adaptive"`). |

**The native route wins when it quotes.** If `Hyperstream` or `HyperstreamUTXO` returns a quote, it is the only route in the response, even when an external route would pay more. External routes appear only when no native route quotes. An explicit list in `?routes=` turns the preference off, so to compare routes yourself, name them there, for example `?routes=Hyperstream,Across,DeBridge`. Most responses therefore carry one route, and picking `routes[0]` is a sound default.

## Quote with or without the wallet

Send `fromAddress` when you know the wallet that will deposit. That is the normal case:

- With `fromAddress`, every route can quote, and the quote is bound to that wallet. The build must use the same address in `from`; any other address returns `400`.
- Without `fromAddress`, Across, deBridge and Glacis do not quote. The native route returns an indicative quote. To build it, pass `from`. The native route then prices it again for that wallet and returns `400` if the price moved, or otherwise a `buildId` that the submit must send back.

## Deposit methods

Each route lists the methods it accepts in `depositMethods`. Ask for one with `depositMethod` on the build. If you leave it out, the build uses the route's only method, or `CONTRACT_CALL` when there are several.

| Method | The user | Then |
|---|---|---|
| `CONTRACT_CALL` | Signs the wallet actions in `approvals[]`. | You submit the deposit's hash. |
| `TRANSFER` | Sends a plain transfer to a deposit address, from any wallet. | No submit. Track with `GET /v1/orders/{refundTo}?orderIds={orderId}`. |
| `TRANSFER_WITH_TX_HASH_SUBMIT` | Sends a plain transfer to a deposit address on TRON or Bitcoin. | You submit the transfer's hash. |

The native route offers `TRANSFER` on some EVM source chains, next to `CONTRACT_CALL`. A TRON or Bitcoin source uses `TRANSFER_WITH_TX_HASH_SUBMIT`. `PERMIT2` is in the schema, but no route offers it, and asking for it returns `400`. See [Deposit](/v1/reference/deposit/) for the response of each method.

## What happens to the user's funds

- On the native route (`Hyperstream`), the deposit goes into Khalani's deposit contract on the source chain, and the order is published as an intent carrying the quoted output, the recipient, the refund address and a deadline (`validBefore`). A filler pays the user on the destination chain. If no filler does before the deadline, the order moves to `refund_pending`, and to `refunded` once the cross-chain refund message is delivered and the deposit is returned to the refund address on the source chain. [How Khalani works](/concepts/how-khalani-works/) and the [trust model](/concepts/trust-model/) describe the hub and the parts you trust.
- On `HyperstreamUTXO`, a TRON or Bitcoin source has no deposit contract, so the user transfers to a deposit address and an operated service credits it.
- On an external route, the deposit goes into that protocol's contracts, and the protocol fills or refunds the order under its own rules. The API builds the transaction and tracks the order; it does not hold the funds.

## Integrator id and fees

v1 takes no API key. If Khalani gave you an integrator id, send it as the `X-Integrator-Id` header on `POST /v1/quotes`. It selects your fee configuration and is recorded on the quote and the order. The build and the submit read it from the stored quote, so they need no header.

- The id is not authentication. A malformed header is ignored, and an unknown or disabled id falls back to the default fees.
- The body field `integratorId` is the older form. When both are sent, the header wins.
- To take a referrer fee on a single quote, send `referrer` and `referrerFeeBps`. Only the native route applies them. See [Quotes](/v1/reference/quotes/).

## Production rules

- **Respect `quoteExpiresAt`.** Do not build or deposit on an expired quote. Quote again instead.
- **Run `approvals[]` in order, one at a time.** Wait for a receipt wherever `waitForReceipt` is `true`. A deposit sent before its approval confirms reverts.
- **Submit each deposit once.** A repeated submit returns `404`, because the quote is consumed when the order is created.
- **Track every order until it is final.** Show `refund_pending` as "refund on its way", not as a failure, and tell the user where the refund goes.
- **Retry by error type.** See [Handling exceptions](/v1/handling-exceptions/).
- **There is no testnet.** `https://api.hyperstream.dev` is the only environment. Test with small amounts.
