# Quickstart

> Create a Brix API key, make your first request with curl, list your screens and cast a playlist to a screen for an hour. Copy-paste commands.

Source: https://brixsignage.com/developers/quickstart/

This page takes you from nothing to content on a screen. You need a Brix workspace with at least one paired screen, and `curl`. Every command runs against the live API.

## 1. Create an API key

1. Sign in to the CMS at [cms.brixsignage.com](https://cms.brixsignage.com).
2. Open **Settings > API & MCP**.
3. Select **New key**.
4. Type a name into **Name**, for example `Quickstart`.
5. Under **Permissions**, select **Screens** and **Playlists**. Leave **Limit to a location** empty.
6. Select **Create key**.
7. Copy the key from the panel. Brix shows the full key once.

A key looks like `ak_us_live_` followed by 32 characters. The second part is your workspace's data region: `us`, `eu`, `oc` or `apac`.

You need the `api-key.create` permission to make a key. Workspace Owners and Admins have it. A key never gets a permission that the person who creates it does not hold.

Store the key in an environment variable:

```bash
export BRIX_API_KEY="ak_us_live_..."
```

## 2. Check who you are

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

```json
{
  "data": {
    "actor": { "kind": "key", "id": "ak_...", "name": "Quickstart", "nodeId": null },
    "workspace": { "id": "...", "name": "Acme Coffee" },
    "permissions": ["screen.view", "screen.cast", "playlist.view", "..."]
  }
}
```

`permissions` is what this key may do. If a later call returns 403 or an empty list, check this first.

A missing header returns `401 {"error":"missing_credentials",...}`. A wrong, revoked or expired key returns `401 {"error":"invalid_credentials",...}`.

## 3. List your screens

```bash
curl "https://api.brixsignage.com/v1/screens?limit=50" \
  -H "Authorization: Bearer $BRIX_API_KEY"
```

```json
{
  "data": [
    { "id": "scr_...", "name": "Lobby", "status": "online", "contentKind": "playlist", "contentId": "pl_...", "lastSeenAt": "..." }
  ],
  "nextCursor": null
}
```

The response is trimmed here. Copy the `id` of the screen you want to use. When `nextCursor` is not null, there are more screens: see [Pagination](/developers/pagination/).

With [jq](https://jqlang.org), print id, name and status:

```bash
curl -s "https://api.brixsignage.com/v1/screens?limit=500" \
  -H "Authorization: Bearer $BRIX_API_KEY" | jq -r '.data[] | [.id, .name, .status] | @tsv'
```

## 4. Find a playlist

```bash
curl -s https://api.brixsignage.com/v1/playlists \
  -H "Authorization: Bearer $BRIX_API_KEY" | jq -r '.data[] | [.id, .name] | @tsv'
```

Copy the `id` of a playlist.

## 5. Cast the playlist to the screen for one hour

A cast is a timed takeover. The screens play your content until `expiresAt`, then go back to their normal schedule by themselves.

```bash
SCREEN_ID="scr_..."
PLAYLIST_ID="pl_..."
EXPIRES_AT=$(( $(date +%s) * 1000 + 3600000 ))   # one hour from now, epoch milliseconds

curl -X POST https://api.brixsignage.com/v1/casts \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"contentKind\": \"playlist\",
    \"contentId\": \"$PLAYLIST_ID\",
    \"scopeKind\": \"screens\",
    \"screenIds\": [\"$SCREEN_ID\"],
    \"expiresAt\": $EXPIRES_AT
  }"
```

The API answers `201` with the cast:

```json
{
  "data": {
    "id": "cast_...",
    "kind": "cast",
    "status": "active",
    "contentKind": "playlist",
    "contentId": "pl_...",
    "scopeKind": "screens",
    "screenCount": 1,
    "triggeredAt": "...",
    "expiresAt": "..."
  }
}
```

Keep the cast id for the next step. With jq, run the same request with `curl -s ... | jq -r .data.id` and store it:

```bash
CAST_ID="cast_..."   # data.id from the response above
```

Always send `scopeKind`. If you leave it out, the cast goes to **every screen** the key can reach.

| Field | Values |
| --- | --- |
| `contentKind` | `media`, `playlist`, `app`, `creative`, `schedule` |
| `contentId` | The id of that content. |
| `scopeKind` | `screens` (with `screenIds`), `node` (with `scopeNodeId`, a location and everything under it), or `all`. Default `all`. |
| `expiresAt` | ISO 8601 date-time or epoch milliseconds. Omit it and the cast stays until you clear it. |
| `contentName` | Optional label shown in the CMS. |

The key needs `screen.cast`. A newer cast on the same screens replaces an older one. An emergency takeover pre-empts a cast, and the cast resumes after it.

## 6. End the cast early

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

The screens go back to their scheduled content at once. Clearing a cast that already ended returns `409 already_inactive`.

To see what is on air now:

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

## Change what a screen plays by default

A cast is temporary. To change the content a screen plays every day, assign it:

```bash
curl -X POST https://api.brixsignage.com/v1/screens/$SCREEN_ID/assign \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"contentKind\": \"playlist\", \"contentId\": \"$PLAYLIST_ID\"}"
```

`contentKind` is one of `playlist`, `schedule`, `layout`, `creative`, `signage`, `app`, `media`. Send `"contentKind": null` to clear the assignment. For many screens at once, use `POST /v1/screens/bulk-assign` with `screenIds`.

## Upload a file

```bash
curl -X POST https://api.brixsignage.com/v1/media/upload \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -F "file=@menu.jpg" \
  -F "name=Winter menu"
```

The key needs `media.create`. The response is `201` with the new media item in `data`. Use its `id` as `contentId` with `"contentKind": "media"`. For files over about 100 MB, use the multipart upload routes under `/v1/media/upload/multipart/`. To import from a public URL, use `POST /v1/media/import-url`. SVG files are refused.

## Next

- [Authentication and scopes](/developers/authentication/) for least-privilege keys.
- [Errors and rate limits](/developers/errors-and-rate-limits/) before you ship an integration.
- [API reference](/developers/api/) for every endpoint.
- [Connect an AI agent (MCP)](/developers/mcp/) to do all of this from Claude or ChatGPT.
