---
title: "Idempotency"
description: "Send an Idempotency-Key on every write so a retry after a timeout cannot charge twice, and learn what happens when you reuse a key with a different body."
canonical_url: "https://twominutebilling.com/help/developers/api-essentials/idempotency"
---
# Idempotency

> Send an Idempotency-Key on every write so a retry after a timeout cannot charge twice, and learn what happens when you reuse a key with a different body.

A network timeout tells you nothing: your request may have been processed, or it may not. Retry
blindly and you risk charging a customer twice. Idempotency keys remove the ambiguity.

Send an `Idempotency-Key` header on every write:

```bash
curl -X POST $TMBILLING_URL/v1/businesses/$BIZ/customers \
  -H "Authorization: Bearer $TMBILLING_API_KEY" \
  -H "Idempotency-Key: 8f14e45f-ea6c-4a1f-b0ba-9a1d1c4b2f30" \
  -H "Content-Type: application/json" \
  -d '{ "email": "maya@example.com" }'
```

Use any unique string — most people use a UUID per logical operation. Generate it before your
first attempt and reuse the same value for every retry.

## Retry safely

tmbilling runs the first request with a given key normally and stores its response. A later
request with the same key does not run the handler again. You get the stored response, with:

```http
Idempotent-Replayed: true
```

So when your client times out and retries, it gets the original answer: the same customer id, the
same invoice, the same charge.

## Retry within 24 hours

tmbilling keeps a finished request's key and response for at least 24 hours. Retry within that
time and you get the stored response. After it, the key can be removed, and a request that uses
it again runs as a new request. A retry loop that gives up within minutes is well inside the
window; never reuse a key for a different operation days later.

## Understand how tmbilling scopes a key

tmbilling scopes each key to the organization that used it, so two organizations can use the same
string without colliding.

Within that scope, it binds the key to a fingerprint of the request — the method, the path and the
body. Reuse a key with a different payload and you get `409` with an `idempotency_error`, because
your client believes it is retrying while actually asking for something else.

<tip title="Derive the key from the operation, not the step">

A key named after the code path, like `create-customer`, is identical for every caller and
collides. Derive it from the thing you are creating, or generate a fresh UUID per attempt.

</tip>

## Handle two replies that surprise people

**A replay of a secret-minting request returns 409, not 200.** Some endpoints return a value
that exists only once: an API key secret, a checkout link carrying a bearer token, a rotated
webhook signing secret. tmbilling deliberately does not store those responses, so a replay cannot
hand the secret out again. The `409` tells you the original request succeeded — look the resource
up rather than retrying.

**A crashed first attempt returns 409 with instructions.** If the first request using your key
died after making a durable change but before recording its response, tmbilling can neither replay
it nor safely re-run it. It returns `409` explaining the situation and asks for a fresh key,
because the durable change already happened.

## Know which requests need one

Every write: `POST`, `PATCH`, `PUT` and `DELETE`. Reads are already idempotent and ignore the
header.

tmbilling deduplicates inbound provider webhooks separately, by the provider's own event id, so a
gateway that delivers the same notification twice never settles an invoice twice.

## Related

- [Errors](https://twominutebilling.com/help/developers/api-essentials/errors)
- [Idempotent usage records](https://twominutebilling.com/help/developers/recipes/usage-based-billing)


## Sitemap

See the full [sitemap](https://twominutebilling.com/sitemap.md) for all pages.
