# Finish an order in sandbox

October 1, 2026 · Sandbox

Sandbox used to stop at a priced cart. You could build against real restaurant sites, but the last step, the one that turns a cart into an order, could only be exercised in production. Now a sandbox user can be taken all the way to a placed order, and every place that reports it marks it as simulated.

## What changed

- **Verify sends nothing.** With an `sk_test_` key, `verify/start` texts nobody and answers with `"sandbox": true`. `verify` accepts the fixed code `000000`.
- **A sandbox build session can confirm.** The `order` tool's `confirm` action works on a sandbox build session. It answers `"status": "placed"` with `"simulated": true`. No code is needed.
- **The order says it was simulated.** The `order.placed` webhook and `GET /v1/orders/:id` for that order carry `simulated: true`.

## The whole flow

Provision a user on a reserved test number, `+1 500 555` followed by four digits, then verify them with the sandbox code.

```
POST /v1/users/usr_4b8e/verify/start
200 OK
{ "ok": true, "id": "usr_4b8e", "phoneHint": "+1 (500) •••-0142", "expiresInSec": 180, "sandbox": true }

POST /v1/users/usr_4b8e/verify
{ "code": "000000" }
200 OK
{ "verified": true, "authorized": true, "status": "active", "claimed": true }
```

Mint a build grant, build over MCP as you already do, and confirm the carted build with its `totalMinor` and a fresh idempotency key.

```
order {
  "action": "confirm",
  "orderId": "0b6f2a54-…",
  "expectedTotalMinor": 1850,
  "idempotencyKey": "a7c1e0d2-…"
}

→ { "action": "confirm", "confirm": { "status": "placed", "orderId": "0b6f2a54-…", "subtotalMinor": 1850, "simulated": true } }
```

- The total still has to match the cart. A stale one is refused with `price_changed`, exactly as in production, so a simulated order still proves the cart you built.
- Asking for a code to be resent answers `code_not_needed` and places nothing, because sandbox has no code.
- If Layout cannot check that the session is a sandbox one, the confirm answers with the error `unavailable`. Retry it: it is never a permanent refusal and never a real order.
- Cancelling is not available on a build session, in sandbox or production.

## Why it matters

You can test your whole integration before you have production keys: the confirm call, the `order.placed` handler, the order read and whatever your product does once an order exists. The cart is real, built on the restaurant's own site, so the test proves what production will do up to the moment the restaurant would receive it.

## What to do

If your code treats every `order.placed` as food being made, check `order.simulated` first. Test for `true`: a real order never carries `simulated: true`.

Never describe a simulated order to a person as a real one. The sandbox session's own instructions tell your model the same.

## Breaking changes

None. A production build session still cannot confirm: the person confirms the order themselves, by replying to Layout's text or in the Layout app. See [Finishing an order in sandbox](https://developer.layout.link/reference/environments#finishing-an-order-in-sandbox).
