Webhooks & API-Schlüssel
Verbinden Sie StageTick mit Ihren eigenen Systemen: Webhooks schicken Ereignisse aus Ihren Räumen an Ihren Server, und mit API-Keys kann Ihr Server einen Raum über die REST-API lesen und steuern. Webhooks verwalten Sie in den Organisation Settings, API-Keys im Menü des jeweiligen Raums.
Webhooks
Ein Webhook schickt eine HTTPS-POST-Anfrage an Ihren Server, sobald eines der folgenden Ereignisse eintritt. Ein Webhook gehört zur Organisation und feuert für jeden Raum Ihrer Organisation; einen Filter pro Raum gibt es nicht. Unterscheiden Sie die Räume anhand der roomId im Payload.
Unterstützte Events
| Event | Wann es gesendet wird |
|---|---|
room.on_air | Wenn jemand den Raum auf On Air schaltet — die Schaltfläche, mit der Publikumsbildschirme den Standby verlassen. Unabhängig von Play und Pause. |
room.off_air | Wenn der Raum wieder Off Air geschaltet wird, sodass Publikumsbildschirme erneut Standby zeigen. Unabhängig von Play und Pause. |
timer.started | Immer wenn ein Timer zu laufen beginnt, auch beim Fortsetzen nach einer Pause, und für den neuen Timer jedes Mal, wenn der Raum bei laufender Uhr zu einem anderen Timer wechselt (zum Beispiel beim automatischen Weiterschalten). |
timer.finished | Einmal, wenn der laufende Timer 0:00 (seine Dauer) erreicht, auch wenn er danach in die Überzeit weiterläuft. Kein Event, wenn vor 0:00 gewechselt, pausiert oder gestoppt wird, und nie für Uhrzeit-Timer, Countdown-bis-Uhrzeit-Timer (T-minus) oder Timer ohne Dauer. |
Die Transport-Befehle der REST-API verhalten sich wie die App: next, prev und jump behalten den Wiedergabezustand bei und senden bei laufender Uhr timer.started für den neuen Timer. Mit dem Body { "keepRunning": false } stoppt die Uhr beim neuen Timer, und es wird kein Event gesendet.
Payload
Die Anfragen haben Content-Type: application/json und einen Body wie diesen:
{
"event": "timer.started",
"roomId": "AbC123roomId",
"timestamp": "2026-10-12T09:30:00.000Z",
"data": {
"timerId": "t9XyZ",
"title": "Keynote",
"speaker": "Jane Smith"
}
}
Bei room.on_air und room.off_air ist data ein leeres Objekt. Den timestamp setzt StageTick, wenn es die Änderung verarbeitet.
Signaturen prüfen
Jede Anfrage trägt den Header X-StageTick-Signature: sha256=…: ein HMAC-SHA256 über den unveränderten Request-Body, berechnet mit dem Signing Secret des Webhooks und hexadezimal geschrieben. Verwenden Sie das Secret genau so, wie es angezeigt wurde (als Text). Berechnen Sie denselben Wert über den unveränderten Body, bevor Sie das JSON parsen, und vergleichen Sie zeitkonstant — zum Beispiel in Node.js:
import crypto from 'node:crypto';
// rawBody: der Request-Body genau wie empfangen (String oder Buffer), vor dem JSON-Parsen
function isFromStageTick(rawBody, signatureHeader, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader ?? '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
} Anforderungen an den Endpunkt und Wiederholungen
- Die URL muss mit
https://beginnen und aus dem Internet erreichbar sein. Adressen in privaten oder lokalen Netzen (etwa localhost, 10.x.x.x oder 192.168.x.x) werden abgelehnt, und Weiterleitungen werden nicht verfolgt. - Antworten Sie innerhalb von 10 Sekunden mit einem 2xx-Status.
- Schlägt die Anfrage fehl, läuft sie in ein Timeout, wird sie weitergeleitet oder antwortet Ihr Server mit einem 5xx-Status, versucht StageTick es erneut: bis zu drei Versuche im Abstand weniger Sekunden, und diese Runde wird in den folgenden Minuten bis zu zweimal wiederholt. Eine 4xx-Antwort gilt als zugestellt und wird nicht wiederholt. Lässt sich der Host-Name Ihres Servers beim Senden nicht auflösen, wird das Event ohne Wiederholung verworfen.
- Wegen der Wiederholungen kann dasselbe Event mehrfach ankommen, und die Reihenfolge ist nicht garantiert. Erkennen Sie Duplikate an
event,roomId,data.timerId(bei Timer-Events) undtimestamp. Das gelingt nicht immer: In seltenen Fällen verarbeitet StageTick dieselbe Änderung zweimal und sendet sie dann mit neuem timestamp. - Zeigt die App „Failed to create webhook. Please try again.“, prüfen Sie zuerst die URL: Eine nicht erlaubte URL führt zur selben Meldung.
Webhooks verwalten
Nur Inhaber und Admins der Organisation können Webhooks sehen, anlegen und löschen; Mitglieder sehen stattdessen einen kurzen Hinweis. Im Free-Plan führt der Bereich den Inhaber zum Abschnitt Billing & Plan auf derselben Seite.
- Als Inhaber oder Admin öffnen Sie Organisation Settings — über das Kontomenü im Dashboard oder über das Raummenü (Ihr Avatar) in einem Raum.
- Scrollen Sie zum Abschnitt API und dort zu Webhooks.
- Tragen Sie die Endpoint URL ein und haken Sie die Events an: Room On Air, Room Off Air, Timer Started, Timer Finished.
- Klicken Sie auf Add Webhook (aktiv, sobald eine URL und mindestens ein Event gesetzt sind). Das Signing Secret wird einmal angezeigt — kopieren Sie es sofort.
- Zum Löschen klicken Sie auf das Papierkorb-Symbol des Webhooks und dann auf Confirm?.
Webhook-Limits
- Pro: bis zu 5 Webhooks pro Organisation
- Enterprise: bis zu 20 Webhooks pro Organisation
API-Keys
Ein API-Key gibt Ihrem Server über die REST-API Zugriff auf einen Raum. Jeder Key gehört zu genau einem Raum und hat einen Scope.
Scopes
- read — nur lesende Anfragen (Raum, Timer, Transport-Status, Nachrichten, Fragen und Event-Stream). Jede Änderung beantwortet die API mit
403 READ_ONLY_KEY. Neue Keys starten mit diesem Scope. - readwrite — Raumdaten lesen und ändern sowie den Transport steuern.
API-Keys verwalten
Inhaber und Admins der Organisation können für jeden Raum API-Keys anlegen, ansehen und widerrufen. Mitglieder können das nur für Räume, die sie selbst angelegt haben, und nur, solange sie zur Organisation gehören.
- Öffnen Sie den Raum im Controller und dort das Raummenü (Ihr Avatar oben rechts).
- Wählen Sie API Keys.
- Geben Sie einen Key name ein (Pflichtfeld), wählen Sie den Scope (read oder readwrite) und klicken Sie auf Create.
- Der Key beginnt mit
stk_und wird einmal angezeigt. Kopieren Sie ihn und bewahren Sie ihn sicher auf. - Zum Widerrufen klicken Sie neben dem Key auf Revoke und innerhalb von drei Sekunden auf Confirm?. Widerrufene Keys funktionieren sofort nicht mehr.
API-Key-Limits
- Pro: bis zu 5 API-Keys pro Raum
- Enterprise: bis zu 20 API-Keys pro Raum
- Pro Organisation: bis zu 10 API-Keys mit Pro und bis zu 50 mit Enterprise
REST-API
Die REST-API ist für Integrationen von Server zu Server gedacht. Rufen Sie sie von Ihrem Server auf: Browser blockieren Anfragen von fremden Websites (CORS), und ein API-Key im Code einer Webseite wäre für alle sichtbar.
Basis-URL und Authentifizierung
Alle Pfade unten beginnen mit https://europe-west1-stagetick-e0911.cloudfunctions.net/api/v1. Die App zeigt diese Basis-URL unter Raummenü → API Keys, mit Kopier-Button und dem Link API reference. Senden Sie den Key im Header Authorization: Bearer stk_…:
curl -H "Authorization: Bearer stk_…" \
https://europe-west1-stagetick-e0911.cloudfunctions.net/api/v1/rooms/ROOM_ID/transport
Die Raum-ID ist der Teil nach /r/ in einem Raum-Link. Anfragen und Antworten sind JSON. Listen liefern bis zu 50 Einträge (?limit= bis 100); den nextCursor aus der Antwort übergeben Sie als ?startAfter= für die nächste Seite.
Die vollständige Referenz (Swagger) steht unter https://europe-west1-stagetick-e0911.cloudfunctions.net/api/v1/docs/, die OpenAPI-Spezifikation unter https://europe-west1-stagetick-e0911.cloudfunctions.net/api/v1/docs/openapi.yaml. Beide sind öffentlich und brauchen keinen Key.
Endpunkte
| Anfrage | Was sie tut |
|---|---|
GET /rooms/:roomId | Raumdaten und aktueller Transport-Status |
GET /rooms/:roomId/timersGET /rooms/:roomId/timers/:timerId | Timer auflisten oder einen lesen, jeweils mit remainingSeconds |
POST /rooms/:roomId/timers | Timer anlegen; duration in Sekunden ist Pflicht |
PATCH /rooms/:roomId/timers/:timerIdDELETE /rooms/:roomId/timers/:timerId | Timer ändern oder löschen. Felder: title, speaker, duration, wrapUpTime, dangerTime, trigger, appearance, labelColor, notes, order, targetTime (Sekunden nach Mitternacht), flashOnPhase, soundOnPhase |
GET /rooms/:roomId/transport | Transport-Status: aktiver Timer, läuft/pausiert/gestoppt, verstrichene Zeit, On Air, Blackout |
POST /rooms/:roomId/transport/play…/pause, …/stop | Aktiven Timer starten oder fortsetzen, pausieren, stoppen. Ist kein Timer aktiv, startet play den ersten Timer. |
POST /rooms/:roomId/transport/next…/prev, …/jump | Nächsten oder vorherigen Timer wählen oder den Timer, der im Body als timerId steht (jump). Der Wiedergabezustand bleibt: Eine laufende Uhr läuft auf dem neuen Timer weiter. Mit { "keepRunning": false } stoppt die Uhr beim Wechsel. |
POST /rooms/:roomId/signals/flash…/blackout, …/on-air | Bildschirme aufblinken lassen; Blackout oder On Air schalten. Ohne Body schalten diese um; mit enabled als true oder false setzen Sie den Zustand. |
GET / POST /rooms/:roomId/messagesPATCH / DELETE …/messages/:messageId | Cue-Nachrichten auflisten, anlegen, ändern oder löschen. Felder: text (Pflicht), color (green, yellow, red, blue, white), bold, uppercase |
POST …/messages/:messageId/show…/hide | Nachricht einblenden (jede andere sichtbare Nachricht wird ausgeblendet) oder ausblenden |
GET /rooms/:roomId/questionsPOST …/questions/:questionId/show, …/hideDELETE …/questions/:questionId | Publikumsfragen auflisten (neueste zuerst), eine live schalten, wieder herausnehmen oder löschen. Fragen einreichen lässt sich über die API nicht. |
GET /rooms/:roomId/events | Live-Event-Stream (siehe unten) |
Keys gelten für genau einen Raum. GET /rooms liefert den Raum des Keys.
Live-Event-Stream (SSE)
GET /rooms/:roomId/events hält die Verbindung offen und sendet Server-Sent Events. Zuerst kommen connected und der aktuelle Stand (transport, ein timer:create pro Timer, message:update und question:update pro Eintrag), danach jede Änderung: transport, timer:create, timer:update, timer:delete, message:update, message:delete, question:update, question:delete, dazu alle 30 Sekunden ein heartbeat.
StageTick schließt jeden Stream nach 5 Minuten. Verbinden Sie sich neu und senden Sie die ID des zuletzt empfangenen Events im Header Last-Event-ID: Sie erhalten reconnected und erneut den aktuellen Stand; Änderungen dazwischen werden nicht einzeln nachgeliefert. Verwenden Sie auf Ihrem Server einen SSE-Client, der den Header Authorization senden kann (das EventSource des Browsers kann das nicht).
Limits und Fehler
- Bis zu 120 Anfragen pro Minute und Organisation. Darüber antwortet die API mit
429 RATE_LIMITED und einem Retry-After-Header. - Offene Event-Streams pro Organisation: 25 mit Pro, 100 mit Enterprise. Darüber:
429 TOO_MANY_CONNECTIONS mit Retry-After: 60. Öffnet eine Organisation viele Streams im selben Moment, kann die API mit 429 CONNECTION_SLOTS_BUSY und Retry-After: 5 antworten. 401 UNAUTHORIZED — der Key fehlt, ist falsch formatiert oder widerrufen. 403 PLAN_REQUIRED — die Organisation ist im Free-Plan, oder eine Zahlung ist überfällig. 403 READ_ONLY_KEY — ein read-Key wollte etwas ändern. 403 FORBIDDEN — der Key gehört zu einem anderen Raum. 400 BAD_REQUEST und 404 (zum Beispiel TIMER_NOT_FOUND) — ungültige Eingabe oder unbekannte ID.
Fehler kommen als JSON mit error.code und error.message zurück, auch für einen Pfad, den es nicht gibt (404 NOT_FOUND). Die bisherige Basis-URL mit /api/api/v1 funktioniert weiter.