API für externe Verwaltungssysteme

Version v1 — Dokumentation aktualisiert am 29. Juli 2026

Diese Seite dokumentiert die HTTP-APIs, die VolleyFriends den Anlagenbetreibern zur Verfügung stellt, um den Platzkalender mit einer externen Verwaltungssoftware oder einer Online-Buchungswebsite zu synchronisieren. Es gelten dieselben Domänenregeln wie im Betreiber-Dashboard (Konflikte, Schließungen, Preisliste): Es ändert sich nur die Art der Authentifizierung.

1. Was die APIs ermöglichen

Mit einem API-Schlüssel kannst du von deiner Software aus den Kalender deiner Sportstätten lesen und beschreiben:

  • Sportstätten und Spielfelder lesen mit ihren Identifikatoren, die für alle anderen Aufrufe benötigt werden;
  • die Buchungen lesen für einen Zeitraum, eine Sportstätte oder ein einzelnes Spielfeld, um sie mit deinem Archiv abzugleichen;
  • Buchungen erstellen von extern (zum Beispiel, wenn ein Kunde über deine Website bucht), mit denselben Prüfungen auf Überschneidungen und Sperrungen im Dashboard;
  • eine bestehende Buchung ändern oder stornieren (Verschiebung von Uhrzeit oder Spielfeld, Zahlungseingang, Notizen, Stornierung);
  • die Verfügbarkeit lesen eines Spielfelds an einem Tag: bereits belegte Slots, Öffnungszeiten und außerordentliche Schließungen, um freie Slots anzubieten, ohne die Regeln replizieren zu müssen;
  • die Preisliste eines Spielfelds lesen, um dem Endkunden die Preise anzuzeigen.
Gültigkeitsbereich der Schlüssel

Jeder Schlüssel ist an das Betreiber-Konto gebunden, das ihn erstellt hat, und sieht nur die Anlagen, Spielfelder und Buchungen dieses Kontos. Eine Ressource, die einem anderen Betreiber gehört, antwortet nicht mit 403, sondern mit 404 not_found: Ihre Existenz wird nicht offengelegt.

Nicht Teil dieser API sind die Anfragen von Organisatoren zur Nutzung von Spielfeldern bei Turnieren (diese werden über die App genehmigt), das Erstellen von Anlagen und Spielfeldern sowie das Speichern von Zeiten, Schließungen und Preislisten: Dies sind Vorgänge im Betreiber-Panel.

2. Voraussetzungen und Aktivierung

  1. Ein Spielfeldbetreiber-Konto VolleyFriends mit mindestens einer Anlage und einem Spielfeld.
  2. Ein aktives Abonnement mit einem Tarif, der die Funktion „API für externe Verwaltungssysteme“ enthält. Die gesamte v1selbst reine Lesezugriffe — ist denjenigen vorbehalten, die diese Funktion haben: Es handelt sich um eine kostenpflichtige Funktion, nicht um ein Zubehör des Panels.
  3. Ein im Verwaltungssystem generierter API-Schlüssel: admin.volleyfriends.comEinstellungenAPI-SchlüsselNeuer Schlüssel.

Der Schlüssel hat das Format vfk_ gefolgt von 40 Hexadezimalzeichen (insgesamt 44 Zeichen) und wird nur ein einziges Mal direkt nach der Erstellung angezeigt: In der Datenbank verbleibt nur sein sha256-Hash, er ist also keinesfalls wiederherstellbar. Wenn du ihn verlierst, widerrufe ihn und generiere einen neuen. In der Liste im Panel siehst du nur das Präfix (z. B. vfk_9f2c), das Erstellungsdatum und das Datum der letzten Verwendung.

3. Authentifizierung

Jede Anfrage muss mit dem Header X-Api-Key authentifiziert werden. Es sind keine Token, Logins, Ablauffristen oder Erneuerungen erforderlich: Der Schlüssel bleibt gültig, bis du ihn widerrufst.

# Die Schlüssel auf dieser Seite sind Beispiele: Ersetze sie durch deine eigenen.
curl -s https://www.volleyfriends.com/api/manager-api/v1/venues   -H "X-Api-Key: vfk_9f2c41a7b83d05e6c19af4728b60d35e1c9a7f42"

In den folgenden Beispielen wird der Schlüssel aus der Umgebungsvariable VF_API_KEY ausgelesen, wie es sich auch in der Produktion empfiehlt.

Fehlender Header, kürzer als 12 Zeichen, unbekannt oder zu einem widerrufenen Schlüssel gehörend: Die Antwort ist 401 mit diesem Body.

{
  "error": "invalid_key",
  "message": "Chiave API mancante o non valida (header X-Api-Key)."
}
Aufbewahrung des Schlüssels
  • Der Schlüssel gilt als Passwort mit vollen Zugriffsrechten auf den Kalender deiner Anlagen: Füge ihn nicht in Webseiten, Apps oder browserseitiges JavaScript ein, wo er für jeden lesbar wäre. Verwende ihn nur von Server zu Server.
  • Hinterlege ihn nicht im Quellcode oder in einem Repository: Verwende eine Umgebungsvariable oder einen Secrets-Manager.
  • Verwende einen Schlüssel für jedes verbundene System (Website, Verwaltungssystem, Abgleichs-Skript): So kannst du einen widerrufen, ohne die anderen abzuschalten.
  • Wenn du vermutest, dass er offengelegt wurde, widerrufe ihn sofort im Panel: Der Widerruf erfolgt sofort und wird niemals durch den Status des Abonnements blockiert. Ab diesem Zeitpunkt erhält jeder Aufruf mit diesem Schlüssel 401 invalid_key.
  • Datenverkehr ausschließlich über HTTPS; das Feld „Letzte Verwendung“ im Panel hilft dir, unerwartete Nutzungen zu bemerken.

4. Basis-URL

https://www.volleyfriends.com/api

Die unten dokumentierten Pfade müssen an die Basis angehängt werden. Das Präfix /api gehört zum Reverse Proxy, daher lautet die vollständige Adresse eines Endpunkts beispielsweise:

GET https://www.volleyfriends.com/api/manager-api/v1/availability

