Developers

Table Buddy API v1

Server-to-server access to one restaurant. The API uses the same order, stock and report engines as the console.

Your first request

Create a scoped key under API Keys. Store it as TABLEBUDDY_API_KEY on your server and set TABLEBUDDY_URL to this installation’s origin.

curl "$TABLEBUDDY_URL/api/v1/restaurant" \
  -H "Authorization: Bearer $TABLEBUDDY_API_KEY"

Keys are shown once, stored as a SHA-256 digest, expire after the selected lifetime and can be revoked. Every request rechecks the creator’s membership, suspension status and current permissions. A key is revoked outright when its creator signs out everywhere, resets a lost password, is suspended or has their sessions ended by the platform, or leaves or is removed from the restaurant; being invited back does not revive it, so issue a new key. A routine password change keeps keys working. Browser cookies do not authenticate API calls.

Writes have no idempotency support. Do not automatically retry a timed-out POST: it may already have succeeded. Check the order or stock card first. Payments and refunds are performed in the console, where cash drawer rules apply.

Conventions

  • Base path: /api/v1. Send JSON with Content-Type: application/json. Maximum body: 1 MiB.
  • Money is integer minor units; each response carries currency and minor_digits. Rates ending in _bp are basis points (750 means 7.5%). Stock quantities ending in _milli are thousandths of the material unit.
  • Instants are ISO timestamps. Report days use the restaurant’s IANA time zone.
  • Lists accept limit (1–100, default 50) and cursor. Responses contain data, has_more and next_cursor. Copy the last response’s cursor. Categories, items, tables and materials use ID order; orders and stock movements are newest first. The report catalogue is a complete, unpaginated list.
  • Keys allow 60 requests per minute in a shared fixed window. A 429 response includes Retry-After; all authenticated responses include rate-limit headers and a request-id.
  • Errors use {"error":{"code":"...","message":"..."}}. Expect 401 for invalid keys, 403 for missing scopes or lost issuer access, 404 for unknown resources, 409 for a business-rule refusal, 413 for large bodies, 415 for non-JSON, 422 for invalid fields and 429 for limits.
  • Requests begun before a revocation may finish. Keep keys out of URLs, browser code and logs.

Endpoints

Select a section below for request examples. {id} is a resource ID; for reports it is the report slug.

Method and pathScopePurpose
GET /api/v1/restaurantAny valid keyRestaurant profile and currency
GET /api/v1/menu/categoriesmenu:readList menu categories
GET /api/v1/menu/itemsmenu:readList menu items and add-ons
GET /api/v1/menu/items/{id}menu:readGet a menu item
PATCH /api/v1/menu/items/{id}/availabilitymenu:writeSet menu availability
GET /api/v1/tablestables:readList tables
PATCH /api/v1/tables/{id}/statustables:writeSet an unoccupied table status
GET /api/v1/ordersorders:readList orders (newest first)
GET /api/v1/orders/{id}orders:readGet an order and its lines
POST /api/v1/ordersorders:writeCreate an order
POST /api/v1/orders/{id}/itemsorders:writeAdd a round to an order
POST /api/v1/orders/{id}/sendorders:writeSend unsent items to the kitchen
POST /api/v1/orders/{id}/cancelorders:cancelCancel an unpaid order
GET /api/v1/inventory/materialsinventory:readList materials and stock balances
GET /api/v1/inventory/materials/{id}inventory:readGet a material
GET /api/v1/inventory/materials/{id}/movementsinventory:readGet a stock card
POST /api/v1/inventory/materials/{id}/adjustmentsinventory:writeAdjust stock
GET /api/v1/reportsreports:readList available reports
GET /api/v1/reports/{id}reports:readRun a report; id is its catalogue slug

Restaurant profile and currency

GET /api/v1/restaurant

Required scope: any valid key.

No request body.

List menu categories

GET /api/v1/menu/categories

Required scope: menu:read.

No request body.

Set menu availability

PATCH /api/v1/menu/items/{id}/availability

Required scope: menu:write.

{
  "available": false
}

List tables

GET /api/v1/tables

Required scope: tables:read.

No request body.

Set an unoccupied table status

PATCH /api/v1/tables/{id}/status

Required scope: tables:write.

{
  "status": "CLEANING"
}

status: AVAILABLE, RESERVED or CLEANING. Tables with open orders cannot be changed by hand.

List orders (newest first)

GET /api/v1/orders

Required scope: orders:read.

No request body.

Get an order and its lines

GET /api/v1/orders/{id}

Required scope: orders:read.

No request body.

Create an order

POST /api/v1/orders

Required scope: orders:write.

{
  "type": "COUNTER",
  "lines": [
    {
      "menu_item_id": "ITEM_ID",
      "quantity": 1,
      "addon_ids": []
    }
  ],
  "send": false
}

type: DINE_IN, TAKEAWAY, COUNTER or DELIVERY. lines: 1–200 items; quantity: 1–999; up to 40 addon_ids per line. Optional table_id, customer_name (100 characters), customer_phone (40), delivery_address (500), guests (1–999), note (500). send defaults to false. Dine-in requires a table when table ordering is enabled; delivery requires delivery_address. An item whose category is hidden from the POS (is_active false under menu/categories) is refused with 409, as it is at the till — here and when adding a round.

Add a round to an order

POST /api/v1/orders/{id}/items

Required scope: orders:write.

{
  "lines": [
    {
      "menu_item_id": "ITEM_ID",
      "quantity": 1,
      "addon_ids": []
    }
  ],
  "send": false
}

Send unsent items to the kitchen

POST /api/v1/orders/{id}/send

Required scope: orders:write.

{}

Cancel an unpaid order

POST /api/v1/orders/{id}/cancel

Required scope: orders:cancel.

{
  "reason": "Duplicate order"
}

List materials and stock balances

GET /api/v1/inventory/materials

Required scope: inventory:read.

No request body.

Get a material

GET /api/v1/inventory/materials/{id}

Required scope: inventory:read.

No request body.

Get a stock card

GET /api/v1/inventory/materials/{id}/movements

Required scope: inventory:read.

No request body.

Adjust stock

POST /api/v1/inventory/materials/{id}/adjustments

Required scope: inventory:write.

{
  "mode": "count",
  "quantity_milli": 1500,
  "reason": "Physical count"
}

mode: in, out, wastage or count. quantity_milli: non-negative integer. Optional unit_cost is minor currency units per whole material unit. reason is required (up to 300 characters). Stock out and wastage cannot exceed on-hand.

List available reports

GET /api/v1/reports

Required scope: reports:read.

No request body.

Run a report; id is its catalogue slug

GET /api/v1/reports/{id}

Required scope: reports:read.

No request body.

Use day=YYYY-MM-DD, month=YYYY-MM, or from/to day keys according to the catalogue’s span. Presets: today, yesterday, 7d, 30d, month, lastMonth, 90d, year. The resolved span is returned; future or out-of-range dates follow the console’s clamping rules. Pending settlement always reports now. Report results retain the console’s column keys and raw values for consistent rendering.