---
title: "Create a screen"
method: POST
path: "/v1/screens"
tags: ["screens"]
---

# Create a screen

`POST /v1/screens`

## Request

- Base URL: `https://api.brixsignage.com`
- URL: `https://api.brixsignage.com/v1/screens`
- Auth: HTTP bearer

Create a screen. `name` is required; `nodeId`, `location`, and `tags` are optional. This operation is safe to retry with an idempotency key. Each screen created increases your billed screen count, so this request is refused if your account is suspended or cancelled.

**Notes.**
- Returns the stored row, not the composed Screen that GET /v1/screens/{id} returns: `tags` is the JSON-encoded string, and the composed fields (`contentName`, `state`, …) are absent.
- The screen waits in `pairing` status until a device claims it (POST /v1/screens/{id}/claim-replacement) — or use POST /v1/screens/claim or /v1/screens/enroll, which create and pair in one step.

## Request body

- object
  - `name` string, required
  - `nodeId` string: Location to create it in; default: the API key's own location, else the workspace root.
  - `billingGroupId` string, nullable: Billing group that pays for the screen.
  - `payment` 'later': Answer to `plan_full`: create the screen waiting for payment. It starts to play when the plan has room.

## Response `201`

Success.

- object
  - `data` ScreenRow, required: A screen as stored, before composition.
    - `id` string, required: Screen id.
    - `spaceId` string, required: Workspace id.
    - `nodeId` string, nullable, required: Location (org node) the screen belongs to; null = workspace root.
    - `name` string, required
    - `status` 'online' | 'offline' | 'pairing', required: `pairing` = no device has checked in yet.
    - `lastSeenAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `coreUpdateOfferedAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `contentKind` 'playlist' | 'schedule' | 'layout' | 'creative' | 'app' | 'media' | 'signage', nullable, required: What is assigned. Null = nothing assigned.
    - `contentId` string, nullable, required
    - `contentFit` unknown, required
    - `deactivatedAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `awaitingPaymentAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `rotation` integer, required: 0, 90, 180 or 270 degrees.
    - `rotationCommandedAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `timezone` string, nullable, required: IANA time zone; null = inherited.
    - `timezoneSource` 'operator' | 'device', nullable, required
    - `operatingHours` string, required: `default`, or a JSON-encoded weekly window.
    - `lastPanelCommand` string, nullable, required
    - `scheduleScreensOff` boolean, required
    - `displayPowerMode` 'always-on' | 'follow-schedule' | 'os-default', required
    - `playbackMode` 'sync' | 'unsync' | 'device-time', required
    - `locationLabel` string, nullable, required
    - `locationLat` number, nullable, required
    - `locationLng` number, nullable, required
    - `ipCity` string, nullable, required
    - `ipRegion` string, nullable, required
    - `ipCountry` string, nullable, required
    - `ipLat` number, nullable, required
    - `ipLng` number, nullable, required
    - `ipTimezone` string, nullable, required
    - `ipGeoAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `playerSettings` string, nullable, required: Player settings as a JSON-ENCODED string (not an object).
    - `kioskEnabled` boolean, required
    - `kioskPinMode` 'workspace' | 'custom', required
    - `kioskGraceSeconds` integer, required
    - `activeEmergencyId` string, nullable, required: The live emergency overriding this screen, if any.
    - `activeCastId` string, nullable, required: The live cast overriding this screen, if any.
    - `playerVersionHold` string, nullable, required
    - `sealed` boolean, required
    - `sealedAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `powerPolicyId` string, nullable, required
    - `importSourceId` string, nullable, required
    - `billingGroupId` string, nullable, required
    - `customFields` string, nullable, required: Custom fields as a JSON-ENCODED string.
    - `lanSecretAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `createdAt` string, required: ISO-8601 timestamp (UTC).
    - `updatedAt` string, required: ISO-8601 timestamp (UTC).
    - `deletedAt` string, nullable, required: ISO-8601 timestamp (UTC).
    - `tags` string, required: Tags as a JSON-ENCODED array string (the stored column), not an array.

## Other responses

- `401`: Missing, expired or revoked bearer token.
- `402`: `plan_full`: every screen on the plan is in use. The body has `data.plan` with the price of one more screen today. Add screens to the plan, or send `payment: "later"`.
- `403`: The token lacks the permission this operation needs (see `x-brix-permission`).
- `404`: The location does not exist.
- `409`: The account is suspended or cancelled.
- `422`: `name` is missing.
- `5XX`: Server error. The body carries a `requestId` to quote to support.

## Changes

- **2026-10-20** `02fd3665dc7d`: 3 info
  - added the new optional request property `payment`
  - added the non-success response with the status `402`
  - added the required property `data/awaitingPaymentAt` to the response with the `201` status

[Operation history](https://skmtc.dev/brixsignage/apis/brix-api/changes/v1/screens/post.md)

---

[API](https://skmtc.dev/brixsignage/apis/brix-api.md) · [All operations](https://skmtc.dev/brixsignage/apis/brix-api/llms.txt) · [OpenAPI document](https://skmtc.dev/brixsignage/apis/brix-api/revisions/02fd3665dc7d?raw)
