Safer codes, fairer limits
A security issue with the codes Layout texts people is fixed. The fix changes what one response says and what the texts read, and a few limits now keep testing traffic and production traffic apart.
Codes do one thing
- A verification code verifies. The code
POST /v1/users/:id/verify/starttexts is good for that person's number, for your application, for 3 minutes from the text and five tries. With no text sent there is no code to check. - An order code approves one order. The code a confirm asks for approves that order at that amount, once.
- The texts say what they are for. The order text names the total the card is charged, fees and credit included, and the store as Layout knows it. It never carries the card, and never words your application sent.
The person now reads:
Layout: 482913 verifies this number for an app you are connecting to Layout. It expires in 3 minutes and does not sign you in. If you did not ask for it, ignore this text. Layout: 482913 approves $7.50 at Layout test kitchen. It expires in 10 minutes. If you did not just order, ignore this text.
The request and response shapes for confirming are unchanged on MCP. If the person once replied STOP to Layout, no code can reach them: POST /v1/users/:id/verify/start answers 409 texts_blocked, and over MCP the order answer says the code could not be texted. They reply START to the number Layout texts from before you try again.
Headless verify in production
A good code on a production user now connects your application to that person and does nothing else. It no longer creates a Layout account, so the response says the person is still provisioned:
POST /v1/users/usr_4b8e/verify
{ "code": "482913" }
200 OK
{ "verified": true, "authorized": true, "status": "provisioned", "claimed": false }
verifiedmeans the code was right, or the person has since signed up to Layout themselves.authorizedsays whether you may build. When it istrueyou can mint a build grant straight away.- When the number belongs to an existing Layout account,
authorizedisfalseand the answer carriesnext: "connect": send the owner the connect link. - After five wrong tries, or three minutes,
verifyanswers400 code_expired. Text a new code. claimedbecomestrueonce the person signs up to Layout themselves, and your connection carries over when they do.- Once you are connected, calling
verifyagain answersverified: truewithout a fresh code. - Sandbox, with the code
000000, answers as before, now withauthorized: true.
Signing up connects only who they approved
When a person you provisioned signs up to Layout themselves, your application stays connected only if it already was: a good headless verify, or the person approving your app on the connect screen. Otherwise POST /v1/users/:id/grant answers 409 until they approve it, and you send them the connect link as you do for an existing account.
Limits of their own
- Place search. In sandbox, and for an application not yet approved,
GET /v1/placessearches only the places Layout already knows, so it can return fewer results than the same search in production. An approved production application can look further, within a daily allowance for your developer account. - Build capacity. Sandbox builds, and builds for an application not yet approved, share a pool of 2,000 a day that is separate from approved production builds, and each developer account may use 250 of it a day in each environment. Testing can no longer use up the room production orders need, and no one developer can use up the testing pool. A refusal names the pool and its number.
- Read allowances are per developer account. Place reads, live menu reads and knowledge answers count every application on your account together, in the same two pools. A live menu read through the API draws its own per-person allowance, separate from the Layout app's. When a limit stops a place search at the places Layout already knows, the answer says so in
searchLimit. - An allowance that cannot be read refuses. If Layout cannot read your sandbox build allowance, your allowance of place reads or live menu reads, or your allowance of knowledge answers when you ask for one, the request is refused and safe to retry. Over REST that is
503 unavailablewithRetry-After.
Smaller fixes
- An OAuth client your application created is refused for MCP, as it already was for the API, when the application is deleted or suspended, or for a production person while the application is not approved.
- A failed cart on a build grant no longer mentions the person's card.
- An unexpected failure on any
/v1developer route answers the published error shape,{ "error": { "code", "message" } }. - One developer's backlog of webhook deliveries no longer holds up another developer's, however many applications either has.
- A build grant never sees the person's card on MCP either: no card brand, no last four, and no confirmation card text.
What to do
If your code waits for claimed: true or status: "active" after a headless verify in production before it builds, wait for authorized: true instead. If a person you provisioned without verifying signs up to Layout and your grant call starts answering 409, send them the connect link.
If you tell people what the text will say, use the wording above.
Breaking changes
Yes, for production headless verify. A good code used to answer "status": "active", "claimed": true for a new number, and now answers "status": "provisioned", "claimed": false until the person signs up themselves. A person who signs up no longer connects an application they never verified with or approved. A code is checked only against the last one Layout texted, for five tries. Nothing else changes in sandbox.