> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.lettbestilt.no/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.lettbestilt.no/_mcp/server.

# Core concepts

## Money is in øre

All amounts are integers in øre: `1 NOK = 100 øre`, so `12900` is kr 129,00. The server calculates every price and total itself and ignores prices you send. Show the `totals` the API returns.

## Time

* Timestamps are ISO 8601 in UTC, for example `2026-10-11T16:30:00.000Z`. Format them for display in the `Europe/Oslo` time zone.
* Opening hours, menu schedules and coupon time windows are wall-clock times in Oslo (`"15:00"`), not UTC.
* Reservation dates (`date=2026-10-16`) are Oslo dates.

## Restaurants are identified by slug

The slug is the restaurant's LettBestilt subdomain: `pizzaroma` for `pizzaroma.lettbestilt.no`. Pass it as `?slug=`, except for the two coupon endpoints, which take it in the JSON body. The internal restaurant ID is not part of the API.

The API only answers for restaurants that are **live**. Until LettBestilt sets a restaurant live, every endpoint that takes a slug responds `404 RESTAURANT_NOT_FOUND`, except `GET /site-gate`.

## Order IDs and public tokens

`POST /orders` returns both `orderId` and `publicToken`.

* `publicToken` is safe to put in URLs and share with the customer. Use it for [order tracking](/api-reference/orders/get-order).
* `orderId` is internal. Keep it for support requests, but do not build URLs with it. Webhooks carry both.

## Capabilities

`/restaurant` and `/menu` include `restaurant.capabilities`:

```json
{
  "pickup": true,
  "delivery": false,
  "reservations": true,
  "payment": { "online": true, "cash": true }
}
```

Read this object instead of keeping your own feature flags. It follows the restaurant's settings, so your site never offers a flow the API would reject. `payment.online` covers card, Vipps and the other methods on SagaPay's hosted payment page. Treat a missing or `false` field as "not offered".

## Opening hours

`restaurant.openingHours` in `/menu` are the **kitchen's** hours and decide whether an order is accepted. Gate your ordering flow on them. `restaurant.venueHours` are when the doors are open, and are for display only; an empty list means the venue follows the kitchen. `restaurant.hoursOverrides` holds special opening hours, such as holidays.

## Preparation time

Rush mode adds minutes to the preparation time. `GET /prep-time` returns base time plus rush, already added up, and is never cached. Use it for "ready in about X minutes". The same value is in `restaurant.prepTime`, but that response is cached.

## Caching

| Endpoint                                     | Cache                                                                             |
| -------------------------------------------- | --------------------------------------------------------------------------------- |
| `GET /menu`                                  | 30 s at the edge, then served stale for up to 300 s while refreshing. Weak `ETag` |
| `GET /restaurant`                            | 60 s at the edge, then stale for up to 600 s while refreshing                     |
| `GET /dine-in/availability`                  | 15 s at the edge, then stale for up to 30 s                                       |
| `GET /prep-time`, `GET /site-gate`           | Never cached                                                                      |
| `GET /orders/{token}`, `GET /address-search` | Never cached (`private, no-store`)                                                |

Changes the restaurant makes in its dashboard therefore reach your site within a few minutes. Send `If-None-Match` with the menu's `ETag` to get a `304` when nothing has changed.

## Order statuses

| Status             | Meaning                                                    |
| ------------------ | ---------------------------------------------------------- |
| `AWAITING_PAYMENT` | Online order waiting for payment. Not shown to the kitchen |
| `PAID`             | Online payment confirmed                                   |
| `CONFIRMED`        | Accepted. Cash orders start here                           |
| `PREPARING`        | The kitchen is making it                                   |
| `READY_FOR_PICKUP` | Ready to be picked up                                      |
| `OUT_FOR_DELIVERY` | On its way                                                 |
| `COMPLETED`        | Picked up or delivered                                     |
| `CANCELLED`        | Cancelled by the restaurant                                |
| `FAILED`           | The online payment failed                                  |

A table reservation uses the same statuses: `PENDING_APPROVAL` while the restaurant decides, then `CONFIRMED` or `CANCELLED`.

## Address

`restaurant.address` is the restaurant's visiting address, or `null` if it has none. It is never an object with empty fields, so `address ?? fallback` works. `latitude` and `longitude` are either both set or both `null`.

## Language

Names and descriptions come in Norwegian, with English versions in `nameEn` and `descriptionEn` where the restaurant has entered them. Set `locale` to `nb` (default) or `en` on orders and reservations to choose the language of the emails LettBestilt sends to the customer. Error messages are often in Norwegian.

## API version

The API is versioned in the path (`/api/v1`). Every response carries `X-LettBestilt-Api-Version: 1`. New fields can be added to responses at any time, so ignore fields you do not know.