Alle Antworten sind application/json mit UTF-8-Codierung. Anfragen mit Body (POST, PATCH) müssen Content-Type: application/json enthalten.

5. Rate Limiting

Das Limit liegt bei 120 Anfragen pro Minute pro API-Schlüssel (gleitendes Fenster von 1 Minute). Die Zählung erfolgt pro Schlüssel, nicht pro IP-Adresse: Die Verwaltungssysteme befinden sich oft hinter derselben Provider-Adresse, und ein Limit pro IP würde verschiedene Betreiber, die auf derselben Infrastruktur gehostet werden, benachteiligen. Wenn der Header X-Api-Key vollständig fehlt, fällt die Zählung auf die IP-Adresse zurück.

Jede Antwort enthält den Status des Zählers in den Headern x-ratelimit-limit, x-ratelimit-remaining und x-ratelimit-reset (Sekunden bis zum Reset). Bei Überschreitung wird auch retry-after hinzugefügt.

Antwort bei Überschreitung — 429

{
  "error": "rate_limited",
  "message": "Limite di 120 richieste al minuto superato per questa chiave API."
}
Wie du innerhalb des Limits bleibst
  • Verwende für den periodischen Abgleich nur einen einzigen Aufruf von /bookings mit einem großen fromto-Intervall anstelle eines Aufrufs pro Tag.
  • Speichere die Liste der Sportstätten und Spielfelder im Cache: Sie ändert sich selten.
  • Warte im Falle eines 429 und versuche es mit exponentiellem Backoff (z. B. 2, 4, 8 Sekunden) erneut, unter Berücksichtigung von retry-after.

6. Endpunkte

Sechs Endpunkte, alle unter /manager-api/v1. Jeder Aufruf durchläuft dieselbe Kette von Prüfungen in dieser Reihenfolge: gültiger API-Schlüssel → Funktion „API für externe Verwaltungssysteme“ im Paket enthalten → Rate Limit → Validierung der Parameter → Überprüfung, ob die Ressource dir gehört.

6.1 Sportstätten und Spielfelder

GET/api/manager-api/v1/venues

Listet deine Sportstätten auf, jede mit ihren eigenen verschachtelten Spielfeldern. Dies ist der Ausgangspunkt: Die ids der Spielfelder (courtId) werden für alle anderen Endpunkte benötigt. Die Sportstätten sind nach Namen sortiert, die Spielfelder nach Namen.

Parameter

Keine.

Beispiel für eine Anfrage

curl -s https://www.volleyfriends.com/api/manager-api/v1/venues   -H "X-Api-Key: $VF_API_KEY"

Beispiel für eine Antwort — 200

{
  "venues": [
    {
      "id": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
      "name": "Centro Sportivo Aurora",
      "city": "Verona",
      "address": "Via delle Palestre 12",
      "verified": true,
      "courts": [
        {
          "id": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
          "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
          "name": "Campo 1",
          "surface": "parquet",
          "indoor": true,
          "lighting": true
        },
        {
          "id": "e2a71f64-9c03-4bd8-b512-38f6cd90a7e1",
          "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
          "name": "Campo 2 beach",
          "surface": "sabbia",
          "indoor": false,
          "lighting": true
        }
      ]
    }
  ]
}

Antwortfelder

FeldTypBeschreibung
venues[].iduuidIdentifikator der Sportstätte (venueId in den anderen Endpunkten).
venues[].namestringName der Sportstätte.
venues[].citystring | nullStadt.
venues[].addressstring | nullAdresse.
venues[].verifiedbooleantrue, wenn die Anlage das Badge VERIFIZIERT hat.
venues[].courts[]arraySpielfelder der Anlage. Leeres Array, wenn keine vorhanden sind.
courts[].iduuidID des Spielfelds (courtId in den anderen Endpunkten).
courts[].venueIduuidAnlage, zu der das Spielfeld gehört.
courts[].namestringName des Spielfelds.
courts[].surfacestring | nullBelag, Freitext vom Betreiber eingegeben.
courts[].indoorbooleanHallenspielfeld.
courts[].lightingbooleanBeleuchtung vorhanden.

Wenn das Konto noch keine Anlagen hat, lautet die Antwort {"venues": []}.

Spezifische Fehler

Keine außer den allgemeinen.

6.2 Buchungsliste

GET/api/manager-api/v1/bookings

Gibt die Buchungen deiner Anlagen zurück, sortiert nach aufsteigender Startzeit. Die Liste ist paginiert: maximal limit Zeilen pro Aufruf (Standard 500, Obergrenze 1000) — wenn du genau limit Zeilen erhältst, rufe sie erneut mit erhöhtem offset für die nächste Seite auf. Filtere in der Produktionsumgebung dennoch immer mindestens nach Datumsbereich.

Parameter (Query-String)

NameTypPflichtBeschreibung
venueIduuidneinAuf eine Anlage beschränken. Wenn sie nicht dir gehört: 404 not_found.
courtIduuidneinAuf ein Spielfeld beschränken. Wenn es nicht deins ist: 404 not_found. In Kombination mit einer venueId einer anderen deiner Sportstätten ist das Ergebnis eine leere Liste.
fromISO-Datum oder -ZeitstempelneinInklusive unterer Grenze. Ein reines Datum AAAA-MM-GG gilt für die lokale italienische Mitternacht dieses Tages.
toISO-Datum oder -ZeitstempelneinExklusive oberer Grenze. Ein reines Datum gilt für die lokale Mitternacht des folgenden Tages: to=2026-08-31 schließt den gesamten 31. August ein.
limitinteger 1–1000neinMaximale Anzahl an Zeilen (Standardwert 500).
offsetinteger ≥ 0neinZu überspringende Zeilen (Standardwert 0): offset=500 ist die zweite Seite mit dem Standard-Limit.
Worauf der Filter wirkt

from und to beziehen sich auf den Startzeitpunkt der Buchung. Eine Buchung, die vor from begonnen hat und danach noch läuft, wird nicht angezeigt: Wenn du sie benötigst, erweitere die untere Grenze um einige Stunden. Der Filter schließt stornierte Buchungen nicht aus: Die Liste enthält auch solche mit status: "cancelled".

