Zum Inhalt springen
Anleitung

Neuen Displays automatisch ein Programm geben

Jedes neue Display bekommt von selbst das Programm seines Standorts, über einen Webhook und einen API-Aufruf.

3 Min LesezeitStand 30. Okt. 2026Als Markdown
Für wen
Entwicklerinnen und Entwickler, die viele Standorte betreuen oder Displays in Wellen ausrollen
Voraussetzung
ein Paket mit Webhooks (ab Premium), die Rolle Inhaber für den Endpunkt, ein Schlüssel ak_… der Klasse Individuell mit fleet.player.read und schedule.update und ein Server mit öffentlicher https-Adresse
Ort
Ihr eigener Server und Einstellungen › Für Entwickler › Webhooks
Auf dieser Seite

Am Ende bekommt jedes neue Display von selbst das Programm seines Standorts, wenige Sekunden nachdem es in der Flotte erscheint. Zieht ein Display an einen anderen Standort um, übernimmt es dessen Programm. Nach einem Rollout muss niemand mehr daran denken, Inhalte zuzuweisen.

So funktioniert es

Ereignis Wann es kommt Was der Empfänger tut
fleet.player.created Ein Display ist entstanden, als Web-Display oder durch Koppeln eines Geräts Seinen Standort lesen und das Programm dieses Standorts zuweisen.
fleet.player.updated mit locationId in changedFields Ein Display ist an einen anderen Standort umgezogen Das Programm des neuen Standorts zuweisen. Das ersetzt die bisherige Zuweisung.

Der Empfänger führt eine Tabelle, welcher Standort welches Programm bekommt, dazu eine Vorgabe für Displays ohne Standort.

Schritte

  1. Schreiben Sie die Tabelle aus Standorten und Programmen als JSON auf. Die Standort-Kennungen liefert GET /v1/locations, die Programm-Kennungen stehen in der Portal-Adresse:

    JSON
    {  "loc_01KFB7QPW0LOCATION00000001": "sch_01KWVAFRM0ZETPAN0000000001",  "loc_01KFB7QPW0LOCATION00000002": "sch_01KWVAFRM0ZETPAN0000000002",  "default": "sch_01KWVAFRM0ZETPAN0000000003"}
  2. Speichern Sie den Empfänger:

    TypeScript
    // auto-assign.ts: node auto-assign.tsimport { createServer } from 'node:http';import { createHmac, timingSafeEqual } from 'node:crypto';import { readFileSync } from 'node:fs'; const SECRET = process.env.WEBHOOK_SECRET ?? ''; // whsec_…const API = process.env.SZENERA_API;const KEY = process.env.SZENERA_API_KEY; // fleet.player.read und schedule.updateconst PROGRAMS: Record<string, string> = JSON.parse(readFileSync('programs.json', 'utf8'));const seen = new Set<string>(); function isFromSignage(rawBody: string, header: string): boolean {  const expected = createHmac('sha256', SECRET).update(rawBody).digest('base64url');  const a = Buffer.from(expected);  const b = Buffer.from(header);  return a.length === b.length && timingSafeEqual(a, b);} async function call(method: string, path: string, body?: unknown) {  const res = await fetch(`${API}${path}`, {    method,    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },    body: body === undefined ? undefined : JSON.stringify(body),  });  if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${await res.text()}`);  return res.json();} async function assignProgramOfLocation(playerId: string): Promise<void> {  const { player } = await call('GET', `/v1/players/${playerId}`);  const scheduleId = PROGRAMS[player.locationId ?? ''] ?? PROGRAMS.default;  if (!scheduleId) return;  await call('PUT', `/v1/players/${playerId}/program`, {    program: { kind: 'schedule', scheduleId },  });  console.log(`${player.name}: ${scheduleId}`);} createServer((req, res) => {  const chunks: Buffer[] = [];  req.on('data', (chunk) => chunks.push(chunk));  req.on('end', async () => {    const raw = Buffer.concat(chunks).toString('utf8');    if (!isFromSignage(raw, String(req.headers['x-signature'] ?? ''))) {      res.writeHead(401).end();      return;    }    res.writeHead(204).end(); // Binnen 10 Sekunden antworten, danach arbeiten     const deliveryId = String(req.headers['x-delivery-id']);    if (seen.has(deliveryId)) return;    seen.add(deliveryId);     const event = req.headers['x-event-type'];    const payload = JSON.parse(raw);    const moved = event === 'fleet.player.updated' && payload.changedFields?.includes('locationId');    if (event === 'fleet.player.created' || moved) {      await assignProgramOfLocation(payload.playerId).catch((error) => console.error(error));    }  });}).listen(8080);
  3. Legen Sie den Endpunkt an, im Portal unter Einstellungen › Für Entwickler › Webhooks mit Endpunkt anlegen. Tragen Sie Ihre https-Adresse ein, wählen Sie unter Abonnierte Ereignisse fleet.player.created und fleet.player.updated und klicken Sie auf Anlegen. Kopieren Sie das Secret nach WEBHOOK_SECRET und starten Sie den Empfänger.

  4. Probieren Sie es aus mit einem neuen Web-Display, siehe Ein Display anlegen und bespielen, aber ohne Programm zuzuweisen. Wenige Sekunden später nennt GET /v1/players/{id}/program das Programm seines Standorts.

Dasselbe Programm zweimal zuzuweisen schadet nicht. Eine wiederholte Zustellung richtet also auch nach einem Neustart des Empfängers keinen Schaden an.

Ergebnis prüfen

  • Der Empfänger schreibt je neuem Display eine Zeile mit Namen und Programm.
  • Im Portal zeigt das neue Display das Programm seines Standorts.
  • Im Zustell-Log des Endpunkts zeigt jede Zustellung Zugestellt mit HTTP 204.

Wenn etwas nicht klappt

Symptom Bedeutung Lösung
Der Empfänger meldet 403 Dem Schlüssel fehlt fleet.player.read oder schedule.update. Einen Schlüssel der Klasse Individuell mit beiden Rechten erzeugen.
Neue Displays bekommen das Vorgabe-Programm Sie haben beim Anlegen noch keinen Standort. Den Standort im Portal zuordnen. Der Umzug löst fleet.player.updated aus, und der Empfänger weist das richtige Programm zu.
Ein von Hand gewähltes Programm wurde ersetzt Das Display ist an einen anderen Standort umgezogen. fleet.player.updated aus den abonnierten Ereignissen nehmen, wenn ein Umzug das Programm behalten soll.
Das Zustell-Log zeigt HTTP 401 Das Secret passt nicht. Mit Secret rotieren ein neues ausstellen und setzen, siehe Die Signatur einer Zustellung prüfen.