REFERENZ · STATUS v1

VetTime Public API v1

Die API liefert die aktuell veröffentlichten Schichtzuweisungen eines Mandanten über einen Kalenderzeitraum. Entwürfe, interne Mitarbeiter-IDs, Abwesenheiten, Verträge, Lohn- und Zeiterfassungsdaten werden nicht ausgeliefert.

Protokoll: HTTPS, JSON, UTF-8. Zielgruppe: Backend- und Praxis-Management-System-Entwickler.

Basis-URL und Authentifizierung

Basis-URL
https://app.vettime.de/api/public/v1

Jeder Request muss den mandantenbezogenen API-Key als HTTP-Bearer-Token übergeben:

Header
Authorization: Bearer vt_live_...
API-Keys sind serverseitige Geheimnisse. Sie gehören nicht in URLs, Browser- oder Mobile-Code, Versionskontrolle, Logs, E-Mails oder Chats. Ein ersetzter oder gelöschter Key ist sofort ungültig.

GET /shifts

Liefert alle Zuweisungen, die den angefragten inklusiven Zeitraum überschneiden, aus dem jeweils zuletzt veröffentlichten Plan pro Standort und Planungsperiode.

Query-Parameter

NameTypPflichtRegeln
fromdateJaErstes lokales Datum, inklusive; YYYY-MM-DD.
todateJaLetztes lokales Datum, inklusive; YYYY-MM-DD; nicht vor from.
location_idpositive integerNeinBegrenzt das Ergebnis auf einen Standort des Mandanten.
limitintegerNeinSeitengröße, 1 bis 250; Standard 100.
cursorstringNeinUndurchsichtiger meta.next_cursor der vorherigen Seite.

Der maximale Zeitraum beträgt 366 Kalendertage. Datumsangaben beziehen sich auf Europe/Berlin inklusive Sommerzeitumstellung. Eine Schicht überschneidet den Zeitraum, wenn:

Overlap-Regel
shift.starts_at < Beginn des Tages nach `to`
und
shift.ends_at > Beginn von `from`

Beispiel-Request

curl
curl --fail-with-body \
  --get 'https://app.vettime.de/api/public/v1/shifts' \
  --header "Authorization: Bearer ${VETTIME_API_KEY}" \
  --data-urlencode 'from=2026-08-17' \
  --data-urlencode 'to=2026-08-31' \
  --data-urlencode 'limit=100'

Erfolgreiche Antwort

200 OK
{
  "data": [
    {
      "id": "1f0eb3ea-29cf-4f1e-97b8-0ef39e7a6225",
      "local_date": "2026-08-17",
      "starts_at": "2026-08-17T06:00:00.000Z",
      "ends_at": "2026-08-17T14:00:00.000Z",
      "timezone": "Europe/Berlin",
      "employee": {
        "external_id": "PMS-EMP-148",
        "first_name": "Anna",
        "last_name": "Beispiel",
        "display_name": "Anna Beispiel",
        "active": true,
        "role": {
          "id": "e04bbef6-1cab-4d30-ad1a-b9b3b96ab0ac",
          "name": "Tierärztin"
        },
        "skills": [
          {
            "id": "77cabf7f-2ba7-49f9-b91e-bb8d7f6aa6b4",
            "name": "Ultraschall",
            "source": "manual"
          }
        ]
      },
      "shift_type": {
        "id": "33f17d45-16ba-4be1-a116-11d53192dbdb",
        "name": "Sprechstunde",
        "color": "#3B82F6",
        "required_skills": []
      },
      "location": {
        "id": 12,
        "name": "Praxis Berlin-Mitte",
        "slug": "berlin-mitte"
      },
      "publication": {
        "schedule_id": "cf7bf85c-d676-4101-aafc-897748185894",
        "published_at": "2026-08-14T15:42:10.000Z"
      },
      "updated_at": "2026-08-14T15:41:50.000Z"
    }
  ],
  "meta": {
    "tenant": { "id": 839204, "name": "Tierarztpraxis Beispiel" },
    "from": "2026-08-17",
    "to": "2026-08-31",
    "timezone": "Europe/Berlin",
    "limit": 100,
    "has_more": false,
    "next_cursor": null,
    "generated_at": "2026-08-17T12:05:31.420Z"
  }
}

Hinweise zu den Feldern

employee.external_id ist eine undurchsichtige, case-sensitive Zeichenkette, die der Mandant passend zu seinem Datensatz im angebundenen System konfiguriert. Ist keine Zuordnung hinterlegt, ist der Wert null. Die interne VetTime-Mitarbeiter- oder Benutzer-ID wird nie ausgeliefert; ein Abgleich über Namen als Fallback ist nicht zulässig.

employee.role kann null sein. location kann bei einem älteren mandantenweiten Plan null sein. publication.published_at und updated_at können bei Altdaten null sein.

Paginierung und Synchronisation

Zeilen sind nach starts_at und anschließend nach Zuweisungs-id sortiert. Solange meta.has_more den Wert true hat, ruft ihr denselben Endpunkt mit meta.next_cursor auf und lasst alle übrigen Parameter unverändert. Cursor sind als undurchsichtig zu behandeln.

Die Antwort ist ein aktueller Snapshot, kein Event-Stream. Holt alle Seiten, stellt den vollständigen Zeitraum bereit, upsertet die gelieferten Zuweisungen, entfernt zuvor importierte Zuweisungen, die im vollständigen Snapshot fehlen, und committet atomar. Zuweisungs-IDs und publication.schedule_id können sich nach erneutem Veröffentlichen ändern, deshalb ist ein regelmäßiger vollständiger Abgleich notwendig.

Fehler

Fehlerformat
{
  "error": {
    "code": "invalid_request",
    "message": "from must use the YYYY-MM-DD format.",
    "details": { "field": "from" }
  }
}
HTTPCodeBedeutung
400invalid_requestUngültiges Datum, ungültiger Zeitraum, Limit, Standort oder Cursor.
401invalid_api_keyFehlender, fehlerhafter, widerrufener Key oder inaktiver Mandant.
429rate_limit_exceededAnfragelimit überschritten; Retry-After beachten.
500internal_errorVorübergehender Serverfehler; mit Backoff und Jitter erneut versuchen.
Jede Antwort enthält X-Request-Id. Gebt diesen Wert zusammen mit der UTC-Anfragezeit an, wenn ihr den Support kontaktiert. Sendet niemals den API-Key mit.

Limits und Kompatibilität

Authentifizierte Keys sind auf 120 Requests pro Minute begrenzt. Fehlgeschlagene Authentifizierungsversuche sind separat auf 30 pro IP pro 15 Minuten begrenzt.

Clients müssen unbekannte JSON-Felder ignorieren. Innerhalb von v1 können additive Felder eingeführt werden; Breaking Changes erhalten einen neuen versionierten Pfad.

OpenAPI 3.1

Der maschinenlesbare Vertrag steht als YAML bereit:

openapi-public-v1.yaml
Fragen zur Anbindung?

Schreibt uns kurz, welches System ihr anbindet.

Integration anfragen