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(withWWW-Authenticate: Bearer). The four look the same on purpose. GET /api/v1/businessanswers the key's own name, permissions and branch: use it to check a key.
Permissions
| Permission | What it allows | Includes | Endpoints |
|---|---|---|---|
business:read | Read the business, its branches and this key itself. Every key has it. | — | GET /businessGET /branches |
orders:read | See orders and sales: list and get orders, and the sales summary. | — | GET /ordersGET /orders/summaryGET /orders/{id} |
orders:write | Move orders along, mark them paid or reject them. | orders:read | POST /orders/{id}/actions |
loyalty:read | Find a card by phone or scanned QR, and read its balance and history. | — | POST /cards/lookupGET /cards/{id}GET /cards/{id}/events |
loyalty:write | Join customers, add stamps and points, redeem rewards and undo (void) events. | loyalty:read | POST /cardsPOST /cards/{id}/earnPOST /cards/{id}/redeemPOST /loyalty-events/{id}/void |
menu:read | Read categories, items, prices and sold-out state. | — | GET /menuGET /menu/items/{id} |
menu:write | Create, update and delete categories and items, and mark items sold out. | menu:read | POST /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:contact | Adds customer.name and customer.phone to orders and cards. Nothing else. | — | — |
webhooks:manage | Lets 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:write | Set 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:writecan also look cards up. business:readis on every key; you never ask for it.customers:contactaddscustomer.nameandcustomer.phoneto 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_scopewith the permission it needs indetails:
{
"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) answers403 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 withoutbranch_id; another branch answers404 not_found. GET /api/v1/brancheslists only its branch, and menu items show only its branch inbranches.
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_disableduntil 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.