Beispiel für eine Anfrage

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/bookings   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"   --data-urlencode "from=2026-08-01"   --data-urlencode "to=2026-08-31"

Beispiel für eine Antwort — 200

{
  "bookings": [
    {
      "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
      "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
      "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
      "courtName": "Campo 1",
      "startsAt": "2026-08-12T16:00:00.000Z",
      "endsAt": "2026-08-12T17:30:00.000Z",
      "customerName": "Marta Bellini",
      "customerPhone": "+39 340 1122334",
      "customerEmail": "marta.bellini@example.com",
      "priceCents": 3000,
      "playersCount": null,
      "status": "confirmed",
      "paymentMethod": null,
      "paymentLink": null,
      "notes": "Prenotato dal sito della struttura",
      "source": "api",
      "recurrenceId": null,
      "createdAt": "2026-07-28T09:14:02.517Z",
      "updatedAt": "2026-07-28T09:14:02.517Z"
    }
  ],
  "limit": 500,
  "offset": 0
}

Felder einer Buchung

Die gleiche Struktur wird von POST und PATCH zurückgegeben (innerhalb des Schlüssels booking).

FeldTypBeschreibung
iduuidID der Buchung.
venueIduuidSportstätte.
courtIduuidGebuchtes Spielfeld.
courtNamestringName des Spielfelds, zur einfacheren Anzeige.
startsAtISO-ZeitstempelStart, immer in UTC (Suffix Z).
endsAtISO-ZeitstempelEnde, Grenze exklusive.
customerNamestringName des Kunden.
customerPhonestring | nullTelefon.
customerEmailstring | nullE-Mail.
priceCentsinteger | nullVereinbarter Preis in Cent. null = noch zu definieren (niemals 0 für „nicht definiert“).
playersCountinteger | nullAnzahl der angegebenen Personen (nur Buchungen in Zeitfenstern mit Preis pro Person). null = nicht anwendbar oder nicht angegeben.
statusstringpending · confirmed · paid · cancelled — siehe Status.
paymentMethodstring | nullcash · bank_transfer · paypal · stripe · other. null = nicht kassiert.
paymentLinkstring | nullVom Dashboard generierter Link für Kartenzahlung, falls vorhanden. Schreibgeschützt.
notesstring | nullFreie Notizen.
sourcestringQuelle: manual (Dashboard) · api (diese API) · app (Anfrage eines Spielers aus der App) · tournament (Turnier).
recurrenceIduuid | nullVorhanden und identisch bei allen Terminen einer über das Dashboard erstellten wiederkehrenden Serie.
createdAtISO-ZeitstempelErstellung.
updatedAtISO-ZeitstempelLetzte Änderung.

Spezifische Fehler

CodeerrorWann
400invalid_inputvenueId/courtId sind keine UUIDs oder from/to sind keine interpretierbaren Datumswerte.
404not_foundDie Anlage ("Struttura non trovata") oder das Spielfeld ("Campo non trovato") existiert nicht oder gehört dir nicht.

6.3 Neue Buchung

POST/api/manager-api/v1/bookings

Erstellt eine Buchung auf einem deiner Spielfelder. Die Buchung wird mit source: "api" erstellt, damit sie im Dashboard von den manuell eingegebenen unterschieden werden kann, und der Betreiber erhält eine Push-Benachrichtigung „Neue Buchung“ in der App.

Es gelten dieselben Regeln wie im Dashboard, in dieser Reihenfolge:

  1. Außerordentliche Schließung der Anlage am Startdatum → 409 venue_closed;
  2. Überschneidung mit einer anderen, nicht stornierten Buchung desselben Spielfelds → 409 overlap;
  3. Preis fehlt → wird aus der Preisliste des Spielfelds berechnet (null, wenn die Startzeit in kein Zeitfenster fällt). Wenn das Zeitfenster einen Preis pro Person hat, wird auch playersCount benötigt: Ohne diesen wird die Anfrage mit 400 players_required abgelehnt (es sei denn, es wird ein expliziter priceCents angegeben).

Die Öffnungszeiten blockieren nicht die Erstellung: Sie dienen der Information, der Betreiber bleibt souverän auf seinem eigenen Spielfeld. Wenn du Buchungen außerhalb der Öffnungszeiten verhindern willst, überprüfe selbst hours, das von /availability zurückgegeben wird, bevor du die POST aufrufst.

Anfrage-Body (JSON)

NameTypPflichtBeschreibung
courtIduuidjaZu buchendes Spielfeld. Es muss zu einer deiner Anlagen gehören.
startsAtISO 8601-Zeitstempel mit OffsetjaBeginn. Akzeptiert werden sowohl das Format 2026-08-12T18:00:00Z als auch 2026-08-12T18:00:00+02:00. Ohne Offset: 400.
endsAtISO 8601-Zeitstempel mit OffsetjaEnde, muss nach startsAt liegen.
customerNamestring (1–160)jaName des Kunden.
customerPhonestring (max. 40)neinTelefon.
customerEmailE-Mail (max. 200)neinE-Mail, als Adresse validiert.
priceCentsinteger ≥ 0neinPreis in Cent. Wenn weggelassen, wird er aus der Preisliste des Spielfelds berechnet. Gib 0 nur für eine wirklich kostenlose Buchung an.
playersCountinteger 1–500neinWie viele Personen. Erforderlich, wenn der Preis aus der Preisliste berechnet werden soll und der Zeitraum der Startzeit pro Person ist; der Gesamtbetrag wendet das eventuelle garantierte Minimum des Zeitraums an.
notesstring (max. 2000)neinFreie Notizen, für den Betreiber im Dashboard sichtbar.
statuspending | confirmed | paid | cancelledneinStandardwert confirmed. Verwende von einem externen Verwaltungssystem aus confirmed oder paid: pending ist für Anfragen reserviert, die über die Spieler-App eingehen (siehe Status).
paymentMethodcash | bank_transfer | paypal | stripe | otherneinWie es kassiert wurde (oder wird). Weggelassen = nicht kassiert.
recurrenceobjectneinVon diesen APIs nicht unterstützt: Falls vorhanden, wird die Anfrage mit 400 recurrence_unsupported abgelehnt (keine Buchung erstellt). Serientermine bleiben eine Funktion des Dashboards: Wiederhole bei einem externen Verwaltungssystem die POST-Anfrage für jedes Vorkommen.

