Approvals API

Approvals endpoints in the Brix REST API for digital signage: 5 operations (GET, POST). 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/approvals

Auth: Bearer token. Permission: screen.view.

List approval requests the caller is allowed to see, newest first. Use ?state= to narrow the list to requests still awaiting a decision. The response is capped because approval history only grows over time. Newest first. The route needs screen.view, but each request is listed only if the caller can also view (or approve) that content kind at its location — e.g. playlist.view for a playlist. A screen.view-only key gets an empty list.

ParameterInTypeRequiredDescription
statequery"pending" | "approved" | "rejected" | "withdrawn"noOnly requests in this state (pending = the inbox).
limitqueryintegernoAt most this many (default and max 500).
curl "https://api.brixsignage.com/v1/approvals" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataarray of ApprovalRequest
data[].idstringApproval request id.
data[].contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data[].contentIdstring
data[].contentNamestring
data[].thumbnailUrlstring | null
data[].nodeIdstringThe content's home location; empty string for the workspace root.
data[].nodeNamestring
data[].requestedByNamestring
data[].requestedAtstringISO-8601 timestamp (UTC).
data[].notestring | null
data[].changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data[].state"pending" | "approved" | "rejected" | "withdrawn"
data[].requestedByIdstringUser id, or apikey:<id> for a key.
data[].levelsarray of objectThe approval chain, one entry per tier.
data[].levels[].nodeIdstring
data[].levels[].nodeNamestring
data[].levels[].approverIdsarray of string
data[].levels[].approverNamesarray of string
data[].currentLevelintegerIndex into levels awaiting a decision while pending.
data[].decisionsarray of object
data[].decisions[].levelinteger
data[].decisions[].decidedByIdstring
data[].decisions[].decidedByNamestring | null
data[].decisions[].decidedAtstringISO-8601 timestamp (UTC).
data[].decisions[].notestring | null
data[].decidedByNamestring | null
data[].decidedAtstring | null
data[].decisionNotestring | null
data[].canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

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/approvals

Auth: Bearer token. Permission: screen.view.

Open an approval request for a piece of content. The authenticated caller becomes the requester. Decide the request with POST /v1/approvals/:id/decide, or cancel it with POST /v1/approvals/:id/withdraw. Notes. - The request goes to the content's own location; a nodeId in the body is ignored. The content's review state becomes pending. - The requester is the caller (apikey:<id> for a key).

Request body: application/json

FieldTypeRequiredDescription
contentKindstringyesplaylist, schedule, creative, layout, media, app, …
contentIdstringyes
contentNamestringyes
notestringno
thumbnailUrlstringno
changesarray of anynoUsed only for content kinds the server does not compare itself.
curl -X POST "https://api.brixsignage.com/v1/approvals" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contentKind":"playlist","contentId":"pl_2b3c4d5e6f7a8b9c","contentName":"Lobby Loop","note":"New spring menu"}'

Response 200: Success: A request for this content is already pending: that request is returned and nothing is created.

FieldTypeDescription
dataApprovalRequestA request to approve content before it can air.
data.idstringApproval request id.
data.contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data.contentIdstring
data.contentNamestring
data.thumbnailUrlstring | null
data.nodeIdstringThe content's home location; empty string for the workspace root.
data.nodeNamestring
data.requestedByNamestring
data.requestedAtstringISO-8601 timestamp (UTC).
data.notestring | null
data.changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data.state"pending" | "approved" | "rejected" | "withdrawn"
data.requestedByIdstringUser id, or apikey:<id> for a key.
data.levelsarray of objectThe approval chain, one entry per tier.
data.levels[].nodeIdstring
data.levels[].nodeNamestring
data.levels[].approverIdsarray of string
data.levels[].approverNamesarray of string
data.currentLevelintegerIndex into levels awaiting a decision while pending.
data.decisionsarray of object
data.decisions[].levelinteger
data.decisions[].decidedByIdstring
data.decisions[].decidedByNamestring | null
data.decisions[].decidedAtstringISO-8601 timestamp (UTC).
data.decisions[].notestring | null
data.decidedByNamestring | null
data.decidedAtstring | null
data.decisionNotestring | null
data.canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

