# Quotes and pricing

> Price a trade from either side, what a quote guarantees, and how size limits work.

`GET /v2/quote` prices one direction and size without creating an order. Use it on your confirmation screen: "you send X, you receive Y". It is a required step, because the price exists nowhere else. The API never invents one.

## Price from either side

| `mode` | You send | You get back |
|---|---|---|
| `exact_input` (default) | `srcAmount`: what the user spends | `receive.amount`: what the user gets |
| `exact_output` | `outcomeAmount`: what the user should receive | `spend.amount`: the smallest deposit that gets there |

Both amounts come back either way, so you never invert a rate yourself. Send only the amount that `mode` names. Both, neither, or the other one is a `400`.

```bash
curl -s "https://api.hyperstream.dev/v2/quote?fromChainId=42161&from=0xaf88d065e77c8cC2239327C5EDb3A432268e5831&toChainId=1&to=0xdAC17F958D2ee523a2206206994597C13D831ec7&srcAmount=100000000" \
  -H "X-API-Key: $KHALANI_API_KEY"
```

## What to show the user

Show `spend.amount` and `receive.amount` using their respective `decimals`. They reflect the token fees; source-chain transaction gas and the native-token relay fee in `depositTx.value` are additional. `details.protocolFee` is Khalani's part of the fees and does not include your commission. See [Fees and commission](/guides/fees/).

`details.intentOutcomeRate` is the solver's rate for the amount left after fees, not the all-in rate for the deposit. Don't display it.

## What a quote guarantees

**A `200` means the size is fillable right now.** Solvers name a minimum and a maximum on every quote, and the API refuses sizes outside them rather than pricing something it would not fill. On `exact_output` there is no minimum. A small target returns a larger `spend.amount` instead.

Prices move, and a quote reserves nothing. Two quotes seconds apart can differ.

**The rate per unit is guaranteed; the total is not.** Orders can fill partially. If an order for 1,000 fills 600, the user receives 600's worth at the quoted rate and is refunded the rest, less the flat fee and the percentage fees on the filled 600. So `exact_output` means "if the order fills completely, the user receives at least this amount". When a shortfall is unacceptable, such as paying an invoice of a fixed amount, read the order's `settledOutcome` and top up.

**`exact_output` can deliver slightly more, never less.** `receive.amount` comes back at or above `outcomeAmount`. The excess is at most one source base unit's worth, because a deposit moves in whole source base units.

## The build object

`build` is the `/v2/build` request, already assembled. Send it back unchanged with the depositor's address added:

```ts
await post("/v2/build", { ...quote.build, depositor });
```

`build.terms` is Khalani's signed attestation of this quote. It pins the build to exactly the numbers you showed the user, and it is valid for five minutes, until `build.terms.expiresAt` (Unix seconds). From that second on the build returns `409` and you quote again. A build with any field of `build` changed returns `400`.

A quote is not used up by a build. You can build the same quote more than once within its five minutes, and each build creates a separate order.

:::caution[Always send `terms`]
`/v2/build` accepts a request without `terms`, but then nothing ties the order to the quote: the rate you send is signed as is, and the flat fee is recomputed at current settings. The user can end up with less than you showed, and nothing reports it. Always send `quote.build` complete.
:::

## Size limits

Too small returns `400` with `detail.minSrcAmount`. Too large returns `409` with `detail.maxSrcAmount` (`exact_input`) or `detail.maxOutcomeAmount` (`exact_output`). Re-quote at the returned figure.

- The returned figures are adjusted so that re-quoting at them works. The limits can move between calls, so a retry can still fail. If it does, follow the new figure.
- A too-small refusal can mean the deposit does not exceed the flat fee, solvers will not fill that little, or the output would round below one destination base unit. The flat-fee check runs first, before solvers are asked, so its `minSrcAmount` clears only the flat fee: quote again and follow the next figure. The other two refusals return a `minSrcAmount` that clears all three.
- There is no minimum in `GET /v2/params`. Only a quote can tell you.

As of 19 October 2026, quoting 1,000 base units (0.001 USDC) from Arbitrum USDC to Ethereum USDT returned:

```json
{ "error": "Deposit is at or below the flat fee, so nothing would be published", "detail": { "minSrcAmount": "99899" } }
```

## Timing

The quote asks solvers for a price and waits up to five seconds. The solver-minimum and one-base-unit refusals make a second pricing call to compute the minimum, so those `400`s can take about twice as long as a `200`.

See the [`GET /v2/quote` reference](/api/operations/getquote/) for every field and status.
