# Coding agents

A coding agent can integrate Layout into your product and prove it against sandbox on its own. A person does the first step, because only a person can create the developer account.

## What a person does first

1. Sign up at [developer.layout.link](https://developer.layout.link/auth/signup) and verify your email.
2. On the console's [CLI](https://developer.layout.link/console/cli) page, choose **New token** and give the agent the `lcli_` token as `LAYOUT_CLI_TOKEN`. It works in sandbox only, so it cannot reach production or move money. Creating one needs a console sign-in from the last 15 minutes.
3. If your product will use [Sign in with Layout](https://developer.layout.link/reference/sign-in-with-layout), also create an OAuth client with your redirect URIs, and a sign-in test account, on the console's [OAuth clients](https://developer.layout.link/console/oauth-clients) page. Give the agent the `client_id`, the test account's number and its sign-in code.

Everything after that runs from the [Layout CLI](https://developer.layout.link/reference/cli) and the API.

## What the agent does

1. Installs the CLI with `npm i -g @layoutplatforms/cli` and runs `layout init --name "<your app>" --json`. That finds or creates the application, prints `env.LAYOUT_APP` and `env.LAYOUT_SECRET_KEY` (an `sk_test_` key), and runs a simulated test order. It is safe to run again: it finds the same application and never rotates its key. Use it rather than `layout apps create`, which makes a new application on every run.
2. Picks one way in for each person, before writing any code. [Provisioning](https://developer.layout.link/reference/provisioning): your product collects the phone number, then, with your secret, provisions the person (`POST /v1/users`), verifies their number (`/verify/start`, then `/verify` with the code they read back) or, when the number already has a Layout account, sends a connect link (`POST /v1/users/:id/connect`), sends a [card link](https://developer.layout.link/reference/card-links) (`POST /v1/users/:id/links`), and mints a build grant (`lgb_`, `POST /v1/users/:id/grant`). [Sign in with Layout](https://developer.layout.link/reference/sign-in-with-layout): the person signs in on Layout's page and your product holds their OAuth access token. The same person gets a different id each way. See [Two ways in](https://developer.layout.link/reference/sign-in-with-layout#two-ways-in).
3. Builds the order flow on [Carts](https://developer.layout.link/reference/carts): `POST /v1/carts` with the person's grant or token, poll `GET /v1/carts/:id` until it is `ready`, show the person the cart, then `POST /v1/carts/:id/confirm` once they say yes.
4. Handles [webhooks](https://developer.layout.link/reference/webhooks) on your server, and tests them locally with `layout listen --forward-to <your local URL> --json`, run in the background. Each run signs with a new secret, the `secret` of its first line.
5. Tests every ending against the [test restaurants](https://developer.layout.link/reference/sandbox#the-test-restaurants), with its own code or `layout test-order --place <id>`. They never open a browser and cost nothing.

## Rules for the agent

- Use only `sk_test_`. An `sk_live_` secret places real orders and charges real cards with the same code. It never belongs in development, tests or CI.
- Keep the secret on your server. Places, menus, item images and carts take the person's build grant or OAuth access token, never your secret.
- Confirm with the cart's `totalMinor`, exactly as the cart gives it. The webhook's `total_minor` is the restaurant's total without Layout's service fee, and confirming with it is refused.
- Only `placed` means the order exists. A confirm answers `placing`, which can still end `failed`. `unconfirmed` is never a failure: never build it again, and never tell the person it failed.
- Send a new `idempotencyKey` for each new cart and confirm, and the same one when you retry the same request. A confirm sent again with the person's code is the same request: keep its `idempotencyKey`.
- In sandbox, people have `+1 500 555` numbers and the code is `000000`. Nothing is texted.
- An order with `"simulated": true` never reached a restaurant. Never show it to anyone as a real order.
- Verify every webhook's signature over the raw body, and skip an `event_id` you have already handled. Never de-duplicate on the order id and event type: `order.updated` can come more than once for one order, each with its own `event_id`.
- The pickup time can arrive after `placed`. On every `order.updated`, read `GET /v1/orders/:id`. Show `ready_eta` word for word, never parse it, and show no time while it is null.
- Orders are pickup only today. Read `fulfillment.type` rather than assuming it.
- When a person leaves your product, call `DELETE /v1/users/:id`.
- `POST /v1/orders` is retired and answers `410`. Orders start as carts.

## A prompt to start with

Hand this to your agent, or save it in the file your agent reads for project instructions, such as `AGENTS.md`, or `CLAUDE.md` for Claude Code.

```
Integrate Layout into this project so people can order pickup food from it.

Read https://developer.layout.link/reference/coding-agents.md first, then
https://developer.layout.link/llms.txt for the rest. The OpenAPI spec is
https://developer.layout.link/openapi.json.

LAYOUT_CLI_TOKEN is set. Run `layout init --name "<our app>" --json` and keep the
LAYOUT_APP and LAYOUT_SECRET_KEY it prints in our development environment,
never in source control.

Ask me which way in we use (provisioning, or Sign in with Layout) before
writing code. Work in sandbox only. Follow the rules on that page, test every
test restaurant ending, and verify our webhook handler with `layout listen`.
Tell me what you could not do.
```

## What the agent cannot do

These stay with a person, on purpose:

- **Production.** Your person requests it from the console, where a form asks about the company, its policies and the app's listing, and a person at Layout decides it. `layout request-live-access` prints that page's link for them. The `sk_live_` secret is revealed only in the console, once the application is approved, and the production signing secret is shown only there too.
- **Webhook endpoints.** Added and removed on the console's [Webhooks](https://developer.layout.link/console/webhooks/subscriptions) page. `layout webhooks add` and `layout webhooks remove` also do it while the application is under review, from CLI 0.4.2. `layout listen` needs none.
- **OAuth clients and sign-in test accounts.** Created on the console's OAuth clients page, as above.
- **Return URLs.** A [card link](https://developer.layout.link/reference/card-links) sends the person back only to a return URL registered on the console's [App details](https://developer.layout.link/console/app-details) page. A person adds it there; the CLI cannot. For local tests register `http://localhost:<port>/<path>`, which works with the sandbox key only.
- **Real orders.** A real person confirms a real order, with a verified number and a card on their Layout account.
