Partner API
The partner API, under https://www.lettbestilt.no/api/v1/partner, lets you create sandboxes, read a restaurant’s setup, rotate and revoke its keys, and manage its webhooks without opening the partner portal. Everything it does can also be done in the portal.
Partner keys are test keys for now (lbp_test_…). They see and create only sandboxes. Live partner keys are not available yet; real restaurants are created in the partner portal.
Two keys
The partner key alone can only see the surface and create new restaurants. Anything that touches an existing restaurant also needs that restaurant’s own key. A leaked partner key can therefore not read details about, change or delete a restaurant.
Send them like this:
Rules for the pair:
- Both keys must be in the same environment. A test partner key with a live restaurant key fails with
401 UNAUTHORIZED. - The restaurant key must have full access (scope
*). A key limited to some scopes gives403 INSUFFICIENT_SCOPE. The key you get when you create a restaurant has full access. - The
slugin the path must match the restaurant key. A slug that does not exist, belongs to another partner or does not match the key always gives the same404 RESTAURANT_NOT_FOUND, so the API never tells you who owns a slug. - Older restaurant keys without an environment in the prefix (
lbs_<random>) are not accepted. Rotate them in the partner portal first. - The partner key is rejected on every other
/api/v1endpoint with401. Use the restaurant key there, as before.
Server to server only
Call the partner API from your back end. A request with an Origin header is rejected with 403 FORBIDDEN, and preflight requests get no Access-Control-Allow-* headers, so a browser can never use it. Never put a partner key in browser code, a mobile app or a repository.
Create a restaurant
POST /partner/restaurants with a test partner key creates a sandbox: a restaurant that is never live, has no ordering page on {slug}.lettbestilt.no, and accepts test orders through /api/v1. A partner can have up to 20 sandboxes.
The Idempotency-Key header is required. Use a new key, for example a UUID, for every restaurant you want to create, and reuse it only to retry that request.
The 201 response contains the new restaurant key in plain text, once, in restaurantKey.key. Store it before you do anything else: every call about this restaurant needs it, and LettBestilt cannot show it again.
Retries and replays
The Idempotency-Key is remembered per partner for 30 days.
A replay never returns the restaurant key again. If the first response was lost (a timeout, for example) and you never stored the key, create a new key for the restaurant in the partner portal.
A slug that is already in use gives 409 SLUG_TAKEN. That does not count towards the limit on creations.
Read, list and delete
GET /partner/restaurantslists your restaurants with slug, name, environment, whether it is live or archived, and when it was created. It is paginated: passnextCursorback ascursoruntil it isnull.limitis 1–100 (default 25).GET /partner/restaurants/{slug}returns setup status, SagaPay status (real restaurants only), verified domains, webhooks without secrets, and the restaurant’s keys: name, last four characters, environment, scopes and expiry.DELETE /partner/restaurants/{slug}:- A sandbox is deleted for good, together with its keys. A second
DELETEwith the same key therefore gives401. Confirm with the list that the slug is gone. A sandbox with accounting records that must be kept cannot be deleted (409 RETENTION). - A real restaurant is never deleted. It is archived: turned off and closed in
/api/v1, while orders and accounting records are kept. Its webhooks are paused. You can still read it, revoke its keys and delete its webhooks, but not rotate keys or add webhooks (409 RESTAURANT_ARCHIVED). Only LettBestilt can restore an archived restaurant.
- A sandbox is deleted for good, together with its keys. A second
Keys and webhooks
- Rotate a restaurant key with
POST …/keys/{keyId}/rotate. The new key gets the same scopes, and the old one keeps working forgraceHours(default 24). See Rotating keys without downtime. - Revoke with
DELETE …/keys/{keyId}, now (graceHours: 0, the default) or after up to 24 hours. You cannot revoke the key you are calling with immediately (409 KEY_IN_USE); rotate it instead. - Webhooks:
GET …/webhookslists them,POST …/webhookscreates one (the signing secret is in the response, once),DELETE …/webhooks/{webhookId}removes one. A restaurant can have up to 10. Pausing, resending and test events are in the partner portal; see Webhooks.
Key ids are in apiKeys in GET /partner/restaurants/{slug}.
Rate limits
Over the limit you get 429 RATE_LIMITED with Retry-After.
Responses and errors
- Every response with content wraps it in
data. Responses are never cached (Cache-Control: no-store) and always carryX-Request-Id. - Validation errors are
422 VALIDATION_FAILEDwitherror.details.issues, also forlimitandcursor. Invalid JSON is400 INVALID_JSON. - Calls with a restaurant key appear in that restaurant’s API log in the partner portal. Calls with the partner key alone (list and create) do not, because they are not about one restaurant. See Debugging with request IDs.
All codes are listed in Errors, and every endpoint in the API reference.

