# Quickstart

> Go from zero to a live stream of matching web pages in about five minutes — get a management key, create a tap, add a rule, then open the stream.

This walkthrough uses the API end to end. You'll create a management key, mint a tap, add a rule,
and open the stream. Everything here can also be done from the [dashboard](https://firehose.com/dashboard).

## 1. Get a management key

Sign in at [firehose.com](https://firehose.com), open **Management keys**, and create one. It's
shown once and prefixed `fhm_` — store it securely.

```bash
export FIREHOSE_MGMT_KEY=fhm_your_management_key
```

## 2. Create a tap

A **tap** is a scoped API token (prefixed `fh_`) that owns a set of rules and is what you stream from.

```bash
curl -s -X POST https://api.firehose.com/v1/taps \
  -H "Authorization: Bearer $FIREHOSE_MGMT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Brand mentions"}'
```

The response includes the full tap token. Save it:

```bash
export FIREHOSE_TAP_TOKEN=fh_your_tap_token
```

## 3. Add a rule

Rules are written in [Firehose query syntax](/stream/rules). This one matches pages whose content
mentions Tesla, published in the last 24 hours.

```bash
curl -s -X POST https://api.firehose.com/v1/rules \
  -H "Authorization: Bearer $FIREHOSE_TAP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value": "tesla AND recent:24h", "tag": "brand"}'
```

## 4. Open the stream

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

You'll receive a `connected` event, then one `update` event per matching page. A real first
event looks like this:

```text
event: connected
data: {}

id: 0-43368
event: update
data: {"query_ids":["1"],"matched_at":"2026-02-13T08:06:32Z","tap_id":"1","document":{"url":"https://example.com/news/tesla-q4-earnings","title":"Tesla Q4 earnings beat expectations","publish_time":"2026-02-13T07:58:11","diff":{"chunks":[{"typ":"ins","text":"Tesla reported record Q4 deliveries…"}]},"page_category":["/News"],"page_types":["/Article"],"language":"en"}}
```

The `id:` is what you send back as `Last-Event-ID` to resume after a
drop. The matched content arrives in the `diff` — Firehose delivers the change that matched, not the
whole page. See [Match payload](/stream/match-payload) for every field on `document`.

<Callout type="tip">
  The stream closes after `timeout` seconds (default 300). Reconnect to continue — the browser
  `EventSource` API sends `Last-Event-ID` automatically so you resume where you left off.
</Callout>

## Next steps

<CardGrid>
  <Card title="Rules & query syntax" href="/stream/rules">
    Fields, operators, URL/domain filters, recency, and quality.
  </Card>
  <Card title="Streaming reference" href="/stream/streaming">
    Event types, parameters, and reconnection.
  </Card>
  <Card title="Not getting matches?" href="/troubleshooting/no-matches">
    Why a brand-new stream can look empty, and how to confirm it works.
  </Card>
</CardGrid>
