Authentication & permissions

Keys

  • A key looks like serveu_live_ followed by 43 letters, digits, - and _.
  • The business owner creates it in Settings → Developers and chooses its permissions and, optionally, one branch.
  • It is shown once. ServeU stores only a hash of it, so nobody (not even ServeU) can show it again: if it's lost, create a new one.
  • A key belongs to one business and only ever sees that business.

Sending the key

Send it on every request as a bearer token:

curl https://serveu-psi.vercel.app/api/v1/business -H "Authorization: Bearer serveu_live_XXXX…"
  • Always use HTTPS.
  • Call the API from your server, never from a browser or a mobile app: a key in an app can be read by anyone who has the app. The API sends no CORS headers, so browsers refuse to call it.
  • A missing, malformed, unknown or revoked key answers 401 unauthorized (with WWW-Authenticate: Bearer). The four look the same on purpose.
  • GET /api/v1/business answers the key's own name, permissions and branch: use it to check a key.

Permissions

PermissionWhat it allowsIncludesEndpoints
business:readRead the business, its branches and this key itself. Every key has it.—GET /businessGET /branches
orders:readSee orders and sales: list and get orders, and the sales summary.—GET /ordersGET /orders/summaryGET /orders/{id}
orders:writeMove orders along, mark them paid or reject them.orders:readPOST /orders/{id}/actions
loyalty:readFind a card by phone or scanned QR, and read its balance and history.—POST /cards/lookupGET /cards/{id}GET /cards/{id}/events
loyalty:writeJoin customers, add stamps and points, redeem rewards and undo (void) events.loyalty:readPOST /cardsPOST /cards/{id}/earnPOST /cards/{id}/redeemPOST /loyalty-events/{id}/void
menu:readRead categories, items, prices and sold-out state.—GET /menuGET /menu/items/{id}
menu:writeCreate, update and delete categories and items, and mark items sold out.menu:readPOST /menu/categoriesPATCH /menu/categories/{id}DELETE /menu/categories/{id}PUT /menu/categories/by-external-id/{externalId}POST /menu/itemsPATCH /menu/items/{id}DELETE /menu/items/{id}PUT /menu/items/by-external-id/{externalId}POST /menu/items/{id}/availability
customers:contactAdds customer.name and customer.phone to orders and cards. Nothing else.——
webhooks:manageLets the system manage its own webhook endpoints. Needs a key for all branches.—GET /webhook-endpointsPOST /webhook-endpointsGET /webhook-endpoints/{id}PATCH /webhook-endpoints/{id}DELETE /webhook-endpoints/{id}POST /webhook-endpoints/{id}/testPOST /webhook-endpoints/{id}/rotate-secret
stock:writeSet stock counts per item and branch (by id or your external_id, one at a time or up to 100 per call). ServeU takes stock off as customers order. Reading stock needs menu:read.—PUT /menu/items/{id}/stockPUT /menu/items/by-external-id/{externalId}/stockPOST /stock
  • A write permission includes its read permission: a key with loyalty:write can also look cards up.
  • business:read is on every key; you never ask for it.
  • customers:contact adds customer.name and customer.phone to orders and cards, and nothing else. Contact details are personal data under the PDPL: ask for this permission only if your system really needs them.
  • A request outside the key's permissions answers 403 insufficient_scope with the permission it needs in details:
{
  "error": {
    "code": "insufficient_scope",
    "message": "This API key doesn't have the permission for this request.",
    "details": { "required": "orders:write" },
    "request_id": "5f0c2a1e-8b3d-4c7a-9e21-6d4b8a0c3f19"
  }
}

Branch-bound keys

A key limited to one branch acts only at that branch:

  • Earns, redeems and joins happen at its branch; you don't need to send branch_id.
  • Naming another branch's branch_id (listing orders, the sales summary, earning, redeeming, joining) answers 403 forbidden.
  • Another branch's orders and loyalty events answer 404 not_found, so a key can't probe which ids exist elsewhere.
  • Business-wide changes (creating, changing or deleting menu categories and items) answer 403 forbidden. A menu sync needs a key for all branches.
  • Marking an item sold out (POST /api/v1/menu/items/{id}/availability) works at its own branch, with or without branch_id; another branch answers 404 not_found.
  • GET /api/v1/branches lists only its branch, and menu items show only its branch in branches.

Revoking and rotating

  • The owner revokes a key in Settings → Developers. The next request with it answers 401 unauthorized.
  • To rotate: create the new key, deploy it, check it with GET /api/v1/business, then revoke the old one.

Suspended businesses and API access

  • When a business is suspended, reads keep working (card lookup too) and writes answer 403 business_suspended.
  • If ServeU turns API access off for a business, every key answers 403 api_disabled until it is turned back on.
Never put a key in a URL, a log line, a chat or a support ticket. Quote the request_id instead.

Next: Errors →