Webhooks API

Webhooks endpoints in the Brix REST API: 8 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/webhooks

Auth: Bearer token. Permission: integration.edit.

List the workspace's outbound webhook endpoints. The signing secret is never included in this response; it is shown only once, at creation. Notes. - Needs the permission at the workspace root: a location-scoped key is refused.

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

Response 200: Success.

FieldTypeDescription
dataarray of WebhookEndpoint
data[].idstringWebhook endpoint id.
data[].urlstringWhere deliveries are POSTed.
data[].descriptionstring | null
data[].secretPreviewstringFirst 8 characters of the signing secret.
data[].eventsarray of stringSubscribed event names (see GET /v1/webhooks/events).
data[].enabledboolean
data[].autoDisabledAtstring | nullSet when repeated failures switched the endpoint off.
data[].autoDisabledReasonstring | null
data[].consecutiveFailuresinteger
data[].lastDeliveryAtstring | null
data[].lastStatusinteger | nullHTTP status of the last delivery attempt.
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/webhooks

Auth: Bearer token. Permission: integration.edit.

Create an endpoint. The response includes the signing secret once; after that, only a preview of it is available, since it is stored encrypted and cannot be retrieved in full. The endpoint URL is checked at creation and again before every delivery, since a hostname that resolved to a public address at save time could later be re-pointed at an internal address. Only content.recalled and content.restored events are actually sent today, even though the event catalog lists more. The response carries the signing secret ONCE. Store it: later reads return only secretPreview. Notes. - Validation failures are 400 bad_request, where most other routes answer 422 validation_error.

Request body: application/json

FieldTypeRequiredDescription
urlstringyesAn https URL on the public internet (private and loopback hosts are refused).
eventsarray of "screen.offline" | "screen.online" | "content.recalled" | "content.restored" | "approval.requested" | "approval.decided" | "emergency.started" | "emergency.cleared"noEvents to deliver. Default: none. An unknown name is refused.
descriptionstringnoLabel; cut to 200 characters.
curl -X POST "https://api.brixsignage.com/v1/webhooks" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.example.com/brix","events":["screen.offline","screen.online"],"description":"Ops alerts"}'

Response 201: Success.

FieldTypeDescription
dataobject
data.idstringWebhook endpoint id.
data.urlstringWhere deliveries are POSTed.
data.descriptionstring | null
data.secretPreviewstringFirst 8 characters of the signing secret.
data.eventsarray of stringSubscribed event names (see GET /v1/webhooks/events).
data.enabledboolean
data.autoDisabledAtstring | nullSet when repeated failures switched the endpoint off.
data.autoDisabledReasonstring | null
data.consecutiveFailuresinteger
data.lastDeliveryAtstring | null
data.lastStatusinteger | nullHTTP status of the last delivery attempt.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-8601 timestamp (UTC).
data.secretstringThe HMAC signing secret (64 hex characters). Shown only in this response.
{
  "data": {
    "id": "whe_7a8b9c0d1e2f3a4b",
    "url": "https://hooks.example.com/brix",
    "description": "Ops alerts",
    "secretPreview": "3f9a1c2e",
    "events": [
      "screen.offline",
      "screen.online"
    ],
    "enabled": true,
    "autoDisabledAt": null,
    "autoDisabledReason": null,
    "consecutiveFailures": 0,
    "lastDeliveryAt": null,
    "lastStatus": null,
    "createdAt": "2026-09-28T09:00:00.000Z",
    "updatedAt": "2026-09-28T09:00:00.000Z",
    "secret": "3f9a1c2e4b5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f"
  }
}

Response 400: bad_request (missing url, unknown event) or unsafe_url.

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.

PATCH /v1/webhooks/{id}

Auth: Bearer token. Permission: integration.edit.

Change a webhook endpoint's URL, event subscriptions, description, or enabled state. Re-enabling an endpoint clears any automatic disable and resets its failure count, since re-enabling means the receiver has been confirmed fixed. Notes. - Needs the permission at the workspace root: a location-scoped key is refused. - Validation failures are 400 bad_request, where most other routes answer 422 validation_error.

ParameterInTypeRequiredDescription
idpathstringyesWebhook endpoint id.

Request body: application/json

FieldTypeRequiredDescription
urlstringnoAn https URL on the public internet.
eventsarray of "screen.offline" | "screen.online" | "content.recalled" | "content.restored" | "approval.requested" | "approval.decided" | "emergency.started" | "emergency.cleared"noReplaces the subscription. An unknown name is refused.
descriptionstringnoCut to 200 characters.
enabledbooleannotrue also clears an automatic switch-off and the failure count.
curl -X PATCH "https://api.brixsignage.com/v1/webhooks/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}'

