Authentication and scopes
A key belongs to one restaurant and acts as the person who made it, cut down, endpoint by endpoint, to the scope that endpoint is filed under. It never acts as an owner or an admin, and it can do nothing its maker cannot do in the console.
Sending the key
Send it as a bearer token. x-api-key is accepted too, for clients that cannot send one; when both are sent, Authorization wins. Prefer Authorization: a proxy’s logs are more likely to keep a custom header.
Authorization: Bearer $TABLEBUDDY_API_KEY # or x-api-key: $TABLEBUDDY_API_KEY
Who makes keys
Keys are made under API Keys in the console. Owners and admins make them, and so can anyone whose staff role has Create API keys (api.keys), for keys of their own. Someone who holds Change restaurant settings (settings.manage) sees and revokes every key in the restaurant. A maker may put on a key only the scopes their own role allows; the form shows the rest disabled, with the reason.
Scopes
A key’s scopes are chosen when it is made and never change: a new need is a new key. Calling an endpoint outside them answers 403 insufficient_scope. A scope with a caution is never ticked for you; a new key starts with the reads that carry none, so it starts read-only and holds no guest, staff or pay details.
- Moves money
- Guest details
- Staff details
- Pay and labor cost
- Cancels or voids
- Emails staff
- menu:readRead the menuTicked on a new key
Its maker needs one of: Take orders on the POS (
pos.use), Edit the menu (menu.manage)It grants, on its endpoints: Take orders on the POS (
pos.use), Edit the menu (menu.manage) - menu:writeMark items sold out
Its maker needs one of: Edit the menu (
menu.manage)It grants, on its endpoints: Edit the menu (
menu.manage) - tables:readRead tablesTicked on a new key
Its maker needs one of: Manage tables and reservations (
tables.manage), Take orders on the POS (pos.use)It grants, on its endpoints: Manage tables and reservations (
tables.manage), Take orders on the POS (pos.use)Endpoints: - tables:writeSet table status
Its maker needs one of: Manage tables and reservations (
tables.manage), Take orders on the POS (pos.use)It grants, on its endpoints: Manage tables and reservations (
tables.manage), Take orders on the POS (pos.use)Endpoints: - orders:readGuest detailsRead orders, payments and tips
Its maker needs one of: Take orders on the POS (
pos.use), View reports (reports.view)It grants, on its endpoints: Take orders on the POS (
pos.use), View reports (reports.view)Endpoints: - orders:writeCreate orders, send rounds and change unsent items
Its maker needs one of: Take orders on the POS (
pos.use)It grants, on its endpoints: Take orders on the POS (
pos.use) - orders:cancelCancels or voidsCancel unpaid orders
Its maker needs one of: Cancel orders and items (
pos.void)It grants, on its endpoints: Cancel orders and items (
pos.void)Endpoints: - inventory:readRead stock and costsTicked on a new key
Its maker needs one of: View stock (
inventory.view)It grants, on its endpoints: View stock (
inventory.view) - inventory:writeAdjust stock
Its maker needs one of: Adjust stock (
inventory.manage)It grants, on its endpoints: Adjust stock (
inventory.manage)Endpoints: - payroll:readPay and labor costRead pay, labor cost and labor %
Its maker needs one of: Pay rates and payroll (
payroll.manage)It grants, on its endpoints: Pay rates and payroll (
payroll.manage)Also counts on these, beside their own scope: - reports:readRead reportsTicked on a new key
Its maker needs one of: View reports (
reports.view)It grants, on its endpoints: View reports (
reports.view)Endpoints: - no scopeAny valid key
What a scope lets a key call grows only on purpose: a stronger power arrives as a new scope that no existing key carries, and an endpoint filed under a scope keys already hold is announced in the changelog first.
Endpoint by endpoint
On each request the API works out what the key may do on that endpoint alone: its maker’s permissions today, cut down to what the endpoint’s scope grants. Another scope on the same key adds nothing there. The one deliberate exception is written on the endpoint’s page: a scope such as payroll:read that widens it when the key carries both. Each endpoint page names the permission its maker needs, and the answer is 403 permission_required, naming it, when the key’s permissions there do not include it.
- The maker’s permissions are read on every request, so taking a permission away takes it from their keys at once.
- A key is never an owner or an admin to the engines, and never oversees a cash drawer: cash moves only through its maker’s own open drawer.
- A write made with a key is recorded in the restaurant’s activity log as its maker’s act, marked as made through the API.
What ends a key
- Someone revokes it under API Keys.
- Its creator signs out everywhere.
- Its creator resets a lost password.
- The platform suspends its creator, or ends their sessions.
- Its creator leaves the restaurant, or is removed from it. Being invited back does not revive it: make a new key.
- It reaches the end of the lifetime chosen when it was made.
- Its creator no longer holds any permission that could put one of its scopes on a key: those endpoints answer
issuer_permission_changeduntil the permission is back.
- A routine password change keeps keys working.
A request already under way when a key is revoked may finish; the next one is refused.
401 and 403
A 401 carries WWW-Authenticate and no rate-limit headers: the key is not known yet, so it has no window to report. A missing or malformed key costs nothing; a well-formed key that is unknown, revoked or expired counts toward a limit per network (see Rate limits).
missing_api_keyAuthorization: Bearer header and no x-api-key header.Fix: Send the key as Authorization: Bearer <key>.
WWW-Authenticate: Bearer realm="Table Buddy API"
invalid_api_keyFix: Check the key on API Keys; make a new one if it was revoked or expired.
WWW-Authenticate: Bearer realm="Table Buddy API", error="invalid_token", error_description="The API key is invalid, expired or revoked"
insufficient_scopeFix: Scopes are fixed when a key is made: make a new key with the scope.
WWW-Authenticate: Bearer realm="Table Buddy API", error="insufficient_scope", scope="orders:read"
issuer_access_endedFix: Make a new key from an active account.
issuer_permission_changedFix: Ask an owner to restore the permission, or make a new key from an account that holds it.
permission_requiredFix: Use a key with the named scope, from a creator who holds the named permission.