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

# Quote Request Stream

> Subscribe to the Convallax maker quote-request stream over Server-Sent Events — connection, X-API-Key auth, snapshot and live events, and Last-Event-ID reconnect/replay semantics.

The quote-request stream is **channel 1** of the Convallax maker transport: a **Server-Sent Events (SSE)** feed that pushes live `quote_request` events to you as traders open them. It replaces the old WebSocket `quote_request` broadcast.

| Channel              | Transport | Direction      | Purpose                                                                                |
| -------------------- | --------- | -------------- | -------------------------------------------------------------------------------------- |
| 1 — Quote requests   | **SSE**   | server → maker | Receive live `quote_request` events (this page)                                        |
| 2 — Quote submission | REST      | maker → server | [`POST /v1/mm/quotes`](/api-reference/market-maker/submit-quote) and confirm signature |
| 3 — Post-trade       | WebSocket | server → maker | [`quote:accepted` / `quote:confirmed` / `quote:rejected`](/guides/websocket)           |

<Info>
  To fully participate you must hold **both** this SSE stream open (to receive requests) **and** the [post-trade WebSocket](/guides/websocket) (to learn when you win). Quotes and confirmation signatures are submitted over [REST](/api-reference/market-maker/submit-quote).
</Info>

## Connecting

```
GET https://api.convallax.com/v1/mm/quote-requests/stream
```