Response 200: Success.

FieldTypeDescription
dataWebhookEndpointA customer webhook endpoint. The signing secret is never returned after creation.
data.idstringWebhook endpoint id.
data.urlstringWhere deliveries are POSTed.
data.descriptionstring | null
data.secretPreviewstringFirst 8 characters of the signing secret.
data.eventsarray of stringSubscribed event names (see GET /v1/webhooks/events).
data.enabledboolean
data.autoDisabledAtstring | nullSet when repeated failures switched the endpoint off.
data.autoDisabledReasonstring | null
data.consecutiveFailuresinteger
data.lastDeliveryAtstring | null
data.lastStatusinteger | nullHTTP status of the last delivery attempt.
data.createdAtstringISO-8601 timestamp (UTC).
data.updatedAtstringISO-8601 timestamp (UTC).
{
  "data": {
    "id": "whe_7a8b9c0d1e2f3a4b",
    "url": "https://hooks.example.com/brix",
    "description": "Ops alerts",
    "secretPreview": "3f9a1c2e",
    "events": [
      "screen.offline",
      "screen.online"
    ],
    "enabled": true,
    "autoDisabledAt": null,
    "autoDisabledReason": null,
    "consecutiveFailures": 0,
    "lastDeliveryAt": null,
    "lastStatus": null,
    "createdAt": "2026-09-28T09:00:00.000Z",
    "updatedAt": "2026-09-28T09:00:00.000Z"
  }
}

Response 400: bad_request (unknown event) or unsafe_url.

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 endpoint in this workspace.

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

DELETE /v1/webhooks/{id}

Auth: Bearer token. Permission: integration.edit.

Delete a webhook endpoint. Any deliveries still pending for it are abandoned rather than retried. Notes. - Answers { data: { id } } — without the deleted: true most other deletes return.

ParameterInTypeRequiredDescription
idpathstringyesWebhook endpoint id.
curl -X DELETE "https://api.brixsignage.com/v1/webhooks/{id}" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataobject
data.idstring

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 endpoint in this workspace.

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

POST /v1/webhooks/{id}/test

Auth: Bearer token. Permission: integration.edit.

Send a real, signed sample delivery to this endpoint now. It is a genuine delivery rather than a simulation, so it exercises the same signature verification your receiver uses in production. The payload has the same fields as a real event of that type, filled from one of your screens where possible, plus test: true. Pick the event with event in the body; by default the test uses the first event the endpoint is subscribed to. This call returns 409 if the endpoint is not subscribed to that event. Sends a real, signed delivery of one subscribed event now and records it in the delivery log. data carries every documented key of that event (the same shape a real event has), filled from a screen in the workspace when there is one and with sample values otherwise, plus test: true. A failed send is NOT an HTTP error: the answer is 200 with ok: false. Notes. - A test payload has data.test: true. Real events never carry test. - Needs the permission at the workspace root: a location-scoped key is refused.

ParameterInTypeRequiredDescription
idpathstringyesWebhook endpoint id.

Request body: application/json

FieldTypeRequiredDescription
event"screen.offline" | "screen.online" | "content.recalled" | "content.restored" | "approval.requested" | "approval.decided" | "emergency.started" | "emergency.cleared"noThe event to test. Default: the first event the endpoint is subscribed to.
curl -X POST "https://api.brixsignage.com/v1/webhooks/{id}/test" \
  -H "Authorization: Bearer $BRIX_API_KEY" \
  -H "Content-Type: application/json"

Response 200: Success.

FieldTypeDescription
dataobject
data.deliveryIdstringId of the delivery this call made (a new whd_… row in the delivery log).
data.okbooleanThe receiver answered 2xx.
data.statusinteger | nullHTTP status the receiver answered with; null when no answer came.
data.errorstring | nullWhy the delivery failed (http 500, a timeout, an unsafe address); null on success.
data.event"screen.offline" | "screen.online" | "content.recalled" | "content.restored" | "approval.requested" | "approval.decided" | "emergency.started" | "emergency.cleared"The event the test delivery sent.

Response 400: bad_request: event is not a webhook event.

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 endpoint in this workspace.

Response 409: not_subscribed: the endpoint is not subscribed to event (or to any event), or it is switched off.

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

GET /v1/webhooks/deliveries

Auth: Bearer token. Permission: integration.edit.

