---
title: "Confirm a cart"
method: POST
path: "/carts/{cartId}/confirm"
tags: ["Carts"]
---

# Confirm a cart

`POST /carts/{cartId}/confirm`

## Request

- Base URL: `https://api.layout.link/v1`
- URL: `https://api.layout.link/v1/carts/{cartId}/confirm`
- Auth: HTTP bearer

Sends the order to be placed and answers `placing`, never `placed`: read GET /orders/{orderId} for the outcome. On a connected person's token, a live confirm needs the 6-digit code Layout texts the person only when they keep codes on, the total is over Layout's amount limit for codes (which can change), Layout's risk checks ask for one, or a code is already out for this cart; otherwise one call places it. A live build grant meets the same rules once the person has connected your application, since connecting is their agreement that it places orders for them; for a person who connected before that, the first order's code says so and agrees to it. When it is required the first call texts the person Layout's code, which names the total, the store and the card, and answers `code_required` (when a code texted for this cart in the last 10 minutes is still good, nothing new is texted and you ask the person for that one); you send the same request again with the `code` the person gives you. Layout texts at most four codes per cart. In sandbox the order is simulated and needs no code, except at `test_place_code`, whose code is `000000` and is never texted. `placing` means the confirm was accepted: follow the order, which can still end `failed` without reaching the restaurant.

## Path parameters

- `cartId` string, required

## Headers

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

## Request body

- ConfirmCartRequest
  - `expectedTotalMinor` integer, required: The cart's `totalMinor`, exactly as Layout returned it. The restaurant's total alone (`fees.merchantTotalMinor`) is refused when a fee applies.
  - `idempotencyKey` string: Unique per real intent. A retry with the same key and body returns the same answer. Optional when the request carries an Idempotency-Key header, whose value is then used; when both are sent, this one names the cart or the confirm.
  - `code` string

## Response `202`

Placing.

- OrderPlacing
  - `order` object, required
    - `id` string, required
    - `status` 'placing', required
    - `simulated` true
    - `trackUrl` string: Layout's live status page for this order, safe to show the person: it shows the store, items, total and pickup details, never the card or the person's account, and nobody can sign in with it. It follows the order while it is placed and stops answering 15 minutes after the order ends, or 3 hours after confirm at the latest. Absent when Layout could not make one. For anything later, read GET /orders/{orderId}.

## Other responses

- `400`: `code_required`: ask the person for the code Layout texted and send the same request with it. `code_invalid` / `code_expired`: the code did not match, or is no longer valid (used, expired, replaced, or issued for another total). `invalid_request`: a malformed body, or `expectedTotalMinor` is the restaurant's total without Layout's fee. `unsupported_version`: the Layout-Version header names no version this API answers.
- `401`: The token is missing, expired, revoked, issued for another audience, or the person disconnected. Every 401 reads the same.
- `402`: `card_declined`: the person's card was declined. Nothing was placed.
- `403`: `risk_denied`: Layout will not place this order. `build_only`: the person cannot confirm through Layout yet; `error.next.step` names what is missing (`sign_up_required`: sign up with this number and add a card; `connect_required`: approve a connect link because the number already has a Layout account; `link_expired`: the invitation is too old to claim; the person signs up to Layout themselves with this number, and then the step is `connect_required`; `phone_required`: verify their number; `card_required`: add a card), and `error.next.url`, when present, is the Layout page where the person does it. Otherwise: The credential is real and may not do this: an application or account that is suspended, a live person on an unapproved application, a scope the token was not granted, or a person whose Layout account cannot order yet.
- `404`: No such cart for this application and person. Another application's cart is a 404 too.
- `409`: `price_changed`: the total moved; read the cart again and show the person the new total. `over_daily_cap`: over the person's daily limit. `cart_not_ready` / `cart_closed`: still building, or no longer confirmable (a canceled or `canceling` cart is `cart_closed`). `approval_required`: the person must approve paying through Layout first. `over_order_limit` / `not_placed`: not placed. `idempotency_conflict` / `in_progress`: the key was used for another confirm, or one is running. `texts_blocked`: the person's number replied STOP to Layout, so no code can be texted; they reply START to the number Layout texts from, then you confirm again. `already_confirmed`: the cart was already confirmed, by the person replying YES to Layout's text, in the Layout app, or by another of your requests; nothing was confirmed or charged again. `error.order` is the order and its state now (`placing`, `placed`, `unconfirmed` or `refunded`), with `confirmedVia` when Layout knows where; read GET /orders/{orderId} and do not confirm or build it again. `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`: `code_attempts_exceeded`: too many wrong codes. `rate_limited`: too many codes in a row, the cart's code limit, or the application's daily code limit.
- `500`: `internal`: the outcome is not known. Read the order before doing anything else, and do not build it again until it reports a final state.
- `502`: `send_failed`: on a live build grant, the code could not be texted. Nothing was confirmed or charged. Retry the same request shortly.
- `503`: `unavailable`: a check could not run. Nothing was confirmed or charged. Retry the same request.

---

[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)
