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

# Idempotency

> Retry any write safely: give each intent one id, so a repeated request never does the work twice.

A request can time out after trdrs has already acted on it, and your code can't tell. Idempotency
makes that safe: you give each intent an id, and sending the same intent again never does the work
twice. Use this page when you write the retry logic for orders and venue writes.

There are two mechanisms, one for each side of the API, and one rule for both: one intent, one id,
forever.

## Orders: `clientOrderId`

Every call that places, replaces or protects an order carries a `clientOrderId` that you choose. It
names one trading intent.

* Create a new id when the trader makes a new decision.
* Send the same id when you retry that decision, whatever went wrong the first time.
* Never reuse an id for a different decision.

```ts theme={null}
// Create the id once, at the moment the trader commits.
const clientOrderId = crypto.randomUUID()

// Every retry of this order sends the same id.
await placeOrder({ instrument: 'ESU6', side: 'buy', qty: 1, clientOrderId })
```

If the first attempt timed out, retry with the same id. Either the order is placed now, or the
answer is `409` because it was placed the first time. Both outcomes are correct, and neither
doubles the trader's position.

Cancels don't take an id. A cancel is already safe to repeat at the market, so you can send it
again after a partial failure.

## Venue writes: `Idempotency-Key`

Every write under `/api/partner/venues/{venueId}/…` takes an `Idempotency-Key` header of 1 to 128
characters: saving an instrument, a route or a group, publishing a risk policy, issuing an account,
moving money on one, resetting, halting, advancing a stage, registering a webhook or sending it a
test ping. A write without one is refused with `400 idempotency_key_required`. Three writes take no
key: removing a webhook, and updating the brand or its logo.

```bash theme={null}
curl -X POST "$TRDRS_API_BASE_URL/api/partner/venues/$TRDRS_VENUE_ID/accounts/$TRDRS_ACCOUNT_ID/balance" \
  -H "Authorization: Bearer $TRDRS_VENUE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: payout-2026-08-31-a" \
  -d '{ "op": "debit", "amount": 800 }'
```

What a repeat returns depends on the write:

| You send | You get |
| - | - |
| The same key and the same configuration write | The first result again, with nothing done twice |
| The same key and a different body | `409 idempotency_conflict`. A new intent needs a new key |
| The same key on a balance operation | `409 duplicate_reference`, and no money moves a second time. The key is your `referenceId`, and [the receipt](/api-reference/venue-platform-preview/read-the-receipt-of-one-balance-operation) reads what it did |
| The same `referenceId` and request when issuing an account | The same account, with `created: false` |

The Legacy Partner API carries the same rule in the body instead of a header: a `referenceId` on
issuing, resetting and balance operations.

## Side by side

| | Orders | Venue writes |
| - | - | - |
| Where the id goes | The request body | The `Idempotency-Key` header |
| What it names | One trading intent | One configuration or account write |
| A repeat with the same body | `409`, and the earlier order stands | The first result, or `409 duplicate_reference` on a balance operation |
| A repeat with a different body | A different intent that needs a new id | `409 idempotency_conflict` |
| When you create it | When the trader commits | When your system decides |