Beispiel für eine Anfrage

curl -s -X POST https://www.volleyfriends.com/api/manager-api/v1/bookings   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "startsAt": "2026-08-12T18:00:00+02:00",
    "endsAt": "2026-08-12T19:30:00+02:00",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "notes": "Prenotato dal sito della struttura"
  }'

Antwortbeispiel — 201

{
  "booking": {
    "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
    "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "courtName": "Campo 1",
    "startsAt": "2026-08-12T16:00:00.000Z",
    "endsAt": "2026-08-12T17:30:00.000Z",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "priceCents": 3000,
    "playersCount": null,
    "status": "confirmed",
    "paymentMethod": null,
    "paymentLink": null,
    "notes": "Prenotato dal sito della struttura",
    "source": "api",
    "recurrenceId": null,
    "createdAt": "2026-07-28T09:14:02.517Z",
    "updatedAt": "2026-07-28T09:14:02.517Z"
  }
}

Im Beispiel wurde priceCents nicht angegeben: 90 Minuten in einem Zeitraum von 20,00 €/Std. ergeben 3000 Cent (die Berechnung erfolgt proportional zu den tatsächlichen Minuten mit dem Tarif des Zeitraums, in dem die Buchung beginnt).

Spezifische Fehler

CodeerrorWann
400invalid_inputUngültiger Body: fehlendes Pflichtfeld, Zeitstempel ohne Offset, endsAt liegt nicht nach startsAt, ungültige E-Mail, Längen außerhalb der Grenzwerte.
400players_requiredPreis soll aus der Preisliste für einen Zeitraum pro Person berechnet werden, aber playersCount fehlt.
400recurrence_unsupportedDer Body enthält recurrence: Serientermine sind über diese APIs nicht verfügbar.
403subscription_requiredKein aktives Betreiber-Abonnement.
404not_found"Campo non trovato" — die courtId existiert nicht oder gehört nicht dir.
409venue_closedDie Anlage hat eine außerordentliche Schließung am Startdatum.
409overlapDas Spielfeld hat bereits eine nicht stornierte Buchung, die sich mit dem Zeitraum überschneidet.
// 409 — Überschneidung
{ "error": "overlap", "message": "Il campo è già prenotato in quell'orario." }

// 409 — außerordentliche Schließung (der Grund, falls vom Betreiber angegeben, steht in der Nachricht)
{ "error": "venue_closed", "message": "Struttura chiusa in quella data (manutenzione)." }
Idempotenz

Es gibt keinen Idempotenz-Schlüssel: Das Wiederholen desselben POST nach einem Timeout kann ein Duplikat erstellen oder, häufiger, 409 overlap zurückgeben, weil der erste Versuch erfolgreich war. Bei einer unsicheren Antwort überprüfe dies vor einem erneuten Versuch mit GET /bookings für den betroffenen Zeitraum.

6.4 Buchung bearbeiten

PATCH/api/manager-api/v1/bookings/{id}

Aktualisiert eine bestehende Buchung. Es handelt sich um eine partielle Aktualisierung: Sende nur die Felder, die sich ändern, die anderen bleiben unverändert. Der Body muss mindestens ein Feld enthalten.

Es gibt keinen Endpunkt zum Löschen: Um eine Buchung zu stornieren, wird status: "cancelled" gesetzt. Der Verlauf bleibt im Dashboard erhalten und der Slot wird wieder frei (stornierte Buchungen belegen das Spielfeld nicht und erzeugen kein overlap).

Pfadparameter

NameTypPflichtBeschreibung
iduuidjaID der Buchung, aus GET /bookings oder aus der Antwort des POST.

Anfrage-Body (JSON)

Alle Felder sind optional. Die als „aufhebbar“ markierten Felder akzeptieren null, um den Wert zu leeren.

NameTypNotizen
courtIduuidVerschiebt die Buchung auf ein anderes deiner Spielfelder, auch in einer anderen deiner Anlagen (venueId wird entsprechend aktualisiert).
startsAtISO-Zeitstempel mit OffsetNeuer Beginn.
endsAtISO-Zeitstempel mit OffsetNeues Ende. Das Endergebnis muss nach dem Beginn liegen, auch wenn nur ein Grenzwert mit dem bereits gespeicherten Wert kombiniert wird.
customerNamestring (1–160)
customerPhonestring (max. 40)Aufhebbar.
customerEmailE-Mail (max. 200)Aufhebbar.
priceCentsinteger ≥ 0Aufhebbar (null = Preis noch zu definieren). Bei PATCH wird der Preis nicht anhand der Preisliste neu berechnet: Wenn du die Uhrzeit verschiebst und den neuen Preis möchtest, gib ihn an.
playersCountinteger 1–500Aufhebbar. Aktualisiert nur die Daten: Der Preis wird nicht automatisch neu berechnet — wenn die Anzahl der Personen den Gesamtbetrag ändert, sende auch den neuen priceCents.
notesstring (max. 2000)Aufhebbar.
statuspending | confirmed | paid | cancelledJeder Übergang ist zulässig. Dies ist auch der Weg, um auf eine über die App eingegangene Anfrage zu antworten (status: "pending" mit source: "app"): Setze sie auf confirmed, um sie anzunehmen, oder auf cancelled, um sie abzulehnen — der Spieler erhält die Benachrichtigung.
paymentMethodcash | bank_transfer | paypal | stripe | otherAufhebbar.
Wann Konflikte erneut geprüft werden

Die Prüfungen auf Schließung und Überlappung werden in zwei Fällen erneut durchgeführt: wenn die Anfrage den Slot verschiebt (startsAt, endsAt oder courtId) und wenn sie eine stornierte Buchung reaktiviert (status von cancelled in einen beliebigen anderen Status) — als storniert belegte sie das Spielfeld nicht, und in der Zwischenzeit kann der Slot vergeben worden sein: In diesem Fall antwortet der PATCH mit 409 overlap oder 409 venue_closed. Ein PATCH, der nur andere Felder ändert (Preis, Notizen, Einnahmen), wiederholt diese Prüfungen nicht.

