# Retry any POST safely

October 1, 2026 · API

A request that times out leaves you guessing whether it ran. Every `POST` on the REST API now takes an `Idempotency-Key` header, so the safe move after a timeout is always the same: send the same request again with the same key.

## What changed

- **Every POST takes the header**: provisioning, verification, connect, grants, carts, answers, confirms, code resends, cancels and menus. The retired `POST /v1/orders` is the only exception.
- **Same key, same body.** The first success is stored for 24 hours and comes back with `Idempotent-Replayed: true`. Layout does not run the request again.
- **Same key, different body** is `409 idempotency_conflict`. While the first request is still running, the same request is `409 in_progress` with `Retry-After`.
- **Only a success is stored.** After an error the key is free again, so a confirm answered with `code_required` is retried with the same key and the person's `code` added. A `4xx` ran nothing. A `5xx` may have, so after a `500` on a confirm, read the order before sending anything changed.
- **A replay is the first answer.** A stored `202 building` stays `building`. Read the cart for its state.
- **The body's `idempotencyKey` keeps working.** On carts, answers and confirms it is now optional when you send the header, whose value then stands in for it. When you send both, the body's key names the cart or the confirm.

## Why it matters

A confirm is where a careless retry costs the most. If one times out, retry the same call with the same key, never a new one: the retry gets the answer the first call earned, and the person is charged once.

## What to do

Send a fresh random `Idempotency-Key` with every POST that changes something, and carry it into every retry of that call. See [Idempotency](https://developer.layout.link/reference/limits#idempotency).

## Breaking changes

None. The header is optional, and a request without it behaves as before.