Response 201: Success.

FieldTypeDescription
dataApprovalRequestA request to approve content before it can air.
data.idstringApproval request id.
data.contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data.contentIdstring
data.contentNamestring
data.thumbnailUrlstring | null
data.nodeIdstringThe content's home location; empty string for the workspace root.
data.nodeNamestring
data.requestedByNamestring
data.requestedAtstringISO-8601 timestamp (UTC).
data.notestring | null
data.changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data.state"pending" | "approved" | "rejected" | "withdrawn"
data.requestedByIdstringUser id, or apikey:<id> for a key.
data.levelsarray of objectThe approval chain, one entry per tier.
data.levels[].nodeIdstring
data.levels[].nodeNamestring
data.levels[].approverIdsarray of string
data.levels[].approverNamesarray of string
data.currentLevelintegerIndex into levels awaiting a decision while pending.
data.decisionsarray of object
data.decisions[].levelinteger
data.decisions[].decidedByIdstring
data.decisions[].decidedByNamestring | null
data.decisions[].decidedAtstringISO-8601 timestamp (UTC).
data.decisions[].notestring | null
data.decidedByNamestring | null
data.decidedAtstring | null
data.decisionNotestring | null
data.canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

Response 401: Missing, expired or revoked bearer token.

Response 403: The content is approved, and you do not hold its approve permission (playlist.approve, …) at its location.

Response 404: No such content, or it is at a location where you do not hold screen.view.

Response 422: contentKind, contentId or contentName is missing.

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

GET /v1/approvals/{id}

Auth: Bearer token. Permission: screen.view.

Retrieve one approval request. If the request falls outside what you are allowed to see, this returns 404 rather than 403, so its existence is not revealed. Notes. - Besides screen.view, the caller must be able to view or approve the content kind at its location (e.g. playlist.view); otherwise 404.

ParameterInTypeRequiredDescription
idpathstringyesApproval request id.
curl "https://api.brixsignage.com/v1/approvals/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataApprovalRequestA request to approve content before it can air.
data.idstringApproval request id.
data.contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data.contentIdstring
data.contentNamestring
data.thumbnailUrlstring | null
data.nodeIdstringThe content's home location; empty string for the workspace root.
data.nodeNamestring
data.requestedByNamestring
data.requestedAtstringISO-8601 timestamp (UTC).
data.notestring | null
data.changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data.state"pending" | "approved" | "rejected" | "withdrawn"
data.requestedByIdstringUser id, or apikey:<id> for a key.
data.levelsarray of objectThe approval chain, one entry per tier.
data.levels[].nodeIdstring
data.levels[].nodeNamestring
data.levels[].approverIdsarray of string
data.levels[].approverNamesarray of string
data.currentLevelintegerIndex into levels awaiting a decision while pending.
data.decisionsarray of object
data.decisions[].levelinteger
data.decisions[].decidedByIdstring
data.decisions[].decidedByNamestring | null
data.decisions[].decidedAtstringISO-8601 timestamp (UTC).
data.decisions[].notestring | null
data.decidedByNamestring | null
data.decidedAtstring | null
data.decisionNotestring | null
data.canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

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 request, or you cannot view (or approve) that kind of content at its location.

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

POST /v1/approvals/{id}/decide

Auth: Bearer token. Permission: screen.view.

Approve or reject a pending approval request. A reason is required when rejecting. The decision is applied to the underlying content's approval status. Decides the CURRENT level of the chain. Approving the last level lets the content air; approving an earlier level passes it to the next. Besides screen.view, the caller must be a named approver for the level or hold the content kind's approve permission (playlist.approve, schedule.approve, …) at the level's location.