Beispiel für eine Anfrage — Verschiebung und Einnahmen

curl -s -X PATCH   https://www.volleyfriends.com/api/manager-api/v1/bookings/9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{
    "startsAt": "2026-08-12T19:00:00+02:00",
    "endsAt": "2026-08-12T20:30:00+02:00",
    "status": "paid",
    "paymentMethod": "cash",
    "priceCents": 3000
  }'

Beispiel für eine Anfrage — Stornierung

curl -s -X PATCH   https://www.volleyfriends.com/api/manager-api/v1/bookings/9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{ "status": "cancelled" }'

Beispiel für eine Antwort — 200

Die aktualisierte Buchung im gleichen Format wie der POST:

{
  "booking": {
    "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
    "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "courtName": "Campo 1",
    "startsAt": "2026-08-12T17:00:00.000Z",
    "endsAt": "2026-08-12T18:30:00.000Z",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "priceCents": 3000,
    "playersCount": null,
    "status": "paid",
    "paymentMethod": "cash",
    "paymentLink": null,
    "notes": "Prenotato dal sito della struttura",
    "source": "api",
    "recurrenceId": null,
    "createdAt": "2026-07-28T09:14:02.517Z",
    "updatedAt": "2026-07-28T11:02:47.883Z"
  }
}

Spezifische Fehler

CodeerrorWann
400invalid_inputLeerer Body ("Nessun campo da aggiornare"), ungültige Werte oder Endzeit nicht nach der Startzeit ("L'orario di fine deve essere successivo a quello di inizio").
403subscription_requiredKein aktives Betreiber-Abonnement.
404not_found"Prenotazione non trovata" oder "Campo non trovato", wenn die neue courtId nicht dir gehört.
409venue_closedVerschiebung auf ein Datum mit außerordentlicher Schließung.
409overlapDie neue Uhrzeit überschneidet sich mit einer anderen, nicht stornierten Buchung desselben Spielfelds.

6.5 Verfügbarkeit eines Spielfelds an einem Tag

GET/api/manager-api/v1/availability

Gibt für ein Spielfeld und einen Tag die belegten Slots, die Öffnungszeiten dieses Wochentags und eine eventuelle außerordentliche Schließung zurück. Dies ist der Endpunkt, der verwendet werden sollte, um freie Slots auf einer externen Website zu berechnen, ohne die Regeln des Verwaltungssystems zu duplizieren: Ziehe die Buchungen vom Öffnungsfenster ab.

Es werden alle Slots aufgelistet, die das Spielfeld belegen, in jedem Status außer cancelled: also auch noch pending Online-Buchungsanfragen. Der Tag ist der lokale italienische Tag und die Intervalle sind halboffen: Eine Buchung, die genau um Mitternacht endet, gehört zum Vortag. Eine Buchung über Mitternacht hinweg erscheint an beiden Tagen, die sie schneidet, mit ihren tatsächlichen Zeitpunkten (die außerhalb des angeforderten Tages liegen können).

Parameter (Query-String)

NameTypPflichtBeschreibung
courtIduuidjaSpielfeld, dessen Verfügbarkeit ausgelesen werden soll. Es muss dir gehören.
dateAAAA-MM-GGjaLokaler italienischer Tag. Abweichendes Format: 400 mit der Meldung "Data non valida (AAAA-MM-GG)".

Beispiel für eine Anfrage

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/availability   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"   --data-urlencode "date=2026-08-12"

Beispiel für eine Antwort — 200

{
  "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
  "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
  "date": "2026-08-12",
  "timezone": "Europe/Rome",
  "hours": {
    "weekday": 2,
    "openMinute": 540,
    "closeMinute": 1380,
    "closed": false,
    "configured": true
  },
  "closure": null,
  "bookings": [
    {
      "startsAt": "2026-08-12T16:00:00.000Z",
      "endsAt": "2026-08-12T17:30:00.000Z",
      "status": "confirmed"
    },
    {
      "startsAt": "2026-08-12T18:00:00.000Z",
      "endsAt": "2026-08-12T19:00:00.000Z",
      "status": "paid"
    },
    {
      "startsAt": "2026-08-12T19:00:00.000Z",
      "endsAt": "2026-08-12T20:30:00.000Z",
      "status": "pending"
    }
  ]
}

Antwortfelder

FeldTypBeschreibung
courtIduuidAngefordertes Spielfeld.
venueIduuidStruktur des Spielfelds.
dateAAAA-MM-GGAngeforderter Tag, wiederholt.
timezonestringImmer "Europe/Rome": die Zeitzone, in der date und die Minuten der Uhrzeiten zu interpretieren sind.
hours.weekdayinteger 0–6Wochentag: 0 = Montag … 6 = Sonntag.
hours.openMinuteinteger | nullÖffnung in Minuten ab lokaler Mitternacht (540 = 09:00). null, wenn der Tag als geschlossen deklariert ist.
hours.closeMinuteinteger | nullSchließung in Minuten (1380 = 23:00). null, wenn der Tag als geschlossen deklariert ist.
hours.closedbooleantrue, wenn der Betreiber diesen Wochentag als geschlossen deklariert hat.
hours.configuredbooleanfalse, wenn der Betreiber die Zeiten für diesen Tag nicht festgelegt hat: In diesem Fall gelten für openMinute/closeMinute die Standardwerte 480 (08:00) – 1380 (23:00), was eine Behelfslösung für die Anzeige ist, keine deklarierte Uhrzeit.
closureobject | nullAußerordentliche Schließung am angeforderten Tag aktiv, oder null.
closure.fromAAAA-MM-GGErster Tag der Schließung.
closure.toAAAA-MM-GGLetzter Tag der Schließung, inklusive.
closure.reasonstring | nullGrund, falls vom Betreiber angegeben.
bookings[]arrayBelegte Slots, sortiert nach Beginn. Nur startsAt, endsAt und status (pending, confirmed oder paid): keine Kundendaten, sodass die Antwort zur Erstellung eines öffentlichen Kalenders verwendet werden kann.
Mit einer laufenden Schließung

Wenn closure nicht null ist, ist der Tag als nicht buchbar zu betrachten, unabhängig von hours: Ein POST-Request an diesem Datum würde 409 venue_closed erhalten.

