Webhooks

Übersicht

Mit Webhooks ruft Veeting Ihr System auf, sobald in einem Meeting etwas geschieht. So müssen Sie die API nicht laufend abfragen. Tritt ein Event ein, sendet die Plattform einen HTTP-Aufruf an eine URL, die Sie konfiguriert haben. Im JSON-Body steht das betroffene Objekt.

Sie konfigurieren Webhooks an zwei Stellen. Beide lösen beim selben Event aus:

  • Auf Ebene der White-Label-Instanz, im Abschnitt «Web Hooks» der Systemkonfiguration. Löst für jedes Konto der Instanz aus.
  • Auf Kontoebene, pro Konto. Löst nur für dieses Konto aus.

Konfigurieren Sie beide, ruft die Plattform Ihren Endpunkt beim selben Event zweimal auf, einmal pro Ebene.

Verwendung mit einem KI-Assistenten

Wenn Sie mit einem KI-Coding-Assistenten arbeiten, können Sie den folgenden Text in Ihren Assistenten kopieren und mit einem Satz ergänzen, der beschreibt, was Sie programmieren möchten.

Der Prompt verweist auf unsere Entwicklerdokumentation, die wir für Coding-Assistenten in einer separaten, token-optimierten KI-Version ausliefern.

Lies zuerst diese Seite, bevor Du Code schreibst:
https://www.veeting.com/de/developer-documentation/web-hooks

Sie dokumentiert die Webhooks von Veeting Rooms. Halte Dich an
diese fünf Regeln:

1. Veeting versucht die Zustellung genau einmal. Es gibt keine
   Wiederholung. Bestätige schnell, lege die Arbeit in eine Queue
   und gleiche bei Bedarf über die REST API ab.
2. Die Payload ist NICHT in responseCode und data verpackt, ausser
   bei onMeetingSummaryCreated.
3. Manche Events senden ein Array statt eines Objekts. Alle fünf
   Reminder und onMeetingDeleted tun das. Prüfe das, bevor Du
   Felder liest.
4. Die Authentifizierung ist ein einziger optionaler
   X-API-KEY-Header. Möchte ich den Endpunkt geschützt haben, dann
   prüfe diesen Header und weise alles andere ab.
5. Frage mich, ob der Webhook auf Instanzebene oder auf Kontoebene
   konfiguriert ist. Beide können aktiv sein, was zwei Aufrufe pro
   Event bedeutet.

Was ich bauen möchte:

Regeln für jeden Webhook

  1. Wir versuchen die Zustellung genau einmal. Es gibt keine Wiederholung, kein Backoff und keine Dead-Letter-Queue. Ist Ihr Endpunkt nicht erreichbar oder antwortet er zu spät oder mit einem Fehlerstatus, loggen wir das Event auf unserer Seite. Auf Ihrer Seite ist es verloren. Richten Sie sich darauf ein: rasch bestätigen, die Arbeit intern in eine Queue legen und bei Bedarf das Meeting mit GET /meeting/{id} zurücklesen, statt darauf zu vertrauen, dass jedes Event angekommen ist.

  2. Antworten Sie schnell. Für die Zustellung ist kein Timeout konfiguriert. Ein langsamer Endpunkt hält deshalb eine Verbindung offen, statt zügig zu scheitern. Geben Sie ein 2xx zurück, sobald Sie die Payload angenommen haben, und erledigen Sie die Arbeit danach.

  3. Der Body ist das Objekt selbst, kein Wrapper. Anders als bei der REST API steckt eine Webhook-Payload nicht in responseCode und data. Zwei Events weichen ab: onMeetingSummaryCreated kommt in responseCode und data verpackt an, und onMeetingRecordingCreated kommt als Objekt an, in dem das Meeting steckt, statt als Meeting selbst. Beide sind unten beschrieben.

  4. Prüfen Sie die Form der Payload, bevor Sie sie lesen. Manche Events senden ein einzelnes Objekt, andere ein Array. Welche das sind, steht unten.

Konfiguration

Sie konfigurieren jeden Webhook einzeln, mit vier Einstellungen:

EinstellungBedeutung
enabledOb dieser Webhook überhaupt auslöst
urlDer Endpunkt, den wir aufrufen
methodPOST, PUT oder DELETE. Leere oder unbekannte Werte fallen auf POST zurück.
apiKeyOptional. Siehe unten.

Ihren Endpunkt schützen

Setzen Sie apiKey, sendet die Plattform ihn bei jedem Aufruf als X-API-KEY-Header. Ihr Endpunkt weist damit alle Aufrufe ohne diesen Header ab. Lassen Sie das Feld leer, sendet die Plattform gar keinen solchen Header.

Mehr Authentifizierung hat ein Webhook-Aufruf nicht. Einen Endpunkt ohne konfigurierten API-Key ruft jeder auf, der seine URL kennt.