ParameterInTypeRequiredDescription
idpathstringyesApproval request id.

Request body: application/json

FieldTypeRequiredDescription
decision"approved" | "rejected"yes
decisionNotestringnoRequired to reject.
curl -X POST "https://api.brixsignage.com/v1/approvals/{id}/decide" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 200: Success.

FieldTypeDescription
dataApprovalRequestA request to approve content before it can air.
data.idstringApproval request id.
data.contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data.contentIdstring
data.contentNamestring
data.thumbnailUrlstring | null
data.nodeIdstringThe content's home location; empty string for the workspace root.
data.nodeNamestring
data.requestedByNamestring
data.requestedAtstringISO-8601 timestamp (UTC).
data.notestring | null
data.changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data.state"pending" | "approved" | "rejected" | "withdrawn"
data.requestedByIdstringUser id, or apikey:<id> for a key.
data.levelsarray of objectThe approval chain, one entry per tier.
data.levels[].nodeIdstring
data.levels[].nodeNamestring
data.levels[].approverIdsarray of string
data.levels[].approverNamesarray of string
data.currentLevelintegerIndex into levels awaiting a decision while pending.
data.decisionsarray of object
data.decisions[].levelinteger
data.decisions[].decidedByIdstring
data.decisions[].decidedByNamestring | null
data.decisions[].decidedAtstringISO-8601 timestamp (UTC).
data.decisions[].notestring | null
data.decidedByNamestring | null
data.decidedAtstring | null
data.decisionNotestring | null
data.canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

Response 401: Missing, expired or revoked bearer token.

Response 403: Not eligible to decide this level, or self_approval (another approver exists).

Response 404: No such request.

Response 409: already_decided.

Response 422: Bad decision, or a rejection without decisionNote.

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

POST /v1/approvals/{id}/withdraw

Auth: Bearer token. Permission: screen.view.

Cancel your own pending approval request. The content it was attached to returns to draft status. Notes. - The content's review state goes back to draft.

ParameterInTypeRequiredDescription
idpathstringyesApproval request id.
curl -X POST "https://api.brixsignage.com/v1/approvals/{id}/withdraw" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataApprovalRequestA request to approve content before it can air.
data.idstringApproval request id.
data.contentKindstringplaylist, schedule, creative, layout, creative-override, media, app, …
data.contentIdstring
data.contentNamestring
data.thumbnailUrlstring | null
data.nodeIdstringThe content's home location; empty string for the workspace root.
data.nodeNamestring
data.requestedByNamestring
data.requestedAtstringISO-8601 timestamp (UTC).
data.notestring | null
data.changesarray of anyWhat changed since the last approved version: {kind, label, detail, thumbnailUrl?} items for kinds the server diffs; for other kinds, whatever the requester sent.
data.state"pending" | "approved" | "rejected" | "withdrawn"
data.requestedByIdstringUser id, or apikey:<id> for a key.
data.levelsarray of objectThe approval chain, one entry per tier.
data.levels[].nodeIdstring
data.levels[].nodeNamestring
data.levels[].approverIdsarray of string
data.levels[].approverNamesarray of string
data.currentLevelintegerIndex into levels awaiting a decision while pending.
data.decisionsarray of object
data.decisions[].levelinteger
data.decisions[].decidedByIdstring
data.decisions[].decidedByNamestring | null
data.decisions[].decidedAtstringISO-8601 timestamp (UTC).
data.decisions[].notestring | null
data.decidedByNamestring | null
data.decidedAtstring | null
data.decisionNotestring | null
data.canDecidebooleanOn the list and single reads: whether the caller may approve or reject the request at its current level (a named approver, or the kind's approve permission there). False once it is decided.

Response 401: Missing, expired or revoked bearer token.

Response 403: You are not the requester, and not an approver for the current level.

Response 404: No such request.

Response 409: already_decided: the request is no longer pending.

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