Screen groups API

Screen groups endpoints in the Brix REST API: 9 operations (GET, POST, PATCH, DELETE). Each lists its path, auth, required permission and a curl example.

View as Markdown · For AI agents: the full docs index is at /llms.txt

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, Errors and rate limits and Pagination.

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

FieldTypeDescription
errorstringMachine-readable code: unauthorized, forbidden, not_found, validation_error, conflict, rate_limited, internal_error, …
messagestringHuman-readable explanation. Safe to show an operator.
requestIdstringPresent on 5xx: quote it to support.

GET /v1/screen-groups

Auth: Bearer token. Permission: screen.view.

List the screen groups in your workspace. Each group includes the number of screens in it and the IDs of the screens you have access to see.

curl "https://api.brixsignage.com/v1/screen-groups" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataarray of ScreenGroup
data[].idstringScreen group id.
data[].namestring
data[].descriptionstring | null
data[].screenCountintegerMembers the caller can see.
data[].screenIdsarray of stringMember screen ids the caller can see, oldest membership first.
data[].arrangement"none" | "stagger" | "mirror" | "chase" | "each"How the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
data[].positionsarray of stringPosition names in wall order: left to right, then top to bottom. Empty when the set has none.
data[].positionOfobjectScreen id → index into positions, for the members that have a position.
data[].rulesarray of object
data[].rules[].namestringName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
data[].rules[].endingstringThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
data[].rules[].tagstringThe screen has this tag.
data[].rules[].nodeIdstringThe screen is in this location, or in one inside it.
data[].rules[].positioninteger | nullThe position a matching screen takes: an index into positions.
data[].autoAddbooleanA new, renamed, re-tagged or moved screen that matches a rule joins by itself. A rule never takes a screen out.
data[].layoutobject | nullHow the positions sit on the wall. Null = one row.
data[].positionContentarray of object | nullWhat each position plays (arrangement: each), one entry per position. Empty when the set has none.
data[].healthobjectHow many of the members the caller can see are on.
data[].health.onlineinteger
data[].health.offlineinteger
data[].health.otherintegerMembers that are neither: not paired yet, or turned off for the account.
data[].createdAtstringISO-8601 timestamp (UTC).
data[].updatedAtstringISO-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/screen-groups

Auth: Bearer token. Permission: screen.edit.

Create a named group of screens. Optionally pass screenIds to add screens to the group at creation time.

Request body: application/json

FieldTypeRequiredDescription
namestringyesUnique in the workspace (case-insensitive). Trimmed; longer names are cut at 120.
descriptionstringnoTrimmed; cut at 500 characters.
screenIdsarray of stringnoSeed members, with no position. Ids you cannot edit are skipped.
placeScreensarray of objectnoSeed members IN positions, one entry per position. Send positions in the same call. A screen is named in one position only. Without positions a group cannot use content per position or play different items side by side.
placeScreens[].positionintegeryesIndex into positions, 0 = the first (left).
placeScreens[].screenIdsarray of stringyes
arrangement"none" | "stagger" | "mirror" | "chase" | "each"noHow the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
positionsarray of stringnoReplaces the position names. Wall order: left to right, then top to bottom.
layoutobject | nullno
rulesarray of objectnoReplaces the rules. An empty rule is dropped: it never selects every screen.
rules[].namestringnoName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
rules[].endingstringnoThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
rules[].tagstringnoThe screen has this tag.
rules[].nodeIdstringnoThe screen is in this location, or in one inside it.
rules[].positioninteger | nullnoThe position a matching screen takes: an index into positions.
autoAddbooleanno
applyRulesbooleannoTrue adds every screen the rules select now. Screens you cannot edit are skipped. A member that has a position keeps it; a member with no position takes the one its rule names.
positionContentarray of object | null | nullnoContent per position. Sets arrangement to each; null (or all nulls) clears the list and returns the set to none, and the screens keep what they play. Needs screen.edit and screen.cast for the whole workspace. Not behind the playback switch. The response's assigned lists, per position, updated, notShared, needsApproval and the screen ids that changed.
curl -X POST "https://api.brixsignage.com/v1/screen-groups" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 201: Success.

