Schankpilot API
REST/JSON API für POS-Apps, Küchen-Display-Systeme und Runner-Apps. Authentifizierung via Laravel Sanctum (Bearer Token).
Alle Endpunkte erfordern den Header X-Location-ID, um den Standort zu identifizieren.
Authentifizierung
Die API verwendet Laravel Sanctum (Token-basierte Authentifizierung). Nach dem Login wird ein Bearer Token zurückgegeben, der bei allen weiteren Requests im Authorization-Header mitgegeben werden muss.
E-Mail-Login
Für Account-Inhaber und Manager. Token ist 30 Tage gültig und erlaubt den Zugriff auf alle zugeordneten Standorte.
- → E-Mail + Passwort
- → Gibt Liste aller Standorte zurück
- → Token-Ablauf: 30 Tage
PIN-Login
Für managed Staff (Kellner, Koch, Runner). Token ist 12 Stunden gültig, enthält eine Location-Ability und ist an einen Standort gebunden.
- → user_id + PIN (4-stellig) + location_id
- → Ability:
location:{id} - → Token-Ablauf: 12 Stunden
Authorization: Bearer 1|bx3dG6HQP0zefSkTQpXnJyCmVwR5uDsAl...
Content-Type: application/json
Accept: application/json
X-Location-ID: 3
Headers
| Header | Pflicht | Beschreibung |
|---|---|---|
| Authorization | Ja* | Bearer {token} — bei allen geschützten Endpunkten |
| X-Location-ID | Ja* | ID des aktiven Standorts — bei allen standortbezogenen Endpunkten |
| Content-Type | Empfohlen | application/json bei allen POST/PATCH-Requests |
| Accept | Empfohlen | application/json — stellt sicher, dass Fehler als JSON zurückkommen |
* Nicht erforderlich bei öffentlichen Endpunkten wie POST /auth/login, POST /auth/pin und GET /auth/staff/{id}.
Fehlerbehandlung
Alle Fehler werden als JSON zurückgegeben. Das Feld message enthält eine lesbare Fehlermeldung. Bei Validierungsfehlern (422) enthält errors ein Objekt mit feldspezifischen Fehlern.
| HTTP-Code | Bedeutung |
|---|---|
| 200 | OK |
| 201 | Ressource erstellt |
| 401 | Nicht authentifiziert |
| 403 | Kein Zugriff |
| 404 | Nicht gefunden |
| 422 | Validierungsfehler |
| 429 | Rate Limit überschritten |
| 500 | Serverfehler |
Beispiel: Validierungsfehler (422)
{
"message": "The given data was invalid.",
"errors": {
"email": [
"Die eingegebenen Anmeldedaten sind nicht korrekt."
],
"items.0.quantity": [
"The quantity field must be at least 1."
]
}
}
Beispiel: Allgemeiner Fehler (403)
{
"message": "You do not have access to this location."
}
Rate Limiting
API-Requests sind auf 60 Requests pro Minute pro Token begrenzt (Laravel-Standard). Der PIN-Login ist zusätzlich auf 5 Versuche pro Minute pro User-ID + IP gedrosselt.
| Response-Header | Beschreibung |
|---|---|
| X-RateLimit-Limit | Maximale Anzahl erlaubter Requests pro Fenster |
| X-RateLimit-Remaining | Verbleibende Requests im aktuellen Fenster |
| Retry-After | Sekunden bis zum Zurücksetzen (nur bei 429) |
Auth
Authentifizierung und Token-Verwaltung. Keine Authorization-Header erforderlich außer bei logout und me.
/api/v1/auth/login
E-Mail-Login — Authentifiziert einen Account-Inhaber oder Manager via E-Mail und Passwort. Gibt ein Token und die Liste aller zugänglichen Standorte zurück.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| string | Ja | E-Mail-Adresse des Benutzers | |
| password | string | Ja | Passwort |
| device | string | Nein | Gerätename zur Identifikation des Tokens (z. B. „POS-iPad-1") |
Request
{
"email": "chef@restaurant.at",
"password": "geheim1234",
"device": "manager-macbook"
}
Response 200 OK
{
"token": "1|bx3dG6HQP0zef...",
"token_type": "Bearer",
"expires_at": "2026-05-15T14:00:00Z",
"user": {
"id": 1,
"name": "Max Mustermann",
"email": "chef@restaurant.at",
"is_managed": false
},
"locations": [
{
"id": 3,
"name": "Restaurant Zum Goldenen Hirsch",
"tenant_name": "Hirsch Gastronomie GmbH",
"role": "manager"
}
]
}
/api/v1/auth/pin
PIN-Login (Personal) — Authentifiziert einen managed Staff-Account (Kellner, Koch, Runner) via user_id, PIN und location_id. Das zurückgegebene Token ist auf 12 Stunden und einen Standort begrenzt.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| location_id | integer | Ja | ID des Standorts, an dem die Person arbeitet |
| user_id | integer | Ja | ID des Staff-Mitglieds |
| pin | string | Ja | 4-stellige PIN |
| device | string | Nein | Gerätename |
Request
{
"location_id": 3,
"user_id": 12,
"pin": "4812",
"device": "pos-ipad-1"
}
Response 200 OK
{
"token": "2|Xk9pLqR7mNvY...",
"token_type": "Bearer",
"expires_at": "2026-04-16T08:00:00Z",
"user": {
"id": 12,
"name": "Anna Kellner",
"is_managed": true,
"role": "waiter_cashier"
},
"location": {
"id": 3,
"name": "Restaurant Zum Goldenen Hirsch"
}
}
/api/v1/auth/staff/{locationId}
Personal einer Location abrufen — Gibt alle managed Staff-Mitglieder eines Standorts zurück. Wird vom PIN-Login-Screen verwendet, um die Auswahlliste zu befüllen. Kein Token erforderlich.
Request
GET /api/v1/auth/staff/3
Response 200 OK
{
"location": { "id": 3, "name": "Restaurant Zum Goldenen Hirsch" },
"staff": [
{ "id": 12, "name": "Anna Kellner" },
{ "id": 15, "name": "Bernd Koch" }
]
}
/api/v1/auth/logout
Logout — Widerruft das aktuelle Access Token. Nach dem Logout sind alle weiteren Requests mit diesem Token ungültig.
Request
DELETE /api/v1/auth/logout
Authorization: Bearer {token}
Response 200 OK
{
"message": "Abgemeldet."
}
/api/v1/auth/me
Aktueller Benutzer — Gibt die Daten des aktuell authentifizierten Benutzers und seine zugänglichen Standorte zurück.
Request
GET /api/v1/auth/me
Authorization: Bearer {token}
Response 200 OK
{
"id": 1,
"name": "Max Mustermann",
"email": "chef@restaurant.at",
"is_managed": false,
"locations": [
{
"id": 3,
"name": "Restaurant Zum Goldenen Hirsch",
"tenant_name": "Hirsch Gastronomie GmbH",
"role": "manager"
}
]
}
Tables
Tische des Standorts mit ihrem aktuellen Status. Das Feld active_order_id verweist auf die laufende Bestellung des Tisches, sofern vorhanden.
/api/v1/tables
Alle Tische — Gibt alle Tische des Standorts zurück, sortiert nach Name. Enthält die ID der aktiven Bestellung, falls der Tisch besetzt ist.
Request
GET /api/v1/tables
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": [
{
"id": 1,
"name": "Tisch 1",
"capacity": 4,
"status": "free",
"is_reservable": true,
"active_order_id": null
},
{
"id": 2,
"name": "Tisch 2",
"capacity": 2,
"status": "occupied",
"is_reservable": true,
"active_order_id": 117
}
]
}
/api/v1/tables/{id}
Einzelner Tisch — Gibt einen einzelnen Tisch mit seiner aktiven Bestellung (inklusive Items) zurück.
Request
GET /api/v1/tables/2
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": {
"id": 2,
"name": "Tisch 2",
"capacity": 2,
"status": "occupied",
"active_order_id": 117
}
}
Orders
Bestellungen anlegen und verwalten. Standardmäßig werden nur aktive Bestellungen (pending, working, ready) zurückgegeben.
| Status | Bedeutung | Farbe |
|---|---|---|
| pending | Eingegangen, noch nicht in Bearbeitung | |
| working | Wird in der Küche/Bar zubereitet | |
| ready | Bereit zur Ausgabe / Abholung | |
| completed | Abgeschlossen und verrechnet | |
| cancelled | Storniert |
/api/v1/orders
Bestellungen abrufen — Gibt aktive Bestellungen des Standorts zurück. Optional filterbar nach Status (einzelner Wert oder Array) und Tisch-ID.
Query-Parameter
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string|array | Nein | Filter: pending, working, ready, completed, cancelled (Standard: pending+working+ready) |
| table_id | integer | Nein | Filter nach Tisch-ID |
Request
GET /api/v1/orders?status[]=pending&status[]=working
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": [
{
"id": 117,
"status": "working",
"status_label": "In Zubereitung",
"table_id": 2,
"table_name": "Tisch 2",
"pickup_number": null,
"total_amount": 32.70,
"note": null,
"created_at": "2026-04-15T18:42:00Z",
"items": [
{
"id": 301,
"product_id": 42,
"product_name": "Bruschetta",
"quantity": 2,
"price": 6.90,
"total_price": 13.80,
"options": { "Größe": "Groß" },
"note": "Ohne Knoblauch",
"course": "Vorspeise",
"status": "working",
"is_called": false,
"production_station": { "id": 2, "name": "Küche" }
}
]
}
]
}
/api/v1/orders
Bestellung erstellen — Erstellt eine neue Bestellung mit einem oder mehreren Positionen. Der Preis wird zum Zeitpunkt der Bestellung aus der Datenbank übernommen. Optionen werden als Key-Value-Objekt übergeben.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| table_id | integer | Nein | Tisch-ID (null für Counter/Takeaway) |
| note | string | Nein | Bestellnotiz (max. 500 Zeichen) |
| items | array | Ja | Mindestens eine Bestellposition |
| items[].product_id | integer | Ja | ID des Produkts |
| items[].quantity | integer | Ja | Menge (min. 1) |
| items[].options | object | Nein | Ausgewählte Optionen als { "OptionName": "Choice" } |
| items[].note | string | Nein | Positionsnotiz (max. 255 Zeichen) |
| items[].course | string | Nein | Kurs (Getränke, Vorspeise, Hauptspeise, …) |
Request
POST /api/v1/orders
Authorization: Bearer {token}
X-Location-ID: 3
Content-Type: application/json
{
"table_id": 2,
"items": [
{
"product_id": 42,
"quantity": 2,
"options": { "Größe": "Groß" },
"note": "Ohne Knoblauch"
},
{
"product_id": 88,
"quantity": 1
}
]
}
Response 200 OK
{
"data": {
"id": 118,
"status": "pending",
"total_amount": 21.80,
"table_id": 2,
"items": [...]
}
}
/api/v1/orders/{id}
Einzelne Bestellung — Gibt eine einzelne Bestellung mit allen Items zurück.
Request
GET /api/v1/orders/117
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": { "id": 117, "status": "working", ... }
}
/api/v1/orders/{id}/items
Positionen hinzufügen — Fügt einer bestehenden Bestellung neue Positionen hinzu. Nur möglich wenn die Bestellung im Status pending oder working ist.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| items | array | Ja | Array von Bestellpositionen (gleiche Struktur wie beim Erstellen) |
Request
POST /api/v1/orders/117/items
Authorization: Bearer {token}
X-Location-ID: 3
{
"items": [
{ "product_id": 55, "quantity": 1 }
]
}
Response 200 OK
{
"data": { "id": 117, "total_amount": 40.20, "items": [...] }
}
/api/v1/orders/{id}/items/{itemId}
Position entfernen — Entfernt eine Bestellposition, solange sie noch nicht verrechnet ist (invoice_id ist null). Der Bestellbetrag wird entsprechend aktualisiert.
Request
DELETE /api/v1/orders/117/items/301
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": { "id": 117, "total_amount": 26.40, "items": [...] }
}
/api/v1/orders/{id}/status
Bestellstatus aktualisieren — Ändert den Status einer Bestellung manuell. Wird vom Kellner verwendet, um z. B. eine Bestellung als abgeschlossen zu markieren.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string | Ja | Einer von: pending, working, ready, completed, cancelled |
Request
PATCH /api/v1/orders/117/status
Authorization: Bearer {token}
X-Location-ID: 3
{ "status": "completed" }
Response 200 OK
{
"data": { "id": 117, "status": "completed", ... }
}
Kitchen
Endpunkte für das Küchen-Display-System (KDS). Gibt aktive Bestellungen nach Produktionsstation gefiltert zurück und ermöglicht das Weiterrücken des Item-Status. Der KDS-Status-Workflow: pending → working → ready → served.
/api/v1/kitchen/orders
Offene Bestellungen (KDS) — Gibt alle Bestellungen mit offenen Items zurück. Optional filterbar nach Produktionsstation. Zeigt nur Items im Status pending oder working.
Query-Parameter
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| station_id | integer | Nein | Filter auf eine Produktionsstation (Küche, Bar, etc.) |
Request
GET /api/v1/kitchen/orders?station_id=2
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": [
{
"id": 117,
"status": "working",
"table_name": "Tisch 2",
"created_at": "2026-04-15T18:42:00Z",
"items": [
{
"id": 301,
"product_name": "Bruschetta",
"quantity": 2,
"status": "working",
"note": "Ohne Knoblauch",
"production_station": { "id": 2, "name": "Küche" }
}
]
}
]
}
/api/v1/kitchen/stations
Produktionsstationen — Gibt alle Produktionsstationen des Tenants zurück (z. B. Küche, Bar, Ausgabe). Wird zum Initialisieren von Station-Filtern verwendet.
Request
GET /api/v1/kitchen/stations
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
[
{ "id": 1, "name": "Bar" },
{ "id": 2, "name": "Küche" },
{ "id": 3, "name": "Ausgabe" }
]
/api/v1/kitchen/items/{id}/status
Item-Status aktualisieren — Ändert den Status einer einzelnen Bestellposition. Löst automatisch ein Status-Update auf der übergeordneten Order aus (z. B. working wenn erste Item gestartet, ready wenn alle Items ready/served sind).
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string | Ja | Einer von: pending, working, ready, served |
Request
PATCH /api/v1/kitchen/items/301/status
Authorization: Bearer {token}
X-Location-ID: 3
{ "status": "ready" }
Response 200 OK
{
"item_id": 301,
"status": "ready",
"order": { "id": 117, "status": "ready", ... }
}
/api/v1/kitchen/orders/{id}/station-status
Alle Items einer Station fertig melden — Setzt alle offenen Items einer Bestellung für eine bestimmte Station auf einen neuen Status. Nützlich für den „Alles fertig"-Button auf dem KDS-Display.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string | Ja | Einer von: working, ready, served |
| station_id | integer | Ja | ID der Produktionsstation |
Request
PATCH /api/v1/kitchen/orders/117/station-status
Authorization: Bearer {token}
X-Location-ID: 3
{
"status": "ready",
"station_id": 2
}
Response 200 OK
{
"data": { "id": 117, "status": "ready", "items": [...] }
}
Runner
Aufgaben für das Ausgabe-Personal (Runner). Der Status-Workflow: pending → picked_up → completed. Beim Setzen auf picked_up wird der aktuelle Benutzer als Runner eingetragen.
/api/v1/runner/tasks
Offene Runner-Aufgaben — Gibt offene Runner-Aufgaben für den Standort zurück. Standardmäßig nur pending und picked_up. Mit dem Parameter status kann auf andere Zustände gefiltert werden.
Query-Parameter
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string|array | Nein | Filter: pending, picked_up, completed (Standard: pending+picked_up) |
Request
GET /api/v1/runner/tasks
Authorization: Bearer {token}
X-Location-ID: 3
Response 200 OK
{
"data": [
{
"id": 45,
"status": "pending",
"table_name": "Tisch 2",
"production_station": { "id": 2, "name": "Küche" },
"items": [
{
"id": 301,
"product_name": "Bruschetta",
"quantity": 2,
"course": "Vorspeise",
"note": "Ohne Knoblauch"
}
],
"created_at": "2026-04-15T18:52:00Z"
}
]
}
/api/v1/runner/tasks/{id}/status
Aufgaben-Status aktualisieren — Ändert den Status einer Runner-Aufgabe. Beim Setzen auf picked_up wird der aktuell authentifizierte Benutzer als Runner eingetragen.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| status | string | Ja | Einer von: pending, picked_up, completed |
Request
PATCH /api/v1/runner/tasks/45/status
Authorization: Bearer {token}
X-Location-ID: 3
{ "status": "picked_up" }
Response 200 OK
{
"data": {
"id": 45,
"status": "picked_up",
"table_name": "Tisch 2",
...
}
}
Status-Codes Referenz
Order-Status
pendingworkingreadycompletedcancelled
OrderItem-Status (KDS)
pendingworkingreadyserved
RunnerTask-Status
pendingpicked_upcompleted
Datentypen
| Typ | Format | Beispiel |
|---|---|---|
| Preis | float (Dezimalzahl, 2 Stellen) | 6.90 |
| Datum/Zeit | ISO 8601 UTC | 2026-04-15T18:42:00Z |
| Optionen (OrderItem) | JSON-Objekt { "Name": "Auswahl" } | { "Größe": "Groß" } |
| Allergene | Array von Buchstaben-Codes (EU-VO 1169/2011) | ["A", "G", "L"] |
| Boolean | true / false | true |