# Casts

Base URL: `https://api.brixsignage.com`. Send `Authorization: Bearer $BRIX_API_KEY` unless an operation says Auth: none.

## GET /v1/casts

List casts, which are timed content takeovers, newest first. Use `?status=active` to filter to casts currently on air, and `?limit` (up to 500, default 200) to bound the number of results. Cast history is kept indefinitely.

Auth: Bearer token. Permission: `screen.cast`.

Parameters:

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | "active" \| "cleared" \| "expired" | no | Only casts in this state. |
| `limit` | query | integer | no | At most this many, newest first (default 200, max 500). |

```bash
curl "https://api.brixsignage.com/v1/casts" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of Override |  |
| `data[].id` | string | Override (cast_… or emg_…) id. |
| `data[].spaceId` | string | Workspace id. |
| `data[].kind` | "emergency" \| "cast" |  |
| `data[].status` | "active" \| "cleared" \| "expired" |  |
| `data[].severity` | "info" \| "warning" \| "critical" | Always `info` for a cast. |
| `data[].headline` | string | An emergency's message; for a cast, the content's name (or "Cast"). |
| `data[].body` | string \| null |  |
| `data[].contentKind` | "media" \| "creative" \| "playlist" \| "app" \| "schedule" \| null |  |
| `data[].contentId` | string \| null |  |
| `data[].scopeKind` | "all" \| "node" \| "screens" |  |
| `data[].scopeNodeId` | string \| null | The location, when `scopeKind` is `node`. |
| `data[].nodeId` | string \| null | Location the override is attributed to (null = workspace root). |
| `data[].screenCount` | integer | Screens targeted, snapshotted when it started. |
| `data[].triggeredBy` | string | User id, or `system`. |
| `data[].triggeredAt` | string | ISO-8601 timestamp (UTC). |
| `data[].expiresAt` | string \| null | Auto-clear time; null = until cleared. |
| `data[].clearedBy` | string \| null |  |
| `data[].clearedAt` | string \| null |  |
| `data[].triggeredByName` | string | Display name of `triggeredBy`. |
| `data[].clearedByName` | string \| null |  |
| `data[].scopeName` | string \| null | Location name, `All screens`, or null for a screen list. |
| `data[].confirmedCount` | integer \| null | Active emergencies only: screens confirmed showing it now. Null otherwise. |

```json
{
  "data": [
    {
      "id": "cast_9f2c4a1b7d3e5f60",
      "spaceId": "space_1a2b3c4d5e6f7a8b",
      "kind": "cast",
      "status": "active",
      "severity": "info",
      "headline": "Friday lunch special",
      "body": null,
      "contentKind": "media",
      "contentId": "med_0c1d2e3f4a5b6c7d",
      "scopeKind": "screens",
      "scopeNodeId": null,
      "nodeId": null,
      "screenCount": 2,
      "triggeredBy": "usr_5e6f7a8b9c0d1e2f",
      "triggeredAt": "2026-09-28T11:30:00.000Z",
      "expiresAt": "2026-09-28T13:30:00.000Z",
      "clearedBy": null,
      "clearedAt": null,
      "triggeredByName": "Sam Rivera",
      "clearedByName": null,
      "scopeName": null,
      "confirmedCount": null
    }
  ]
}
```

Response 401: Missing, expired or revoked bearer token.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 403: The token lacks the permission this operation needs (see `x-brix-permission`).

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 5XX: Server error. The body carries a `requestId` to quote to support.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

## POST /v1/casts

Cast content to screens

Put content on air across a set of screens for a period of time, after which the screens automatically revert to their normal content. Send `contentKind` (media, playlist, app, creative, or schedule), `contentId`, `scopeKind`, and optionally `scopeNodeId`, `screenIds`, and `expiresAt`. `scopeKind` accepts all, node, or screens and defaults to all: a request sent with no scope casts to every screen the caller can reach. An active emergency override takes priority over a cast, and the cast resumes automatically once the emergency is cleared.

Puts one piece of content on the chosen screens now, above their schedule, until it expires or is cleared. An emergency still pre-empts a cast.

Auth: Bearer token. Permission: `screen.cast`.

Request body (`application/json`):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `contentKind` | "media" \| "playlist" \| "app" \| "creative" \| "schedule" | yes | What kind of thing `contentId` names. |
| `contentId` | string | yes | The media, playlist, app instance, creative or schedule to put on air. |
| `contentName` | string | no | Label for the cast (shown in the console). Defaults to "Cast". |
| `scopeKind` | "all" \| "node" \| "screens" | no | Which screens: every screen you can reach (`all`), one location's subtree (`node`), or a list (`screens`). **Defaults to `all`: omit it and the cast goes to EVERY screen you can reach.** |
| `scopeNodeId` | string | no | Location id, with `scopeKind: node`. |
| `screenIds` | array of string | no | Screen ids, with `scopeKind: screens`. |
| `expiresAt` | string \| number \| null | no | When the cast ends by itself: ISO-8601 or epoch milliseconds. Omit or null to run until cleared. |

```bash
curl -X POST "https://api.brixsignage.com/v1/casts" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contentKind":"media","contentId":"med_0c1d2e3f4a5b6c7d","contentName":"Friday lunch special","scopeKind":"screens","screenIds":["scr_1a2b3c4d5e6f7a8b","scr_2b3c4d5e6f7a8b9c"],"expiresAt":"2026-09-28T13:30:00.000Z"}'
```

Response 201: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | Override | A cast or an emergency override. |
| `data.id` | string | Override (cast_… or emg_…) id. |
| `data.spaceId` | string | Workspace id. |
| `data.kind` | "emergency" \| "cast" |  |
| `data.status` | "active" \| "cleared" \| "expired" |  |
| `data.severity` | "info" \| "warning" \| "critical" | Always `info` for a cast. |
| `data.headline` | string | An emergency's message; for a cast, the content's name (or "Cast"). |
| `data.body` | string \| null |  |
| `data.contentKind` | "media" \| "creative" \| "playlist" \| "app" \| "schedule" \| null |  |
| `data.contentId` | string \| null |  |
| `data.scopeKind` | "all" \| "node" \| "screens" |  |
| `data.scopeNodeId` | string \| null | The location, when `scopeKind` is `node`. |
| `data.nodeId` | string \| null | Location the override is attributed to (null = workspace root). |
| `data.screenCount` | integer | Screens targeted, snapshotted when it started. |
| `data.triggeredBy` | string | User id, or `system`. |
| `data.triggeredAt` | string | ISO-8601 timestamp (UTC). |
| `data.expiresAt` | string \| null | Auto-clear time; null = until cleared. |
| `data.clearedBy` | string \| null |  |
| `data.clearedAt` | string \| null |  |
| `data.triggeredByName` | string | Display name of `triggeredBy`. |
| `data.clearedByName` | string \| null |  |
| `data.scopeName` | string \| null | Location name, `All screens`, or null for a screen list. |
| `data.confirmedCount` | integer \| null | Active emergencies only: screens confirmed showing it now. Null otherwise. |

```json
{
  "data": {
    "id": "cast_9f2c4a1b7d3e5f60",
    "spaceId": "space_1a2b3c4d5e6f7a8b",
    "kind": "cast",
    "status": "active",
    "severity": "info",
    "headline": "Friday lunch special",
    "body": null,
    "contentKind": "media",
    "contentId": "med_0c1d2e3f4a5b6c7d",
    "scopeKind": "screens",
    "scopeNodeId": null,
    "nodeId": null,
    "screenCount": 2,
    "triggeredBy": "usr_5e6f7a8b9c0d1e2f",
    "triggeredAt": "2026-09-28T11:30:00.000Z",
    "expiresAt": "2026-09-28T13:30:00.000Z",
    "clearedBy": null,
    "clearedAt": null,
    "triggeredByName": "Sam Rivera",
    "clearedByName": null,
    "scopeName": null,
    "confirmedCount": null
  }
}
```

Response 401: Missing, expired or revoked bearer token.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 403: `not_shared`: the content is not shared to one or more target locations.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 404: The content does not exist in this workspace.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 422: Invalid body, the scope matched no screens you can reach (`no_screens`), or the content cannot play (empty playlist, unprocessed media).

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 5XX: Server error. The body carries a `requestId` to quote to support.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

## POST /v1/casts/{id}/clear

End a cast immediately and return its screens to their scheduled content.

Ends an active cast; its screens return to their scheduled content immediately.

Auth: Bearer token. Permission: `screen.cast`.

Parameters:

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Cast id. |

```bash
curl -X POST "https://api.brixsignage.com/v1/casts/{id}/clear" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | Override | A cast or an emergency override. |
| `data.id` | string | Override (cast_… or emg_…) id. |
| `data.spaceId` | string | Workspace id. |
| `data.kind` | "emergency" \| "cast" |  |
| `data.status` | "active" \| "cleared" \| "expired" |  |
| `data.severity` | "info" \| "warning" \| "critical" | Always `info` for a cast. |
| `data.headline` | string | An emergency's message; for a cast, the content's name (or "Cast"). |
| `data.body` | string \| null |  |
| `data.contentKind` | "media" \| "creative" \| "playlist" \| "app" \| "schedule" \| null |  |
| `data.contentId` | string \| null |  |
| `data.scopeKind` | "all" \| "node" \| "screens" |  |
| `data.scopeNodeId` | string \| null | The location, when `scopeKind` is `node`. |
| `data.nodeId` | string \| null | Location the override is attributed to (null = workspace root). |
| `data.screenCount` | integer | Screens targeted, snapshotted when it started. |
| `data.triggeredBy` | string | User id, or `system`. |
| `data.triggeredAt` | string | ISO-8601 timestamp (UTC). |
| `data.expiresAt` | string \| null | Auto-clear time; null = until cleared. |
| `data.clearedBy` | string \| null |  |
| `data.clearedAt` | string \| null |  |
| `data.triggeredByName` | string | Display name of `triggeredBy`. |
| `data.clearedByName` | string \| null |  |
| `data.scopeName` | string \| null | Location name, `All screens`, or null for a screen list. |
| `data.confirmedCount` | integer \| null | Active emergencies only: screens confirmed showing it now. Null otherwise. |

Response 401: Missing, expired or revoked bearer token.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 403: The token lacks the permission this operation needs (see `x-brix-permission`).

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 404: No such cast in this workspace.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 409: `already_inactive`: the cast is already cleared or expired.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |

Response 5XX: Server error. The body carries a `requestId` to quote to support.

| Field | Type | Description |
| --- | --- | --- |
| `error` | string | Machine-readable code: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `conflict`, `rate_limited`, `internal_error`, … |
| `message` | string | Human-readable explanation. Safe to show an operator. |
| `requestId` | string | Present on 5xx: quote it to support. |
