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

# Stream Quote Updates

> Subscribe to real-time best-quote updates for a quote request via Server-Sent Events.

Open a Server-Sent Events (SSE) stream to receive real-time best-quote updates for a specific quote request. As market makers submit, update, and withdraw quotes, you receive the current best offer automatically.

## Authentication

API key required. Pass your API key in the `X-API-Key` header. The key needs the `positions:read` scope.

```
X-API-Key: <your-api-key>
```

A Privy JWT (`Authorization: Bearer <jwt>`) is also accepted — see [Authentication](/guides/authentication).

## Path parameters

<ParamField path="id" type="string" required>
  The quote request ID (UUID).
</ParamField>

## SSE event types

### `best_quote`

Sent whenever the quote book changes (new quote submitted, quote updated, quote withdrawn, or quote expired). The `book_seq` increments monotonically so you can detect missed updates.

```json theme={null}
{
  "book_seq": 5,
  "version": 3,
  "request_hash": "sha256:9f86d08...",
  "best_quote": {
    "id": "b2c3d4e5-6789-0abc-def1-234567890abc",
    "payout_odds": 4.25,
    "user_cost": 25,
    "total_payout": 106.25,
    "mm_cost": 81.25,
    "valid_until": "2026-06-01T18:45:45.000Z",
    "market_maker_id": "mm-uuid-1234"
  }
}
```

When no quotes are active, `best_quote` is `null`:

```json theme={null}
{
  "book_seq": 6,
  "version": 3,
  "request_hash": "sha256:9f86d08...",
  "best_quote": null
}
```

### `status`

Sent when the quote request transitions out of the `active` state (committed, cancelled, or expired). The stream closes after this event. `committed_rfq_id` is the created RFQ id when `status` is `committed`, and `null` otherwise.

```json theme={null}
{
  "status": "committed",
  "committed_rfq_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd"
}
```

Immediately after `status`, the stream emits one **terminal event** matching the outcome, then closes. Listen for either the generic `status` event or the specific one below.

### `committed`

The quote request was committed into a real RFQ. Use `rfq_id` to follow the trade through confirmation and settlement on the [WebSocket](/guides/websocket) `rfq:{rfq_id}` channel.

```json theme={null}
{
  "quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40",
  "rfq_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd"
}
```

### `cancelled`

The quote request was cancelled (by you, via [Cancel](/api-reference/quote-service/cancel)).

```json theme={null}
{
  "quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40"
}
```

### `expired`

The quote request reached its `expires_at` without being committed.

```json theme={null}
{
  "quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40"
}
```

## Integration guide

1. Open the SSE stream after creating or updating a quote request.
2. On each `best_quote` event, update your displayed payout odds and store the `book_seq` and best quote `id`.
3. When the user is ready to commit, pass `expected_version`, `displayed_quote_id`, `displayed_quote_book_seq`, and `min_payout_odds_seen` to the [Commit](/api-reference/quote-service/commit) endpoint.
4. On a terminal event, close the stream and handle the outcome. When the request commits, read the new RFQ id from `committed_rfq_id` (on the `status` event) or `rfq_id` (on the `committed` event), then follow the trade on the [WebSocket](/guides/websocket) `rfq:{rfq_id}` channel.

## Errors

| Status | Code           | Description                        |
| ------ | -------------- | ---------------------------------- |
| 401    | `UNAUTHORIZED` | Missing or invalid API key.        |
| 403    | `FORBIDDEN`    | You do not own this quote request. |
| 404    | `NOT_FOUND`    | Quote request not found.           |

<RequestExample>
  ```bash curl theme={null}
  curl -N https://api.totalis.trade/v1/quote-requests/1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40/stream \
    -H "X-API-Key: $TOTALIS_API_KEY" \
    -H "Accept: text/event-stream"
  ```

  ```javascript JavaScript theme={null}
  // Native EventSource can't send an X-API-Key header — read the SSE stream
  // with fetch instead (works in browsers and Node 18+).
  async function streamQuotes(id, apiKey) {
    const res = await fetch(
      `https://api.totalis.trade/v1/quote-requests/${id}/stream`,
      { headers: { 'X-API-Key': apiKey, Accept: 'text/event-stream' } }
    );

    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) return;
      buffer += decoder.decode(value, { stream: true });

      let sep;
      while ((sep = buffer.indexOf('\n\n')) !== -1) {
        const frame = buffer.slice(0, sep);
        buffer = buffer.slice(sep + 2);
        const event = frame.match(/^event: (.+)$/m)?.[1];
        const data = frame.match(/^data: (.+)$/m)?.[1];
        if (!event || !data) continue;
        const payload = JSON.parse(data);

        if (event === 'best_quote') {
          console.log('Best quote:', payload.best_quote, 'book_seq:', payload.book_seq);
        } else if (event === 'committed') {
          console.log('RFQ created:', payload.rfq_id);
          return; // the stream closes after a terminal event
        } else if (event === 'cancelled' || event === 'expired') {
          console.log('Terminal:', event);
          return;
        }
      }
    }
  }
  ```

  ```python Python theme={null}
  import requests
  import json

  url = 'https://api.totalis.trade/v1/quote-requests/1a6d1f06.../stream'
  headers = {
      'X-API-Key': api_key,
      'Accept': 'text/event-stream',
  }

  event_type = None
  with requests.get(url, headers=headers, stream=True) as resp:
      for line in resp.iter_lines(decode_unicode=True):
          if line.startswith('event: '):
              event_type = line[7:]
          elif line.startswith('data: '):
              payload = json.loads(line[6:])
              if event_type == 'best_quote':
                  print('Best quote:', payload['best_quote'])
              elif event_type in ('committed', 'cancelled', 'expired'):
                  print(f'Terminal: {event_type}', payload)
                  break
              event_type = None
  ```
</RequestExample>

<ResponseExample>
  ```text SSE stream theme={null}
  event: best_quote
  data: {"book_seq":1,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"b2c3d4e5-6789-0abc-def1-234567890abc","payout_odds":4.25,"user_cost":25,"total_payout":106.25,"mm_cost":81.25,"valid_until":"2026-06-01T18:45:45.000Z","market_maker_id":"mm-uuid-1234"}}

  event: best_quote
  data: {"book_seq":2,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"e5f6a7b8-9012-cdef-3456-7890abcdef12","payout_odds":4.50,"user_cost":25,"total_payout":112.50,"mm_cost":87.50,"valid_until":"2026-06-01T18:45:50.000Z","market_maker_id":"mm-uuid-5678"}}

  event: status
  data: {"status":"committed","committed_rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}

  event: committed
  data: {"quote_request_id":"1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40","rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
  ```
</ResponseExample>
