# Triggers CLI commands

> Canonical HTML: https://screenrig.ai/docs/cli/triggers

Take screens over from CAP emergency alerts and show overlays posted by Home Assistant, sensors or any HTTP client: create, test and rotate triggers. Every command here runs as described in the [CLI reference](https://screenrig.ai/docs/cli.md): global flags, JSON output, exit codes, revisions and retries.

## CAP alert triggers

A trigger lets an emergency notification system, such as Everbridge, Rave, Alertus or an IPAWS relay, take screens over with CAP 1.2 alerts. Each trigger has its own URL, username and password, which you enter in the sending system as its CAP HTTP POST destination with HTTP Basic authentication. An organization has at most 20 triggers across its projects.

Triggers come in two kinds. A CAP trigger, described here, takes an emergency system's alerts. An [overlay trigger](https://screenrig.ai/docs/cli/triggers.md#overlay-triggers) shows what any sender posts, such as Home Assistant, a sensor hub or an alerting tool, as a bar over what plays or as a takeover; `triggers create --kind overlay` makes one, and `triggers update`, `triggers clear` and `triggers rotate-secret` serve both kinds, while `triggers deliveries` reads an overlay trigger's log.

A trigger targets a tag, resolved when each alert arrives, or up to 500 screen ids. Each Alert becomes a takeover of the trigger's own playlist: a full-screen card in the colour of its severity, with the event, headline, description and instruction. An Exercise adds an `EXERCISE` banner. The takeover holds until the alert's `<expires>`, else the trigger's `--for` default (1 minute to 7 days, 1 hour unless set), and never past 7 days. An Update redraws the card, and a Cancel or AllClear gives every screen back to what it played before. A new Alert replaces the one showing. Test, System and Draft messages, Ack and Error messages and expired alerts are ignored, and a repeated sender and identifier is a duplicate. A screen needs a default playlist to be taken over; other screens are skipped.

The password, `srtg_…`, is shown only by `triggers create` and `triggers rotate-secret`, with the warning `trigger_password_shown_once`. The CLI keeps it out of its configuration, operation log and recovery state. The URL and username are not secret.

| Problem code | Exit | Meaning |
| --- | --- | --- |
| `trigger_limit_reached` | `5` | The organization already has 20 triggers. Nothing was created. Delete one first. |
| `resource_conflict` | `5` | `triggers test` or `triggers delete` while an alert is active. `next` is `triggers clear`. |
| `not_found` | `4` | No trigger has this id in the project. |
| `revision_conflict` | `6` | The `--expect-rev` revision was stale. Run `triggers show`, then retry. |

### `triggers create`

Create a trigger and receive its URL, username and password.

```console
triggers create --name NAME [--kind cap|overlay] (--tag TAG | --screen-id ID...) [--for DURATION] [--pull FILE]
    [--show bar|takeover] [--edge bottom|top] [--style FILE] [--map FILE] [--signing]
    [--verify VENDOR [--verify-secret-file FILE] [--verify-header NAME] [--verify-encoding hex|base64]
        [--verify-timestamp-header NAME] [--verify-tolerance SECONDS]]
    [--handshake VENDOR]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `--name NAME` | string | yes | none | The trigger's name, 1 to 80 characters without control characters. |
| `--kind KIND` | `cap` or `overlay` | no | `cap` | `cap` takes an emergency system's CAP 1.2 alerts. `overlay` takes a few words from any sender and needs `--show`. |
| `--tag TAG` | string | one of `--tag` or `--screen-id` | none | Every active screen with this tag when an alert arrives. |
| `--screen-id ID` | string | one of `--tag` or `--screen-id` | none | A `scr_` screen id. Repeat it, or list ids comma-separated; at most 500. |
| `--for DURATION` | duration | no | `1h` (overlay `10m`) | How long an alert without `<expires>`, or an overlay post without a `duration`, holds the screens, such as `30m`, `2h` or `1d`; 1 minute to 7 days for a CAP trigger, 10 seconds to 7 days for an overlay trigger. |
| `--pull FILE` | path | no | none | A CAP trigger: a JSON object, from a file or `-` for stdin, that also has the platform read CAP alert sources for the trigger. Its members are the params of the `cap-alert` card, listed below. |
| `--show SHOW` | `bar` or `takeover` | with `--kind overlay` | none | `bar` draws a strip over whatever plays on the target screens. `takeover` plays the alert full screen. |
| `--edge EDGE` | `bottom` or `top` | no | `bottom` | The edge a bar takes. Only with `--show bar`. |
| `--style FILE` | path | no | none | A JSON object, from a file or `-` for stdin, of the text card's style: `theme`, `accent`, `background`, `backgroundColor`, `textColor` and `align`. At most 64 KiB. |
| `--map FILE` | path | no | none | A JSON template, from a file or `-` for stdin, that builds the overlay post from the body a sender posts; see [overlay triggers](https://screenrig.ai/docs/cli/triggers.md#overlay-triggers). At most 64 KiB. |
| `--signing` | flag | no | off | Also require a `ScreenRig-Signature` header on every post, and print the signing secret once. Not with `--verify`. |
| `--verify VENDOR` | string | no | none | An overlay trigger: accept a post that carries this vendor's own signature in place of the `srtg_` password, which keeps working beside it. `github`, `stripe`, `shopify`, `slack`, `linear`, `vercel`, `asana` or `generic_hmac`. |
| `--verify-secret-file FILE` | path | with `--verify`, except `asana` | none | The vendor's secret, from a file or `-` for stdin, never an argument: the webhook secret GitHub, Stripe, Shopify, Slack, Linear or Vercel shows, or a `generic_hmac` sender's. `asana` takes none: its handshake delivers it. |
| `--verify-header NAME` | string | with `--verify generic_hmac` | none | The header that carries the signature. |
| `--verify-encoding ENCODING` | `hex` or `base64` | no | `hex` | With `--verify generic_hmac`: how the signature is written. It may begin with `sha256=`. |
| `--verify-timestamp-header NAME` | string | no | none | With `--verify generic_hmac`: a header that carries the Unix time in seconds, or in milliseconds as 13 digits. The signed text is then `<timestamp>.<body>`. |
| `--verify-tolerance SECONDS` | integer | no | 300 | With `--verify-timestamp-header`: how far the timestamp may sit from the server's clock, 1 to 86400. |
| `--handshake VENDOR` | string | no | none | An overlay trigger: answer the setup challenge of `microsoft_graph`, `monday`, `trello` or `azure_event_grid`. Slack and Asana answer theirs through `--verify`. |

```console
screenrig triggers create --name "Campus alerts" --tag Campus
screenrig triggers create --name "Campus alerts" --tag Campus --pull pull.json
screenrig triggers create --name "Lobby sensors" --kind overlay --show bar --tag Lobby
screenrig triggers create --name "Doorbell" --kind overlay --show takeover --tag Lobby --for 30s
screenrig triggers create --name "Payments" --kind overlay --show bar --tag Lobby --verify stripe --verify-secret-file stripe.secret --map stripe-map.json
screenrig triggers create --name "Boards" --kind overlay --show bar --tag Lobby --handshake trello
```

The envelope is the trigger with `data.url` (`https://api.screenrig.ai/api/triggers/<id>/cap`, or `.../overlay` for an overlay trigger), `data.username` (the trigger id) and `data.password`. Enter them in the sending system now; an overlay trigger's sender needs the url and the password (`Authorization: Bearer`). With `--signing` the envelope also carries `data.signing_secret`, shown once, with the warning `trigger_signing_secret_shown_once`. After an interrupted or ambiguous create, rerun the identical command within 24 hours: it reuses the saved idempotency key, and the server returns the same trigger and password instead of creating another.

`--pull` adds sources the platform reads beside the posted URL, which keeps working. The object holds `sources` (up to 5 http or https URLs of CAP 1.0 to 1.2 alerts or ATOM/RSS indexes), `publicAlerts`, `location` (`name`, `latitude`, `longitude`, and `geocodes` as `[{name, value}]`), `minSeverity`, `maxSeverity`, `minUrgency`, `minCertainty`, `events`, `excludeEvents`, `senders`, `statuses`, `scopes`, `languages` and `areaUnknown`; `feeds get cap` takes the same filters as flags. `location` is required unless `sources` are given, and with no `sources` the public feeds covering `location` are read. Each source is fetched once a minute. The most severe matching alert takes the screens over like a posted one, and when the sources show none a pulled alert ends; a stale or failing source never ends an alert. For example `{"location": {"latitude": 49.25, "longitude": -123}, "minSeverity": "moderate"}`.

The overlay options (`--show`, `--edge`, `--style`, `--map`, `--signing`, `--verify` with its companions, and `--handshake`) need `--kind overlay`, and `--pull` needs a CAP trigger. `--style`, `--map` and `--verify-secret-file` each read a file, and only one of them can read `-` (stdin).

`--verify VENDOR` lets a vendor's own webhook post straight to `data.url`: a post that carries the vendor's valid signature in its own header is accepted without `data.password`, which keeps working beside it. The vendor's secret is stored sealed and read back only as `overlay.verify.secret`, with `set` and its last four characters. `asana` takes no secret: its handshake delivers one, and events answer `secret_pending` until then. `generic_hmac` needs `--verify-header` and takes `--verify-encoding`, `--verify-timestamp-header` and `--verify-tolerance`. `--handshake VENDOR` answers that vendor's setup challenge before any credential is asked; it changes no alert, is never billed and shows in `triggers deliveries` as outcome `handshake`. The vendors, their headers and the settings to enter at each are listed under [vendor signatures and handshakes](https://screenrig.ai/docs/cli/cards.md#vendor-signatures-and-handshakes).

### `triggers list`

List this project's triggers and their latest alerts, oldest first.

```console
triggers list
```

```console
screenrig triggers list
```

`--human` prints `ID`, `KIND`, `LABEL`, `TARGET`, `ALERT` and `LAST_RECEIVED`; for an overlay trigger `ALERT` says what it draws and how many alerts it holds. A list never carries a password or a signing secret.

### `triggers show`

Inspect a trigger and its latest alert.

```console
triggers show <id>
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |

```console
screenrig triggers show trg_01EXAMPLETRIGGER00
```

`data.alert` is the latest alert: its CAP fields, `state` `active` or `ended` (with `ended_reason` `cancelled`, `all_clear`, `cleared` or `expired`), `until`, and `screens` with `targeted`, `taken_over`, `cleared`, `skipped`, `failed` and `pending`. `pending` is true while screens are still being written, and failed screens are retried. `data.playlist_id` is the trigger's alert playlist, and `screen show` reports an alert as a takeover of it. For an overlay trigger `data.overlay` holds `show`, `edge`, `enabled`, `signing`, `verify` and `handshake` while set, `card_id`, `alerts` (the active alerts, newest first; the first shows), `screens` with `targeted`, `holding`, `taken_over`, `removed`, `edge_taken`, `skipped` and `failed`, and `pending`.

### `triggers test`

Show a 60-second exercise alert on the trigger's screens.

```console
triggers test <id>
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |

```console
screenrig triggers test trg_01EXAMPLETRIGGER00
```

The envelope is the receipt: `data.outcome` `shown` and `data.alert`. The answer arrives before every screen is written; `triggers show` reports the counts. An overlay trigger shows the alert `screenrig-test` (label `Test`, title `Test overlay`) for 60 seconds, and the receipt is the one a post gets (`data.alert_id`, `data.until`, `data.active`). Both kinds refuse a test while an alert shows.

### `triggers update`

Change a trigger without changing its URL or secret.

```console
triggers update <id> [--name NAME] [--tag TAG | --screen-id ID...] [--for DURATION] [--pull FILE | --no-pull]
    [--edge bottom|top] [--style FILE | --clear-style] [--map FILE | --clear-map] [--enable | --disable]
    [--signing | --no-signing]
    [--verify VENDOR [--verify-secret-file FILE] [--verify-header NAME] [--verify-encoding hex|base64]
        [--verify-timestamp-header NAME] [--verify-tolerance SECONDS] | --clear-verify]
    [--handshake VENDOR | --clear-handshake] [--expect-rev REVISION]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |
| `--name NAME` | string | no | unchanged | Rename the trigger. |
| `--tag TAG`, `--screen-id ID` | string | no | unchanged | A new target, as in `triggers create`. |
| `--for DURATION` | duration | no | unchanged | A new hold for alerts that name no end: 1 minute to 7 days for a CAP trigger, 10 seconds to 7 days for an overlay trigger. |
| `--pull FILE`, `--no-pull` | path, flag | no | unchanged | A CAP trigger: replace its CAP sources, or stop reading them. |
| `--edge EDGE` | `bottom` or `top` | no | unchanged | An overlay bar: move it to this edge. |
| `--style FILE`, `--clear-style` | path, flag | no | unchanged | An overlay trigger: replace the whole style, or remove it. |
| `--map FILE`, `--clear-map` | path, flag | no | unchanged | An overlay trigger: replace the template, or remove it so the posted object is the post. |
| `--enable`, `--disable` | flag | no | unchanged | An overlay trigger: a disabled trigger answers every post with the 404 a wrong secret gets. |
| `--signing`, `--no-signing` | flag | no | unchanged | An overlay trigger: turn the signature check on, printing the signing secret once, or off. Not with `--verify`. |
| `--verify VENDOR` | string | no | unchanged | An overlay trigger: replace the vendor verification, as in `triggers create`. Without `--verify-secret-file` it keeps the stored secret when the vendor stays the same; a different vendor needs its own. |
| `--verify-secret-file FILE` | path | no | unchanged | With `--verify`: the vendor's secret, from a file or `-` for stdin. |
| `--verify-header NAME` | string | no | unchanged | With `--verify generic_hmac`: the header that carries the signature. |
| `--verify-encoding ENCODING` | `hex` or `base64` | no | unchanged | With `--verify generic_hmac`: how the signature is written. |
| `--verify-timestamp-header NAME` | string | no | unchanged | With `--verify generic_hmac`: a header that carries the Unix time. |
| `--verify-tolerance SECONDS` | integer | no | unchanged | With `--verify-timestamp-header`: how far the timestamp may sit from the server's clock, 1 to 86400. |
| `--clear-verify` | flag | no | off | An overlay trigger: stop accepting a vendor's signature and forget its secret. |
| `--handshake VENDOR` | string | no | unchanged | An overlay trigger: answer the setup challenge of `microsoft_graph`, `monday`, `trello` or `azure_event_grid`. |
| `--clear-handshake` | flag | no | off | An overlay trigger: stop answering the vendor handshake. |
| `--expect-rev REVISION` | string | no | none | Optional revision precondition. |

```console
screenrig triggers update trg_01EXAMPLETRIGGER00 --tag Lobby
screenrig triggers update trg_01EXAMPLETRIGGER00 --edge top --style style.json
screenrig triggers update trg_01EXAMPLETRIGGER00 --map map.json --signing
screenrig triggers update trg_01EXAMPLETRIGGER00 --verify github --verify-secret-file github.secret
screenrig triggers update trg_01EXAMPLETRIGGER00 --clear-verify
```

At least one option besides `--expect-rev` is required. A bar re-places itself on the new target screens and edge; a takeover trigger's new target applies from the next alert that starts. A trigger that already signs keeps its signing secret when `--signing` is repeated; `triggers rotate-secret --signing` replaces it. `--clear-verify` removes the vendor verification and forgets its secret, and `--clear-handshake` stops answering the vendor handshake. After an interrupted or ambiguous update, rerun the identical command: it reuses the saved idempotency key.

### `triggers deliveries`

Read an overlay trigger's log of posts: why each one was shown, ignored or refused.

```console
triggers deliveries <id> [--limit N]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |
| `--limit N` | integer | no | `100` | How many deliveries, newest first; 1 to 100. |

```console
screenrig triggers deliveries trg_01EXAMPLETRIGGER00 --limit 20
```

`data.items` holds the posts of the last seven days: `at`, `outcome` (`shown`, `updated`, `unchanged`, `ended`, `ignored`, `refused`, `invalid` or `handshake`), `reason` for a refused or invalid post (`credentials`, `signature`, `signature_missing`, `signature_invalid`, `timestamp_missing`, `timestamp_stale`, `secret_pending`, `handshake_invalid`, `disabled`, `body`, `mapping`, `field`, `rate_limited` or `internal`), `detail` (the member or mapping path that was wrong), `status`, `bytes`, `files` (the file parts of a multipart post, which are ignored), `alert_id` and `request_id`. `signature` is a failed `ScreenRig-Signature`; the other signature, timestamp and handshake reasons are a vendor's, as the table under [vendor signatures and handshakes](https://screenrig.ai/docs/cli/cards.md#vendor-signatures-and-handshakes) explains. The log never keeps a body, a header or a credential. A wrong secret, a bad signature and a disabled trigger all answer the sender the same 404, so this log is where to read which it was. A CAP trigger has no deliveries.

### `triggers clear`

End the trigger's alert now.

```console
triggers clear <id> [--alert-id ID]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |
| `--alert-id ID` | string | no | none | An overlay trigger: end only this alert. Without it every alert ends. |

```console
screenrig triggers clear trg_01EXAMPLETRIGGER00
screenrig triggers clear trg_01EXAMPLETRIGGER00 --alert-id front-door
```

The alert ends with `ended_reason` `cleared`, and its screens go back to what they played before. A screen whose takeover something else has replaced since is left alone. With no active alert, nothing changes. On an overlay trigger a clear of an alert that is not active changes nothing, and the last alert ending lowers the bar or gives the takeover's screens back.

### `triggers rotate-secret`

Replace a trigger's password.

```console
triggers rotate-secret <id> [--signing] [--expect-rev REVISION]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |
| `--signing` | flag | no | off | An overlay trigger that signs: replace the signing secret instead of the password. |
| `--expect-rev REVISION` | string | no | none | Optional revision precondition. |

```console
screenrig triggers rotate-secret trg_01EXAMPLETRIGGER00
```

The envelope carries the new password in `data.password`. The old password stops working at once, so enter the new one in the sending system. With `--signing` the envelope carries the new `data.signing_secret` instead, shown once; the old one stops working at once, and a trigger that does not sign answers `invalid_request`. After an interrupted or ambiguous rotation, rerun the identical command within 24 hours: it reuses the saved idempotency key, so the server returns the rotation that already happened instead of rotating again.

### `triggers delete`

Delete a trigger. Its URL stops accepting alerts and posts at once; an overlay trigger's bars come off its screens and its card is deleted. A trigger showing an alert is refused with `resource_conflict`: run `triggers clear` first.

```console
triggers delete <id> [--expect-rev REVISION]
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `trg_` trigger id. |
| `--expect-rev REVISION` | string | no | none | Optional revision precondition. |

```console
screenrig triggers delete trg_01EXAMPLETRIGGER00
```

## Overlay triggers

An overlay trigger shows what an outside system posts. Home Assistant, a door or motion sensor hub, a camera system or an alerting tool sends a few words with one HTTP POST, and the trigger's screens show them until they expire or the sender clears them. It is a trigger like a CAP trigger: `triggers create --kind overlay` makes it, and it counts toward the same limit of 20 per organization.

`--show bar` draws a strip over whatever plays on every target screen, on the bottom edge or, with `--edge top`, the top. The strip slides in when an alert starts and out when the last one ends; the playlist, its pages and its timing are untouched. A screen holds one bar per edge, so an overlay trigger whose edge a screen's other overlay trigger already holds does not show there (`triggers show` counts those screens as `edge_taken`), and a page that has its own strip with presence on that edge keeps it. A corner or chip card on that edge moves in past the bar's height whether or not the bar is showing. No bar draws on an ad slot page or while a takeover plays. `--show takeover` plays the alert full screen on target screens that have a default playlist from the first alert until the last one ends. A takeover trigger never replaces a takeover that is already on a screen, such as an operator's or an emergency alert, and a CAP alert replaces it.

A tag target is resolved when an alert starts; a screen tagged later gets the bar with the next alert that starts. Screens without a default playlist are skipped by a takeover. A screen that is offline catches up when it reconnects.

The sender posts JSON, a form or `multipart/form-data` (file parts are ignored) to `data.url` with `Authorization: Bearer SECRET`, or HTTP Basic with the trigger id as the username and the secret as the password. The secret never goes in the URL. A post has these members; an unknown member is refused naming it.

| Member | Type | Notes |
| --- | --- | --- |
| `alert_id` | string | The sender's id for the alert, 1 to 200 characters. The same id updates that alert instead of stacking another. Absent is one alert called `default`. On a clear, absent ends every alert. |
| `label` | string | A short label above the title, at most 40 characters. |
| `title` | string | At most 120 characters. |
| `message` | string | The main text, at most 400 characters. |
| `note` | string | A quiet line at the foot, at most 120 characters. |
| `duration` | number or string | How long this post holds its alert, from now: seconds from `10` to `604800`, or `10s`, `5m`, `2h`, `1d`, or `until_cleared`. Absent takes the trigger's `--for` (10 minutes unless set). |
| `clear` | boolean or string | `true` (or `yes`, `y`, `1`, `x`) ends the alert; `false` (or `no`, `n`, `0`, empty) raises it. A clear ignores the other members. |
| `state` | string | A state word from the sender. `off`, `closed`, `clear`, `cleared`, `resolved`, `ok`, `normal`, `inactive` and `ended`, in any case, end the alert; any other state raises it. |

A raise needs at least one of `label`, `title`, `message` and `note`. Text longer than its limit is refused, and `duration` outside 10 seconds to 7 days is refused, both with `invalid_request` naming the member. Every raise or update holds its alert for `duration` from that post, so a motion sensor that posts every few seconds keeps the bar up and the bar leaves `duration` after the last post. A trigger shows its newest alert; ending it shows the one before it again. It holds ten alerts, and an eleventh replaces the oldest. An alert ends within about ten seconds of its time. A clear sent twice ends the alert once, and a clear of an alert that is not active changes nothing.

The answer is a receipt: `outcome` (`shown`, `updated`, `unchanged`, `ended` or `ignored`), `alert_id`, `until` (null for an alert held until cleared) and `active`, the alerts the trigger holds after the post. An `Idempotency-Key` header of 8 to 200 characters answers a sender's retry with the first receipt for 24 hours. A trigger takes 120 posts a minute. A post does not count toward the agent request cap, and a clear is never refused, so an alert can always be taken off the screens.

```sh
curl -X POST https://api.screenrig.ai/api/triggers/trg_01EXAMPLETRIGGER00/overlay \
  -H "Authorization: Bearer srtg_YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"alert_id":"front-door","title":"Front door","message":"The front door is open","duration":"10m"}'
```

A wrong address, a wrong secret, a disabled trigger, a missing or bad signature and every GET answer the same 404 `not_found`, so a sender or a link previewer learns nothing about which it was. `triggers deliveries` shows the project why, for the last seven days, with no post body. `--style FILE` sets the text card's `theme`, `accent`, `background`, `backgroundColor`, `textColor` and `align`; use one trigger per look.

`--map FILE` builds the post from the body an alerting tool sends, with the template language of card webhooks. A string with `{{body.title}}` is text, a string that is exactly one placeholder keeps its type, `{"$text": "{{body.message}}", "$max": 400}` cuts text, and a path starts with `body` or `query`. This template maps an alert from a monitoring tool and clears it when its status is `resolved`:

```json
{"alert_id": "{{body.groupKey}}", "title": "{{body.title}}", "message": {"$text": "{{body.message}}", "$max": 400}, "state": "{{body.status}}"}
```

`--signing` also requires `ScreenRig-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with `data.signing_secret` (`whsec_…`, shown once), with `t` within five minutes of the server's clock. A sender may carry two `v1` values while it rotates the secret.

```sh
body='{"alert_id":"front-door","title":"Front door","message":"The front door is open"}'
t=$(date +%s)
sig=$(printf '%s.%s' "$t" "$body" | openssl dgst -sha256 -hmac "$SIGNING_SECRET" -hex | sed 's/^.* //')
curl -X POST "$URL" -H "Authorization: Bearer $SECRET" -H "ScreenRig-Signature: t=$t,v1=$sig" \
  -H "Content-Type: application/json" -d "$body"
```

An alerting tool or a vendor that signs its own posts can have its signature verified in place of the secret, and a vendor's setup handshake answered, as for [card webhooks](https://screenrig.ai/docs/cli/cards.md#vendor-signatures-and-handshakes): `triggers create` and `triggers update` take `--verify VENDOR` with `--verify-secret-file FILE`, and `--handshake VENDOR`, and `triggers update` takes `--clear-verify` and `--clear-handshake` to remove each. The vendors, their headers and the `generic_hmac` options are the ones listed there. A post that carries the vendor's valid signature is accepted without the trigger's `srtg_` password, which keeps working beside it, `--verify` excludes `--signing`, and a handshake changes no alert. `triggers deliveries` shows why a signature failed.

A Home Assistant `rest_command` posts to the trigger. Keep the secret in `secrets.yaml`, and give each automation the alert it raises or clears:

```yaml
# secrets.yaml
screenrig_lobby_overlay: "Bearer srtg_YOUR_SECRET"

# configuration.yaml
rest_command:
  screenrig_lobby:
    url: "https://api.screenrig.ai/api/triggers/trg_01EXAMPLETRIGGER00/overlay"
    method: post
    headers:
      Authorization: !secret screenrig_lobby_overlay
    content_type: "application/json"
    payload: >-
      {{ {"alert_id": alert_id | default(""), "title": title | default(""),
          "message": message | default(""), "duration": duration | default("10m"),
          "clear": clear | default(false)} | tojson }}

# automations.yaml
- alias: Front door open on the lobby screens
  triggers:
    - trigger: state
      entity_id: binary_sensor.front_door
      to: "on"
  actions:
    - action: rest_command.screenrig_lobby
      data: {alert_id: front-door, title: Front door, message: The front door is open, duration: until_cleared}
- alias: Front door closed
  triggers:
    - trigger: state
      entity_id: binary_sensor.front_door
      to: "off"
  actions:
    - action: rest_command.screenrig_lobby
      data: {alert_id: front-door, clear: true}
- alias: Driveway motion
  triggers:
    - trigger: state
      entity_id: binary_sensor.driveway_motion
      to: "on"
  actions:
    - action: rest_command.screenrig_lobby
      data: {alert_id: driveway, title: Driveway, message: Motion at the driveway, duration: 2m}
```

Two facts make this work. Each motion post holds the bar for 2 minutes from that post, so it stays while motion continues and leaves 2 minutes after the last event. And Home Assistant renders the `{{ }}` template before it posts, so the trigger receives plain JSON; the trigger's own `--map` template is a separate step that runs every post through it, so leave `--map` off for a sender that already posts the overlay members, as Home Assistant does here, or give that sender its own trigger.

## Other command groups

- [Projects](https://screenrig.ai/docs/cli/projects.md)
- [Service clients](https://screenrig.ai/docs/cli/service-clients.md)
- [Help and support](https://screenrig.ai/docs/cli/help.md)
- [Media](https://screenrig.ai/docs/cli/media.md)
- [Media sync](https://screenrig.ai/docs/cli/media-sync.md)
- [Playlists](https://screenrig.ai/docs/cli/playlists.md)
- [Cards](https://screenrig.ai/docs/cli/cards.md)
- [Applications](https://screenrig.ai/docs/cli/applications.md)
- [Screens](https://screenrig.ai/docs/cli/screens.md)
- [Schedules](https://screenrig.ai/docs/cli/schedules.md)
- [Campaigns](https://screenrig.ai/docs/cli/campaigns.md)
- [Device health](https://screenrig.ai/docs/cli/device.md)
- [Reviews and notes](https://screenrig.ai/docs/cli/reviews.md)
- [Notifications](https://screenrig.ai/docs/cli/notifications.md)
- [Reports](https://screenrig.ai/docs/cli/reports.md)
- [Data sources](https://screenrig.ai/docs/cli/data-sources.md)
- [BI dashboards](https://screenrig.ai/docs/cli/bi.md)
- [Fleet links](https://screenrig.ai/docs/cli/fleet-links.md)
- [Advertising](https://screenrig.ai/docs/cli/ads.md)
