Locations
Mirror a branch structure: fields of a location, its routes, assigning a display, and analytics by location.
6 minute readAPIUpdated: 10/25/2026
On this page
Before you start
- For
- Anyone who mirrors a branch structure from their own system or groups analytics by location.
- Prerequisite
- an
ak_…key with thelocation.*permissions, which are key-capable
A location is the place where displays are installed: name, address, time zone, optionally the position on the map, the federal state, the opening hours, and the venue type. This page lists the fields, the routes, the assignment of a display, and the other places where the location appears.
What a location is
A folder above displays, not a second tenant. It carries no permissions, no licenses, and no inventory of its own. A display points to it with locationId, and there is no tighter binding than that. Tags and video walls remain what they are: The location does not replace them, it answers a different question.
| Field | Rule |
|---|---|
id |
loc_ and 26 characters |
name |
1 to 120 characters, unique per organization |
address |
four required fields as soon as an address exists at all: street, postalCode, city, country (country code per ISO 3166-1 alpha-2, uppercase). null means “none on file” |
timeZone |
required, a zone from the IANA database (Europe/Berlin) |
coordinates |
lat and lng or null. Set by a person, without an accuracy value |
region |
the federal state as an identifier per ISO 3166-2 (DE-HH, currently the sixteen German federal states) or null. Determines the statutory holidays |
openingHours |
{ weekly, specialDays }, or null as long as no hours are maintained, see Opening hours |
note |
free text up to 500 characters for the people on site |
venueType |
the venue type (pharmacy, workshop, bakery, beverage_store, grocery, kiosk, fitness_studio, medical_practice, retail, other) or null. Ad bookings are targeted by it, and analytics groups by it, and likewise by the federal state |
version |
the version for If-Match, see ETag and If-Match |
The time zone belongs to the location, not to the display: Two displays in the same room never have two different ones.
The routes
| Route | Permission | Note |
|---|---|---|
GET /v1/locations |
location.list |
complete, without paging. Each row gives the number of displays at the location in playerCount |
GET /v1/locations/{id} |
location.read |
one location with all details |
POST /v1/locations |
location.create |
201. Needs the Locations capability of the organization |
PATCH /v1/locations/{id} |
location.update |
partial change. address: null, coordinates: null, region: null, openingHours: null, and venueType: null remove the value, and an omitted field stays as it is. openingHours replaces the previous value as a whole |
DELETE /v1/locations/{id} |
location.delete |
only an empty location |
curl -sS -X POST "$SZENERA_API/v1/locations" \
-H "Authorization: Bearer $SZENERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Filiale Nord",
"timeZone": "Europe/Berlin",
"address": { "street": "Nordstraße 12", "postalCode": "30159", "city": "Hannover", "country": "DE" }
}'
Assign a display
The assignment does not go through the location route but through the display: A location is a master data field of the display, like its name.
curl -sS -X PATCH "$SZENERA_API/v1/players/ply_01KFB7QPW0PLAYER0000000001" \
-H "Authorization: Bearer $SZENERA_API_KEY" \
-H "Content-Type: application/json" \
-H "If-Match: 3" \
-d '{ "locationId": "loc_01KFB7QPW0LOCATION00000001" }'
"locationId": null detaches the display again. A location never takes displays down with it: An occupied location cannot be deleted, so the displays are moved or detached first. When a display gets a different location or none at all, it rebuilds its snapshot immediately: Opening hours, pharmacies on duty, weather, and time zone follow the new location.
Opening hours
openingHours carries the weekly hours and the special days. The times are wall-clock times in the time zone of the location.
| Field | Rule |
|---|---|
weekly.mon … weekly.sun |
per day up to six windows { "opens": "08:00", "closes": "13:00" }, ascending and without overlap, empty means closed. If closes is not after opens, the window ends on the next day (22:00 to 02:00), and equal times mean 24 hours (00:00 to 00:00 is open around the clock). A window across midnight is the last one of the day and does not extend into the first window of the next day. A missing day counts as closed |
specialDays[] |
up to 100 entries { startDate, endDate, label, closed, windows }: a day or a period of up to 92 days (endDate inclusive), a label of up to 60 characters, closed without windows or open with at least one. Special days do not overlap |
What applies on a given day follows a fixed order of precedence: a special day, otherwise a statutory holiday of the federal state (closed), otherwise the weekly hours. The platform does not store the holidays. It calculates them per federal state from the date of Easter and the state holidays. Holidays of individual municipalities are entered by the organization as a special day.
curl -sS -X PATCH "$SZENERA_API/v1/locations/loc_01KFB7QPW0LOCATION00000001" \
-H "Authorization: Bearer $SZENERA_API_KEY" \
-H "Content-Type: application/json" \
-H 'If-Match: "3"' \
-d '{
"region": "DE-HH",
"openingHours": {
"weekly": {
"mon": [{ "opens": "08:30", "closes": "13:00" }, { "opens": "14:00", "closes": "18:30" }],
"sat": [{ "opens": "09:00", "closes": "14:00" }]
},
"specialDays": [
{ "startDate": "2026-12-24", "endDate": "2026-12-24", "label": "Heiligabend",
"closed": false, "windows": [{ "opens": "08:30", "closes": "12:00" }] }
]
}
}'
If the weekly hours, special days, federal state, or time zone change, the event fleet.location.opening-hours-changed is raised in addition to fleet.location.updated. All displays of the organization then rebuild their snapshot, because a widget can show the hours of every location, not only its own. A display whose snapshot stays the same receives nothing, and the others show the new times after a few seconds. The same applies when a location is deleted.
Where else the location appears
| Place | How |
|---|---|
| Display list | GET /v1/players?locationId=loc_… filters to one location |
| Playback analytics | location is a grouping axis. Grouping uses the current assignment, and a display without a location falls into a row of its own |
| Command line | the location group, plus player assign-location and player unassign-location, see Commands for your organization |
| Assistant | the tools list_locations, get_location, assign_player_location, create_location, and set_location_opening_hours of the MCP service |
| Apps | the location of the display in the resolver context, with location-hours including opening hours, see Data access, permissions, and terms |
If something goes wrong
| Symptom | Meaning | Solution |
|---|---|---|
409 Location.HasPlayers |
Displays are still attached to the location. The response gives the number. | Move or detach the displays, then delete. |
409 Location.NameAlreadyExists |
The name already exists in this organization. | Choose another one: Two rows named “Filiale Nord” would be a trap in every selection. |
404 Location.NotFound |
The identifier does not belong to any location of this organization. | Take the identifier from GET /v1/locations. |
422 Validation.Failed on timeZone |
The value is not a zone of the IANA database. | Europe/Berlin instead of MEZ or +01:00. |
403 Billing.FeatureNotEntitled when creating |
The Locations capability is switched off for this organization. | Have the platform operator enable it. |
409 Conflict.OptimisticLock when changing |
Someone else made a change between your read and your write. | Read again and send with the new version. |
The three Location.* codes are listed with meaning, trigger, and status under Error codes: devices, playback, notifications, operations.