# Screens (part 3 of 4)

> For AI agents: the full docs index is at https://brixsignage.com/llms.txt, and every page has a markdown twin (add .md to the path).

Screens is split into 4 pages: [part 1](https://brixsignage.com/developers/api/screens.md) (`/v1/screens` to `/v1/screens/{id}`), [part 2](https://brixsignage.com/developers/api/screens-2.md) (`/v1/screens/{id}` to `/v1/screens/{id}/mirror`), [part 3](https://brixsignage.com/developers/api/screens-3.md) (`/v1/screens/{id}/outages` to `/v1/screens/{id}/unpower-and-delete`), [part 4](https://brixsignage.com/developers/api/screens-4.md) (`/v1/screens/{id}/up-next` to `/v1/screens/touch-content`).

Base URL `https://api.brixsignage.com`. Send `Authorization: Bearer $BRIX_API_KEY` unless an operation says Auth: none or Auth: no API key. The Permission line names what the key must hold. See [Authentication and scopes](https://brixsignage.com/developers/authentication.md), [Errors and rate limits](https://brixsignage.com/developers/errors-and-rate-limits.md) and [Pagination](https://brixsignage.com/developers/pagination.md).

- [GET /v1/screens/{id}/outages](#get-v1-screens-id-outages)
- [GET /v1/screens/{id}/playback-quality](#get-v1-screens-id-playback-quality)
- [GET /v1/screens/{id}/preview](#get-v1-screens-id-preview)
- [GET /v1/screens/{id}/quality](#get-v1-screens-id-quality)
- [POST /v1/screens/{id}/replace-device](#post-v1-screens-id-replace-device)
- [GET /v1/screens/{id}/resource-pressure](#get-v1-screens-id-resource-pressure)
- [POST /v1/screens/{id}/restore](#post-v1-screens-id-restore)
- [POST /v1/screens/{id}/revoke-device](#post-v1-screens-id-revoke-device)
- [POST /v1/screens/{id}/rotate-token](#post-v1-screens-id-rotate-token)
- [GET /v1/screens/{id}/state](#get-v1-screens-id-state)
- [GET /v1/screens/{id}/telemetry](#get-v1-screens-id-telemetry)
- [POST /v1/screens/{id}/trigger](#post-v1-screens-id-trigger)
- [POST /v1/screens/{id}/unpower-and-delete](#post-v1-screens-id-unpower-and-delete)

Every 4xx and 5xx response below returns this body:

| 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. |

## GET /v1/screens/{id}/outages

Get a screen's outage history

Get the outage history for a screen over the last N days (default 30, capped at the retention window). Each outage includes when it happened, how long it lasted, a plain-language cause such as a Wi-Fi drop or a power cut, and supporting evidence, along with a summary sentence such as "went down 6 times in the last 30 days, all Wi-Fi drops". Planned downtime is listed but excluded from the outage count.

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

Parameters:

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Screen id. |
| `days` | query | string | no | Window in days (default 30), capped at the workspace's retention. |
| `limit` | query | string | no | Most outages to list (default 50). |

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/outages" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.screenId` | string |  |
| `data.windowDays` | integer |  |
| `data.retentionDays` | integer |  |
| `data.summary` | OutageSummary | Outages in a window, by cause. |
| `data.summary.windowDays` | integer |  |
| `data.summary.count` | integer | Unplanned outages in the window. |
| `data.summary.byCause` | object | Outage count per cause; a cause with none is absent. |
| `data.summary.byCause.power-loss` | integer |  |
| `data.summary.byCause.powered-off` | integer |  |
| `data.summary.byCause.os-reboot` | integer |  |
| `data.summary.byCause.app-crash` | integer |  |
| `data.summary.byCause.app-killed-low-memory` | integer |  |
| `data.summary.byCause.app-anr` | integer |  |
| `data.summary.byCause.app-restart` | integer |  |
| `data.summary.byCause.wifi-dropped` | integer |  |
| `data.summary.byCause.wifi-weak` | integer |  |
| `data.summary.byCause.wifi-no-internet` | integer |  |
| `data.summary.byCause.ethernet-dropped` | integer |  |
| `data.summary.byCause.brix-unreachable` | integer |  |
| `data.summary.byCause.display-off` | integer |  |
| `data.summary.byCause.sleep` | integer |  |
| `data.summary.byCause.scheduled-off` | integer |  |
| `data.summary.byCause.unknown` | integer |  |
| `data.summary.byCause.power-cycle` | integer |  |
| `data.summary.byCause.network-only` | integer |  |
| `data.summary.byBucket` | object |  |
| `data.summary.byBucket.app` | integer |  |
| `data.summary.byBucket.display` | integer |  |
| `data.summary.byBucket.unknown` | integer |  |
| `data.summary.byBucket.network` | integer |  |
| `data.summary.byBucket.power` | integer |  |
| `data.summary.byBucket.brix` | integer |  |
| `data.summary.byBucket.planned` | integer |  |
| `data.summary.topCause` | string \| null |  |
| `data.summary.topCauseShare` | number |  |
| `data.summary.hedgedShare` | number |  |
| `data.summary.lastCause` | object \| null |  |
| `data.summary.lastAt` | string \| null |  |
| `data.summary.lastKnownCause` | object \| null |  |
| `data.summary.avgRssiDbm` | number \| null |  |
| `data.summary.insight` | string \| null | The rollup sentence, e.g. `All 6 were Wi-Fi drops.` |
| `data.outages` | array of object |  |
| `data.outages[].id` | string |  |
| `data.outages[].from` | string | ISO-8601 timestamp (UTC). |
| `data.outages[].to` | string \| null | Null while the screen is still down. |
| `data.outages[].durationSec` | integer \| null |  |
| `data.outages[].open` | boolean |  |
| `data.outages[].detectionPath` | string |  |
| `data.outages[].cause` | object \| null |  |
| `data.outages[].label` | string \| null |  |
| `data.outages[].sentence` | string \| null |  |
| `data.outages[].evidence` | object \| null |  |
| `data.outages[].expectedDark` | boolean \| null | True for planned darkness (operating hours): listed, never counted. |
| `data.outages[].expectedReason` | string \| null |  |
| `data.outages[].selfReportedReason` | string \| null |  |
| `data.outages[].playerVersion` | string \| null |  |
| `data.truncated` | boolean |  |

Response 401: Missing, expired or revoked bearer token.

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

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

## GET /v1/screens/{id}/playback-quality

Get a screen's playback quality

Check whether this screen's device is limiting playback quality. The response reports, for each 4K-capable video, whether it plays at full quality or has been reduced because of device limitations or stuttering, along with any hardware upgrade recommendation.

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

Parameters:

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

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/playback-quality" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.model` | string \| null |  |
| `data.tier` | string \| null |  |
| `data.serves4k` | boolean | True when the device is sent 4K renditions. |
| `data.videos4k` | array of object |  |
| `data.videos4k[].id` | string |  |
| `data.videos4k[].name` | string |  |
| `data.videos4k[].demoted` | boolean |  |
| `data.videos4k[].served` | boolean |  |
| `data.recommendation` | string \| null |  |
| `data.limitedBy` | "panel" \| "decoder" \| null | Why a 4K-tier device is not sent 4K: its panel shows less than 4K, or it has no hardware 4K decoder. Null when not limited. |

Response 401: Missing, expired or revoked bearer token.

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

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

## GET /v1/screens/{id}/preview

Preview what a screen would play at a given time, without affecting the actual device. Pass `at` as an ISO timestamp to preview a different time; it defaults to now.

**Notes.**
- `data` is the player manifest. Content blocks are open objects in the player's own format; `v` versions it.

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

Parameters:

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Screen id. |
| `at` | query | string | no | ISO timestamp to build the preview for; default now. |

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/preview" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | ManifestPreview | What the screen would play: the player manifest, built as the device would receive it. |
| `data.v` | integer | Manifest format version. |
| `data.screen` | object |  |
| `data.screen.id` | string |  |
| `data.screen.name` | string |  |
| `data.screen.rotation` | integer |  |
| `data.screen.tags` | array of string |  |
| `data.generatedAt` | string | ISO-8601 timestamp (UTC). |
| `data.minPlayerVersion` | string |  |
| `data.content` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.content.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.standbyContent` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.standbyContent.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.screensOff` | boolean | True when the rules say the panel should be off now. |
| `data.operatingWindow` | object \| null | Weekly on-hours by weekday key (`mon`…`sun`), or null for always on. |
| `data.proofOfPlay` | boolean |  |
| `data.dooh` | boolean | True when the workspace has advertising on. Players ignore ad pods when this is false. |
| `data.playbackMode` | "sync" \| "unsync" \| "device-time" |  |
| `data.clock` | object |  |
| `data.clock.timeZone` | string |  |
| `data.language` | string |  |
| `data.location` | object \| null |  |
| `data.playerSettings` | object | Effective player settings (volume, watermark, download policy, …). |
| `data.watermarkText` | string \| null |  |
| `data.watermarkLogoUrl` | string | The customer's own logo as the corner mark, on the device-readable media route. Present only for a direct, paying workspace with a Brand Kit logo and the logo switch on. Draw it instead of the text mark; when it fails to load, draw no mark. |
| `data.accountHold` | object | Present when the account is on hold: the screen shows a hold card, not content. |
| `data.accountHold.status` | string |  |
| `data.accountHold.reason` | string |  |
| `data.kiosk` | object | Screen Lock. The device's PIN material is never returned here — only whether it is set. |
| `data.kiosk.enabled` | boolean |  |
| `data.kiosk.graceSeconds` | integer |  |
| `data.kiosk.hasPin` | boolean |  |
| `data.kiosk.hasRecovery` | boolean |  |
| `data.apkUpdatePolicy` | object |  |
| `data.apkUpdatePolicy.window` | boolean |  |
| `data.apkUpdatePolicy.hourLocal` | integer |  |
| `data.apkUpdatePolicy.forceAfterDays` | integer |  |
| `data.apkUpdatePolicy.windowMinutes` | integer |  |
| `data.apkUpdatePolicy.force` | boolean |  |
| `data.apkUpdate` | object |  |
| `data.apkUpdate.version` | string |  |
| `data.apkUpdate.url` | string |  |
| `data.apkUpdate.sha256` | string |  |
| `data.apkUpdate.signature` | string \| null |  |
| `data.testMode` | true |  |
| `data.testEligible` | true |  |
| `data.flightRecorder` | object |  |
| `data.flightRecorder.sampleMs` | number |  |
| `data.flightRecorder.maxEdge` | number |  |
| `data.flightRecorder.quality` | number |  |
| `data.mediaBenchClipUrl` | string | A short public clip the player decodes off-screen for its media self-test. Absent unless configured. |
| `data.fonts` | array of object |  |
| `data.fonts[].family` | string |  |
| `data.fonts[].url` | string |  |
| `data.fonts[].weights` | array of integer |  |
| `data.upcomingBlocks` | array of object | The next scheduled changes, so an offline device can pre-load them. |
| `data.upcomingBlocks[].activatesAt` | string | ISO-8601 timestamp (UTC). |
| `data.upcomingBlocks[].content` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.upcomingBlocks[].content.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.upcomingBlocks[].screensOff` | boolean |  |
| `data.retiredMediaIds` | array of string | Media this workspace deleted from its library in the last 30 days (newest first, at most 200). The device deletes its stored copies. Absent when there are none. |
| `data.nextRefreshAt` | string | ISO-8601 timestamp (UTC). |
| `data.prestagedOverrides` | array of object | Emergency templates pre-loaded on the device. |
| `data.prestagedOverrides[].id` | string |  |
| `data.prestagedOverrides[].kind` | "emergency" \| "cast" |  |
| `data.prestagedOverrides[].severity` | "info" \| "warning" \| "critical" |  |
| `data.prestagedOverrides[].headline` | string |  |
| `data.prestagedOverrides[].body` | string \| null |  |
| `data.prestagedOverrides[].content` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.prestagedOverrides[].content.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.prestagedOverrides[].triggeredAt` | string \| null |  |
| `data.prestagedOverrides[].expiresAt` | string \| null |  |
| `data.cast` | object |  |
| `data.cast.id` | string |  |
| `data.cast.kind` | "emergency" \| "cast" |  |
| `data.cast.severity` | "info" \| "warning" \| "critical" |  |
| `data.cast.headline` | string |  |
| `data.cast.body` | string \| null |  |
| `data.cast.content` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.cast.content.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.cast.triggeredAt` | string \| null |  |
| `data.cast.expiresAt` | string \| null |  |
| `data.emergency` | object |  |
| `data.emergency.id` | string |  |
| `data.emergency.kind` | "emergency" \| "cast" |  |
| `data.emergency.severity` | "info" \| "warning" \| "critical" |  |
| `data.emergency.headline` | string |  |
| `data.emergency.body` | string \| null |  |
| `data.emergency.content` | ManifestContentBlock | Resolved content: `kind` plus the fields for that kind (`media`, `playlist` + `items`, `app`, `layout` + `zones`, `creative`, `signage`). The inner shape is the player's format and grows with it. |
| `data.emergency.content.kind` | "none" \| "creative" \| "signage" \| "playlist" \| "app" \| "media" \| "layout" |  |
| `data.emergency.triggeredAt` | string \| null |  |
| `data.emergency.expiresAt` | string \| null |  |
| `data.sealed` | true |  |
| `data.brand` | object |  |
| `data.brand.partnerId` | string \| null |  |
| `data.brand.productName` | string |  |
| `data.brand.logoUrl` | string \| null | The logo the screen draws. A screen sits on a dark background, so this is the partner's logo for dark backgrounds when they set one. |
| `data.brand.logoDarkUrl` | string \| null | The partner's logo for dark backgrounds, or null. |
| `data.brand.brandColor` | string |  |
| `data.brand.cmsHost` | string |  |
| `data.brand.supportEmail` | string |  |
| `data.brand.termsUrl` | string \| null |  |
| `data.brand.privacyUrl` | string \| null |  |
| `data.brand.isWhiteLabel` | boolean |  |

Response 401: Missing, expired or revoked bearer token.

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

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

## GET /v1/screens/{id}/quality

Get a screen's playback and device quality

Returns the quality data the screen's Health tab shows: the content items that played badly in the last 7 days (worst first), how often the player started today and why, and the device health readings from the last 24 hours, such as frame gaps, decoder failures, cache clears and the highest temperature.

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

Parameters:

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

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/quality" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.problemItems` | array of object | Items that failed or played badly on this screen in the last 7 days, worst first. |
| `data.problemItems[].contentId` | string |  |
| `data.problemItems[].name` | string \| null |  |
| `data.problemItems[].kind` | string \| null |  |
| `data.problemItems[].plays` | integer |  |
| `data.problemItems[].fails` | integer |  |
| `data.problemItems[].lastFailReason` | string \| null |  |
| `data.problemItems[].ttffMsMax` | number \| null |  |
| `data.problemItems[].stallCount` | integer |  |
| `data.problemItems[].stallMsMax` | number \| null |  |
| `data.problemItems[].blackMsMax` | number \| null |  |
| `data.problemItems[].dropPctMax` | number \| null |  |
| `data.problemItems[].seamWorstMs` | number \| null |  |
| `data.problemItems[].path` | string \| null |  |
| `data.problemItems[].src` | string \| null |  |
| `data.problemItems[].days` | integer |  |
| `data.restartsToday` | object | Player starts since 00:00 UTC, per launch reason. |
| `data.restartSummary` | string \| null |  |
| `data.mediaBench` | object \| null | The screen's own media self-test (what it can decode), when it has run. |
| `data.signals` | object \| null | The last 24 hours of device-health readings. Null when the screen reported none. |

Response 401: Missing, expired or revoked bearer token.

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

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

## POST /v1/screens/{id}/replace-device

Unpair a screen's device

Release the device currently paired with a screen, without deleting the screen itself. The screen's name, content, location, and history are kept. Follow up with POST /v1/screens/:id/claim-replacement to pair a new device.

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

Parameters:

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

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

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string |  |
| `data.awaitingReplacement` | true |  |

Response 401: Missing, expired or revoked bearer token.

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

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

## GET /v1/screens/{id}/resource-pressure

Get a screen's resource pressure

Check a screen's storage, memory, and offline cache pressure. The response ranks the content contributing most to that pressure, with suggestions to remove or replace it, and includes hardware upgrade recommendations if relevant.

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

Parameters:

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

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/resource-pressure" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.severity` | "none" \| "warning" \| "critical" |  |
| `data.resources` | array of "storage" \| "memory" \| "cache" | The resources under pressure. |
| `data.storage` | object |  |
| `data.storage.severity` | "none" \| "warning" \| "critical" |  |
| `data.storage.freeMb` | number \| null |  |
| `data.storage.totalMb` | number \| null |  |
| `data.storage.freeFrac` | number \| null | Free as a fraction of total (0–1). |
| `data.storage.headline` | string \| null |  |
| `data.storage.daysLeft` | number \| null | Days until full at the recent rate; null when not shrinking. |
| `data.memory` | object |  |
| `data.memory.severity` | "none" \| "warning" \| "critical" |  |
| `data.memory.freeMb` | number \| null |  |
| `data.memory.totalMb` | number \| null |  |
| `data.memory.freeFrac` | number \| null | Free as a fraction of total (0–1). |
| `data.memory.headline` | string \| null |  |
| `data.memory.daysLeft` | number \| null | Days until full at the recent rate; null when not shrinking. |
| `data.cache` | object |  |
| `data.cache.severity` | "none" \| "warning" \| "critical" |  |
| `data.cache.cacheableBytes` | integer |  |
| `data.cache.budgetBytes` | integer \| null |  |
| `data.cache.ramTotalMb` | number \| null |  |
| `data.cache.videoCount` | integer |  |
| `data.cache.overBytes` | integer |  |
| `data.cache.headline` | string \| null |  |
| `data.heavyContent` | array of object | Assigned content that costs the most, with what removing it frees. |
| `data.heavyContent[].kind` | "layout" \| "app" \| "media" |  |
| `data.heavyContent[].id` | string |  |
| `data.heavyContent[].name` | string |  |
| `data.heavyContent[].detail` | string |  |
| `data.heavyContent[].freesMb` | number |  |
| `data.heavyContent[].estimated` | boolean |  |
| `data.heavyContent[].freesLabel` | string |  |
| `data.heavyContent[].reason` | string |  |
| `data.hardware` | object \| null | A hardware upgrade suggestion, when the device is the limit. |
| `data.summary` | string \| null |  |

Response 401: Missing, expired or revoked bearer token.

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

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

## POST /v1/screens/{id}/restore

Restore a deleted screen

Restore a screen deleted within the last 30 days, and restore its device pairing. A device that has kept its access token reconnects automatically, without needing to be re-paired on site.

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

Parameters:

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

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

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string |  |
| `data.restored` | true |  |

Response 401: Missing, expired or revoked bearer token.

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

Response 404: No deleted screen with this id.

Response 409: The screen is not deleted, or restoring it would exceed the plan.

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

## POST /v1/screens/{id}/revoke-device

Revoke a screen's device access

Immediately invalidate the access token of the device currently paired with a screen, for example after a device is lost or stolen. The token can no longer be used, including to pair as a new screen. The screen itself is not deleted.

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

Parameters:

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

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

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string |  |
| `data.revoked` | true |  |
| `data.at` | string | ISO-8601 timestamp (UTC). |

Response 401: Missing, expired or revoked bearer token.

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

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

## POST /v1/screens/{id}/rotate-token

Rotate a screen's device token

Generate a new access token for a screen's paired device, invalidating the previous one immediately. The new token is returned once in the response and cannot be retrieved afterward.

**Notes.**
- The response carries the NEW device credential. The device holding the old token is disconnected and must be given this token (or re-paired) to keep playing.

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

Parameters:

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

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

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string |  |
| `data.deviceToken` | string | The new device credential. Shown once; the old token stops working now. |
| `data.rotatedAt` | string | ISO-8601 timestamp (UTC). |

Response 401: Missing, expired or revoked bearer token.

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

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

## GET /v1/screens/{id}/state

Get a screen's reported device state

Get the screen's most recently reported state, including what is currently displayed, the player software version, and its cache and resource status.

The device's last heartbeat snapshot (telemetry, cache, current content, pending updates). Free-form: fields vary by player shell and version.

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

Parameters:

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

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/state" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object \| null | Null before the first heartbeat. |

Response 401: Missing, expired or revoked bearer token.

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

Response 404: No such screen in this workspace.

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

## GET /v1/screens/{id}/telemetry

Get a screen's raw telemetry

Get the 100 most recent raw telemetry events sent by a screen, newest first, with parsed payload data.

**Notes.**
- The newest 100 events.

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

Parameters:

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

```bash
curl "https://api.brixsignage.com/v1/screens/{id}/telemetry" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of object |  |
| `data[].id` | string |  |
| `data[].spaceId` | string |  |
| `data[].screenId` | string |  |
| `data[].type` | string |  |
| `data[].payload` | any | The event payload (decoded JSON); its shape depends on `type`. |
| `data[].occurredAt` | string | ISO-8601 timestamp (UTC). |
| `data[].receivedAt` | string | ISO-8601 timestamp (UTC). |

Response 401: Missing, expired or revoked bearer token.

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

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

## POST /v1/screens/{id}/trigger

Trigger a screen interaction

Send a real-time trigger to a screen: `refresh`, `next`, `go-to-scene`, or `send-event`. The screen receives it immediately.

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

Parameters:

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

Request body: `application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `kind` | "refresh" \| "next" \| "prev" \| "go-to-page" \| "go-to-scene" \| "send-event" | yes |  |
| `page` | integer | no | `go-to-page`: 1–100. |
| `sceneId` | string | no | `go-to-scene`: the scene to show. |
| `event` | string | no | `send-event`: the event name the content listens for. |
| `payload` | string | no | `send-event`: an optional string payload. |
| `overlay` | object | no | A popup shown over what is playing for `seconds`, then removed. The content underneath does not restart. |
| `overlay.contentKind` | "media" \| "app" \| "canvas" | yes |  |
| `overlay.contentId` | string | yes |  |
| `overlay.seconds` | number | no | 1–600 (clamped); default 15. |
| `overlay.position` | "center" \| "top" \| "bottom" \| "top-left" \| "top-right" \| "bottom-left" \| "bottom-right" | no | Default `center`. |
| `overlay.params` | object | no | Values passed to the content, e.g. `{ "table": "4" }`. |

```bash
curl -X POST "https://api.brixsignage.com/v1/screens/{id}/trigger" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"
```

Response 201: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string | The command id. |
| `data.kind` | "trigger" |  |
| `data.trigger` | object | The trigger as stored (only the fields its kind uses). |
| `data.trigger.kind` | string |  |
| `data.trigger.page` | integer |  |
| `data.trigger.sceneId` | string |  |
| `data.trigger.event` | string |  |
| `data.trigger.payload` | string |  |
| `data.overlay` | object |  |
| `data.overlay.contentKind` | "media" \| "app" \| "canvas" |  |
| `data.overlay.contentId` | string |  |
| `data.overlay.seconds` | integer | 1–600; default 15. |
| `data.overlay.position` | "center" \| "top" \| "bottom" \| "top-left" \| "top-right" \| "bottom-left" \| "bottom-right" |  |
| `data.overlay.params` | object | Values passed to the content, e.g. `{ "table": "4" }`. |

Response 401: Missing, expired or revoked bearer token.

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

Response 422: Not a valid trigger, or the overlay content is not in this workspace.

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

## POST /v1/screens/{id}/unpower-and-delete

Power off and delete a screen

Retire a screen in one action: turn off the physical display, unpair the device, and delete the screen. The screen can be recovered within 30 days.

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

Parameters:

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

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

Response 200: Success.

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string |  |
| `data.deleted` | true |  |
| `data.commandId` | string | The `cec-off` command sent before the device was unpaired. |

Response 401: Missing, expired or revoked bearer token.

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

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