Veeting Rooms REST APIs

Übersicht

Mit der Veeting REST API erstellen Sie aus Ihrer eigenen Software heraus Konten, planen Meetings im Namen Ihrer User und verwalten diese Meetings über den ganzen Lebenszyklus. Es ist eine ganz normale JSON-API über HTTPS, Sie können also jeden HTTP-Client einsetzen. Die Beispiele unten verwenden curl.

Basis-URL: https://<DOMAIN-NAME>/api/v6

<DOMAIN-NAME> ist Ihre eigene Meeting-Domain. Einen gemeinsamen oder globalen Host gibt es nicht: Nehmen Sie die Domain, unter der Ihre Instanz läuft.

Authentifizierung: ein X-API-KEY-Header bei jedem Aufruf.

Content-Type: application/json bei jedem POST und PUT.

Verwendung mit einem KI-Assistenten

Viele Integrationen entstehen heute mit einem KI-Assistenten. Arbeiten Sie ebenso, dann kopieren Sie den folgenden Text in Ihren Assistenten und schreiben Sie einen Satz dazu, was Sie bauen möchten.

Der Text schickt den Assistenten zuerst auf diese Seite und warnt ihn vor den wenigen Dingen, die er sonst gerne falsch macht.

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

Sie dokumentiert die Veeting Rooms REST API. Halte Dich an diese
fünf Regeln:

1. Frage mich nach meiner Veeting-Domain. Rate nicht.
2. Der API-Key ist ein serverseitiges Geheimnis. Frage ich nach
   einer Browser-Integration, dann baue stattdessen ein Backend
   dafür und sage mir warum.
3. Ein Aufruf war nur dann erfolgreich, wenn der HTTP-Status 200
   ist UND der Body responseCode 0 enthält. Prüfe beides.
4. Ein Meeting hat zwei IDs. Verwende die 24-stellige «id» in
   API-Aufrufen und die «meetingId» mit den Bindestrichen im
   Meeting-Link. Vertausche sie nie.
5. Frage mich, ob mein API-Key auf Kontoebene oder auf
   Instanzebene liegt. Das ändert, welche Endpunkte und Header
   gelten.

Was ich bauen möchte:

Regeln für jeden Aufruf

Diese vier Regeln gelten für jeden Endpunkt auf dieser Seite. Regel 2 überrascht die meisten: Lesen Sie sie auch dann, wenn Sie den Rest überspringen.

  1. Der API-Key ist ein serverseitiges Geheimnis. Wer ihn hat, steuert Ihre ganze Meeting-Plattform. Legen Sie ihn deshalb nie in Browser-JavaScript, in ein Mobile-App-Bundle oder in ein öffentliches Repository. Wollen Sie Meetings aus dem Browser heraus starten, dann rufen Sie die API von Ihrem eigenen Backend aus auf und geben nur das Ergebnis an die Seite weiter.

  2. Ein erfolgreicher Aufruf liefert HTTP 200 und responseCode: 0. Die meisten Endpunkte antworten auch dann mit HTTP 200, wenn der Aufruf fehlgeschlagen ist. Das tatsächliche Ergebnis steht in einem negativen responseCode. Wer nur den HTTP-Status prüft, hält Fehler für Erfolge. Prüfen Sie immer beides.

  3. Die Payload liegt immer unter data. Lesen Sie Ihre Werte aus data, nie von der obersten Ebene. Eine Fehlerantwort enthält gar kein data-Feld.

  4. Alle Zeitstempel sind ISO 8601 in UTC, mit einem Z am Ende. Das Feld timezone eines Meetings steuert nur, wie Einladungen die Zeiten anzeigen. Es verschiebt weder startTime noch endTime.

Den richtigen API-Key wählen

Es gibt zwei Arten. Welche Sie haben, entscheidet darüber, was Sie tun können.

KontoebeneInstanzebene
Erstellt unterKontoeinstellungenWhite-Label-Einstellungen
Kann Konten erstellenneinja
Kann Meetings verwaltenja, innerhalb des eigenen Kontosja, für jeden User der Instanz
Berechtigungenimmer nur Meetingswählbar: Konten, User, Meetings, Reporting, Branding
Wer ihn haben darfder Kontoinhaberausschliesslich der Betreiber der White-Label-Instanz

Hinweis: Geben Sie Keys auf Instanzebene nie an Kunden weiter. Wer einen solchen Key hat, erstellt Konten und handelt für jeden User der Instanz.