FieldTypeDescription
dataobject
data.idstringScreen group id.
data.namestring
data.descriptionstring | null
data.screenCountintegerMembers the caller can see.
data.screenIdsarray of stringMember screen ids the caller can see, oldest membership first.
data.arrangement"none" | "stagger" | "mirror" | "chase" | "each"How the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
data.positionsarray of stringPosition names in wall order: left to right, then top to bottom. Empty when the set has none.
data.positionOfobjectScreen id → index into positions, for the members that have a position.
data.rulesarray of object
data.rules[].namestringName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
data.rules[].endingstringThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
data.rules[].tagstringThe screen has this tag.
data.rules[].nodeIdstringThe screen is in this location, or in one inside it.
data.rules[].positioninteger | nullThe position a matching screen takes: an index into positions.
data.autoAddbooleanA new, renamed, re-tagged or moved screen that matches a rule joins by itself. A rule never takes a screen out.
data.layoutobject | nullHow the positions sit on the wall. Null = one row.
data.positionContentarray of object | nullWhat each position plays (arrangement: each), one entry per position. Empty when the set has none.
data.healthobjectHow many of the members the caller can see are on.
data.health.onlineinteger
data.health.offlineinteger
data.health.otherintegerMembers that are neither: not paired yet, or turned off for the account.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-8601 timestamp (UTC).
data.matchedintegerScreens that joined because of applyRules.
data.assignedarray of objectWith content per position: what the save assigned, per position.
data.assigned[].positioninteger
data.assigned[].updatedinteger
data.assigned[].notSharedinteger
data.assigned[].needsApprovalinteger
data.assigned[].refusedstring
data.assigned[].screenIdsarray of string

Response 401: Missing, expired or revoked bearer token.

Response 403: A set-wide setting from a caller without screen.edit for the whole workspace; positionContent from a caller without screen.cast for the whole workspace; or feature_disabled: stagger, mirror or chase where the workspace does not have it yet.

Response 409: name_taken: a group with this name exists.

Response 422: name missing, screenIds empty / over 5000, or a set-wide setting with the wrong shape.

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

GET /v1/screen-groups/{id}

Auth: Bearer token. Permission: screen.view.

Get one screen group and the screens in it. Requesting a group that belongs to a different workspace returns a not-found error.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.
curl "https://api.brixsignage.com/v1/screen-groups/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataScreenGroupA named, saved set of screens — the unit for bulk content, commands and settings. It can also arrange its screens: positions, rules that add screens, and a way to play one playlist together.
data.idstringScreen group id.
data.namestring
data.descriptionstring | null
data.screenCountintegerMembers the caller can see.
data.screenIdsarray of stringMember screen ids the caller can see, oldest membership first.
data.arrangement"none" | "stagger" | "mirror" | "chase" | "each"How the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
data.positionsarray of stringPosition names in wall order: left to right, then top to bottom. Empty when the set has none.
data.positionOfobjectScreen id → index into positions, for the members that have a position.
data.rulesarray of object
data.rules[].namestringName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
data.rules[].endingstringThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
data.rules[].tagstringThe screen has this tag.
data.rules[].nodeIdstringThe screen is in this location, or in one inside it.
data.rules[].positioninteger | nullThe position a matching screen takes: an index into positions.
data.autoAddbooleanA new, renamed, re-tagged or moved screen that matches a rule joins by itself. A rule never takes a screen out.
data.layoutobject | nullHow the positions sit on the wall. Null = one row.
data.positionContentarray of object | nullWhat each position plays (arrangement: each), one entry per position. Empty when the set has none.
data.healthobjectHow many of the members the caller can see are on.
data.health.onlineinteger
data.health.offlineinteger
data.health.otherintegerMembers that are neither: not paired yet, or turned off for the account.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-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 404: No such group in this workspace.

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

PATCH /v1/screen-groups/{id}

Auth: Bearer token. Permission: screen.edit.

Update a screen group's name or description. A name already used by another group in your workspace is refused with a name_taken conflict error. Renames a group, and changes its set-wide settings: its positions, its physical layout, the rules that add screens to it, and how its screens play one playlist together. The set-wide settings (arrangement, positions, layout, rules, autoAdd, applyRules) need screen.edit for the whole workspace, not for one location: a rule selects screens anywhere and a way of playing changes what every member shows.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.

Request body: application/json

