Limits built for a launch

API

The limits on an approved application in production were sized for a pilot. They are now sized for a launch, and every one is visible to you before you meet it.

Higher production limits

  • Users provisioned: 600 an hour per credential, up from 60, and 10,000 a day per developer account, up from 500.
  • Build sessions minted: 1,200 an hour per credential, up from 120, and 50,000 a day, up from 2,000.
  • Verification and approval texts: 6,000 a day each, up from 600, and 250 verification starts an hour.
  • Requests: 3,000 a minute per credential across every endpoint, up from 600.

Sandbox numbers, and those for an application awaiting approval, are unchanged. Sandbox now counts users provisioned, build sessions and texts on its own counter, so higher production traffic cannot use up the sandbox day. Layout's hourly ceiling on the texts it sends for every developer together is unchanged at 300 verification texts and 300 approval texts an hour, and in a burst it is reached before your own numbers are. It now has its own refusal message with Retry-After, and GET /v1/usage lists it. See Per-minute and per-hour limits and Users, sessions and texts.

One address is not a limit

Requests that authenticate no longer count against your calling address, so a backend that sends everything through one address gets the same room as one that does not. Only credentials Layout has no record of count against an address, at 300 a minute, and a credential that authenticated recently keeps working from an address that is over it. A revoked secret or an expired grant or token never counts against its address; it counts against itself, at 600 a minute. Wrong verification codes count against your developer account, so another developer's guesses never lock your user's number.

Build grants refresh

Send the current grant back as refresh to POST /v1/users/:id/grant before it expires, and the same token lasts another 15 minutes, up to 24 hours from when it was minted. A refresh never counts toward your build-session limits. A grant that cannot be refreshed answers 409 grant_expired.

POST /v1/users/usr_4b8e/grant
{ "refresh": "lgb_9f3a2c" }

200 OK
{ "token": "lgb_9f3a2c", "expiresAt": "2026-10-01T18:15:41Z", "scope": "build", "refreshed": true }

See every limit

  • GET /v1/usage answers every daily pool with your limit, what you used today and what is left, the ceiling across every developer, your application's own build allowance, the per-person limits and every rolling window. See Seeing your limits and usage.
  • RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset come back on every answer to a request that authenticated, for your per-credential minute. A 429 from a per-endpoint limit carries that limit's numbers instead, and a 429 from a daily ceiling or the address limit carries none.
  • A refusal at a daily limit names the limit and its number.

Raising a limit

Layout can now raise any developer pool GET /v1/usage lists for your account without waiting for a release, including order builds, live menu reads and place searches. Ask from Usage in the console, saying which limit, or email developer@layout.link. A raised number shows in GET /v1/usage with custom: true.

What to do

Nothing is required. If you mint a new grant every 15 minutes for a long session, switch to refresh. If you throttle yourself on fixed numbers, read GET /v1/usage or the RateLimit headers instead.

Breaking changes

None. refreshed, the RateLimit headers, GET /v1/usage and grant_expired are new. POST /v1/users/:id/grant still takes no body: with none, or without a refresh token, it mints as before. A refresh that is not a grant token is a new 400 invalid_request. Refusal messages at daily and hourly limits now name the number.

All changes