List the webhook delivery log: what was sent, the response received, the number of attempts, and what is still pending. Each entry includes the exact payload that was sent. Results are paginated and can be filtered by endpoint and status. Failed deliveries are retried with increasing delay over roughly 8 to 12 hours before they are given up on. Notes. - Always paged: without ?limit a page has 50 deliveries (not every row, unlike the lists that page only on request), and nextCursor is always present. - Needs the permission at the workspace root: a location-scoped key is refused.

ParameterInTypeRequiredDescription
limitquerystringnoPage size, 1–200. Default 50.
cursorquerystringnoThe nextCursor of the previous page.
endpointIdquerystringnoOnly this endpoint's deliveries.
statusquery"pending" | "delivered" | "failed" | "abandoned"noOnly deliveries in this state. Another value is ignored.
curl "https://api.brixsignage.com/v1/webhooks/deliveries" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataarray of WebhookDeliveryNewest first.
data[].idstringWebhook delivery id.
data[].endpointIdstring
data[].eventstring
data[].status"pending" | "delivered" | "failed" | "abandoned"failed is retried later; abandoned is not retried again.
data[].attemptsinteger
data[].occurredAtstringISO-8601 timestamp (UTC).
data[].createdAtstringISO-8601 timestamp (UTC).
data[].nextAttemptAtstring | nullWhen the next retry is due; null when none is.
data[].deliveredAtstring | null
data[].responseStatusinteger | null
data[].errorstring | null
data[].replayOfstring | nullSet on a delivery made by a replay: the delivery it resends.
data[].payloadobject | nullThe JSON body as it was sent; null if the stored copy cannot be read.
nextCursorstring | nullSend it back as ?cursor= for the next page; null on the last page.

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/webhooks/deliveries/{id}/replay

Auth: Bearer token. Permission: integration.edit.

Resend a delivery as a new delivery with its own id and a replayOf field pointing at the original. The original delivery record is left unchanged, so a receiver that deduplicates on delivery id will not silently ignore the resend. Sends the payload again now, as a new delivery. A failed send is NOT an HTTP error: the answer is 200 with ok: false. Notes. - Needs the permission at the workspace root: a location-scoped key is refused.

ParameterInTypeRequiredDescription
idpathstringyesId of the delivery to send again.
curl -X POST "https://api.brixsignage.com/v1/webhooks/deliveries/{id}/replay" \
  -H "Authorization: Bearer $BRIX_API_KEY"

Response 200: Success.

FieldTypeDescription
dataobject
data.deliveryIdstringId of the delivery this call made (a new whd_… row in the delivery log).
data.okbooleanThe receiver answered 2xx.
data.statusinteger | nullHTTP status the receiver answered with; null when no answer came.
data.errorstring | nullWhy the delivery failed (http 500, a timeout, an unsafe address); null on success.

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 delivery in this workspace.

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

GET /v1/webhooks/events

Auth: Bearer token. Permission: integration.view.

List the catalog of event types that can be subscribed to, each with a label and a description of what it carries. Only content.recalled and content.restored events are actually sent today; other listed events are not yet emitted. Notes. - data per event — screen.offline: screenId, screenName, status, nodeId, nodeName, lastSeenAt, upForSec, scheduledOff. screen.online: screenId, screenName, status, nodeId, nodeName, lastSeenAt, offlineSince, offlineForSec. approval.requested: requestId, contentKind, contentId, contentName, nodeId, nodeName, requestedById, requestedByName, requestedAt, note. approval.decided: the same plus decision (approved | rejected | withdrawn), decidedById, decidedByName, decidedAt, decisionNote. emergency.started: emergencyId, headline, body, severity, contentKind, contentId, scopeKind, scopeNodeId, scopeName, screenCount, triggeredById, triggeredByName, triggeredAt, expiresAt, templateId, templateName. emergency.cleared: the same plus clearedAt, clearedById, clearedByName, reason (cleared | expired | replaced | content-deleted). content.recalled: kind, id, name, reason, recalledBy. content.restored: kind, id, name. - screen.offline is sent once per outage, when Brix marks the screen offline (seconds after a socket drop, up to 45 minutes for a screen that reports only by heartbeat). A screen that drops again before it is back is the same outage. screen.online follows when it reports again, within about 5 minutes.

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

Response 200: Success.

FieldTypeDescription
dataarray of object
data[].event"screen.offline" | "screen.online" | "content.recalled" | "content.restored" | "approval.requested" | "approval.decided" | "emergency.started" | "emergency.cleared"
data[].labelstring
data[].whatstringWhat the event means and carries.
data[].fieldsarray of stringThe keys of the delivery's data object. Every key is always sent (null when unknown). Keys are added over time, never renamed or removed.

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.