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

# Idempotency

> Make a cash movement retry safe.

Add an optional `idempotency_key` to `POST /portfolios/{id}/cash-movements` so a retry after a timeout can't apply a deposit or withdrawal twice.

## How it works

Pass a unique string as `idempotency_key` alongside `direction`, `amount`, and `comment`:

```json theme={null}
{
  "direction": "DEPOSIT",
  "amount": 5000,
  "comment": "Q1 contribution",
  "idempotency_key": "q1-2027-contribution"
}
```

* **Same key, same body** (`direction`, `amount` and `comment` all match): Allocait returns the original result with `idempotent_replay: true` and doesn't apply the movement again. A missing `comment` and a `null` one match.
* **Same key, different body**: the request is refused with `409` and `error_code: IDEMPOTENCY_KEY_CONFLICT`.
* **No key**: the call is applied normally, with no deduplication. Omit it for a call you know will only ever be made once.

The key is a string of up to 200 characters, scoped to the portfolio. A longer key is refused (`idempotency_key must be 200 characters or fewer`), and a key that isn't a string gets `400`.

A call that Allocait refuses, such as a withdrawal that would overdraw cash (`INSUFFICIENT_CASH`), stores nothing, so a retry with the same key is judged again.

## Choose and reuse a key

Generate one key per logical action, such as a UUID or a hash of the action's inputs, and send the same key on every retry of that action. If two requests with the same key arrive at once, Allocait applies the movement once.

No other endpoint in this API accepts an idempotency key. Some writes are safe to repeat because you send the full desired state, not a delta: a repeated `POST /portfolios/{id}/positions/apply` with the same body reaches the same end state. A create is not covered by that. A repeat can add another record or be refused, depending on the route. Cash movements need the key because a deposit or withdrawal is a delta, not a state.

The MCP tool `record_cash_movement` takes the same `idempotency_key`, with the same rules. Two kinds of MCP write are safe to repeat without a key. `save_position` and `replace_positions` take total shares (negative for a short), so a repeat reaches the same state. A create that reuses a name already taken returns `ALREADY_EXISTS` with the first record's id. Check any other write before you repeat it.

## Related

* [Error codes](https://docs.allocait.app/api/error-codes.md): `IDEMPOTENCY_KEY_CONFLICT`.
* [Update with an agent](https://docs.allocait.app/guides/update-with-an-agent.md): set holdings by state instead of by change.
* [Endpoints by task](https://docs.allocait.app/api/endpoints-by-task.md)


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