# Streaming

> The stream sends you trades and market moves the moment they land, over Server-Sent Events, with the same filters as the list routes.

Source: https://rivo.markets/docs/streaming

`GET /v2/stream` keeps one HTTP connection open and sends each new trade and market move the moment it lands. Each frame has the same shape as a row from [List Trades](https://rivo.markets/docs/reference/list-trades) or [List Moves](https://rivo.markets/docs/reference/list-moves). Rivo applies your filters before it sends anything, so you receive only what you asked for.

```bash
curl -N "https://api.rivo.markets/v2/stream?channels=trades&venue=kalshi&minWinRate=0.6" \
  -H "Authorization: Bearer $RIVO_API_KEY"
```

## Frames

| Event | Carries |
| --- | --- |
| `trade` | One trade, in the same shape as a `/v2/trades` row. |
| `move` | One market move, in the same shape as a `/v2/moves` row. |
| `error` | An object with `code` and `error`. Rivo sends it just before it closes the stream, for example when you have used up the day's trades. |
| `: ping` | A comment line that Rivo sends every 25 seconds so proxies keep the connection open. You can ignore it. |

## One market, everything on it

The `market` filter applies to both channels. Send `?market=<ref>` to receive every trade and every move on one market over a single connection. Repeat `market` to watch up to 50 markets.

## Reconnecting

Connections drop when we deploy, when a network fails, or when a laptop goes to sleep. Save the time of the last frame you handled. When the connection drops, reconnect after a short backoff, then fetch the trades you missed from the list route with the same filters.

```typescript
let lastSeen = new Date().toISOString();

async function fillGap(): Promise<void> {
  const res = await fetch(`https://api.rivo.markets/v2/trades?venue=kalshi&since=${lastSeen}&limit=200`, { headers });
  for (const trade of (await res.json()).data.reverse()) handle(trade);
}

// On every trade frame: lastSeen = trade.time
// After a reconnect: await fillGap(), then keep reading the stream.
```

Remove duplicates by `id`, because a trade that arrived just before the drop can appear again when you fetch the gap.

## Limits

- Each key can hold three streams open at once, including any on `/v1/stream`. The API refuses a fourth with `429 QUOTA_EXCEEDED`.
- An open stream counts as one request a minute.
- Each trade the stream sends counts toward your 50,000 trades a day. Moves do not count.

The [Stream reference](https://rivo.markets/docs/reference/stream) lists every parameter and shows a full client in three languages.
