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

# Idempotency

> Retry any write safely: send an Idempotency-Key and duplicates become impossible.

A network timeout leaves you not knowing whether your request landed. For most APIs that is an inconvenience; for an invoicing API it is a legal problem, because a duplicated invoice can only be undone with a corrective invoice. Idempotency keys remove the dilemma: retrying is always safe.

## How it works

Send an `Idempotency-Key` header on `POST /v1/invoices` (and any future write that documents the header):

```bash theme={null}
curl https://api.finseed.es/v1/invoices \
  -H "Authorization: Bearer ev_live_..." \
  -H "Idempotency-Key: order-84312-invoice" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

* The key is any string of 1–255 printable ASCII characters, scoped to your environment. Derive it from something unique on your side (your order id, your job id), or use a UUID.
* The **first** request with a key executes normally and its response is stored for 24 hours.
* A **retry** with the same key and the same body returns the stored response without executing again, marked with an `Idempotent-Replayed: true` header. The invoice is issued exactly once no matter how many times you retry.
* The same key with a **different body** is rejected with `409 idempotency_conflict`: a key names one logical request, not a slot to reuse.
* While the original request is **still running**, a concurrent retry answers `409 idempotency_conflict`. Wait and retry: once the original completes you get its stored response.

## Failures

* Deterministic rejections (4xx, for example `invalid_tax_id`) are stored and replayed like successes: retrying the same wrong request repeats the same answer without re-executing.
* A `503 tax_id_validation_unavailable` (census down) releases the key: nothing was persisted, so retrying with the same key re-executes once the census recovers. This is the retry the `Retry-After` header schedules.
* If a request ends in a truly unknown state (a crash mid-flight), the key stays blocked with `409` for up to 24 hours rather than risking a duplicate. If you never received a response and the 409 persists, issue with a fresh key after checking `GET /v1/invoices` for whether the original landed.

## What not to do

* Do not reuse a key across different invoices, even after the previous one succeeded.
* Do not retry a 409 in a tight loop; use backoff and let in-flight requests finish.
* Do not skip the header on invoice creation. It is optional in the schema, mandatory in spirit.