Ein Key auf Kontoebene erreicht immer nur die Meeting-Endpunkte, ganz gleich, welche Berechtigungen Sie ihm sonst zu geben versuchen. Die Plattform erzwingt diese Grenze selbst, sie ist keine blosse Konvention. Einen Key auf Kontoebene können Sie deshalb gefahrlos einem Integrator geben, der nur Meetings planen muss.

Ausserdem müssen Sie auf der White-Label-Instanz die Funktion accountLevelApiKeys einschalten. Ist sie aus, weist die Plattform jeden Aufruf mit einem Key auf Kontoebene ab.

Im Namen eines Users handeln

Standardmässig handelt ein Key als synthetischer API-User, der zu keiner Person gehört. Wollen Sie stattdessen als echter Meeting-Organisator handeln, senden Sie einen dieser Header:

X-USER-ID: <USER-ID>
X-USER-EMAIL: <USER-EMAIL>

Senden Sie beide, gewinnt X-USER-ID und die Plattform ignoriert X-USER-EMAIL. Senden Sie deshalb nur einen davon.

Das funktioniert mit beiden Key-Arten. Ein Key auf Instanzebene handelt als jeder beliebige User der Instanz, ein Key auf Kontoebene nur als Organisator im eigenen Konto. Jedes andere Ziel weist die Plattform ab.

Die beiden IDs

Ein Meeting hat zwei IDs, und die beiden sind nicht austauschbar. Wer sie verwechselt, macht den häufigsten Fehler im Umgang mit dieser API.

NameSieht aus wieWofür sie da ist
data.id5e945c36b863b82cefdddf5424 Zeichen hexadezimal. Verwenden Sie sie in jedem API-Aufruf.
data.meetingId9974-7653-8886-0485Ziffern mit Bindestrichen. Verwenden Sie sie im Meeting-Link und überall dort, wo Sie das Meeting Personen anzeigen.

Faustregel: Was Bindestriche hat, ist für Menschen. Was 24 hexadezimale Zeichen hat, ist für die API. PUT /meeting akzeptiert zufällig beides, alle übrigen Endpunkte nicht. Nehmen Sie deshalb überall data.id, dann liegen Sie immer richtig.

Drei weitere IDs erscheinen in Antworten:

NameQuelle
Konto-IDdata.id von POST /account
User-IDdata[].id von GET /account/admin/{accountId}
Raum-IDdata.roomId eines Meetings, wird zusammen mit dem Konto erstellt

Konto erstellen

Mit diesem Aufruf erstellen Sie ein Konto und dessen ersten Administrator in einem Schritt. Nur mit Keys auf Instanzebene.

FeldTypPflichtHinweise
adminEmailstringjaMuss auf der ganzen Instanz eindeutig sein. Jede E-Mail-Adresse gibt es nur einmal, auch über verschiedene Konten hinweg.
adminFirstnamestringja
adminLastnamestringja
adminPreferredLanguagestringjaISO 639-1, zum Beispiel en oder de
accountTypestringjatrial, standard, business, professional, confidential, boardroom, classroom, boardroomClassroom, school, payAsYouGo, internal
sendPasswordbooleanjatrue sendet ein Passwort per E-Mail an adminEmail. Beim Testen false setzen, damit Sie keine echten Personen anschreiben.
paidUntilISO 8601neinNach diesem Zeitpunkt funktioniert das Konto nicht mehr.
curl 'https://<DOMAIN-NAME>/api/v6/account' \
  -X POST \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'content-type: application/json' \
  --data-binary '{"sendPassword":true,"accountType":"trial","adminFirstname":"Test","adminLastname":"User","adminEmail":"test-user@example.com","adminPreferredLanguage":"en","paidUntil":"2026-12-31T23:59:59.000Z"}'
{
  "responseCode": 0,
  "data": {
    "id": "5e9459c5b863b82cefdddf4f",
    "name": "test-user@example.com",
    "accountType": "trial",
    "numberOfMeetingRooms": 1,
    "paidUntil": "2026-12-31T23:59:59.000Z",
    "accountRooms": []
  }
}

data.id ist die Konto-ID. Merken Sie sich den Wert, der nächste Aufruf braucht ihn.

Die Antwort beschreibt das Konto, nicht den soeben erstellten Administrator. Dessen User-ID fehlt darin also. Die holen Sie mit dem nächsten Aufruf.

Kontoadministrator abrufen

Dieser Aufruf liefert die Administratoren eines Kontos. Nur mit Keys auf Instanzebene. So kommen Sie an die User-ID des Administrators, den POST /account erstellt hat.