Spezifische Fehler

CodeerrorWann
400invalid_inputcourtId fehlt oder ist keine UUID, date fehlt oder ist nicht im Format AAAA-MM-GG.
404not_found"Campo non trovato" — das Spielfeld existiert nicht oder gehört nicht dir.

6.6 Preisliste eines Spielfelds

GET/api/manager-api/v1/rates

Die Preisliste des Spielfelds in schreibgeschützter Form: Sie dient dazu, dem Kunden vor der Buchung die Preise anzuzeigen, mit denselben Zeitfenstern, die das Verwaltungssystem zur automatischen Preisberechnung verwendet. Die Zeitfenster können nur über das Panel geändert werden. Sie sind nach aufsteigendem fromMinute sortiert.

Parameter (Query-String)

NameTypPflichtBeschreibung
courtIduuidjaSpielfeld, dessen Preisliste gelesen werden soll. Es muss deines sein.

Beispiel für eine Anfrage

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/rates   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"

Beispiel für eine Antwort — 200

{
  "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
  "rates": [
    {
      "id": "4a1e0b72-6d35-4c81-93af-0b7e2d5814c6",
      "label": "Mattina infrasettimanale",
      "daysMask": 31,
      "fromMinute": 480,
      "toMinute": 840,
      "pricePerHourCents": 1500,
      "pricingMode": "court",
      "minPlayers": null
    },
    {
      "id": "c07d9b31-8f42-4a05-b6e9-15d3c8017a2b",
      "label": "Serale",
      "daysMask": 127,
      "fromMinute": 1080,
      "toMinute": 1380,
      "pricePerHourCents": 600,
      "pricingMode": "person",
      "minPlayers": 10
    }
  ]
}

Antwortfelder

FeldTypBeschreibung
courtIduuidAngefordertes Spielfeld.
rates[].iduuidKennung des Zeitfensters.
rates[].labelstringVom Betreiber gewähltes Label (z. B. „Abendtarif“).
rates[].daysMaskinteger 1–127Bitmaske der Tage: Mo 1, Di 2, Mi 4, Do 8, Fr 16, Sa 32, So 64. 127 = alle Tage, 31 = von Montag bis Freitag.
rates[].fromMinuteinteger 0–1440Beginn des Zeitfensters in Minuten ab lokaler Mitternacht.
rates[].toMinuteinteger 0–1440Ende des Zeitfensters, immer größer als fromMinute.
rates[].pricePerHourCentsinteger > 0Stundenpreis in Cent (2000 = 20,00 €). Bei pricingMode: "person" ist es der Stundenpreis pro Person (600 = 6,00 €/Person pro Stunde).
rates[].pricingModecourt | personcourt = Preis des Spielfelds (Standard). person = Preis pro Person: Der Gesamtbetrag skaliert mit der Anzahl der Personen, jedoch nie nach unten.
rates[].minPlayersinteger | nullGarantierte Mindestanzahl des Tarifs pro Person: Unter dieser Zahl wird trotzdem der Mindestpreis berechnet. null = kein Minimum.
Wie der Preis einer Buchung berechnet wird

Es wird der Startzeitpunkt betrachtet: Aus den Tarifen des Spielfelds wird der erste (in der Reihenfolge von fromMinute) genommen, dessen Tag in der Bitmaske aktiv ist und der die Startminute enthält (fromMinute ≤ inizio < toMinute). Der Preis ist proportional zu den tatsächlichen Minuten: arrotonda(pricePerHourCents × minuti / 60) — 90 Minuten zu 20,00 €/Std. ergeben 30,00 €. Eine Buchung, die sich über zwei Tarife erstreckt, wird weiterhin mit dem Tarif des Starts bewertet. Kein passender Tarif: priceCents ist null (Preis noch zu definieren), niemals 0.

Bei einem Tarif pro Person (pricingMode: "person") das stündliche Ergebnis mit den in Rechnung gestellten Personen multipliziert: max(playersCount, minPlayers). Beispiel mit dem Abendtarif oben (6,00 €/Person pro Stunde, Mindestanzahl 10): 60 Minuten bei 12 Personen → 72,00 €; bei 16 → 96,00 € (der Preis pro Person sinkt nicht); bei 8 → 60,00 € (das garantierte Minimum greift). Ohne playersCount ist der Preis nicht berechenbar: null beim Lesen, 400 players_required beim POST, der sich auf die Preisliste stützt.

Spezifische Fehler

CodeerrorWann
400invalid_inputcourtId fehlt oder ist keine UUID.
404not_found"Campo non trovato" — das Spielfeld existiert nicht oder gehört nicht dir.

Ein Spielfeld ohne Preisliste antwortet mit 200 und "rates": [].

7. Datenkonventionen

7.1 Daten und Uhrzeiten

  • Als Eingabe sind die Zeitpunkte ISO 8601-Strings mit obligatorischem Offset: 2026-08-12T18:00:00+02:00 oder 2026-08-12T18:00:00Z. Ein String ohne Offset (2026-08-12T18:00:00) wird mit 400 abgelehnt: Er wäre mehrdeutig, und für einen Kalender ist das eine Mehrdeutigkeit, die man mit um eine Stunde falschen Buchungen bezahlt.
  • Als Ausgabe sind die Zeitpunkte immer in UTC mit dem Suffix Z und Millisekunden normalisiert: "2026-08-12T16:00:00.000Z". Konvertiere sie vor der Anzeige in die lokale Zeitzone.
  • Die reinen Datumsangaben (date, closure.from, closure.to und from/to, wenn du sie in Form eines Tages verwendest) sind AAAA-MM-GG und beziehen sich auf den lokalen italienischen Tag.
  • Die Intervalle sind halboffen [inizio, fine): 18:00–19:00 und 19:00–20:00 stehen nicht im Konflikt.

7.2 Zeitzone

Buchungen werden als absolute Zeitpunkte gespeichert, aber alle Kalenderregeln — Wochentag, Tarife der Preisliste, Öffnungszeiten, Schließungsdaten, Tagesgrenzen — werden in der Zeitzone Europe/Rome ausgewertet, wobei die Sommerzeit automatisch verwaltet wird. Das Feld timezone der Antwort von /availability deklariert dies explizit. Wenn dein Server in UTC oder einer anderen Zeitzone läuft, konvertiere die Minuten nicht manuell: Sie sind bereits in der lokalen italienischen Zeit ausgedrückt.

