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.
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
- Ein Spielfeldbetreiber-Konto VolleyFriends mit mindestens einer Anlage und einem Spielfeld.
- Ein aktives Abonnement mit einem Tarif, der die Funktion „API für externe Verwaltungssysteme“ enthält. Die gesamte
v1— selbst reine Lesezugriffe — ist denjenigen vorbehalten, die diese Funktion haben: Es handelt sich um eine kostenpflichtige Funktion, nicht um ein Zubehör des Panels. - Ein im Verwaltungssystem generierter API-Schlüssel: admin.volleyfriends.com → Einstellungen → API-Schlüssel → Neuer 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)."
}
- 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."
}
- Verwende für den periodischen Abgleich nur einen einzigen Aufruf von
/bookingsmit einem großenfrom–to-Intervall anstelle eines Aufrufs pro Tag. - Speichere die Liste der Sportstätten und Spielfelder im Cache: Sie ändert sich selten.
- Warte im Falle eines
429und versuche es mit exponentiellem Backoff (z. B. 2, 4, 8 Sekunden) erneut, unter Berücksichtigung vonretry-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
/api/manager-api/v1/venuesListet 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
| Feld | Typ | Beschreibung |
|---|---|---|
venues[].id | uuid | Identifikator der Sportstätte (venueId in den anderen Endpunkten). |
venues[].name | string | Name der Sportstätte. |
venues[].city | string | null | Stadt. |
venues[].address | string | null | Adresse. |
venues[].verified | boolean | true, wenn die Anlage das Badge VERIFIZIERT hat. |
venues[].courts[] | array | Spielfelder der Anlage. Leeres Array, wenn keine vorhanden sind. |
courts[].id | uuid | ID des Spielfelds (courtId in den anderen Endpunkten). |
courts[].venueId | uuid | Anlage, zu der das Spielfeld gehört. |
courts[].name | string | Name des Spielfelds. |
courts[].surface | string | null | Belag, Freitext vom Betreiber eingegeben. |
courts[].indoor | boolean | Hallenspielfeld. |
courts[].lighting | boolean | Beleuchtung vorhanden. |
Wenn das Konto noch keine Anlagen hat, lautet die Antwort {"venues": []}.
Spezifische Fehler
Keine außer den allgemeinen.
6.2 Buchungsliste
/api/manager-api/v1/bookingsGibt 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)
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
venueId | uuid | nein | Auf eine Anlage beschränken. Wenn sie nicht dir gehört: 404 not_found. |
courtId | uuid | nein | Auf 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. |
from | ISO-Datum oder -Zeitstempel | nein | Inklusive unterer Grenze. Ein reines Datum AAAA-MM-GG gilt für die lokale italienische Mitternacht dieses Tages. |
to | ISO-Datum oder -Zeitstempel | nein | Exklusive 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. |
limit | integer 1–1000 | nein | Maximale Anzahl an Zeilen (Standardwert 500). |
offset | integer ≥ 0 | nein | Zu überspringende Zeilen (Standardwert 0): offset=500 ist die zweite Seite mit dem Standard-Limit. |
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).
| Feld | Typ | Beschreibung |
|---|---|---|
id | uuid | ID der Buchung. |
venueId | uuid | Sportstätte. |
courtId | uuid | Gebuchtes Spielfeld. |
courtName | string | Name des Spielfelds, zur einfacheren Anzeige. |
startsAt | ISO-Zeitstempel | Start, immer in UTC (Suffix Z). |
endsAt | ISO-Zeitstempel | Ende, Grenze exklusive. |
customerName | string | Name des Kunden. |
customerPhone | string | null | Telefon. |
customerEmail | string | null | E-Mail. |
priceCents | integer | null | Vereinbarter Preis in Cent. null = noch zu definieren (niemals 0 für „nicht definiert“). |
playersCount | integer | null | Anzahl der angegebenen Personen (nur Buchungen in Zeitfenstern mit Preis pro Person). null = nicht anwendbar oder nicht angegeben. |
status | string | pending · confirmed · paid · cancelled — siehe Status. |
paymentMethod | string | null | cash · bank_transfer · paypal · stripe · other. null = nicht kassiert. |
paymentLink | string | null | Vom Dashboard generierter Link für Kartenzahlung, falls vorhanden. Schreibgeschützt. |
notes | string | null | Freie Notizen. |
source | string | Quelle: manual (Dashboard) · api (diese API) · app (Anfrage eines Spielers aus der App) · tournament (Turnier). |
recurrenceId | uuid | null | Vorhanden und identisch bei allen Terminen einer über das Dashboard erstellten wiederkehrenden Serie. |
createdAt | ISO-Zeitstempel | Erstellung. |
updatedAt | ISO-Zeitstempel | Letzte Änderung. |
Spezifische Fehler
| Code | error | Wann |
|---|---|---|
| 400 | invalid_input | venueId/courtId sind keine UUIDs oder from/to sind keine interpretierbaren Datumswerte. |
| 404 | not_found | Die Anlage ("Struttura non trovata") oder das Spielfeld ("Campo non trovato") existiert nicht oder gehört dir nicht. |
6.3 Neue Buchung
/api/manager-api/v1/bookingsErstellt 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:
- Außerordentliche Schließung der Anlage am Startdatum →
409 venue_closed; - Überschneidung mit einer anderen, nicht stornierten Buchung desselben Spielfelds →
409 overlap; - 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 auchplayersCountbenötigt: Ohne diesen wird die Anfrage mit400 players_requiredabgelehnt (es sei denn, es wird ein expliziterpriceCentsangegeben).
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)
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
courtId | uuid | ja | Zu buchendes Spielfeld. Es muss zu einer deiner Anlagen gehören. |
startsAt | ISO 8601-Zeitstempel mit Offset | ja | Beginn. Akzeptiert werden sowohl das Format 2026-08-12T18:00:00Z als auch 2026-08-12T18:00:00+02:00. Ohne Offset: 400. |
endsAt | ISO 8601-Zeitstempel mit Offset | ja | Ende, muss nach startsAt liegen. |
customerName | string (1–160) | ja | Name des Kunden. |
customerPhone | string (max. 40) | nein | Telefon. |
customerEmail | E-Mail (max. 200) | nein | E-Mail, als Adresse validiert. |
priceCents | integer ≥ 0 | nein | Preis in Cent. Wenn weggelassen, wird er aus der Preisliste des Spielfelds berechnet. Gib 0 nur für eine wirklich kostenlose Buchung an. |
playersCount | integer 1–500 | nein | Wie 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. |
notes | string (max. 2000) | nein | Freie Notizen, für den Betreiber im Dashboard sichtbar. |
status | pending | confirmed | paid | cancelled | nein | Standardwert confirmed. Verwende von einem externen Verwaltungssystem aus confirmed oder paid: pending ist für Anfragen reserviert, die über die Spieler-App eingehen (siehe Status). |
paymentMethod | cash | bank_transfer | paypal | stripe | other | nein | Wie es kassiert wurde (oder wird). Weggelassen = nicht kassiert. |
recurrence | object | nein | Von 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
| Code | error | Wann |
|---|---|---|
| 400 | invalid_input | Ungültiger Body: fehlendes Pflichtfeld, Zeitstempel ohne Offset, endsAt liegt nicht nach startsAt, ungültige E-Mail, Längen außerhalb der Grenzwerte. |
| 400 | players_required | Preis soll aus der Preisliste für einen Zeitraum pro Person berechnet werden, aber playersCount fehlt. |
| 400 | recurrence_unsupported | Der Body enthält recurrence: Serientermine sind über diese APIs nicht verfügbar. |
| 403 | subscription_required | Kein aktives Betreiber-Abonnement. |
| 404 | not_found | "Campo non trovato" — die courtId existiert nicht oder gehört nicht dir. |
| 409 | venue_closed | Die Anlage hat eine außerordentliche Schließung am Startdatum. |
| 409 | overlap | Das 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)." }
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
/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
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
id | uuid | ja | ID 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.
| Name | Typ | Notizen |
|---|---|---|
courtId | uuid | Verschiebt die Buchung auf ein anderes deiner Spielfelder, auch in einer anderen deiner Anlagen (venueId wird entsprechend aktualisiert). |
startsAt | ISO-Zeitstempel mit Offset | Neuer Beginn. |
endsAt | ISO-Zeitstempel mit Offset | Neues Ende. Das Endergebnis muss nach dem Beginn liegen, auch wenn nur ein Grenzwert mit dem bereits gespeicherten Wert kombiniert wird. |
customerName | string (1–160) | — |
customerPhone | string (max. 40) | Aufhebbar. |
customerEmail | E-Mail (max. 200) | Aufhebbar. |
priceCents | integer ≥ 0 | Aufhebbar (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. |
playersCount | integer 1–500 | Aufhebbar. Aktualisiert nur die Daten: Der Preis wird nicht automatisch neu berechnet — wenn die Anzahl der Personen den Gesamtbetrag ändert, sende auch den neuen priceCents. |
notes | string (max. 2000) | Aufhebbar. |
status | pending | confirmed | paid | cancelled | Jeder Ü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. |
paymentMethod | cash | bank_transfer | paypal | stripe | other | Aufhebbar. |
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
| Code | error | Wann |
|---|---|---|
| 400 | invalid_input | Leerer 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"). |
| 403 | subscription_required | Kein aktives Betreiber-Abonnement. |
| 404 | not_found | "Prenotazione non trovata" oder "Campo non trovato", wenn die neue courtId nicht dir gehört. |
| 409 | venue_closed | Verschiebung auf ein Datum mit außerordentlicher Schließung. |
| 409 | overlap | Die neue Uhrzeit überschneidet sich mit einer anderen, nicht stornierten Buchung desselben Spielfelds. |
6.5 Verfügbarkeit eines Spielfelds an einem Tag
/api/manager-api/v1/availabilityGibt 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)
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
courtId | uuid | ja | Spielfeld, dessen Verfügbarkeit ausgelesen werden soll. Es muss dir gehören. |
date | AAAA-MM-GG | ja | Lokaler 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
| Feld | Typ | Beschreibung |
|---|---|---|
courtId | uuid | Angefordertes Spielfeld. |
venueId | uuid | Struktur des Spielfelds. |
date | AAAA-MM-GG | Angeforderter Tag, wiederholt. |
timezone | string | Immer "Europe/Rome": die Zeitzone, in der date und die Minuten der Uhrzeiten zu interpretieren sind. |
hours.weekday | integer 0–6 | Wochentag: 0 = Montag … 6 = Sonntag. |
hours.openMinute | integer | null | Öffnung in Minuten ab lokaler Mitternacht (540 = 09:00). null, wenn der Tag als geschlossen deklariert ist. |
hours.closeMinute | integer | null | Schließung in Minuten (1380 = 23:00). null, wenn der Tag als geschlossen deklariert ist. |
hours.closed | boolean | true, wenn der Betreiber diesen Wochentag als geschlossen deklariert hat. |
hours.configured | boolean | false, 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. |
closure | object | null | Außerordentliche Schließung am angeforderten Tag aktiv, oder null. |
closure.from | AAAA-MM-GG | Erster Tag der Schließung. |
closure.to | AAAA-MM-GG | Letzter Tag der Schließung, inklusive. |
closure.reason | string | null | Grund, falls vom Betreiber angegeben. |
bookings[] | array | Belegte 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. |
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
| Code | error | Wann |
|---|---|---|
| 400 | invalid_input | courtId fehlt oder ist keine UUID, date fehlt oder ist nicht im Format AAAA-MM-GG. |
| 404 | not_found | "Campo non trovato" — das Spielfeld existiert nicht oder gehört nicht dir. |
6.6 Preisliste eines Spielfelds
/api/manager-api/v1/ratesDie 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)
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
courtId | uuid | ja | Spielfeld, 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
| Feld | Typ | Beschreibung |
|---|---|---|
courtId | uuid | Angefordertes Spielfeld. |
rates[].id | uuid | Kennung des Zeitfensters. |
rates[].label | string | Vom Betreiber gewähltes Label (z. B. „Abendtarif“). |
rates[].daysMask | integer 1–127 | Bitmaske 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[].fromMinute | integer 0–1440 | Beginn des Zeitfensters in Minuten ab lokaler Mitternacht. |
rates[].toMinute | integer 0–1440 | Ende des Zeitfensters, immer größer als fromMinute. |
rates[].pricePerHourCents | integer > 0 | Stundenpreis in Cent (2000 = 20,00 €). Bei pricingMode: "person" ist es der Stundenpreis pro Person (600 = 6,00 €/Person pro Stunde). |
rates[].pricingMode | court | person | court = Preis des Spielfelds (Standard). person = Preis pro Person: Der Gesamtbetrag skaliert mit der Anzahl der Personen, jedoch nie nach unten. |
rates[].minPlayers | integer | null | Garantierte Mindestanzahl des Tarifs pro Person: Unter dieser Zahl wird trotzdem der Mindestpreis berechnet. null = kein Minimum. |
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
| Code | error | Wann |
|---|---|---|
| 400 | invalid_input | courtId fehlt oder ist keine UUID. |
| 404 | not_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:00oder2026-08-12T18:00:00Z. Ein String ohne Offset (2026-08-12T18:00:00) wird mit400abgelehnt: 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
Zund Millisekunden normalisiert:"2026-08-12T16:00:00.000Z". Konvertiere sie vor der Anzeige in die lokale Zeitzone. - Die reinen Datumsangaben (
date,closure.from,closure.toundfrom/to, wenn du sie in Form eines Tages verwendest) sindAAAA-MM-GGund 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.
| Minuten | Lokale Uhrzeit | Minuten | Lokale Uhrzeit |
|---|---|---|---|
| 0 | 00:00 | 1080 | 18:00 |
| 480 | 08:00 | 1320 | 22:00 |
| 540 | 09:00 | 1380 | 23:00 |
| 840 | 14:00 | 1440 | 24: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
| Status | Bedeutung | Belegt den Slot? |
|---|---|---|
pending | Ausstehende 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 |
confirmed | Gültige Buchung, noch nicht kassiert. Dies ist der Anfangsstatus jeder Buchung, die über diese APIs und das Panel erstellt wird. | Ja |
paid | Gültige und kassierte Buchung. In der Regel von paymentMethod begleitet. | Ja |
cancelled | Buchung storniert (oder Anfrage abgelehnt). Bleibt im Verlauf, gibt aber den Platz frei: Erzeugt kein overlap und erscheint nicht in /availability. | Nein |
- 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 kanncustomerPhoneden Wertnullhaben. - 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 alsconfirmedund ändere sie aufcancelled, falls die Zahlung nicht eingeht.
7.6 Herkunft und Zahlungsmethode
| Feld | Werte | Bedeutung |
|---|---|---|
source | manual | Vom Betreiber im Panel eingetragen. |
api | Von einem externen Verwaltungssystem über diese APIs erstellt. Der Wert wird immer durch die POST-Methode festgelegt und ist nicht änderbar. | |
app | Online-Buchungsanfrage, die von einem Spieler über die VolleyFriends-App gesendet wurde: Sie startet als pending und wartet auf deine Entscheidung. | |
tournament | Erzeugt durch die Organisation eines Turniers auf den Plätzen der Anlage. | |
paymentMethod | cash, bank_transfer, paypal, stripe, other | Wie 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"
}
]
}
| HTTP | error | Bedeutung | Was zu tun ist |
|---|---|---|---|
| 400 | invalid_input | Ungü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. |
| 401 | invalid_key | Header 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. |
| 403 | subscription_required | Kein 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. |
| 403 | feature_not_included | Abonnement 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. |
| 404 | not_found | Ressource 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. |
| 409 | overlap | Das 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. |
| 409 | venue_closed | Außerordentliche Schließung der Anlage am angeforderten Datum. | Schlage ein anderes Datum vor. Schließungen können aus /availability (closure) ausgelesen werden. |
| 429 | rate_limited | Limit 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. |
| 4xx | error | Generischer Code für Anfragefehler, die nicht unter die oben genannten Fälle fallen (selten). | Lies message und korrigiere die Anfrage. |
| 500 | internal | Unerwarteter 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
messageumformulieren bei Fehlern, während dieerror-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.
- 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
nullund ein fehlendes Feld beim Lesen als gleichwertig.
Changelog
| Version | Datum | Notizen |
|---|---|---|
| v1 | Jul 2026 | Kompatible 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). |
| v1 | 2026 | Erste ö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
errorund Antwortnachricht; - Präfix des verwendeten Schlüssels (z. B.
vfk_9f2c).
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.