curl 'https://<DOMAIN-NAME>/api/v6/account/admin/<ACCOUNT-ID>' \
  -X GET \
  -H 'X-API-KEY: <API-KEY>'
{
  "responseCode": 0,
  "data": [
    {
      "id": "5e9459c5b863b82cefdddf4e",
      "email": "test-user@example.com",
      "firstName": "Test",
      "lastName": "User",
      "preferredLanguage": "en",
      "timezone": "Europe/Zurich"
    }
  ]
}

data ist ein Array. Bei einem frisch erstellten Konto steht darin ein Eintrag, ein Konto im laufenden Betrieb kann mehrere haben. Suchen Sie deshalb den Eintrag mit der erwarteten E-Mail-Adresse, statt blind data[0] zu nehmen.

Meeting erstellen

Pflicht sind nur zwei Felder, alles Übrige ist optional. Was Sie weglassen, füllt die Plattform mit den Vorgaben des Kontos. Das Beispiel unten sendet trotzdem den vollständigen Satz, und meistens wollen Sie genau das: Ein Meeting ohne endTime oder duration ist selten so gemeint.

FeldTypPflichtHinweise
topicstringja
startTimeISO 8601ja
endTimeISO 8601nein
durationnumberneinMinuten. Die Plattform leitet den Wert nicht aus den Zeiten ab. Achten Sie also selbst darauf, dass er dazu passt.
typestringneinstandard, offTheRecord, boardroom, classroom, audiobridge
isRecurringbooleannein
recurringobjectneinSenden Sie {}, wenn isRecurring auf false steht. Das Schema steht weiter unten.
isRecordedbooleanneinNur bestimmte Meeting-Typen lassen sich aufzeichnen.
isDialinbooleannein
invitedParticipantsarraynein[] für keine. Den Aufbau eines Eintrags finden Sie weiter unten.
meetingPermissionIdstring oder nullneinnull nimmt die Vorgabe des Kontos.

Mit einem Key auf Instanzebene ergänzen Sie X-USER-ID oder X-USER-EMAIL, um im Namen dieses Organisators zu planen.

curl 'https://<DOMAIN-NAME>/api/v6/meeting' \
  -X POST \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'X-USER-ID: <USER-ID>' \
  -H 'content-type: application/json' \
  --data-binary '{"topic":"My Meeting Topic","startTime":"2026-09-07T09:00:00.000Z","endTime":"2026-09-07T10:00:00.000Z","duration":60,"type":"standard","isRecurring":false,"isRecorded":false,"isDialin":false,"invitedParticipants":[],"recurring":{},"meetingPermissionId":null}'
{
  "responseCode": 0,
  "data": {
    "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",
    "type": "standard",
    "roomId": "5e9459c5b863b82cefdddf50",
    "isActive": false,
    "isOpen": false,
    "isClosed": true,
    "accountId": "5e9459c5b863b82cefdddf4f",
    "addedByUserId": "5e9459c5b863b82cefdddf4e",
    "timezone": "Europe/Zurich"
  }
}

So lesen Sie die Antwort:

  • data.id brauchen Sie in jedem späteren Aufruf.
  • data.meetingId zeigen Sie Personen an, und sie gehört in den Meeting-Link.
  • isClosed steht bei einem soeben erstellten Meeting auf true. Das ist normal. Es heisst nur, dass noch niemand beitreten kann. Für Moderatoren öffnet ein Meeting rund eine Stunde vor Beginn (isPreOpen), für alle anderen rund 15 Minuten vorher (isOpen). Werten Sie das nicht als fehlgeschlagenen Aufruf und wiederholen Sie ihn nicht.

Teilnehmer einladen

Jeder Eintrag in invitedParticipants ist ein Objekt:

FeldTypPflichtHinweise
emailstringjaMuss eine gültige E-Mail-Adresse sein.
namestringneinErscheint in der Einladung.
sendInvitebooleanjatrue schickt dieser Person eine Einladung mit dem Meeting-Link. false fügt sie dem Meeting hinzu, ohne ihr zu schreiben.
"invitedParticipants": [
  { "email": "anna@example.com", "name": "Anna Meier", "sendInvite": true }
]

Setzen Sie sendInvite beim Testen auf false, aus demselben Grund wie sendPassword beim Anlegen eines Kontos: Es ist der Unterschied zwischen einem Testlauf und einer E-Mail an eine echte Person.

Das recurring-Objekt

Steht isRecurring auf false, senden Sie {}. Steht es auf true, gelten diese Felder:

FeldWerte
frequencyTypenever, daily, weekly, monthly, yearly
frequencyZahl. Wie viele Einheiten zwischen zwei Wiederholungen liegen, 2 mit weekly also jede zweite Woche. Maximal 52 wöchentlich, 12 monatlich, 10 jährlich.
weekDaysAn welchen Tagen eine wöchentliche Serie stattfindet, als zweibuchstabige Codes: MO, TU, WE, TH, FR, SA, SU.
monthlyPatternday wiederholt am selben Tag des Monats, nthWeekDay am selben Wochentag des Monats, zum Beispiel am zweiten Dienstag.
endsTypenever, after, on
endsAfterAnzahl Wiederholungen, wenn endsType auf after steht. Die erste zählt mit, 12 ergibt also 12 Meetings insgesamt. Maximal 365.
endsOnISO-8601-Datum, wenn endsType auf on steht
excludeArray von ISO-8601-Daten, die entfallen

weekDays erwartet MO, nicht Monday. Einen Wert, den wir nicht kennen, verwerfen wir ohne Fehlermeldung. Bleibt einer wöchentlichen Serie danach kein erkannter Tag, wiederholt sie sich schlicht an dem Tag, auf den ihre startTime fällt. Nichts schlägt fehl, es lohnt sich also, das gleich richtig zu treffen.

Ein wöchentliches Standup, jeden Montag, 12-mal:

{
  "isRecurring": true,
  "recurring": {
    "frequencyType": "weekly",
    "frequency": 1,
    "weekDays": ["MO"],
    "endsType": "after",
    "endsAfter": 12
  }
}

Die API liefert keinen Link zurück. Bauen Sie ihn selbst aus der meetingId mit den Bindestrichen zusammen:

https://<DOMAIN-NAME>/meeting/<data.meetingId>

Für das Beispiel oben ist das https://<DOMAIN-NAME>/meeting/9974-7653-8886-0485.

Es ist derselbe Link, den Veeting in seine Einladungs-E-Mails und Kalendereinträge schreibt. Zwei Dinge dazu:

  • Er verwendet die meetingId mit den Bindestrichen. Die 24-stellige id funktioniert hier nicht.
  • Der Host ist die Domain, unter der Ihre User den Meetingraum öffnen. Auf den meisten Instanzen ist das dieselbe <DOMAIN-NAME>, unter der Sie die API aufrufen. Eine White-Label-Instanz kann aber eine andere Domain hinterlegt haben. Lesen Sie den Wert deshalb aus Ihrer eigenen Konfiguration, statt ihn zu raten.

Ist das Meeting passwortgeschützt, hängt der Einladungslink zusätzlich den Passwort-Hash an. So muss der Empfänger das Passwort nicht eintippen:

https://<DOMAIN-NAME>/meeting/<data.meetingId>?meetingAccessHash=<data.passwordHash>

An einen Meeting-Link hängen Sie zusätzlich Query-Parameter an. Damit geben Sie den Teilnehmernamen vor, überspringen den Gerätetest, wählen ein Layout und einiges mehr.

Ein Meeting zurücklesen

curl 'https://<DOMAIN-NAME>/api/v6/meeting/5e945c36b863b82cefdddf54' \
  -X GET \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'X-USER-EMAIL: <USER-EMAIL>'

Liefert dasselbe Meeting-Objekt zurück wie POST /meeting. Erwartet ausschliesslich die 24-stellige id.

Sie brauchen das öfter, als es aussieht, denn PUT ersetzt und ergänzt nicht: Meeting lesen, die gewünschten Felder ändern, das vollständige Objekt zurücksenden. Ebenso gleichen Sie damit ab, wenn Ihnen ein Webhook entgangen sein könnte, denn die Zustellung wird genau einmal versucht, ohne Wiederholung.

Der Aufrufer muss Organisator des Kontos sein, dem das Meeting gehört, oder in dessen invitedParticipants stehen.

Meeting aktualisieren

PUT /api/v6/meeting/<MEETING-ID>/<SEND-UPDATE-TO-PARTICIPANTS>

Das zweite Pfadsegment ist ein Boolean und nicht optional:

  • true schickt allen unter invitedParticipants eine aktualisierte Einladung.
  • false ändert das Meeting stillschweigend.

Dieser Aufruf ersetzt das Meeting, er ist kein Patch. Senden Sie deshalb das vollständige Meeting-Objekt, samt einem id-Feld mit der Meeting-ID. Was Sie weglassen, geht verloren.

curl 'https://<DOMAIN-NAME>/api/v6/meeting/5e945c36b863b82cefdddf54/false' \
  -X PUT \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'X-USER-EMAIL: <USER-EMAIL>' \
  -H 'content-type: application/json' \
  --data-binary '{"id":"5e945c36b863b82cefdddf54","topic":"My Updated Meeting Topic","startTime":"2026-09-07T09:30:00.000Z","endTime":"2026-09-07T10:30:00.000Z","duration":60,"type":"standard","isRecurring":false,"isRecorded":false,"isDialin":false,"invitedParticipants":[],"recurring":{},"meetingPermissionId":null}'