FieldTypeRequiredDescription
namestringno
descriptionstring | nullno
arrangement"none" | "stagger" | "mirror" | "chase" | "each"noHow the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
positionsarray of stringnoReplaces the position names. Wall order: left to right, then top to bottom.
layoutobject | nullno
rulesarray of objectnoReplaces the rules. An empty rule is dropped: it never selects every screen.
rules[].namestringnoName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
rules[].endingstringnoThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
rules[].tagstringnoThe screen has this tag.
rules[].nodeIdstringnoThe screen is in this location, or in one inside it.
rules[].positioninteger | nullnoThe position a matching screen takes: an index into positions.
autoAddbooleanno
applyRulesbooleannoTrue adds every screen the rules select now. Screens you cannot edit are skipped. A member that has a position keeps it; a member with no position takes the one its rule names.
positionContentarray of object | null | nullnoContent per position. Sets arrangement to each; null (or all nulls) clears the list and returns the set to none, and the screens keep what they play. Needs screen.edit and screen.cast for the whole workspace. Not behind the playback switch. The response's assigned lists, per position, updated, notShared, needsApproval and the screen ids that changed.
curl -X PATCH "https://api.brixsignage.com/v1/screen-groups/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstringScreen group id.
data.namestring
data.descriptionstring | null
data.screenCountintegerMembers the caller can see.
data.screenIdsarray of stringMember screen ids the caller can see, oldest membership first.
data.arrangement"none" | "stagger" | "mirror" | "chase" | "each"How the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
data.positionsarray of stringPosition names in wall order: left to right, then top to bottom. Empty when the set has none.
data.positionOfobjectScreen id → index into positions, for the members that have a position.
data.rulesarray of object
data.rules[].namestringName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
data.rules[].endingstringThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
data.rules[].tagstringThe screen has this tag.
data.rules[].nodeIdstringThe screen is in this location, or in one inside it.
data.rules[].positioninteger | nullThe position a matching screen takes: an index into positions.
data.autoAddbooleanA new, renamed, re-tagged or moved screen that matches a rule joins by itself. A rule never takes a screen out.
data.layoutobject | nullHow the positions sit on the wall. Null = one row.
data.positionContentarray of object | nullWhat each position plays (arrangement: each), one entry per position. Empty when the set has none.
data.healthobjectHow many of the members the caller can see are on.
data.health.onlineinteger
data.health.offlineinteger
data.health.otherintegerMembers that are neither: not paired yet, or turned off for the account.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-8601 timestamp (UTC).
data.matchedintegerScreens that joined because of applyRules.
data.placedintegerMembers that had no position and took the one their rule names, because of applyRules.
data.assignedarray of objectWith content per position: what the save assigned, per position.
data.assigned[].positioninteger
data.assigned[].updatedinteger
data.assigned[].notSharedinteger
data.assigned[].needsApprovalinteger
data.assigned[].refusedstring
data.assigned[].screenIdsarray of string

Response 401: Missing, expired or revoked bearer token.

Response 403: A set-wide setting from a caller without screen.edit for the whole workspace; positionContent from a caller without screen.cast for the whole workspace; or feature_disabled: stagger, mirror or chase where the workspace does not have it yet.

Response 404: No screen group with this id.

Response 409: name_taken.

Response 422: name is empty, a set-wide setting has the wrong shape, or stagger / chase with fewer than two positions.

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

DELETE /v1/screen-groups/{id}

Auth: Bearer token. Permission: screen.edit.

Delete a screen group. The screens in the group are not affected, and the group's membership is kept so it can be fully restored with POST /v1/screen-groups/:id/restore.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.
curl -X DELETE "https://api.brixsignage.com/v1/screen-groups/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstring
data.deletedtrue

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/screen-groups/{id}/restore

Auth: Bearer token. Permission: screen.edit.

