> 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.

# From sandbox to live

A sandbox is a test restaurant that belongs to you, the partner. It answers in `/api/v1` with a test key, takes test orders and simulated online payments, and is kept out of SagaPay, invoicing and accounting. You build the whole site against it, then point the finished site at the real restaurant.

### Create a sandbox

Either in the partner portal, or with the [partner API](/partner-api):

```bash
curl -X POST "https://www.lettbestilt.no/api/v1/partner/restaurants" \
  -H "Authorization: Bearer $LETTBESTILT_PARTNER_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name":"Pizza Roma (test)","slug":"pizzaroma-test","email":"dev@byraet.no"}'
```

Store `restaurantKey.key` from the response. It is a test key (`lbs_test_…`) with full access, and it is shown only once. You can have up to 20 sandboxes.

Emails from a sandbox, such as order confirmations, only go to your own partner addresses, never to the address a test customer types.

### Build the site against the sandbox

Use the test key from your server exactly as you will use the live key later:

**`.env.local`**

```bash title=".env.local"
LETTBESTILT_SLUG=pizzaroma-test
LETTBESTILT_API_KEY=lbs_test_...
```

To place test orders, the sandbox needs products and opening hours, like any restaurant. Orders outside the kitchen's opening hours are rejected.

### Test payments

Create an order with `paymentMethod: "STRIPE"`. In a sandbox, `stripeUrl` points to LettBestilt's test payment page instead of SagaPay:

* **Betal (test)** marks the order `PAID`, sends `ORDER_PAID` to your webhooks as a real payment would, and returns the customer to `successUrl`.
* **Avbryt** (cancel) marks the order `FAILED` and returns the customer to `cancelUrl`. No webhook is sent, as with a real abandoned payment.

No money moves. `restaurant.capabilities.payment.online` is `true` in a sandbox when online payment is turned on, so your checkout shows it. See [Payments](/payments#testing-payments-in-a-sandbox).

### Test webhooks

Create a webhook for the sandbox (portal or `POST /partner/restaurants/{slug}/webhooks`) and use **Send test event** (*Send testhendelse*) in the portal to check that your endpoint verifies the signature. Then place a test order and follow the deliveries in the webhook's delivery log. See [Webhooks](/webhooks).

### Check the integration

In the restaurant's API section in the partner portal, **Check integration** (*Sjekk integrasjonen*) shows whether the key has been used, webhooks are delivered, the API log has errors and your return URLs were accepted. Fix anything red before you move on. See [Debugging with request IDs](/debugging).

### Get the real restaurant ready

The real restaurant is a separate restaurant with its own slug. It is not the sandbox switched on: a sandbox is never live.

1. Sign the partner agreement and the data processing agreement in the partner portal, under **Get started** (*Kom i gang*). Until you have, you cannot add real restaurants.
2. Add the restaurant in the partner portal. Live partner keys are not available yet, so this cannot be done through the API.
3. Ask LettBestilt to invite the owner. The owner signs the restaurant's own agreements, sets up online payment with SagaPay (with BankID) and sets the restaurant live. Partners cannot do these steps for the owner.
4. Ask LettBestilt to verify every hostname the site runs on, both `example.no` and `www.example.no` if you use both. Domains cannot be registered through the API.

Until the restaurant is live, `/api/v1` answers `404 RESTAURANT_NOT_FOUND` for it (except `GET /site-gate`).

### Create the live key and webhooks

In the restaurant's API section in the partner portal, create a key. It is a live key (`lbs_live_…`). Give it only the scopes the site needs, or full access if you also want to manage the restaurant through the partner API. Then create the webhooks for the real restaurant, with the same events as in the sandbox. Each restaurant has its own webhooks and signing secrets.

### Switch the site

Change the environment variables in production and deploy:

**`Production environment`**

```bash title="Production environment"
LETTBESTILT_SLUG=pizzaroma
LETTBESTILT_API_KEY=lbs_live_...
LETTBESTILT_WEBHOOK_SECRET=whsec_...
```

Keep the sandbox for testing future changes. A test key never works against a live restaurant, and a live key never works against a sandbox, so the two cannot be mixed up.

### Go live

Work through the [go-live checklist](/go-live), then place one real order end to end with the restaurant.