> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.thepennyinc.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.thepennyinc.com/_mcp/server.

# Retries & Idempotency

Network failures are ambiguous.

A timeout, dropped connection, or process restart can prevent your application from receiving a response even though Penny may already have processed the request.

For read-only requests such as `GET`, retrying is normally safe.

For operations that create resources or move money, use the operation's documented retry mechanism rather than blindly submitting the request again.

> **Info**
>
> An `Idempotency-Key` tells Penny whether a request is a retry. Send the same key and Penny returns the original result instead of repeating the operation. Send a different key and Penny treats the request as a new operation.

#### Idempotency-Key

Prevents the same intended operation from being processed more than once on endpoints that accept the header.

#### client_reference

A reference controlled by your application for lookup and reconciliation. It does **not** prevent duplicates.

## Idempotency keys

These endpoints accept an `Idempotency-Key` header:

| API        | Endpoint                          |
| ---------- | --------------------------------- |
| Banking    | `POST /accounts/capital/transfer` |
| Simulation | `POST /transaction/card`          |
| Simulation | `POST /transaction/payment`       |
| Simulation | `POST /transaction/update`        |

The header is optional, but we strongly recommend sending it on every money-movement request. Without it, Penny cannot recognize a retry, and a retried request is processed as a new operation.

Generate one unique key for each **intended operation**, persist it before sending the first request, and reuse that same key only when retrying that operation.

```text
Transfer A → key A
retry A    → key A

Transfer B → key B
```

Even if Transfer A and Transfer B have identical request bodies, they represent different intentions and must use different keys.

A UUID or ULID is a good choice. Keys can be up to 255 characters.

```bash
curl -X POST https://sandbox.api.thepennyinc.com/accounts/capital/transfer \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Idempotency-Key: 3f29c1a2-8b7e-4e51-9a2e-2b6a1c9d7e10" \
  -H "Content-Type: application/json" \
  -d '{
    "from_account_id": "account_019379d9-a170-796b-867a-a17096b67a21",
    "to_account_id": "account_019379d9-b2c4-7d1e-9f0a-3c5e7a9b1d20",
    "amount": "100.00",
    "currency": "USD",
    "description": "Weekly operating float",
    "client_reference": "float-run-2026-09-09-00042"
  }'
```

A successful transfer returns `201 Created` with both sides of the movement:

```json
{
  "source_transaction": {
    "transaction_id": "transaction_019379da-0c1e-7a3b-9d2f-4e6a8b0c2d14",
    // …
  },
  "destination_transaction": {
    "transaction_id": "transaction_019379da-0c1f-7b4c-8e3a-5f7b9c1d3e25",
    // …
  }
}
```

The transaction objects are abridged here. See [Transactions](/banking/transactions) for the full shape.

## Retrying with the same key

When retrying the **same intended operation**, reuse the original key and send the same request body.

| Situation                                           | Response                                                                                                              |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| The original request completed.                     | The original result, with the original status (`201 Created` for a transfer). No second operation is created.         |
| The original request is still being processed.      | `409 Conflict`, in the [standard error format](/get-started/errors#error-format). Wait, then retry with the same key. |
| The original request failed.                        | The key is released, so the retry runs the operation again.                                                           |
| The same key is sent with a different request body. | `422 Unprocessable Entity`. Penny does not treat it as a retry.                                                       |

> **Warning**
>
> Never generate a new idempotency key because the first request timed out. A new key represents a new intended operation and can create a second transfer.

## Idempotency key scope and retention

Penny scopes each key to your business and to the operation it was sent with. The same key sent to a different endpoint is a separate key.

Penny keeps each key for **7 days**. After that, a request with the same key is processed as a new operation.

Store the idempotency key alongside your own record of the intended operation so the same key can be reused during recovery.

## Client Reference

Some Penny resources and transactions support a `client_reference`.

Use it to associate Penny activity with an identifier from your own system:

```json
{
  "from_account_id": "account_019379d9-a170-796b-867a-a17096b67a21",
  "to_account_id": "account_019379d9-b2c4-7d1e-9f0a-3c5e7a9b1d20",
  "amount": "100.00",
  "currency": "USD",
  "client_reference": "float-run-2026-09-09-00042"
}
```

You can then query transactions using that reference:

```http
GET /transactions/by-client-reference?client_reference=float-run-2026-09-09-00042
```

`client_reference` is useful for:

* reconciliation;
* tracing an operation back to your system;
* investigating an ambiguous outcome.

It is **not an idempotency mechanism**.

Penny does not require `client_reference` to be unique and does not deduplicate requests based on it.

For endpoints that support both values:

* use `Idempotency-Key` to make retries safe;
* use `client_reference` for reconciliation and lookup.

## Ambiguous outcomes

A timeout or `5xx` response does not necessarily mean the operation failed.

Treat it as an **unknown outcome** until you determine whether Penny processed the request.

```text
Request sent
    │
    ├── response received ──► handle normally
    │
    └── outcome unknown
             │
             ├── idempotent operation
             │      └── retry using the same key
             │
             └── non-idempotent operation
                    └── reconcile before creating again
```

Do not assume:

> no response = no side effect

## Creation endpoints without idempotency

Endpoints that do not accept an `Idempotency-Key`, such as `POST /cards/virtual`, need more care after an uncertain result: Penny cannot tell an intentional second card from a retried duplicate.

Where the API provides suitable lookup fields:

1. retain the identifiers and request context from the original attempt;
2. query for the intended resource;
3. determine whether the original operation appears to have succeeded;
4. create again only when you can establish that doing so will not produce an unintended duplicate.

#### Check before create

Looking for an existing resource can reduce duplicate risk, but it is **not the same guarantee as idempotency**. A resource may not yet be visible, or another request may race with your lookup.

Do not invent a resource ID you did not receive, and do not assume a list lookup is an atomic duplicate-prevention mechanism.

If your integration requires a stronger exactly-once creation guarantee for an endpoint that does not support idempotency, contact Penny before relying on automated retries.

## Retry guidance

Use the following as a starting point, then follow the operation-specific error contract.

| Outcome                              | Guidance                                                                                                                                                                       |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Successful response                  | Do not repeat the operation unless you intend another one.                                                                                                                     |
| Timeout / connection failure         | Treat the outcome as unknown.                                                                                                                                                  |
| `409 Conflict`                       | For a request still in progress under the same key, wait and retry with the same key. For a concurrent update, see [Resource Versions & Concurrency](/get-started/versioning). |
| `4xx` validation or permission error | Correct the request or permissions before retrying.                                                                                                                            |
| `429 Too Many Requests`              | Wait for the `Retry-After` interval, then retry with backoff and the same key.                                                                                                 |
| `5xx`                                | Retry only when safe for that operation; use the same idempotency key when retrying the same idempotent operation.                                                             |

See [Errors & Rate Limits](/get-started/errors) for general error handling.

## Recommended integration pattern

For every operation that supports idempotency:

1. create a unique operation ID in your system;
2. generate and persist an idempotency key;
3. send the request;
4. store the resulting Penny resource or transaction ID;
5. reuse the original key for retries of that same operation;
6. use `client_reference` where available to support reconciliation.

For example:

```text
Your system
│
├── operation_id: float_48219
├── idempotency_key: 3f29c1a2-...
└── client_reference: float-run-2026-09-09-00042
        │
        ▼
      Penny
        │
        └── transaction_id: transaction_...
```

This makes the intent of each operation explicit and gives both systems identifiers that can be used during recovery and reconciliation.