# Show an emergency message at a location

By the end, one command puts a prepared scene on every display at a location until a time you set, and a second command ends it early. Use it for a closure, a water damage, or an evacuation notice, when there is no time to click through the portal.

> **Type:** guide
> **For:** Developers who connect alarm or facility systems, or who want an emergency button for their team
> **Prerequisite:** a key `ak_…` of the class **Custom** with `location.list`, `fleet.player.list`, and `schedule.update`, and a published scene with the message
> **Where:** command line

## How it works

An override sits above every program and ends at the time you set. It applies to one display at a time, so the script reads the displays of the location page by page and sets the override on each one. The program of each display stays as it is and takes over again when the override ends.

If all displays at the location play the same program, a one-off program entry reaches all of them in one call, see [Schedule a campaign from your own system](/recipes/schedule-campaign). The override is the faster way in an emergency because it needs no knowledge of the programs.

## Steps

1. **Prepare the scene** in the portal and publish it, for example a red page with "Closed today" and a phone number. Open it: the address ends with its ID `scn_…`. Prepare it before you need it.

2. **Find the location ID** with `GET /v1/locations`:

   ```bash
   curl -sS "$SZENERA_API/v1/locations" \
     -H "Authorization: Bearer $SZENERA_API_KEY" \
     | jq -r '.locations[] | "\(.id)  \(.name)  \(.playerCount) displays"'
   ```

3. **Save the script.** It takes the location, the scene, and the end time, and prints the response code for each display:

   ```bash
   #!/usr/bin/env bash
   # emergency.sh <loc_…> <scn_…> <end, such as 2026-10-26T18:00:00+01:00>
   set -euo pipefail
   location="$1" scene="$2" until="$3"
   auth="Authorization: Bearer $SZENERA_API_KEY"
   body=$(jq -nc --arg scene "$scene" --arg until "$until" \
     '{content: {kind: "scene", sceneId: $scene}, until: $until}')

   cursor=""
   while :; do
     page=$(curl -sS -G "$SZENERA_API/v1/players" -H "$auth" \
       --data-urlencode "locationId=$location" --data-urlencode "limit=100" \
       ${cursor:+--data-urlencode "cursor=$cursor"})
     for id in $(jq -r '.items[].id' <<<"$page"); do
       curl -sS -o /dev/null -w "$id %{http_code}\n" -X PUT \
         "$SZENERA_API/v1/players/$id/override" \
         -H "$auth" -H "Content-Type: application/json" -d "$body"
     done
     cursor=$(jq -r '.nextCursor // empty' <<<"$page")
     [ -z "$cursor" ] && break
   done
   ```

4. **Run it.** The end time carries its offset, so it means the same moment everywhere:

   ```bash
   ./emergency.sh loc_01KFB7QPW0LOCATION00000001 scn_01KJPX8NH0SZENE00000000009 2026-10-26T18:00:00+01:00
   ```

   ```text
   ply_01KFB7QPW0PLAYER0000000001 200
   ply_01KFB7QPW0PLAYER0000000002 200
   ```

5. **End it early** with the same loop and `DELETE` instead of `PUT`, without a body. Each display falls back to its program at once:

   ```bash
   curl -sS -X DELETE "$SZENERA_API/v1/players/ply_01KFB7QPW0PLAYER0000000001/override" \
     -H "Authorization: Bearer $SZENERA_API_KEY"
   ```

A single display also works from the command line: `szenera player set-override <ply_…> --content=scene:<scn_…> --until=…` and `szenera player clear-override <ply_…>`.

## Check the result

- Every line of the output ends in `200`.
- `GET /v1/players/{id}/program` shows the override under `override`, with `until` and the scene.
- In the portal, the displays of the location show the override until the end time.

## If something goes wrong

| Symptom | Meaning | Solution |
|---|---|---|
| The output is empty | No display is assigned to this location, or the ID is wrong. | Check `playerCount` in `GET /v1/locations`. |
| `422` for every display | The end time lies in the past or has no offset. | Give a future time with offset, such as `+01:00`. |
| `422 Scene.Blocked` | The scene uses an app that your package no longer covers. | Take the app out of the scene, or use a scene without it. |
| `422 Schedule.ContentNotFound` | The scene ID does not exist. | Check the ID in the portal address. |
| `429 RateLimit.Exceeded` | The key has used up its requests for the window. | Wait for `Retry-After`, then run the script again. Setting the same override twice does no harm. |

## Related

- [Commands for your organization](/cli/commands-organization)
- [Paging: limit, cursor, items, nextCursor](/api/pagination)
- [Throttling and rate-limit headers](/api/rate-limits)
