---
title: "Mint a build grant token"
method: POST
path: "/users/{userId}/grant"
tags: ["Users"]
---

# Mint a build grant token

`POST /users/{userId}/grant`

## Request

- Base URL: `https://api.layout.link/v1`
- URL: `https://api.layout.link/v1/users/{userId}/grant`
- Auth: HTTP bearer

A build grant for one person, for MCP or the REST person routes. It reads places and menus, builds and reads carts, releases a cart it built, and confirms after the person says yes, with the 6-digit code Layout texts them whenever one is due (`codeReason` on the cart says why), which the person relays to you. It cannot add a card. GET /orders/{orderId} reads only the orders this application's grants built for that person. A sandbox grant confirms as a simulation that places and charges nothing, with no code except at `test_place_code` (`000000`). A grant lasts 15 minutes. To keep a session going, send the current grant as `refresh` before it expires: the same token lasts another 15 minutes, up to 24 hours from when it was minted, and no build-session allowance is drawn. The body is optional.

## Path parameters

- `userId` string, required

## Headers

- `Layout-Version` '2026-10-01'
- `Idempotency-Key` string

## Request body

- GrantRequest
  - `refresh` string, nullable: This person's current, unexpired grant. Extends that same token by 15 minutes, up to 24 hours from when it was minted, and draws no build-session allowance. Omit it, or send null, to mint a new grant.

## Response `200`

The grant sent as `refresh`, extended.

- Grant
  - `token` string, required: Build-only. A new grant's token is returned exactly once; a refresh returns the same token.
  - `expiresAt` string, required
  - `scope` 'build', required
  - `refreshed` true: Present when this call extended the grant you sent as `refresh`.

## Other responses

- `201`: Token minted. Returned exactly once.
- `400`: `refresh` is not a build grant token. `unsupported_version`: the Layout-Version header names no version this API answers.
- `401`: Secret not recognised, malformed, or rotated.
- `403`: Application not permitted. Usually production on an unapproved application.
- `404`: No such user for this application.
- `409`: `already_claimed`: that person has claimed their own Layout account. `grant_expired`: the grant sent as `refresh` expired, was revoked, belongs to someone else, or is 24 hours old; mint a new one without `refresh`. `idempotency_conflict`: the Idempotency-Key was already used with a different request. `in_progress`: the first request with that key is still running; retry after `Retry-After`.
- `429`: The build-session ceiling. A refresh does not count toward it.
- `500`: Layout failed to answer. Retry with backoff.
- `503`: Layout or a dependency could not be reached. Retry with backoff.

---

[API](https://skmtc.dev/layout/apis/layout-partner-api.md) · [All operations](https://skmtc.dev/layout/apis/layout-partner-api/llms.txt) · [OpenAPI document](https://skmtc.dev/layout/apis/layout-partner-api/revisions/7ff4ba01bf56?raw)
