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

# Idempotency

> Retry a write safely.

Writes take an `Idempotency-Key` header. A write without one gets `400 IDEMPOTENCY_KEY_REQUIRED`. Each operation's reference page shows whether it takes one.

```bash theme={null}
curl -X POST "$PANOQORE_URL/v1/entries" \
  -H "Authorization: Bearer $PANOQORE_API_KEY" \
  -H "Idempotency-Key: order-1042-settle" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

## How it behaves

| You send | You get |
| - | - |
| A new key | The write runs, and its outcome is stored. |
| The same key and the same request | The stored outcome. Nothing runs again. |
| The same key and a different request | `400 IDEMPOTENCY_KEY_REUSED`. |

A key can be at most 255 characters. Its answer is replayed for 7 days per tenant. After that, a key that posted an entry or created a hold is still refused, with `IDEMPOTENCY_KEY_REUSED`, so a very late retry never posts twice.

## A refusal is replayed too

The stored outcome includes refusals. If a payout got `INSUFFICIENT_FUNDS`, sending the same key again gives `INSUFFICIENT_FUNDS` again, even after the customer has topped up. To try again as a new attempt, use a new key.

If the failure was on PanoQore's side, such as a `500` or a dropped connection, nothing was stored, and retrying with the same key is the right thing to do.

## Choosing a key

Generate it before the call and store it with your own transaction, so a retry after your process restarts uses the same one. A value derived from your own record, like `instalment:42:paid`, works well.

## Operations without the header

* `POST /v1/partners/{partner}/credits` is idempotent on the partner's transaction id. A repeat answers with `result: DUPLICATE` and credits nothing. See [Named accounts](https://docs.panoqore.com/guides/named-accounts.md).
* Webhook endpoint calls do not use the header.
* `POST /v1/fee-schedules/preview` changes nothing, so it does not need one.

## Duplicates across keys

`Idempotency-Key` protects a retry, not your business rule. By default `externalRef` is not unique: two entries can share it.

If your retries can't share a key, for example when each attempt from a queue gets its own, set `uniqueExternalRef: true` on the entry. Only one live entry can then hold that reference, whatever the key, even when attempts race. A second gets `409 EXTERNAL_REF_EXISTS`, and you can read the first by its reference. Voiding an entry frees the reference. A reversal doesn't, because the original still happened.

To find an entry by its reference:

```bash theme={null}
curl "$PANOQORE_URL/v1/entries?externalRef=deposit-1" -H "Authorization: Bearer $PANOQORE_API_KEY"
```


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