7.3 Minuten ab Mitternacht

Die Uhrzeiten „laut Kalender“ (openMinute, closeMinute, fromMinute, toMinute) sind ganze Zahlen von 0 bis 1440, die die Minuten ab der lokalen Mitternacht zählen. Umrechnungen: ore = ⌊m / 60⌋, minuti = m mod 60.

MinutenLokale UhrzeitMinutenLokale Uhrzeit
000:00108018:00
48008:00132022:00
54009:00138023:00
84014:00144024:00 (Tagesende)

7.4 Beträge

Alle Beträge sind ganze Zahlen in Euro-Cent (priceCents, pricePerHourCents): kein Gleitkommawert, kein Währungssymbol. 2000 = 20,00 €. Bei einer Buchung bedeutet priceCents: null „Preis noch zu definieren“ und unterscheidet sich von 0, was „kostenlos“ bedeutet.

7.5 Status einer Buchung

StatusBedeutungBelegt den Slot?
pendingAusstehende Online-Buchungsanfrage, die auf die Entscheidung des Betreibers wartet. Sie entsteht nur aus Anfragen, die von Spielern über die VolleyFriends-App gesendet wurden (source: "app"): Der Betreiber nimmt sie an (confirmed) oder lehnt sie ab (cancelled).Ja — der Slot ist bereits blockiert, um Doppelbuchungen zur gleichen Zeit zu vermeiden
confirmedGültige Buchung, noch nicht kassiert. Dies ist der Anfangsstatus jeder Buchung, die über diese APIs und das Panel erstellt wird.Ja
paidGültige und kassierte Buchung. In der Regel von paymentMethod begleitet.Ja
cancelledBuchung storniert (oder Anfrage abgelehnt). Bleibt im Verlauf, gibt aber den Platz frei: Erzeugt kein overlap und erscheint nicht in /availability.Nein
Wie man mit „pending“-Buchungen umgeht
  • Du findest sie in GET /bookings und in den belegten Slots von /availability: behandle den Slot als nicht verfügbar, genau wie eine confirmed.
  • Du kannst auf die Anfrage aus deinem Verwaltungssystem mit einer PATCH antworten: {"status": "confirmed"} zum Annehmen, {"status": "cancelled"} zum Ablehnen. Der Spieler erhält eine Benachrichtigung über das Ergebnis.
  • Du erkennst sie an der Kombination status: "pending" + source: "app". Die Kundendaten stammen aus dem VolleyFriends-Profil des Spielers (Name und E-Mail), daher kann customerPhone den Wert null haben.
  • Erstelle keine pending-Buchungen über diese APIs: Der Wert wird zwar bei der Validierung akzeptiert, aber dieser Status beschreibt eine Anfrage, die auf eine Antwort des Betreibers wartet, und niemand würde auf deiner Seite darüber entscheiden. Wenn dein Ablauf einen Warenkorb oder eine ausstehende Zahlung enthält, verwalte die Wartezeit in deinem System und rufe die POST-Methode auf, sobald die Buchung endgültig ist — oder erstelle sie als confirmed und ändere sie auf cancelled, falls die Zahlung nicht eingeht.

7.6 Herkunft und Zahlungsmethode

FeldWerteBedeutung
sourcemanualVom Betreiber im Panel eingetragen.
apiVon einem externen Verwaltungssystem über diese APIs erstellt. Der Wert wird immer durch die POST-Methode festgelegt und ist nicht änderbar.
appOnline-Buchungsanfrage, die von einem Spieler über die VolleyFriends-App gesendet wurde: Sie startet als pending und wartet auf deine Entscheidung.
tournamentErzeugt durch die Organisation eines Turniers auf den Plätzen der Anlage.
paymentMethodcash, bank_transfer, paypal, stripe, otherWie kassiert wurde. null = nicht kassiert.

Beide sind Textdomänen: Neue Werte können in Zukunft hinzugefügt werden, ohne die Version zu ändern, daher darf dein Code bei einem unbekannten Wert keinen Fehler verursachen.

7.7 Personenbezogene Daten der Kunden

Name, Telefonnummer und E-Mail-Adresse, die du bei den Buchungen übermittelst, sind personenbezogene Daten deiner Kunden: Du bist der Verantwortliche für die Datenverarbeitung, VolleyFriends speichert sie in deinem Auftrag als Auftragsverarbeiter gemäß Art. 28 GDPR. Sende nur das, was für die Verwaltung des Platzes erforderlich ist, und informiere deine Kunden. Details findest du in der Datenschutzerklärung.

8. Allgemeine Fehler

Jeder Fehler hat denselben Aufbau: einen stabilen Code in error, der für deinen Code gedacht ist, und eine message auf Italienisch, die für Menschen gedacht ist. Triff deine Entscheidungen basierend auf error und dem HTTP-Status, nicht auf dem Text der Nachricht, der sich ändern kann.

{
  "error": "overlap",
  "message": "Il campo è già prenotato in quell'orario."
}

Validierungsfehler fügen issues hinzu, die detaillierte Liste der Probleme Feld für Feld:

