# Streaming (SSE)

> Open the Server-Sent Events connection, pass the right query parameters, handle each event type, and reconnect cleanly without missing matches.

```text
GET /v1/stream?timeout=60&since=30m&limit=100
```

Opens a [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events)
connection authenticated with a **tap token**. Only events matching the tap's rules are delivered.

```bash
curl -N https://api.firehose.com/v1/stream \
  -H "Authorization: Bearer $FIREHOSE_TAP_TOKEN"
```

## Query parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `timeout` | int | Connection duration in seconds, 1–300. Default 300 |
| `since` | string | Replay buffered events from a relative window, e.g. `5m`, `1h`, `24h` (max 24h) |
| `offset` | int | Start from an exact event offset on the tap's stream |
| `limit` | int | Close after delivering this many events, 1–10000 |

Buffered events are retained for roughly 24 hours.

**Precedence:** `Last-Event-ID` > `offset` > `since` > live tail.

## Event types

A `connected` event is sent on open:

```text
event: connected
data: {}
```

An `update` event is a page that matched a rule:

```text
id: 0-43368
event: update
data: {"query_ids":["1"],"matched_at":"2026-02-13T08:06:32Z","tap_id":"1","document":{"url":"https://example.com/page","title":"Example Page","diff":{"chunks":[{"typ":"ins","text":"…"}]}}}
```

An `error` event reports a problem:

```text
event: error
data: {"message":"No rules configured. Create rules first via POST /v1/rules."}
```

An `end` event means the stream closed normally (timeout or limit). Reconnect to continue:

```text
event: end
data: {}
```

## Reconnecting

Each `update` carries an `id:`. Send it back as the
`Last-Event-ID` header to resume from the next event. The browser `EventSource` API does this
automatically on reconnect, so a dropped connection resumes where it left off (within the ~24h buffer).

<Callout type="warning">
  The native browser `EventSource` API cannot send custom headers, so it can't pass the
  `Authorization` bearer token. You'll need an SSE client that supports request headers — see
  [code examples](/api-reference/examples).
</Callout>

See [Match payload](/stream/match-payload) for every field on the delivered `document`.

## Next steps

<CardGrid>
  <Card title="Code examples" href="/api-reference/examples">
    Working SSE clients in curl, Node, and Python.
  </Card>
  <Card title="Stream disconnects or errors" href="/troubleshooting/stream-disconnects">
    What to do when the connection drops, 401s, or 402s.
  </Card>
</CardGrid>
