> ## Documentation Index
> Fetch the complete documentation index at: https://docs.laces.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotency

> Retry order creation and payment safely after a timeout, without holding places twice or charging twice.

Networks fail in the worst place: after Laces has created your order or sent
the payment prompt, but before the response reaches you. Idempotency keys make
the retry safe.

## Where it is required

| Route | `Idempotency-Key` |
| - | - |
| [`POST /orders`](/api-reference/v1/orders/create) | **Required** |
| [`POST /orders/{orderId}/pay`](/api-reference/v1/orders/pay) | **Required** |
| Everything else | Not used |

A missing key is `400 idempotency_key_required`.

## How it behaves

| You send | Laces answers |
| - | - |
| A new key | Processes the request normally |
| The same key and the same request again | The **original response**, with `200` and an "idempotent replay" message. Nothing is created or charged a second time. |
| The same key with a different request | `422 idempotency_key_reuse` |
| The same key while the first request is still running | `409 idempotency_in_progress`. Wait a moment and retry with the same key. |

* Keys are **scoped to your API client**. Another client sending the same
  string never collides with yours, so a key only has to be unique within your
  own integration.
* A pay key is bound to the **order and the phone number**. Sending the same
  key for a different order or a different `msisdn` is `422`.
* Use a **different** key for create and for pay. They are two logical actions.

## Doing it right

1. Generate a key (a UUID is ideal) **when the buyer starts the action**, not
   when you send the request.
2. **Store it with your cart** before calling Laces.
3. On a timeout, a network error or a `5xx`, retry with the **same** key.

<Warning>
  Generating a fresh key on every retry turns the protection off. Two
  different keys are two different orders.
</Warning>

<CodeGroup>
  ```js Node theme={null}
  import crypto from "node:crypto";

  // When the buyer presses "Pay", once:
  cart.createKey ??= crypto.randomUUID();
  await db.saveCart(cart);

  const res = await fetch(`${BASE}/orders`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
      "Idempotency-Key": cart.createKey, // reused on every retry
    },
    body: JSON.stringify(orderBody),
  });
  ```

  ```python Python theme={null}
  import uuid, requests

  # When the buyer presses "Pay", once:
  cart.create_key = cart.create_key or str(uuid.uuid4())
  db.save_cart(cart)

  res = requests.post(
      f"{BASE}/orders",
      headers={
          "Authorization": f"Bearer {token}",
          "Idempotency-Key": cart.create_key,  # reused on every retry
      },
      json=order_body,
      timeout=30,
  )
  ```
</CodeGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.