content-type: application/json sendet die Plattform immer mit.

Die Events

Es gibt 14 Events.

EventLöst aus, wennPayload
onMeetingScheduledEin Meeting erstellt wirdMeeting
onMeetingUpdatedEin Meeting geändert wirdMeeting
onMeetingClosedEin Meeting geschlossen wird, automatisch oder manuellMeeting
onMeetingDeletedMeetings gelöscht werdenArray von Meeting
onMeetingCancelledEin einzelner Termin einer Serie abgesagt wird{ meeting, day }
onMeetingJoinedJemand einem Meeting beitrittMeetingParticipantsStatus
onMeetingLeftJemand ein Meeting verlässtMeetingParticipantsStatus
onMeetingSummaryCreatedEine Summary erstellt wird, üblicherweise rund fünf Minuten nach dem SchliessenMeetingSummary, verpackt
onMeetingRecordingCreatedEin aufgezeichnetes Meeting zusammengefügt wurdeAufzeichnung
onMeetingsReminder15MinutesBefore15 Minuten vor Meeting-BeginnArray von Meeting
onMeetingsReminder30MinutesBefore30 Minuten vor Meeting-BeginnArray von Meeting
onMeetingsReminder60MinutesBefore60 Minuten vor Meeting-BeginnArray von Meeting
onMeetingsReminder24HoursBefore24 Stunden vor Meeting-BeginnArray von Meeting
onMeetingsReminder48HoursBefore48 Stunden vor Meeting-BeginnArray von Meeting

Zwei Dinge zu den Remindern übersieht man leicht:

  • Sie stellen ein Array zu, denn ein Reminder-Lauf umfasst alle Meetings, die zu diesem Zeitpunkt anstehen. Auch ein einzelnes Meeting kommt als Array mit einem Eintrag an.
  • Der Umfang hängt von der Ebene ab. Ein Reminder auf Ebene der White-Label-Instanz erhält jedes anstehende Meeting der Instanz, ein Reminder auf Kontoebene nur die Meetings dieses Kontos. Derselbe Lauf sendet also unterschiedliche Arrays an unterschiedliche Endpunkte.

Payloads

Meeting

Diese Payload senden onMeetingScheduled, onMeetingUpdated und onMeetingClosed. Es ist dasselbe Objekt, das die REST API bei POST /meeting zurückgibt, hier gekürzt:

{
  "id": "5e945c36b863b82cefdddf54",
  "meetingId": "9974-7653-8886-0485",
  "topic": "My Meeting Topic",
  "startTime": "2026-09-07T09:00:00.000Z",
  "endTime": "2026-09-07T10:00:00.000Z",
  "duration": 60,
  "type": "standard",
  "roomId": "5e9459c5b863b82cefdddf50",
  "isRecurring": false,
  "isRecorded": false,
  "isDialin": false,
  "invitedParticipants": [],
  "agenda": "",
  "whitelabelId": "5c737902b377b0f7fbf81fce",
  "accountId": "5e9459c5b863b82cefdddf4f",
  "addedByUserId": "5e9459c5b863b82cefdddf4e",
  "addedByUserEmail": "test-user@example.com",
  "addedByUserName": "Test User",
  "timezone": "Europe/Zurich",
  "isActive": false,
  "isOpen": false,
  "isClosed": true
}

Die beiden IDs verhalten sich genau wie in der REST API: Verwenden Sie id, wenn Sie zurück in die API rufen, und meetingId, wenn Sie einen Link bauen oder das Meeting jemandem anzeigen.

Array von Meeting

Diese Payload senden onMeetingDeleted und alle fünf Reminder. Es ist dasselbe Objekt wie oben, in einem Array:

[
  { "id": "5e945c36b863b82cefdddf54", "meetingId": "9974-7653-8886-0485", "topic": "My Meeting Topic" }
]

Bei onMeetingDeleted kann jedes Meeting zusätzlich ein Feld cancellationMessage mitführen. Darin steht der Text, den der Organisator beim Löschen angegeben hat.

Abgesagter Termin

Diese Payload sendet onMeetingCancelled, wenn jemand einen einzelnen Termin einer Serie absagt und nicht die ganze Serie. Das Meeting steckt verschachtelt im Body, und day bezeichnet den Termin:

{
  "meeting": { "id": "5e945c36b863b82cefdddf54", "meetingId": "9974-7653-8886-0485", "isRecurring": true },
  "day": "2026-09-14"
}

MeetingParticipantsStatus

Diese Payload senden onMeetingJoined und onMeetingLeft:

{
  "meetingId": "5df78199c015b37195230596",
  "meetingToken": "0000-0000-0000-0000",
  "isNamedRoom": false,
  "participant": {
    "name": "Joe Doe",
    "email": "joe@example.com",
    "meetingParticipantId": "4edaf0d2-cb6c-42f1-a266-4ae7d971f2e6",
    "isModerator": false
  },
  "totalNumberOfGuests": 3,
  "totalNumberOfModerators": 1,
  "whitelabelId": "5c737902b377b0f7fbf81fce",
  "accountId": "5e9459c5b863b82cefdddf4f"
}

