Zum Inhalt springen
Anleitung

Eine Kampagne aus dem eigenen System einplanen

Programmpunkte für eine Kampagne Tag für Tag aus dem Marketingkalender anlegen und über ihre Bezeichnung wieder entfernen.

3 Min LesezeitStand 30. Okt. 2026Als Markdown
Für wen
Entwicklerinnen und Entwickler, die einen Marketingkalender, ein Shopsystem oder ein Kampagnen-Werkzeug anbinden
Voraussetzung
ein Schlüssel ak_… der Klasse Ausspielsteuerung, ein Programm, das Ihre Displays spielen, und eine Playlist oder Szene mit der Kampagne
Ort
Kommandozeile
Auf dieser Seite

Am Ende legt ein Befehl eine Kampagne für einen Zeitraum in ein Programm, zu den Stunden, die Sie wählen, und ein zweiter nimmt sie wieder heraus. Die Daten können direkt aus Ihrem Marketingkalender oder Ihrem Shopsystem kommen.

Warum ein Programmpunkt je Tag

Ein Programmpunkt der Art once läuft von startsAt bis endsAt ohne Unterbrechung. Eine Kampagne vom 2. bis 14. November als ein einziger Punkt liefe deshalb durch jede Nacht. Sie würde auch die nächtliche Sendepause verdrängen, denn ein einmaliger Punkt schlägt jeden wiederkehrenden. Das Skript legt stattdessen je Tag einen einmaligen Punkt an, von der Öffnung bis zum Ladenschluss, und gibt allen dieselbe Bezeichnung, damit es sie später findet und entfernt.

Regel Wirkung auf die Kampagne
Ein einmaliger Punkt schlägt einen wiederkehrenden Die Kampagne gewinnt in ihren Stunden gegen den Wochenplan.
Das kürzere Zeitfenster schlägt das längere Eine kurze Aktion innerhalb der Kampagnenstunden gewinnt trotzdem.
Bei Gleichstand gewinnt der zuletzt angelegte Punkt Zwei Kampagnen mit denselben Stunden: Die neuere läuft.
Außerhalb aller Punkte läuft das Grundprogramm Nach Ladenschluss kehren die Displays zum Alltag zurück.

Schritte

  1. Suchen Sie die Kennungen. Öffnen Sie Programm und Playlist im Portal: Die Adressen enden mit ihren Kennungen sch_… und pll_….

  2. Speichern Sie das Skript:

    TypeScript
    // campaign.ts// node campaign.ts add <sch_…> <bezeichnung> <pll_…> <von> <bis> <öffnet> <schließt>// node campaign.ts remove <sch_…> <bezeichnung>const API = process.env.SZENERA_API;const KEY = process.env.SZENERA_API_KEY; // Klasse Ausspielsteuerungconst TIME_ZONE = 'Europe/Berlin'; async function call(method: string, path: string, body?: unknown, idempotencyKey?: string) {  const headers: Record<string, string> = {    Authorization: `Bearer ${KEY}`,    'Content-Type': 'application/json',  };  if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;  const res = await fetch(`${API}${path}`, {    method,    headers,    body: body === undefined ? undefined : JSON.stringify(body),  });  if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${await res.text()}`);  return res.json();} // Eine Ortszeit an diesem Tag mit dem Versatz der Zeitzone, +01:00 im Winter und +02:00 im Sommerfunction at(day: string, time: string): string {  const zone = new Intl.DateTimeFormat('en', { timeZone: TIME_ZONE, timeZoneName: 'longOffset' })    .formatToParts(new Date(`${day}T12:00:00Z`))    .find((part) => part.type === 'timeZoneName')?.value ?? 'GMT';  return `${day}T${time}:00${zone === 'GMT' ? '+00:00' : zone.slice(3)}`;} function nextDay(day: string): string {  const date = new Date(`${day}T00:00:00Z`);  date.setUTCDate(date.getUTCDate() + 1);  return date.toISOString().slice(0, 10);} const [action, scheduleId, label, playlistId, from, to, opens, closes] = process.argv.slice(2); if (action === 'add') {  for (let day = from; day <= to; day = nextDay(day)) {    await call(      'POST',      `/v1/schedules/${scheduleId}/items`,      {        label,        content: { kind: 'playlist', playlistId },        recurrence: { kind: 'once', startsAt: at(day, opens), endsAt: at(day, closes) },      },      `campaign-${encodeURIComponent(label)}-${day}`,    );    console.log(`added ${day} ${opens} to ${closes}`);  }} if (action === 'remove') {  const { schedule } = await call('GET', `/v1/schedules/${scheduleId}`);  for (const item of schedule.items.filter((entry) => entry.label === label)) {    await call('DELETE', `/v1/schedules/${scheduleId}/items/${item.id}`);    console.log(`removed ${item.recurrence.startsAt}`);  }}
  3. Legen Sie die Kampagne an:

    Terminal
    node campaign.ts add sch_01KWVAFRM0ZETPAN0000000001 "Herbstaktion" \  pll_01KWV91ZS0PRGRAMM000000001 2026-11-02 2026-11-14 08:00 20:00
    added 2026-11-02 08:00 to 20:00added 2026-11-03 08:00 to 20:00…

    Der Idempotenz-Schlüssel entsteht aus Bezeichnung und Tag. Bricht das Skript mittendrin ab, starten Sie es binnen 24 Stunden erneut: Tage, die schon da sind, entstehen nicht doppelt.

  4. Entfernen Sie sie, wenn die Kampagne abgesagt oder vorbei ist:

    Terminal
    node campaign.ts remove sch_01KWVAFRM0ZETPAN0000000001 "Herbstaktion"

Vergangene Punkte laufen nicht mehr, bleiben aber im Programm, bis sie jemand entfernt. Ein Programm hält höchstens 200 Punkte, entfernen Sie eine beendete Kampagne also über ihre Bezeichnung.

Ergebnis prüfen

  • Der Wochenplan des Programms im Portal zeigt je Tag einen Block mit der Bezeichnung der Kampagne, siehe Den Wochenplan lesen.
  • In den Stunden der Kampagne spielen die Displays mit diesem Programm die Playlist.
  • Nach remove steht in GET /v1/schedules/{id} kein Punkt mit dieser Bezeichnung mehr.

Wenn etwas nicht klappt

Symptom Bedeutung Lösung
422 Schedule.InvalidRecurrence Die Zeiten passen nicht, etwa weil das Ende vor dem Beginn liegt. Öffnung und Ladenschluss als 08:00 und 20:00 angeben.
422 Schedule.ItemLimitReached Das Programm hält schon 200 Punkte. Beendete Kampagnen über ihre Bezeichnung entfernen.
422 Schedule.ContentNotFound Die Playlist-Kennung gibt es nicht. Die Kennung in der Portal-Adresse prüfen.
422 Validation.IdempotencyKeyReused Dieselbe Bezeichnung und derselbe Tag kamen binnen 24 Stunden mit anderen Stunden. Die Kampagne entfernen und unter neuer Bezeichnung wieder anlegen.
Die Kampagne erscheint auf einem Display nicht Dort läuft ein anderes Programm, eine Übersteuerung ist aktiv, oder ein kürzerer Punkt gewinnt. Siehe Wie entscheidet ein Display, was es zeigt?.
3 Min LesezeitStand 30. Okt. 2026Als Markdown

War das hilfreich?