---
title: Stream API
updatedAt: 2026-09-05T16:42:52.097Z
---

Fetch the complete documentation index at: https://docs.watchers.io/llms.txt

# Stream API

You can create and manage RTMP live streams in rooms via API. Creating a stream returns RTMPS ingest credentials (server and stream key for OBS or any RTMP encoder) and an HLS playback URL. Every broadcast session is recorded automatically and is available as VOD.

Each room has **one stream**: the create endpoint is idempotent and always returns the credentials of the room's current stream. The `externalRoomId` is the same room ID used in the [Room API](https://docs.watchers.io/docs/room-api).

> ⚠️ **Regional endpoints: Replace `stream.watchers.io` with the endpoint matching your project region. See [Supported Regions](https://docs.watchers.io/docs/supported-regions) for details.**
>
> | Region           | Endpoint                |
> | ---------------- | ----------------------- |
> | Europe (default) | `stream.watchers.io`    |
> | North America    | `stream.us.watchers.io` |
> | South America    | `stream.sa.watchers.io` |
> | Asia             | `stream.hk.watchers.io` |
> | Africa           | `stream.za.watchers.io` |

## Create or get a stream

Creates a stream for the room and returns ingest credentials. If the room already has an active stream, the existing credentials are returned — the call is idempotent and safe to repeat.

**Endpoint** `https://stream.watchers.io/stream/rooms/:externalRoomId`

**Method** `PUT`

**Body** application/json (optional)

**Path parameter**

| Parameter        | Type   | Required | Description                               |
| ---------------- | ------ | -------- | ----------------------------------------- |
| `externalRoomId` | string | Yes      | Unique room ID (same as in the Room API). |

**Body**

| Parameter  | Type   | Required | Description                                               |
| ---------- | ------ | -------- | --------------------------------------------------------- |
| `talkerId` | number | No       | Optional. ID of the speaker to associate the stream with. |

```curl
curl -X 'PUT' \
  'https://stream.watchers.io/stream/rooms/liveevent123' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: {Api key of project from admin panel}' \
  -H 'Authorization: Bearer {Bearer token from admin panel}'
```

**Response**

```json
{
  "provider": "cloudflare",
  "streamKey": "d6f3ffb32bdd3fa8b4d4d8284740b6f5k80ee15af9c419fda12f8e2f4a725c40",
  "streamServer": "rtmps://live.cloudflare.com:443/live/",
  "streamUrl": "https://customer-ab12cd34.cloudflarestream.com/8f4e2b1c9d3a4f6e8b0c2d4e6f8a0b1c/manifest/video.m3u8",
  "playbackUrl": "https://customer-ab12cd34.cloudflarestream.com/8f4e2b1c9d3a4f6e8b0c2d4e6f8a0b1c/manifest/video.m3u8"
}
```

**Notes**

- `streamServer` and `streamKey` are the ingest credentials for your encoder: in OBS set **Settings → Stream → Service: Custom**, **Server** = `streamServer`, **Stream Key** = `streamKey`.
- `playbackUrl` is a public HLS manifest (`.m3u8`). It plays in any HLS player (hls.js, Video.js, native Safari). Typical end-to-end latency is 10–20 seconds. `streamUrl` is a legacy alias of `playbackUrl`.
- The credentials are reusable: you can stop and start broadcasting through the same stream many times (including recurring and 24/7 rooms). Each broadcast session is saved as a separate recording.
- Streams that stay idle for over two weeks are cleaned up and their credentials are revoked. The call is idempotent, so simply repeat it before going live to make sure your credentials are current — recordings are not affected by the cleanup.
- When the broadcast starts, the stream automatically appears in the room player on the Watchers frontend — no extra API calls are needed.

## Get stream status

**Endpoint** `https://stream.watchers.io/stream/rooms/:externalRoomId`

**Method** `GET`

**Path parameter**

| Parameter        | Type   | Required | Description     |
| ---------------- | ------ | -------- | --------------- |
| `externalRoomId` | string | Yes      | Unique room ID. |

```curl
curl -X 'GET' \
  'https://stream.watchers.io/stream/rooms/liveevent123' \
  -H 'accept: application/json' \
  -H 'x-api-key: {Api key of project from admin panel}' \
  -H 'Authorization: Bearer {Bearer token from admin panel}'
```

**Response**

```json
{
  "id": 42,
  "provider": "cloudflare",
  "project": "yourproject",
  "externalRoomId": "liveevent123",
  "isLive": true,
  "streamKey": "d6f3ffb32bdd3fa8b4d4d8284740b6f5k80ee15af9c419fda12f8e2f4a725c40",
  "streamServer": "rtmps://live.cloudflare.com:443/live/",
  "playbackUrl": "https://customer-ab12cd34.cloudflarestream.com/8f4e2b1c9d3a4f6e8b0c2d4e6f8a0b1c/manifest/video.m3u8",
  "videoUrl": "https://customer-ab12cd34.cloudflarestream.com/2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f/manifest/video.m3u8",
  "createdAt": "2026-07-08T12:00:00.000Z",
  "streamEndedAt": null
}
```

**Notes**

- `isLive` switches to `true` when the encoder connects and back to `false` when it disconnects.
- `videoUrl` is the HLS URL of the latest finished recording. It is `null` until the first recording has been processed.
- `streamEndedAt` is the time the last broadcast session ended; it is `null` while the stream is live.

## Stop and delete a stream

Ends the broadcast, revokes the ingest credentials and removes the stream from the room.

**Endpoint** `https://stream.watchers.io/stream/rooms/:externalRoomId`

**Method** `DELETE`

**Path parameter**

| Parameter        | Type   | Required | Description     |
| ---------------- | ------ | -------- | --------------- |
| `externalRoomId` | string | Yes      | Unique room ID. |

```curl
curl -X 'DELETE' \
  'https://stream.watchers.io/stream/rooms/liveevent123' \
  -H 'accept: application/json' \
  -H 'x-api-key: {Api key of project from admin panel}' \
  -H 'Authorization: Bearer {Bearer token from admin panel}'
```

**Response**

```json
{
  "deleted": true
}
```

**Notes**

- Only the stream is deleted — **the room itself is not affected**. Rooms are managed separately via the [Room API](https://docs.watchers.io/docs/room-api).
- Recordings are **not** deleted — they remain available via the recordings endpoint (see “List recordings” below).
- After deletion, a new `PUT` request creates a fresh stream with new credentials. The old stream key stops working.

## List recordings

Returns all recordings (VOD) made in the room, newest first.

> ℹ️ **Recording is always enabled: each broadcast session is automatically saved as a separate video. No API calls are needed to start or stop recording.**

**Endpoint** `https://stream.watchers.io/stream/rooms/:externalRoomId/videos`

**Method** `GET`

**Path parameter**

| Parameter        | Type   | Required | Description     |
| ---------------- | ------ | -------- | --------------- |
| `externalRoomId` | string | Yes      | Unique room ID. |

```curl
curl -X 'GET' \
  'https://stream.watchers.io/stream/rooms/liveevent123/videos' \
  -H 'accept: application/json' \
  -H 'x-api-key: {Api key of project from admin panel}' \
  -H 'Authorization: Bearer {Bearer token from admin panel}'
```

**Response**

```json
[
  {
    "id": 7,
    "project": "yourproject",
    "externalRoomId": "liveevent123",
    "slug": "2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f",
    "duration": 5400000,
    "url": "https://customer-ab12cd34.cloudflarestream.com/2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f/manifest/video.m3u8",
    "createdAt": "2026-07-08T12:00:00.000Z"
  }
]
```

**Notes**

- `duration` is in milliseconds.
- `url` is a public HLS manifest of the recording, playable in any HLS player.
- A recording appears in the list within a few minutes after the broadcast session ends.
- Recordings survive stream deletion, so the full VOD history of the room is always available here.

## Errors

| Status | Message                                           | Cause                                             |
| ------ | ------------------------------------------------- | ------------------------------------------------- |
| 404    | `Project not found`                               | The `x-api-key` header is missing or invalid.     |
| 403    | `Bearer token is required` / `Wrong bearer token` | The `Authorization` header is missing or invalid. |
| 404    | `Stream not found`                                | The room has no active stream (GET, DELETE).      |

<br>