Ein Meeting vorzeitig schliessen

Meetings schliessen sich von selbst, sobald sie zu Ende sind. Wollen Sie eines sofort beenden, schliessen Sie es vorzeitig. Die Plattform entfernt dann alle, die noch im Raum sind.

Schliessen ist nicht Löschen: Der Meeting-Datensatz bleibt bestehen.

curl 'https://<DOMAIN-NAME>/api/v6/meeting/close' \
  -X POST \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'X-USER-EMAIL: <USER-EMAIL>' \
  -H 'content-type: application/json' \
  --data-binary '{"meetingId":"5e945c36b863b82cefdddf54"}'

Hinweis: Trotz seines Namens erwartet das Feld meetingId in diesem Body die 24-stellige data.id, nicht die data.meetingId mit den Bindestrichen.

Meetings löschen

curl 'https://<DOMAIN-NAME>/api/v6/meeting/5e945c36b863b82cefdddf54' \
  -X DELETE \
  -H 'X-API-KEY: <API-KEY>' \
  -H 'X-USER-EMAIL: <USER-EMAIL>'

Mehrere Meetings löschen Sie in einem Aufruf, indem Sie die IDs mit Kommas trennen:

DELETE /api/v6/meeting/<ID-1>,<ID-2>,<ID-3>

Im Body senden Sie optional eine cancellationMessage mit. Diesen Text übernimmt die Absage an die eingeladenen Teilnehmer.

Fehler

Eine Fehlerantwort führt einen negativen responseCode und eine responseMessage mit, aber kein data-Feld. Denken Sie daran: Der HTTP-Status lautet meistens trotzdem 200.

{
  "responseCode": -44,
  "responseMessage": "Input validation failed",
  "errors": []
}
responseCodeBedeutungWas zu tun ist
0Erfolg
-1Die Plattform befindet sich in einem WartungsfensterSpäter erneut versuchen
-11Nicht gefundenID prüfen, nicht erneut versuchen
-22AnwendungsfehlerNicht blind wiederholen. Der Aufruf hat nicht getan, worum Sie gebeten haben
-33API-FehlerAufbau des Aufrufs prüfen
-44Eingabevalidierung fehlgeschlagenPayload korrigieren. errors nennt den Grund
-55AbrechnungsfehlerDas Konto darf diese Aktion nicht ausführen
-99Authentifizierung fehlgeschlagenFalscher, inaktiver oder nicht berechtigter API-Key, oder ein User-Header, für den der Key nicht handeln darf. Nicht erneut versuchen

Pro IP-Adresse dürfen Sie 50 Aufrufe pro Sekunde senden, mit einer kurzen Reserve für Spitzen. Darüber antwortet die Plattform mit HTTP 429 statt mit einem responseCode.

Häufige Fehler

  • HTTP 200 als Erfolg werten, ohne responseCode zu prüfen.
  • Die meetingId mit den Bindestrichen dort übergeben, wo die 24-stellige id gefragt ist.
  • Den Meeting-Link mit id statt mit meetingId zusammenbauen.
  • X-USER-ID zusammen mit X-USER-EMAIL senden und erwarten, dass die Plattform die E-Mail-Adresse nimmt.
  • POST /account mit einem Key auf Kontoebene aufrufen.
  • Eine duration senden, die nicht zu startTime und endTime passt.
  • Lokale Zeiten ohne das Z am Ende senden.
  • isClosed: true bei einem soeben erstellten Meeting als Fehler deuten.
  • An PUT /meeting nur die geänderten Felder senden und damit alle übrigen löschen.
  • Den API-Key in clientseitigen Code legen.

Der komplette Ablauf

So richten Sie mit einem Key auf Instanzebene einen Kunden ein und planen dessen erstes Meeting:

POST   /account                       -> data.id           Konto-ID
GET    /account/admin/<ACCOUNT-ID>    -> data[0].id        User-ID
POST   /meeting  + X-USER-ID          -> data.id           für API-Aufrufe
                                         data.meetingId    für den Meeting-Link
PUT    /meeting/<ID>/<true|false>     aktualisieren
POST   /meeting/close                 vorzeitig schliessen
DELETE /meeting/<ID>                  entfernen

Mit einem Key auf Kontoebene überspringen Sie die ersten beiden Schritte und senden direkt an /meeting.

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

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