Hinweis: Hier enthält meetingId die 24-stellige id des Meetings, und meetingToken die Nummer mit den Bindestrichen. Das ist genau umgekehrt zur Benennung überall sonst. Lesen Sie hier also besonders genau.

MeetingSummary

Diese Payload sendet onMeetingSummaryCreated. Es ist die einzige, die in responseCode und data verpackt ankommt:

{
  "responseCode": 0,
  "data": {
    "id": "5f7d49eb62e8f9a43b23f986",
    "meetingId": "5f7d49e662e8f9a43b23f983",
    "meetingType": "boardroom",
    "agenda": "",
    "minutes": "",
    "participants": [
      {
        "name": "Participant 1",
        "durations": [
          { "action": "joined", "timestamp": 1602046445811 },
          { "action": "left", "timestamp": 1602046670808 }
        ],
        "info": {
          "browserName": "Chrome",
          "browserVersion": "82.0.4062.0",
          "osName": "macOS",
          "osVersion": "10.15.6",
          "platformType": "desktop",
          "platformVendor": "Apple"
        }
      }
    ],
    "documents": [],
    "pdf": null,
    "accountId": "5c73790ab377b0f7fbf81fde",
    "isNamedRoom": false,
    "isRecordingPrepared": false,
    "sfuHostname": "ch-01-sfu-02.wlvmr.net",
    "meetingQuestions": [],
    "meetingConversationDuration": 25,
    "meetingConversationStartToEndDuration": 25,
    "meetingParticipantsStartToEndDuration": 35,
    "meetingStartToEndDuration": 60
  }
}

Die vier Dauer-Felder messen Unterschiedliches. Alle Werte sind Sekunden:

FeldWas es misst
meetingConversationDurationWie lange mindestens zwei Personen gleichzeitig im Raum waren
meetingConversationStartToEndDurationVom ersten Moment, in dem zwei Personen zusammen im Raum waren, bis zum letzten
meetingParticipantsStartToEndDurationVom Beitritt der ersten Person bis zum Verlassen der letzten
meetingStartToEndDurationDie geplante Dauer, einschliesslich Verlängerung

Aufzeichnung

Diese Payload sendet onMeetingRecordingCreated. Anders als die übrigen ist sie ein Wrapper: Meeting und Summary stecken darin, statt selbst der Body zu sein.

{
  "meeting": { "id": "5e945c36b863b82cefdddf54", "meetingId": "9974-7653-8886-0485", "topic": "My Meeting Topic" },
  "summary": { "id": "5f48a701ee0c388a879bffa7" },
  "mergedRecordingUrl": "https://<recording-host>/prepared/<meeting>/<token>.webm",
  "recordingUrls": [
    "video-file-1.webm",
    "video-file-2.webm",
    "video-file-3.webm"
  ],
  "emailNotificationRecipients": ["organizer@example.com"]
}
EigenschaftBedeutung
meetingDas vollständige Meeting-Objekt, wie oben beschrieben
summaryDie Summary, zu der diese Aufzeichnung gehört
mergedRecordingUrlDie einzelne, zusammengefügte Aufzeichnung
recordingUrlsDie einzelnen Teile, aus denen sie entstand, so wie der Aufzeichnungs-Host sie meldet
emailNotificationRecipientsWen die Plattform gleich über diese Aufzeichnung informiert

Hinweis: Lesen Sie die IDs des Meetings aus meeting.id und meeting.meetingId. Auf oberster Ebene dieser Payload gibt es kein meetingId.

Häufige Fehler

  • Darauf bauen, dass wir eine fehlgeschlagene Zustellung wiederholen. Wir tun es nicht.
  • Die Payload eines Reminders als einzelnes Meeting behandeln. Alle fünf Reminder senden ein Array.
  • onMeetingSummaryCreated als unverpacktes Objekt lesen. Es ist die einzige verpackte Payload.
  • meetingId in der Join- und Leave-Payload als Nummer mit Bindestrichen lesen. Dort ist es die 24-stellige id, und meetingToken ist die mit den Bindestrichen.
  • Denselben Endpunkt auf Instanz- und auf Kontoebene konfigurieren und den doppelten Aufruf dann für einen Fehler halten.
  • apiKey bei einem Endpunkt leer lassen, der Daten verändert.
  • Erst die langsame Arbeit erledigen und dann antworten. Niemand bricht den Aufruf für Sie ab.

Sind Sie nicht sicher, wie Sie Ihr Projekt am Besten umsetzen sollen?

Sprechen Sie mit unserem Team über Ihre Pläne.