Gastronomie-API
Reservierungs-API für Drittanbieter-Integrationen — Verfügbarkeit prüfen, reservieren, stornieren, ändern und Reservierungen abfragen, unabhängig vom eingesetzten Reservierungssystem des Restaurants.
Basis-URL
https://apointa.org/api/partner/v1Alle Anfragen müssen über HTTPS erfolgen.
Authentifizierung
Jeder Endpunkt (außer /health) erfordert ein Bearer-Token:
Authorization: Bearer apt_live_...Sie erhalten genau einen API-Key pro Partner-Konto. Er gilt für alle Restaurants, die Sie in Ihrem Dashboard hinzugefügt haben. Der Zugriff auf ein nicht freigeschaltetes Restaurant liefert 403 FORBIDDEN.
Rate Limits
60 Anfragen pro Minute pro API-Key über alle Endpunkte hinweg. Bei Überschreitung wird 429 Too Many Requests zurückgegeben.
Tipp: Bei Voice AI sollten Verfügbarkeitsprüfungen für dasselbe Tupel (restaurantId, date, time, partySize) zwischengespeichert werden.
Fehlerbehandlung
Alle Fehler werden als JSON zurückgegeben:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description"
}
}| Code | Status | Wann |
|---|---|---|
| UNAUTHORIZED | 401 | API-Key fehlt oder ist ungültig |
| FORBIDDEN | 403 | Restaurant für diesen API-Key nicht freigegeben |
| VALIDATION_ERROR | 400 | Request-Body besteht die Validierung nicht |
| NOT_FOUND | 404 | Restaurant oder Reservierung nicht gefunden |
| PROVIDER_ERROR | 502 | Fehler im vorgelagerten Reservierungssystem |
| RATE_LIMITED | 429 | Rate Limit überschritten |
Endpunkte
/healthLiveness-Probe. Keine Authentifizierung erforderlich.
Response
{ "status": "ok", "version": "1.0.0" }/check-availabilityPrüft, ob ein bestimmter Zeitslot verfügbar ist. Es wird keine Reservierung angelegt.
Request-Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| restaurantId | string | ja | Restaurant-ID — Sie finden sie in Ihrem Dashboard |
| date | string | ja | JJJJ-MM-TT (Ortsdatum) |
| time | string | ja | HH:MM im 24-Stunden-Format (Ortszeit) |
| partySize | integer | ja | Anzahl der Gäste (1-50) |
Request
{
"restaurantId": "35YDWSFbm7I",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4
}Response
{
"success": true,
"data": {
"available": true,
"closed": false,
"alternatives": ["19:00", "19:45", "20:00"]
}
}/bookErstellt eine echte Reservierung. Jeder erfolgreiche Aufruf legt eine verbindliche Buchung an — nicht zum Testen verwenden. Pflicht sind nur Vorname und Telefonnummer.
Request-Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| restaurantId | string | ja | Restaurant-ID — Sie finden sie in Ihrem Dashboard |
| date | string | ja | JJJJ-MM-TT |
| time | string | ja | HH:MM |
| partySize | integer | ja | Anzahl der Gäste (1-50) |
| customer.firstName | string | ja | Vorname des Gastes |
| customer.lastName | string | nein | Nachname des Gastes. Fehlt er, buchen wir mit einem neutralen Platzhalter. |
| customer.phone | string[] | ja | Telefonnummern des Gastes als Array, primäre Nummer zuerst |
| customer.email | string | nein | E-Mail des Gastes |
| specialRequests | string | nein | Freitext-Hinweis |
Request
{
"restaurantId": "35YDWSFbm7I",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4,
"customer": {
"firstName": "Max",
"lastName": "Mustermann",
"phone": ["+491701234567", "+4989123456"],
"email": "max@example.com"
},
"specialRequests": "Table by the window"
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "confirmed",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4
}
}/cancelStorniert eine Reservierung. Entweder über die reservationId oder — wenn Ihr System sie nicht kennt — über die Telefonnummer, optional mit Datum und Uhrzeit zur Eingrenzung.
Request-Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| restaurantId | string | ja | Restaurant-ID — Sie finden sie in Ihrem Dashboard |
| reservationId | string | nein | ID aus der Antwort von /book. Alternativ per Telefonnummer suchen. |
| phone | string[] | nein | Telefonnummern des Gastes als Array — auch alternative Nummern werden durchsucht. |
| date | string | nein | Datum der Reservierung, grenzt bei mehreren Treffern ein |
| time | string | nein | Uhrzeit der Reservierung, grenzt bei mehreren Treffern ein |
Request
{
"restaurantId": "35YDWSFbm7I",
"reservationId": "gn-a1b2c3d4"
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "cancelled",
"date": "2026-08-15",
"time": "19:30"
}
}/updateFordert eine Änderung an. Die Reservierung wird wie bei /cancel gefunden. Das Restaurant wird benachrichtigt und übernimmt die Änderung.
Request-Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| restaurantId | string | ja | Restaurant-ID — Sie finden sie in Ihrem Dashboard |
| reservationId | string | nein | ID aus der Antwort von /book. Alternativ per Telefonnummer suchen. |
| phone | string[] | nein | Telefonnummern des Gastes als Array — auch alternative Nummern werden durchsucht. |
| date | string | nein | Datum der Reservierung, grenzt bei mehreren Treffern ein |
| time | string | nein | Uhrzeit der Reservierung, grenzt bei mehreren Treffern ein |
| updates.date | string | nein | Neues Datum JJJJ-MM-TT |
| updates.time | string | nein | Neue Uhrzeit HH:MM |
| updates.partySize | integer | nein | Neue Personenzahl |
| updates.specialRequests | string | nein | Neuer Hinweis |
Request
{
"restaurantId": "35YDWSFbm7I",
"phone": ["+491701234567"],
"date": "2026-08-15",
"time": "19:30",
"updates": {
"partySize": 6,
"specialRequests": "Guest with allergies"
}
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "pending",
"message": "Update request forwarded to restaurant."
}
}/reservationsSucht bestehende Reservierungen anhand der Telefonnummern. Liefert nur zukünftige Reservierungen.
Request-Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| restaurantId | string | ja | Restaurant-ID — Sie finden sie in Ihrem Dashboard |
| phone | string[] | ja | Telefonnummern des Gastes als Array — auch alternative Nummern werden durchsucht. |
Request
{
"restaurantId": "35YDWSFbm7I",
"phone": ["+491701234567", "+4989123456"]
}Response
{
"success": true,
"data": {
"reservations": [
{
"reservationId": "gn-a1b2c3d4",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4,
"specialRequests": "Table by the window"
}
]
}
}Wichtig: nur Reservierungen aus diesem System
Die API sieht ausschließlich Reservierungen, die über dieses System angelegt wurden. Hat der Gast telefonisch, über die Website des Restaurants oder einen anderen Kanal reserviert, ist sie für /reservations, /update und /cancel unsichtbar.
In diesem Fall antworten /cancel und /update mit 404 NOT_FOUND. Gleichzeitig benachrichtigen wir automatisch das Restaurant per E-Mail mit allen übermittelten Angaben.
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "No reservation found that was created through this API. The restaurant staff has been notified and will handle the cancellation."
}
}Fangen Sie diesen Fall in Ihrem System ab und teilen Sie dem Anrufer mit, dass ein Mitarbeiter informiert wurde und sich darum kümmert — genau das passiert im Hintergrund.
Format der Telefonnummer
Geben Sie die Ländervorwahl immer im E.164-Format an:
+491701234567(Deutschland)+436641234567(Österreich)+41791234567(Schweiz)
Telefonnummern werden immer als Array übergeben. Kennt Ihr System eine zweite Nummer des Gastes, geben Sie sie mit an — wir durchsuchen alle.
Support
Kontaktieren Sie das Apointa-Team mit: Zeitstempel der Anfrage (UTC), restaurantId, vollständigem Request-Body (personenbezogene Daten schwärzen), HTTP-Status und Response-Body.