Restore a deleted screen group along with its original screen membership. A group that is not currently deleted is refused with a conflict error.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.
curl -X POST "https://api.brixsignage.com/v1/screen-groups/{id}/restore" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataScreenGroupA named, saved set of screens — the unit for bulk content, commands and settings. It can also arrange its screens: positions, rules that add screens, and a way to play one playlist together.
data.idstringScreen group id.
data.namestring
data.descriptionstring | null
data.screenCountintegerMembers the caller can see.
data.screenIdsarray of stringMember screen ids the caller can see, oldest membership first.
data.arrangement"none" | "stagger" | "mirror" | "chase" | "each"How the set's screens play. none: each screen on its own. One playlist together: stagger: every screen changes at the same moment and shows a different item. The order is the group's own: the items are shuffled once for the group, each screen plays every item once per lap, and no item moves to the screen beside it on the next change when the playlist is long enough. The playlist needs at least as many items as the group has positions (with fewer, positions that many apart show the same item); mirror: the same item on every screen at the same moment; chase: the same item, each screen a moment after the one on its left. stagger and chase need at least two positions. each: every position has its own content (positionContent); the screens share no clock.
data.positionsarray of stringPosition names in wall order: left to right, then top to bottom. Empty when the set has none.
data.positionOfobjectScreen id → index into positions, for the members that have a position.
data.rulesarray of object
data.rules[].namestringName pattern. * = any text, ? = one character, case does not count: *-GUN-L. With no wildcard it matches anywhere in the name.
data.rules[].endingstringThe last part of the name (after its last space, -, _ or .) is exactly this, case does not count: L matches 114-GUN-L, not 114-GUN-FULL.
data.rules[].tagstringThe screen has this tag.
data.rules[].nodeIdstringThe screen is in this location, or in one inside it.
data.rules[].positioninteger | nullThe position a matching screen takes: an index into positions.
data.autoAddbooleanA new, renamed, re-tagged or moved screen that matches a rule joins by itself. A rule never takes a screen out.
data.layoutobject | nullHow the positions sit on the wall. Null = one row.
data.positionContentarray of object | nullWhat each position plays (arrangement: each), one entry per position. Empty when the set has none.
data.healthobjectHow many of the members the caller can see are on.
data.health.onlineinteger
data.health.offlineinteger
data.health.otherintegerMembers that are neither: not paired yet, or turned off for the account.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-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 404: No screen group with this id.

Response 409: not_deleted, or a live group has the same name.

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

POST /v1/screen-groups/{id}/screens

Auth: Bearer token. Permission: screen.edit.

Add screens to a group. Adding a screen already in the group has no additional effect. A screen from another workspace, a deleted screen, or a screen outside your organization scope is skipped and counted in the response, but not identified individually.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.

Request body: application/json

FieldTypeRequiredDescription
screenIdsarray of stringyesScreen ids (1–5000). Ids you cannot edit, or that do not exist, are skipped.
positioninteger | nullnoIndex into the set's positions (null = no position), written to EVERY screen in the call, members already in the set included: this is how a screen moves from Left to Right. Leave it out and nothing that is already placed moves.
curl -X POST "https://api.brixsignage.com/v1/screen-groups/{id}/screens" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstring
data.addedintegerScreens newly added (existing members are not counted).
data.positionedintegerMembers whose position this call changed.
data.skippedintegerRequested ids that do not exist or that the caller cannot edit.
data.screenIdsarray of stringThe screens newly added.

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

Response 422: screenIds empty or over 5000, or position past the set's positions.

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

DELETE /v1/screen-groups/{id}/screens/{screenId}

Auth: Bearer token. Permission: screen.edit.

Remove one screen from a group. Returns a not-found error if the screen is not currently in the group.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.
screenIdpathstringyesScreen id.
curl -X DELETE "https://api.brixsignage.com/v1/screen-groups/{id}/screens/{screenId}" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstring
data.removedinteger1 when the screen was a member, else 0.
data.screenIdsarray of stringThe remaining members the caller can see.

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/screen-groups/{id}/screens/remove

Auth: Bearer token. Permission: screen.edit.

Remove one or more screens from a group. This only removes the screens from the group; the screens themselves are not affected. Removing a screen that is not in the group has no effect.

ParameterInTypeRequiredDescription
idpathstringyesScreen group id.

Request body: application/json

FieldTypeRequiredDescription
screenIdsarray of stringyesScreen ids (1–5000). Ids you cannot edit, or that do not exist, are skipped.
curl -X POST "https://api.brixsignage.com/v1/screen-groups/{id}/screens/remove" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstring
data.removedinteger
data.skippedintegerRequested ids that do not exist or that the caller cannot edit.
data.screenIdsarray of stringThe screens removed.

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

Response 422: screenIds empty or over 5000.

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