> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hypermid.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Swap orchestration

> Price a route, hand your user an executable transaction, track it to completion.

The three payment products all end with funds arriving at an address **you**
nominated. Swap orchestration is the one that does not: you price a route
between any two tokens on any two chains, and the funds go where your user
asked.

It is the right product when you are building a swap or bridge interface rather
than collecting a payment.

<Note>
  **Hypermid never custodies the funds.** The quote returns a transaction for the
  user's own wallet to sign and submit. We price and route; we do not hold an
  intermediary balance — which is also why there is no session to create and
  nothing to reconcile afterwards.
</Note>

## The shape of it

<Steps>
  <Step title="Quote">
    `POST /quote` with the pair and an amount. You get back an executable
    `transactionRequest` and the numbers to show the user.
  </Step>

  <Step title="Submit">
    Your frontend hands `transactionRequest` to the connected wallet, approving
    the token first if the route needs an allowance.
  </Step>

  <Step title="Track">
    Poll `GET /v1/status` with the transaction hash until it reaches a terminal
    state.
  </Step>
</Steps>

## Quote

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://server.hypermid.io/quote \
    -H "x-api-key: $HYPERMID_PUBLISHABLE_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "srcChain": "8453",
      "tokenIn": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "dstChain": "42161",
      "tokenOut": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
      "amountIn": "25000000",
      "recipient": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
      "srcAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984"
    }'
  ```

  ```typescript TypeScript (SDK) theme={"system"}
  import { quoteSwap } from "@hypermid/sdk";

  const quote = await quoteSwap(
    {
      srcChain: 8453,
      tokenIn: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
      dstChain: 42161,
      tokenOut: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
      amountIn: "25000000",                                   // 25 USDC, 6 decimals
      recipient: userAddress,
      srcAddress: userAddress,
    },
    { apiKey: process.env.HYPERMID_PUBLISHABLE_KEY },
  );
  ```

  ```python Python theme={"system"}
  import requests

  quote = requests.post(
      "https://server.hypermid.io/quote",
      headers={"x-api-key": PUBLISHABLE_KEY},
      json={
          "srcChain": "8453",
          "tokenIn": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "dstChain": "42161",
          "tokenOut": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
          "amountIn": "25000000",
          "recipient": user_address,
          "srcAddress": user_address,
      },
      timeout=30,
  ).json()
  ```
</CodeGroup>

Omit `dstChain`, or set it equal to `srcChain`, for a same-chain swap.

A **publishable** key is enough — quoting moves no money, so this call is safe
from a browser. Only payment-session creation needs the secret key.

## Submit it

```typescript theme={"system"}
import { useSendTransaction } from "wagmi";

const { sendTransactionAsync } = useSendTransaction();
const tx = quote.transactionRequest;

const hash = await sendTransactionAsync({
  to: tx.to,
  data: tx.data,
  value: BigInt(tx.value ?? "0"),
  chainId: Number(tx.chainId),
});
```

Submit `transactionRequest` **as returned**. Rebuilding the calldata yourself
detaches it from the quote that priced it, and the two are bound: the route
encodes a minimum-output amount the contract enforces, so a hand-built
transaction is the fastest route to a revert.

<Warning>
  **Quotes expire.** `expiresAt` is **Unix seconds** — compare against
  `Date.now() / 1000`, not a `Date`. Past it, re-quote rather than retry: a stale
  route reverts on slippage instead of filling at a bad price, which is the safe
  failure but still a failed transaction for your user.
</Warning>

### Approvals

ERC-20 routes need an allowance before the router can pull funds. The quote
tells you the spender:

```typescript theme={"system"}
const spender = quote.estimate.approvalAddress;
// standard ERC-20 approve(spender, amountIn) if the current allowance is short
```

Native-asset routes carry `value` instead and need no approval.

## Track it

```bash theme={"system"}
curl "https://server.hypermid.io/v1/status?txHash=0xabc…"
```

Same-chain swaps resolve in one block. Cross-chain routes are two transactions
with a bridge in between, so `receiving` stays absent until the destination
side lands — that is normal progress, not a stall. Use
`estimate.executionDuration` to set your user's expectations.

There are two status endpoints and they are not interchangeable:

| Endpoint         | Auth        | Use it for                                                                                  |
| ---------------- | ----------- | ------------------------------------------------------------------------------------------- |
| `GET /v1/status` | none        | Your app's own polling. Anonymous and public.                                               |
| `GET /status`    | partner key | Aggregator-compatible shape, for code already written against a common aggregator envelope. |

## Deposit-based routes

Some routes settle by **deposit address** rather than a contract call — the
user sends funds to an address instead of signing a router transaction. This is
how intent routes and most non-EVM destinations work. The quote
signals it with `isIntent` and a populated `deposit`:

```typescript theme={"system"}
if (quote.deposit) {
  // show quote.deposit.address — and quote.deposit.memo when present
} else {
  // submit quote.transactionRequest
}
```

Using the SDK, `execute` is a discriminated union, so the compiler forces the
branch rather than trusting you to remember:

```typescript theme={"system"}
if (quote.execute.kind === "deposit") {
  show(quote.execute.address, quote.execute.memo);
} else {
  await sendTransactionAsync(quote.execute);
}
```

<Warning>
  On memo chains a transfer sent **without** the memo may be unrecoverable.
  Render the memo as prominently as the address, and never let a user copy one
  without the other.
</Warning>

Branch on `deposit` (or `execute.kind`) **first**. On a deposit route the
`transactionRequest` is an inert placeholder — submitting it does nothing
useful.

### Refunds on intent routes

Intent routes ask for `refundRecipient` at quote time, before the user commits
anything. An intent is a solver's promise to deliver, and a promise that fails
has to unwind somewhere — collect the address up front, while the user is still
present, rather than at failure time when they may be long gone.

Aggregator routes need no such field: funds never leave the user's custody
until the swap executes.

## Fees

Your integrator fee comes out of the route and is itemised in
`estimate.feeCosts`. Read [`GET /v1/fee-config`](/api-reference) with your key
to display your own negotiated rate rather than hard-coding a number that can
change without an API version bump.

This direct Swap contract is distinct from Payments. Checkout, Deposit, and
Withdrawal use a Hypermid fee plus an optional developer fee on one base amount;
the developer fee defaults to 0 and is limited to 0–100 basis points. A partner
Hypermid override replaces the global rate outright. Read
`GET /v1/payments/fee-config` for that contract.

Payments' same-token EVM transfer is its zero fee exception. On EVM Payments
routes, developer earnings are held by Hypermid and settled periodically by
manual transfer. On the Near deposit-address rail, the provider keeps half of
each declared app fee and pays the developer leg directly. These Payments rules
do not change direct Swap's caller-selected fee.