This is a standard SSE endpoint (`Content-Type: text/event-stream`). In a **browser**, you can use the native `EventSource` API only if you authenticate via `?apiKey=` on the URL (browsers cannot set `X-API-Key` on SSE). **Market-maker bots** run in Node.js and should use the [`eventsource`](https://www.npmjs.com/package/eventsource) npm package, which supports custom headers:

```bash theme={null}
npm install eventsource
```

## Authentication

Authenticate with your **per-MM API key** using the `X-API-Key` header:

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

Or, if your SSE client cannot set custom headers, pass the key as a query parameter:

```
GET https://api.convallax.com/v1/mm/quote-requests/stream?apiKey=<your-key>
```

<Note>
  The SSE quote-request stream and the REST quote endpoints authenticate via the **`X-API-Key`** header (or `?apiKey=`). The post-trade WebSocket still uses `?apiKey=` on the URL or an `auth` message. See [Authentication](/guides/authentication).
</Note>

## Connection Handshake

When you connect, the server emits events in a fixed order.

<Steps>
  <Step title="connected">
    The first event confirms your resolved `makerId` and the server time.

    ```
    event: connected
    data: { "makerId": "mm-alpha", "serverTime": "2026-06-15T12:00:00.000Z" }
    ```
  </Step>

  <Step title="Replay or snapshot">
    The server then sends **either** a replay (if you reconnected with a `Last-Event-ID` header that is still in the buffer) **or** a fresh snapshot of all currently open requests:

    ```
    event: snapshot_begin
    data: {}

    event: quote_request
    id: 1042
    data: { "requestId": "req-789", ... }

    event: snapshot_complete
    data: {}
    ```

    Between `snapshot_begin` and `snapshot_complete` you receive zero or more `quote_request` events, each carrying an SSE `id:`.
  </Step>

  <Step title="Live events">
    After the snapshot completes, new `quote_request` and `quote_request_expired` events stream in as they happen.
  </Step>
</Steps>

## Events

### `connected`

Sent once, immediately on connect.

```
event: connected
data: { "makerId": "mm-alpha", "serverTime": "2026-06-15T12:00:00.000Z" }
```

### `snapshot_begin` / `snapshot_complete`

Frame the initial set of open quote requests. Everything between them reflects the state at connect time.

```
event: snapshot_begin
data: {}
```

```
event: snapshot_complete
data: {}
```

### `quote_request` — New or replayed quote request

A live quote request. Each event carries a monotonic integer SSE `id:` — track the last one you processed so the server can replay on reconnect.

```
event: quote_request
id: 1043
data: {
  "requestId": "req-789",
  "expiresAt": "2026-06-15T12:05:00.000Z",
  "params": {
    "wallet": "0xTrader...",
    "market": {
      "conditionId": "0xa4ddc18895cc7b14810283ef8f113939abffd3969c6a0e37f1897110c67e6f73",
      "yesTokenId": "51508280778202349361616850684455231843716212176724253736363122559269229712002",
      "question": "Will there be a Hantavirus outbreak in 2026?"
    },
    "option": {
      "optionType": "call",
      "strikeBps": 50,
      "expiryMs": 1735689600000
    },
    "trade": {
      "side": "buy",
      "budgetUsd": 100
    }
  }
}
```

| Field                       | Type          | Description                                                                                                              |
| --------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `requestId`                 | string        | Unique ID for this quote request — use it when you `POST /v1/mm/quotes`                                                  |
| `expiresAt`                 | string        | ISO 8601 expiry time for the quote request (default 5 min TTL)                                                           |
| `params.wallet`             | string        | Taker wallet address (may be `null` if not yet provided)                                                                 |
| `params.market.conditionId` | string        | Polymarket condition ID (bytes32)                                                                                        |
| `params.market.yesTokenId`  | string        | Polymarket YES CLOB token ID                                                                                             |
| `params.market.question`    | string        | Human-readable market question                                                                                           |
| `params.option.optionType`  | string/number | `"call"` or `"put"` (or `0`/`1`)                                                                                         |
| `params.option.strikeBps`   | number        | Strike in basis points of \$1                                                                                            |
| `params.option.expiryMs`    | number        | Option expiry (Unix ms)                                                                                                  |
| `params.trade.side`         | string        | `"buy"` or `"sell"` (taker's side)                                                                                       |
| `params.trade.budgetUsd`    | number        | **Buys only.** USDC the taker will spend. Fill = `floor(budgetUsd / price)` whole options, capped by your quoted `size`. |
| `params.trade.size`         | number        | **Sells only.** Number of whole options the taker wants to write.                                                        |

### `quote_request_expired` — Request closed

The request closed (committed, expired, or cancelled). Drop it from local state.

```
event: quote_request_expired
data: { "requestId": "req-789" }
```

## Reconnect & Replay

SSE clients should reconnect automatically on disconnect. The standard `EventSource` API tracks the last received `id:` and sends it back as the `Last-Event-ID` header on reconnect; the server replays any events you missed.

* If the gap is **small enough** to be covered by the server buffer, you receive a replay of the missed `quote_request` / `quote_request_expired` events.
* If the gap is **too large**, the server falls back to a fresh `snapshot_begin` … `snapshot_complete` sequence reflecting current open requests.

<Tip>
  If you use a non-browser client that does not automatically manage `Last-Event-ID`, store the last SSE `id:` you processed and set the `Last-Event-ID` header yourself when reconnecting.
</Tip>

## Keep-Alive

The server sends SSE comment lines (`: ping`) roughly every 25 seconds to keep the connection and any intermediary proxies alive. SSE clients ignore comment lines automatically.

## Example

```javascript theme={null}
import EventSource from 'eventsource';

const stream = new EventSource(
  'https://api.convallax.com/v1/mm/quote-requests/stream',
  { headers: { 'X-API-Key': process.env.MAKER_API_KEY } }
);

stream.addEventListener('connected', (e) =>
  console.log('connected', JSON.parse(e.data))
);

stream.addEventListener('quote_request', (e) => {
  const req = JSON.parse(e.data);
  console.log(`New request ${req.requestId}: ${req.params.market.question}`);
  // Price it and submit via POST /v1/mm/quotes (channel 2)
});

stream.addEventListener('quote_request_expired', (e) => {
  const { requestId } = JSON.parse(e.data);
  console.log(`Request ${requestId} closed`);
});

stream.onerror = () => console.log('disconnected — EventSource will retry');
```

<Info>
  See the [Market Maker guide](/guides/market-maker) for the end-to-end flow across all three channels, and the [Quote Request Stream API reference](/api-reference/market-maker/quote-stream) for the endpoint details.
</Info>