{
  "error": "invalid_input",
  "message": "Dati non validi",
  "issues": [
    {
      "code": "invalid_string",
      "validation": "datetime",
      "path": ["startsAt"],
      "message": "Invalid datetime"
    }
  ]
}
HTTPerrorBedeutungWas zu tun ist
400invalid_inputUngültige Parameter oder ungültiger Body. Die Details befinden sich in issues.Korrigiere die Anfrage. Versuche es nicht identisch erneut: Das Ergebnis ändert sich nicht.
401invalid_keyHeader X-Api-Key fehlt, ist fehlerhaft, unbekannt oder widerrufen.Stelle sicher, dass du den Header sendest und dass der Schlüssel im Dashboard aktiv ist. Wenn er widerrufen wurde, generiere einen neuen.
403subscription_requiredKein aktives Abonnement «Spielfeld-Manager» auf dem Konto des Schlüsselbesitzers.Reaktiviere das Abonnement über die App (Profil → Manager-Bereich → Abonnement). Bis dahin funktioniert kein Aufruf.
403feature_not_includedAbonnement aktiv, aber der Tarif beinhaltet nicht «API für externe Verwaltungssysteme». Die Nachricht nennt den aktuellen Tarif.Wechsle zu einem Tarif, der diese Funktion enthält. Gilt für die gesamte v1, einschließlich Lesevorgängen.
404not_foundRessource existiert nicht oder gehört einem anderen Manager: Die beiden Situationen werden nicht unterschieden, um keine fremden Daten preiszugeben.Lies die IDs aus /venues und /bookings erneut aus: Fast immer handelt es sich um eine alte oder von einem anderen Konto kopierte ID.
409overlapDas Spielfeld ist im angeforderten Zeitraum bereits durch eine nicht stornierte Buchung belegt.Schlage ein anderes Zeitfenster vor: Lies /availability erneut aus. Versuche es nicht ohne Änderung der Uhrzeit erneut.
409venue_closedAußerordentliche Schließung der Anlage am angeforderten Datum.Schlage ein anderes Datum vor. Schließungen können aus /availability (closure) ausgelesen werden.
429rate_limitedLimit von 120 Anfragen pro Minute für den Schlüssel überschritten.Warte und versuche es mit exponentiellem Backoff erneut, unter Berücksichtigung von retry-after.
4xxerrorGenerischer Code für Anfragefehler, die nicht unter die oben genannten Fälle fallen (selten).Lies message und korrigiere die Anfrage.
500internalUnerwarteter Fehler auf unserer Seite.Versuche es später noch einmal. Wenn es weiterhin besteht, schreibe uns unter Angabe von Uhrzeit, Endpoint und Präfix des Schlüssels (nicht den Schlüssel).

Ein nicht existierender Pfad unter der Basis antwortet mit 404; das Gleiche gilt für eine nicht vorgesehene Methode auf einem existierenden Pfad:

{
  "error": "not_found",
  "message": "Risorsa non trovata"
}

Die Antworten 502, 503 und 504 kommen vom Reverse Proxy, wenn die API nicht erreichbar ist (Neustart oder Wartung): In diesen Fällen ist der Body nicht garantiert im JSON-Format. Behandle sie als temporäre Fehler und versuche es mit Backoff erneut, ohne zu versuchen, deren Inhalt zu lesen.

9. Versionen und Kompatibilität

Die Version befindet sich im Pfad: /manager-api/v1. Es müssen keine Versions-Header oder Release-Daten angegeben werden: Die einzige derzeit veröffentlichte Version ist v1.

Was wir ohne Vorankündigung ändern können

  • Felder hinzufügen zu bestehenden Antworten.
  • Optionale Parameter hinzufügen zu Anfragen, mit einem Standardwert, der das aktuelle Verhalten beibehält.
  • Neue Endpoints hinzufügen unter /v1.
  • Werte hinzufügen zu offenen Textfeldern (source, paymentMethod, surface).
  • Die message umformulieren bei Fehlern, während die error-Codes unverändert bleiben.

Was sich innerhalb von v1 nicht ändert

  • Kein Feld wird aus den Antworten entfernt oder umbenannt.
  • Kein Feld wird seinen Typ oder seine Bedeutung ändern.
  • Kein derzeit optionaler Parameter wird zu einem Pflichtparameter.
  • Die hier dokumentierten error-Codes und HTTP-Status bleiben unverändert.

Jede Änderung, die diese Garantien verletzt, wird unter einem neuen Präfix (/v2) eingeführt, wobei v1 in Betrieb bleibt und die betroffenen Betreiber vorab benachrichtigt werden.

Wie man einen Client schreibt, der nicht kaputtgeht
  • Ignoriere Felder, die du nicht kennst, anstatt bei ihnen einen Fehler auszulösen (kein „strict“-Parsing, das unerwartete Eigenschaften ablehnt).
  • Behandle unbekannte Werte offener Textfelder mit einem Fallback-Zweig.
  • Verlasse dich weder auf die Reihenfolge der JSON-Schlüssel noch auf den Text der Nachrichten.
  • Behandle null und ein fehlendes Feld beim Lesen als gleichwertig.

Changelog

VersionDatumNotizen
v1Jul 2026Kompatible Ergänzungen: Preise pro Person in der Preisliste (pricingMode, minPlayers) und playersCount bei Buchungen (mit dem Fehler players_required); Paginierung limit/offset auf der Buchungsliste; erneute Konfliktprüfung bei Reaktivierung einer stornierten Buchung; recurrence wird nun explizit mit 400 recurrence_unsupported abgelehnt (zuvor stillschweigend ignoriert).
v12026Erste öffentliche Version: Anlagen und Spielfelder, Buchungen (Liste, Erstellung, Bearbeitung), tägliche Verfügbarkeit, Preisliste. Authentifizierung mit X-Api-Key, 120 Anfragen/Minute pro Schlüssel.

10. Unterstützung bei der Integration

Bei technischen Fragen, unerwartetem Verhalten oder Anfragen zu Endpunkten, die du hier nicht findest, schreibe uns über die Seite Kontakt. Um direkt zum Punkt zu kommen, gib in der Nachricht Folgendes an:

  • Endpoint und Methode, die du aufrufst;
  • Datum und Uhrzeit des Aufrufs (mit Zeitzone) und den erhaltenen HTTP-Code;
  • Code error und Antwortnachricht;
  • Präfix des verwendeten Schlüssels (z. B. vfk_9f2c).
Niemals in der Nachricht

Sende uns den vollständigen API-Schlüssel über keinen Kanal, auch nicht zur Überprüfung eines Problems: Das Präfix reicht uns aus, um ihn zu identifizieren. Wenn du ihn bereits mit jemandem geteilt hast, widerrufe ihn und generiere einen neuen.

Wenn du die Integration testen möchtest, ohne den echten Kalender zu beeinflussen, erstelle eine Testanlage mit einem eigenen Spielfeld und verwende diese: Alle Aufrufe sind auf die Anlagen des Schlüsselbesitzers beschränkt, sodass der Rest deines Kontos nicht betroffen ist.