Anmelden um den Slug und den veröffentlichbaren Schlüssel Ihrer Location in jedem Beispiel zu sehen.
Ihr Konto hat noch keine Location, die Beispiele behalten daher ihre Platzhalter. Abmelden
Angemeldet als · . Legen Sie in der Konsole einen veröffentlichbaren Schlüssel an und laden Sie die Seite neu, um ihn hier zu sehen. Abmelden
Angemeldet als · . Die Beispiele zeigen den veröffentlichbaren Schlüssel Ihrer Location. Abmelden
Entwicklerdokumentation
QR-Codes und Tischsitzungen
QR-Token zu seinem Tisch auflösen, sehen, was der Gast bestellen kann und auf der Rechnung hat, bestellen und die Rechnung schließen – ohne API-Schlüssel.
Jeder Tisch, jede Bahn, jede Scheibe kann einen gedruckten QR-Code tragen. Wer ihn scannt, öffnet eine Seite mit einem Token in der URL; dieses Token ist das Zugangsmerkmal für alles auf dieser Seite – es identifiziert Location und Ressource, lässt sich in der Konsole widerrufen und neu drucken und braucht keinen zusätzlichen API-Schlüssel. Eine Tischsitzung ist die offene Rechnung des Gastes an dieser Ressource: Sie beginnt mit der ersten Bestellung und endet, wenn die Rechnung geschlossen wird.
Endpunkte
GET /api/qr/{token}
Worauf der QR-Code zeigt – genug, um „Tisch 7 im The Neon Tap“ anzuzeigen, bevor der Gast etwas tut.
Antwort 200 OK
| Feld | Typ | Bedeutung |
|---|---|---|
venueSlug, venueName |
string | Die Location, für die weiteren Aufrufe und zur Anzeige |
resourceCode, resourceName |
string | Die Ressource (resourceCode ist ihre id in den Ressourcen der Location) |
resourceType |
string | Einer der Ressourcentypen |
{
"venueSlug": "demo-sportsbar",
"venueName": "The Neon Tap",
"resourceCode": "table-4a",
"resourceName": "Table 4",
"resourceType": "RestaurantTable"
}Fehler – 404 das Token ist unbekannt, widerrufen oder seine Location ist nicht mehr für QR-Codes berechtigt.
curl
curl "https://api.bookdineplay.com/api/qr/<token>"JavaScript
const token = new URL(location.href).searchParams.get('t');
const table = await (await fetch(`https://api.bookdineplay.com/api/qr/${encodeURIComponent(token)}`)).json();
document.title = `${table.resourceName} · ${table.venueName}`;C#
var table = await client.ResolveQrTokenAsync(token, cancellationToken);GET /api/qr/{token}/session
Die Sicht des Gastes auf den Tisch: die Speisekarten, aus denen er hier bestellen darf, und die laufende Rechnung. Vor der ersten Bestellung ist die Sitzung noch nicht offen – isOpen ist false und tab leer –, so entscheidet eine Seite auch, ob sie „Bestellen“ oder „Ihre Rechnung“ zeigt.
Antwort 200 OK
| Feld | Typ | Bedeutung |
|---|---|---|
resourceCode, resourceName, resourceType |
string | Der Tisch |
isOpen |
boolean | Ob eine Rechnung offen ist |
currency |
string | Währung jedes Betrags darunter |
menus[] |
object[] | Bestellbare Karten für diese Ressource: id, name, kind (Food oder Drinks), groups[] → items[] mit name, description, price, currency, taxRate (nullable), imageUrl (nullable). Ein Billardtisch bekommt ggf. nur die Getränkekarte, ein Restauranttisch beide |
tab[] |
object[] | Zusammengefasste Positionen über alle Bestellungen der Sitzung: itemName, quantity, unitPrice, lineTotal |
runningTotal |
decimal | Summe der Rechnung |
{
"resourceCode": "table-4a",
"resourceName": "Table 4",
"resourceType": "RestaurantTable",
"isOpen": false,
"currency": "EUR",
"menus": [
{
"id": "kitchen",
"name": "Kitchen",
"kind": "Food",
"groups": [
{
"name": "Small plates",
"description": null,
"items": [
{
"name": "Loaded nachos",
"description": "Melted cheese, jalapeños, lime crema",
"price": 9.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/nachos.webp"
},
{
"name": "Buffalo wings",
"description": "Blue-cheese dip, celery",
"price": 11.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/wings.webp"
},
{
"name": "Padrón peppers",
"description": "Sea salt, olive oil",
"price": 7.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/padron-peppers.webp"
}
]
},
{
"name": "Mains",
"description": null,
"items": [
{
"name": "Smash burger",
"description": "Double patty, house sauce, fries",
"price": 14.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/smash-burger.webp"
},
{
"name": "BBQ ribs",
"description": "Slow-cooked, slaw, fries",
"price": 19.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/bbq-ribs.webp"
},
{
"name": "Halloumi flatbread",
"description": "Grilled halloumi, harissa, greens",
"price": 13.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/halloumi-flatbread.webp"
}
]
},
{
"name": "Sweet",
"description": null,
"items": [
{
"name": "Churros",
"description": "Cinnamon sugar, chocolate",
"price": 7.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/churros.webp"
}
]
}
]
},
{
"id": "bar",
"name": "Bar",
"kind": "Drinks",
"groups": [
{
"name": "Draft beer",
"description": null,
"items": [
{
"name": "House lager 0.3L",
"description": "Crisp pilsner",
"price": 4.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/lager.webp"
},
{
"name": "Local IPA 0.5L",
"description": "Hoppy, citrus finish",
"price": 6.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/ipa.webp"
}
]
},
{
"name": "Cocktails",
"description": null,
"items": [
{
"name": "Old Fashioned",
"description": "Bourbon, bitters, orange",
"price": 11.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/old-fashioned.webp"
},
{
"name": "Spicy margarita",
"description": "Tequila, chilli, lime",
"price": 10.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/margarita.webp"
}
]
},
{
"name": "Zero proof",
"description": null,
"items": [
{
"name": "Craft soda",
"description": "House-made, ask for today's flavour",
"price": 4.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/craft-soda.webp"
}
]
}
]
}
],
"tab": [],
"runningTotal": 0
}Listen im Beispiel sind auf drei Einträge gekürzt.
Fehler – 404 Token nicht aktiv.
curl
curl "https://api.bookdineplay.com/api/qr/<token>/session"JavaScript
const session = await (await fetch(`https://api.bookdineplay.com/api/qr/${encodeURIComponent(token)}/session`)).json();
const drinks = session.menus.find(m => m.kind === 'Drinks');C#
var session = await client.GetTableSessionAsync(token, cancellationToken);POST /api/qr/{token}/orders
Eine Bestellung aufgeben: eine oder mehrere Positionen, jede mit einer Karte per id und einer Position per name, wie sie in den menus der Sitzung stehen. Die erste Bestellung öffnet die Sitzung; jede Bestellung hält den Preis zum Bestellzeitpunkt auf der Rechnung fest. Die Antwort ist die aktualisierte Sitzung.
Request-Body (Content-Type: application/json)
| Feld | Erforderlich | Bedeutung |
|---|---|---|
lines[] |
ja, mindestens eine | menuId (eine Karten-id aus der Sitzung), itemName (ein Positions-name in dieser Karte), quantity (positiv) |
Antwort 200 OK – dieselbe Struktur wie GET …/session, jetzt mit den neuen Positionen auf tab.
{
"resourceCode": "table-4a",
"resourceName": "Table 4",
"resourceType": "RestaurantTable",
"isOpen": true,
"currency": "EUR",
"menus": [
{
"id": "kitchen",
"name": "Kitchen",
"kind": "Food",
"groups": [
{
"name": "Small plates",
"description": null,
"items": [
{
"name": "Loaded nachos",
"description": "Melted cheese, jalapeños, lime crema",
"price": 9.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/nachos.webp"
},
{
"name": "Buffalo wings",
"description": "Blue-cheese dip, celery",
"price": 11.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/wings.webp"
},
{
"name": "Padrón peppers",
"description": "Sea salt, olive oil",
"price": 7.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/padron-peppers.webp"
}
]
},
{
"name": "Mains",
"description": null,
"items": [
{
"name": "Smash burger",
"description": "Double patty, house sauce, fries",
"price": 14.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/smash-burger.webp"
},
{
"name": "BBQ ribs",
"description": "Slow-cooked, slaw, fries",
"price": 19.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/bbq-ribs.webp"
},
{
"name": "Halloumi flatbread",
"description": "Grilled halloumi, harissa, greens",
"price": 13.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/halloumi-flatbread.webp"
}
]
},
{
"name": "Sweet",
"description": null,
"items": [
{
"name": "Churros",
"description": "Cinnamon sugar, chocolate",
"price": 7.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/churros.webp"
}
]
}
]
},
{
"id": "bar",
"name": "Bar",
"kind": "Drinks",
"groups": [
{
"name": "Draft beer",
"description": null,
"items": [
{
"name": "House lager 0.3L",
"description": "Crisp pilsner",
"price": 4.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/lager.webp"
},
{
"name": "Local IPA 0.5L",
"description": "Hoppy, citrus finish",
"price": 6.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/ipa.webp"
}
]
},
{
"name": "Cocktails",
"description": null,
"items": [
{
"name": "Old Fashioned",
"description": "Bourbon, bitters, orange",
"price": 11.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/old-fashioned.webp"
},
{
"name": "Spicy margarita",
"description": "Tequila, chilli, lime",
"price": 10.50,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/margarita.webp"
}
]
},
{
"name": "Zero proof",
"description": null,
"items": [
{
"name": "Craft soda",
"description": "House-made, ask for today's flavour",
"price": 4.00,
"currency": "EUR",
"taxRate": 0.19,
"imageUrl": "_content/BookDinePlay.App.Shared/menu/craft-soda.webp"
}
]
}
]
}
],
"tab": [
{
"itemName": "Loaded nachos",
"quantity": 2,
"unitPrice": 9.50,
"lineTotal": 19.00
},
{
"itemName": "House lager 0.3L",
"quantity": 1,
"unitPrice": 4.50,
"lineTotal": 4.50
}
],
"runningTotal": 23.50
}Fehler
| Status | Wann |
|---|---|
400 |
lines fehlt oder ist leer (errors.lines); oder eine Position nennt eine Karte oder Position, die an dieser Ressource nicht bestellbar ist – nichts wird aufgegeben |
404 |
Token nicht aktiv |
409 |
Die Rechnung wurde zwischen dem Lesen des Gastes und dieser Bestellung geschlossen. Sitzung neu lesen; die nächste Bestellung öffnet eine neue Rechnung |
curl
curl -X POST "https://api.bookdineplay.com/api/qr/<token>/orders" \
-H "Content-Type: application/json" \
-d '{ "lines": [ { "menuId": "kitchen", "itemName": "Smash burger", "quantity": 2 }, { "menuId": "bar", "itemName": "House lager", "quantity": 1 } ] }'JavaScript
const updated = await (await fetch(`https://api.bookdineplay.com/api/qr/${encodeURIComponent(token)}/orders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ lines: [{ menuId: 'kitchen', itemName: 'Smash burger', quantity: 2 }] })
})).json();
console.log(updated.runningTotal, updated.currency);C#
var updated = await client.PlaceOrderAsync(token, new PlaceOrderRequest([
new OrderLineRequest("kitchen", "Smash burger", 2),
new OrderLineRequest("bar", "House lager", 1)
]), cancellationToken);Die Positionsnamen in den Beispielen sind illustrativ – verwenden Sie die Namen aus den menus der Sitzung.
POST /api/qr/{token}/close
Die Rechnung schließen. Die Antwort ist die Rechnung: jede Position, die Zwischensumme, die darin enthaltene Steuer und die Gesamtsumme. Die Sitzung endet; die nächste Bestellung des Gastes beginnt eine neue.
Antwort 200 OK
| Feld | Typ | Bedeutung |
|---|---|---|
lines[] |
object[] | itemName, quantity, lineTotal |
subtotal, taxTotal, total |
decimal | Preise verstehen sich inklusive Steuer: total ist, was der Gast zahlt, taxTotal die darin enthaltene Steuer |
currency |
string | |
issuedAt |
ISO-8601-Zeitpunkt | Wann die Rechnung geschlossen wurde |
{
"lines": [
{
"itemName": "Loaded nachos",
"quantity": 2,
"lineTotal": 19.00
},
{
"itemName": "House lager 0.3L",
"quantity": 1,
"lineTotal": 4.50
}
],
"subtotal": 19.75,
"taxTotal": 3.75,
"total": 23.50,
"currency": "EUR",
"issuedAt": "2026-09-15T12:55:15.3387817+00:00"
}Fehler – 404 Token nicht aktiv oder keine offene Sitzung zum Schließen.
curl
curl -X POST "https://api.bookdineplay.com/api/qr/<token>/close"JavaScript
const invoice = await (await fetch(`https://api.bookdineplay.com/api/qr/${encodeURIComponent(token)}/close`, { method: 'POST' })).json();
console.log(invoice.total, invoice.currency);C#
var invoice = await client.CloseTableSessionAsync(token, cancellationToken);