> ## 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.

# Operating guide

> Run an integration in production: prices for watching and quotes for trading, requotes over new searches, safe retries, unknown outcomes and following orders.

These are the habits that keep an integration fast, inside its limits and safe with money. Each rule links to the guide that covers it in full, and each example is a runnable sample from those guides.

> [!NOTE]
>
> The API may change until launch. Every change is listed in the [Changelog](https://tetrafi.mintlify.site/changelog.md).

## Watch prices, quote to trade

A quote request asks every venue live, and each venue limits how often it answers. Use `GET /api/v1/prices` or `GET /api/v1/prices/stream` to show prices or watch a market. Request a quote only when you mean to trade: only a quote has an `id` you can order, and only an executable quote holds its terms until `expiresAt`.

Never poll quotes to track a price. You may send one live quote request every 3 seconds per key, and venues that are asked too often answer `askLimitReached` or `firmQuoteLimited` for a while. [Prices before you quote](https://tetrafi.mintlify.site/search/prices.md) covers the price reads.

```bash cURL theme={null}
# Prices for the pair from memory: no venue is asked, so it costs no quote request.
# Each row is one venue, location and variant pair. Rows are indicative, never orderable.
path="/api/v1/prices?sell=$sell&buy=$buy&sellAmount=$amount"
prices=$(tetrafi GET "$path")
jq -c '{referenceMid: .referenceMid.buyPerSell, rows: [.rows[] | {venue: .venue.id,
  location: .location.kind, status, buy: .sizes[0].buy}]}' <<<"$prices" >&2
```

## Requote instead of searching again

When a quote you hold expires, or you want another wallet, corridor or price protection, requote it: `POST /api/v1/quotes` with `requote` set to its id. Only that quote's venue is asked again. The original stays orderable until its own `expiresAt`. [Requotes and expiry](https://tetrafi.mintlify.site/trade/requotes-and-expiry.md) lists what a requote can change.

```bash cURL theme={null}
# Ask the same venue again for the same pair and amount. The answer is a new quote whose
# requoteOf names the original. The original stays orderable until its own expiresAt.
requoted=$(quote "{\"requote\":\"$quote_id\"}")
fresh=$(jq -c '.quotes[0]' <<<"$requoted")
jq -c '{quoteId: .id, requoteOf, firm, buy: .buy.amount, minOut, expiresAt}' <<<"$fresh" >&2
```

```typescript TypeScript SDK theme={null}
// Requote by id. The answer is a new quote set; the refreshed quote carries a new id and `requoteOf`.
const fresh = await client.requote(held.id);
const renewed = fresh.quotes.find((quote) => quote.requoteOf === held.id);
if (!renewed) throw new Error('The requote answered without a quote naming the original in requoteOf.');
// Order `renewed.id` from here on, never the lapsed `held.id`.
```

## Retry with the same key and body

Send one `Idempotency-Key` per order, and store it with the order before you send. When a call times out, the connection drops, or the answer is a retryable `503`, send the same body with the same key. A replay returns the first answer, so no order is placed twice. [Idempotency](https://tetrafi.mintlify.site/trade/idempotency.md) lists which answers to retry.

```bash cURL theme={null}
# Same key, same body: you get the first answer back and no second order is placed.
# Use this to retry after a timeout or a dropped connection.
replayed=$(tetrafi POST /api/v1/orders "$order_body" "Idempotency-Key: $idempotency_key")
jq -n -c --argjson a "$placed" --argjson b "$replayed" \
  '{replayedSameOrder: ($a.orderId == $b.orderId)}' >&2
```

```typescript TypeScript SDK theme={null}
// Sending the same request with the same key again returns the same order; it never places a second one.
const replay = await client.order(request, { idempotencyKey });
const id = (result: OrderResult): string => (result.kind === 'basicTrade' ? result.operation.operationId : result.order.orderId);
```

For every other request, retry only answers marked retryable in the [error-code reference](https://tetrafi.mintlify.site/reference/error-codes.md). Wait `Retry-After` seconds when it is sent:

```bash cURL theme={null}
# One live quote request every 3 seconds. Send two at once: one is answered, the other
# answers 429 QUOTE_RATE_LIMITED with details.retryAfter (ISO 8601, such as PT3S) and the
# same wait in whole seconds in the Retry-After header. Wait that long, then retry once.
# Each signature is accepted once, so the two requests differ in amount.
quote_body() {
  jq -c -n --arg sell "$sell" --arg buy "$buy" --arg amount "$1" \
    '{sell: {asset: $sell}, buy: {asset: $buy}, sellAmount: $amount}'
}
tetrafi POST /api/v1/quotes "$(quote_body 10)" >"$tmp/first" 2>/dev/null & first=$!
tetrafi POST /api/v1/quotes "$(quote_body 11)" >"$tmp/second" 2>/dev/null & second=$!
wait "$first" && first_ok=true || first_ok=false
wait "$second" && second_ok=true || second_ok=false

if [[ $first_ok == true ]]; then limited=$(<"$tmp/second") amount=11; else limited=$(<"$tmp/first") amount=10; fi
jq -c '{error, requestId, retryAfter: .details.retryAfter}' <<<"$limited" >&2
if [[ $(jq -r '.error' <<<"$limited") == QUOTE_RATE_LIMITED ]]; then
  # PT3S is 3 seconds; a fraction such as PT1.5S rounds up.
  wait_seconds=$(jq -r '.details.retryAfter | capture("^PT(?<s>[0-9.]+)S$").s | tonumber | ceil' <<<"$limited")
  sleep "$wait_seconds"
  retried=$(tetrafi POST /api/v1/quotes "$(quote_body "$amount")")
  echo "retried after ${wait_seconds}s: $(jq '.quotes | length' <<<"$retried") quotes" >&2
fi
```

## An unknown outcome is not a failure

When an order times out, or reads `outcomeUnknown`, the trade may still have filled. Never place a new order for the same intent to "make sure". Keep reading its status, or find the order by its quote:

```bash cURL theme={null}
# When you cannot tell whether an order was placed, read it by its quote id before doing
# anything else. ordered: read the order at statusUrl. notOrdered: nothing was placed.
# unknown: wait, then read again.
recovered=$(tetrafi GET "/api/v1/orders/by-quote/$order_quote")
jq -c '{state, orderId, statusUrl}' <<<"$recovered" >&2
unordered=$(tetrafi GET "/api/v1/orders/by-quote/$quote_id")
jq -c '{state, expired}' <<<"$unordered" >&2
```

Only when the order is shown not to exist, or reads a final status that did not fill, is it safe to order again, on a new quote.

## Follow an order to the end

Read an order at its `statusUrl` every 10 to 15 seconds until `terminal` is `true`. When `next` says `wait`, read again after its `retryAfter`; when it says `contact`, contact support with its `reference`. Treat a status you do not recognise as "other" and keep following `terminal`. [Order status](https://tetrafi.mintlify.site/trade/order-status.md) lists every status.

```bash cURL theme={null}
# Read the order at the statusUrl its answer gave: the same envelope as POST /orders, for
# Basic and Advanced orders alike. Poll every 10 to 15 seconds until terminal is true. While it
# is not, next can say what to do: wait (retryAfter) or contact support with its reference.
# A status you do not recognise is "other": keep following terminal.
status_url=$(jq -r '.statusUrl' <<<"$placed")
for _ in $(seq 1 12); do
  read_order=$(tetrafi GET "$status_url")
  jq -c '{kind, status, terminal, next}' <<<"$read_order" >&2
  [[ $(jq -r '.terminal' <<<"$read_order") == true ]] && break
  wait=$(jq -r '.next | select(.kind == "wait") | .retryAfter | capture("^PT(?<s>[0-9]+)S$").s' \
    <<<"$read_order" 2>/dev/null || true)
  sleep "${wait:-10}"
done
```

Or let [webhooks](https://tetrafi.mintlify.site/trade/webhooks.md) tell you: an `order.updated` event is sent to your endpoint on each order status change. It is thin: it names the order and the `statusUrl` to read, so read that URL rather than trusting the order events arrived in. An event can arrive more than once, so record each event's `id` and skip one you have already handled.


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