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

# Firm only

> Keep only quotes whose venue is bound to the price, and leave out estimates and indicative prices.

Each quote says whether its venue is bound to the price, in `firm` and `expiresAt`. A search returns every kind unless you ask for firm quotes only.

| Field | Value | Effect |
| - | - | - |
| `filters.firmOnly` | `true`, or `false` (the default) | With `true`, only quotes with `firm: true` are kept in `quotes`. |

## Firm, executable and indicative

| `firm` and `expiresAt` | What it means | What you can rely on | Kept by `firmOnly` |
| - | - | - | - |
| `firm: true`, `expiresAt` set | Firm: the venue delivers exactly this amount until `expiresAt`. | The quoted amount. | Yes |
| `firm: false`, `expiresAt` set | An executable estimate, such as an order-book or AMM quote: the venue will trade until `expiresAt`, and delivery may move a little. | At least `minOut`, set by your [price protection](https://tetrafi.mintlify.site/search/sort-and-protection.md#price-protection). | No |
| `firm: false`, `expiresAt` `null` | Indicative: the venue's current price, not a commitment. `staleAfter` says when the price is old. | Nothing yet. | No |

Ask for firm quotes only when you are about to trade and want to compare only amounts a venue has committed to. Leave it out when you are comparing prices, or when an order book, a pool or a desk that publishes only indicative prices may give you the best one: an executable estimate is still protected by `minOut`.

To turn an indicative quote into a firm one, requote it: see [Requotes and expiry](https://tetrafi.mintlify.site/trade/requotes-and-expiry.md).

```bash cURL theme={null}
# Keep only firm quotes: the venue is bound to the price until expiresAt. Indicative quotes and
# executable estimates held to minOut (order-book and AMM quotes) are dropped once venues answer,
# so a venue that gave only those still reads answered in sources, with no quote in quotes.
request=$(jq -nc --arg sell "$sell" --arg buy "$buy" --arg amount "$amount" '{
  sell: {asset: $sell},
  buy: {asset: $buy},
  sellAmount: $amount,
  filters: {firmOnly: true}
}')
firm_only=$(quote_request "$request")
jq -c '[.quotes[] | {venue: .legs[0].venue.id, firm, expiresAt}]' <<<"$firm_only" >&2
jq -c '[.quotes[].legs[0].venue.id] as $quoted
  | [.sources[] | select(.status == "answered" and (.venue.id | IN($quoted[]) | not)) | .venue.id]' <<<"$firm_only" >&2
```

```typescript TypeScript SDK theme={null}
const firm = await client.quote({
  sell: { asset: usdc.assetId },
  buy: { asset: eth.assetId },
  sellAmount: '10',
  filters: { locations: ['offChain'], firmOnly: true },
});
```

## What you see for the quotes you leave out

Quotes that are not firm are dropped after venues answer, so this filter does not keep any venue from being asked. A venue that gave only estimates or indicative prices still reads `answered` in `sources`, but has no quote in `quotes`:

```json theme={null}
{
  "quotes": [
    { "id": "q_...", "firm": true, "expiresAt": "2026-11-03T02:39:35.040Z" }
  ],
  "sources": [
    { "status": "answered", "venue": { "id": "...", "modality": "rfq" }, "asked": true, "detail": null },
    { "status": "answered", "venue": { "id": "...", "modality": "orderBook" }, "asked": true, "detail": null }
  ]
}
```

Here two venues answered and one quote is left: the order book's quote was an estimate. The sample prints those venues: an `answered` source with no quote.

Because the same venues are asked, a search with `firmOnly: true` counts against the [quote limit](https://tetrafi.mintlify.site/search/how-it-works.md#rate-limit) exactly as it would without the filter.

## Refusals

| Code | Why | What to do |
| - | - | - |
| `INVALID_REQUEST` | `firmOnly` is not `true` or `false`, with `details.field` `filters.firmOnly`. | Send a boolean. |
| `INVALID_REQUEST` | The request names the filter's earlier name, `filters.executableOnly`. | Send `filters.firmOnly` instead. |

## In the app

The trade page has no control for this filter. A shared link can carry it in its `firm` parameter, and it then shows as a **Firm only** chip you can remove; it is then sent with the request.

The results list also has a commitment toggle and an **All types** select. They only filter the quotes already returned, so nothing is sent and no venue is asked again.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.