Making retries safe
Failed API requests are common. A network timeout occurs, or your service goes down right after it sends a request. Retrying is natural, and you need to be sure Midaz will not process the same operation twice. By attaching a unique key to each request, you’re telling Midaz: “This is the same operation. If you’ve already processed it, don’t do it again.” Midaz stores this key temporarily and uses it to determine whether the request is new, complete, or still in progress. This protects your system from duplicates.Idempotency in Midaz
Midaz uses idempotency keys to make sure transaction operations are safe to retry and never processed more than once. This mechanism is available on all transaction endpoints:
/transactions/json, /transactions/dsl, /transactions/inflow, /transactions/outflow, /transactions/annotation, and /transactions/{id}/revert.
Other Lerian products also support idempotency through their own headers. See the Idempotency across Lerian products section below. This page focuses on idempotency for the Midaz Ledger API.
The
commit and cancel transaction endpoints use a Redis-based lock to prevent concurrent processing of the same transaction, but they do not support full idempotency (no cached responses or X-Idempotency-Replayed header).X-Idempotency: the unique key that identifies the request.X-TTL: the time-to-live (in seconds) that Midaz should store this key in cache.
If you don’t send the
X-Idempotency header, Midaz automatically generates one by computing a SHA-256 hash of the request body. Midaz therefore deduplicates identical request bodies sent to the same organization and ledger.- When a new key arrives, Midaz marks it as
pending, processes the request, and stores the full response in cache. - If you send the same key again within the TTL window:
- While the operation runs, Midaz returns a
409 Conflict(error code0084) withX-Idempotency-Replayed: false. - If it’s done, Midaz returns the exact same response with a
201 Createdstatus code andX-Idempotency-Replayed: true.
- While the operation runs, Midaz returns a
- If the transaction fails due to validation or insufficient balance errors, Midaz deletes the idempotency key. You can then fix the issue and retry with the same key.
Workflow summary
Figure 1 shows the full lifecycle of an idempotent request:Figure 1. Idempotent request lifecycle in Midaz.
- If the request doesn’t include an existing idempotency key, Midaz creates a new one, or auto-generates one from the request body hash. Midaz then processes the request, stores the response, and returns it with
X-Idempotency-Replayed: false. - If the key already exists:
- While the operation runs, Midaz returns a
409 ConflictwithX-Idempotency-Replayed: false. - If the operation is complete, Midaz skips execution and returns the cached response with a
201 Createdstatus code andX-Idempotency-Replayed: true.
- While the operation runs, Midaz returns a
- If the original request failed due to validation or balance errors, Midaz deletes the key automatically. You can safely retry with the same key.
Example request
Here’s how to send an idempotent request to create a transaction:Key generation
You can provide your own
X-Idempotency key or let Midaz generate one automatically.
Automatic key generation
If you omit theX-Idempotency header, Midaz computes a SHA-256 hash of the request body and uses it as the idempotency key. Midaz therefore deduplicates the exact same JSON body sent to the same organization and ledger.
This is sufficient for most retry scenarios where the request body doesn’t change between attempts.
Custom key generation
Use a custom key when you need to:- Correlate the idempotency key with an ID in your own system (e.g., an order ID).
- Retry with a modified request body while still deduplicating (e.g., after correcting a field).
- Control the key format for logging or auditing purposes.
Best practices
Always validate the X-Idempotency-Replayed header
When your system receives a response from a transaction endpoint, always check the X-Idempotency-Replayed response header before processing the result. This header tells you whether the response is from a new operation or a cached replay:
X-Idempotency-Replayed: false: This is a fresh response. Midaz just processed the transaction.X-Idempotency-Replayed: true: This response comes from cache. Midaz already processed the transaction.
X-Idempotency-Replayed to avoid settling the same boleto twice.
Use explicit idempotency keys for critical flows
While Midaz auto-generates keys from the request body, for critical financial flows (settlements, payouts, transfers), always provide an explicitX-Idempotency key tied to your business process ID. This gives you:
- Full control over deduplication, even if the request body changes slightly between retries.
- A clear audit trail linking Midaz transactions to your internal operations.
- Protection against edge cases where request serialization might differ.
Set appropriate TTL values
Choose TTL values that match your retry window:- For synchronous operations with fast retries: 60–120 seconds.
- For asynchronous workflows with potential delays: 300–600 seconds.
- For batch processing with long retry windows: consider longer TTLs and explicit keys.
Retry strategy
Use these patterns for different failure scenarios:
Retryable failures
These failures are safe to retry with the same idempotency key:Non-retryable failures
These failures require a different approach:Exponential backoff
For transient errors, use exponential backoff with jitter to avoid overwhelming the server:Preventing entity duplication
For some endpoints, you don’t need idempotency keys to avoid duplication. Midaz enforces uniqueness constraints on critical resources. If you attempt to create an entity that conflicts with an existing one, the system blocks the request and returns a
409 Conflict with a descriptive error:
Unlike idempotency keys, these constraints are permanent and don’t expire.
Idempotency across Lerian products
Multiple Lerian products support idempotency, each with its own header convention. Most products return the
X-Idempotency-Replayed response header to show whether the response replays a cached result. Midaz always includes this header (false for new requests, true for replays), while other services only add it when the response is a replay. An absent header means a new request. Direct Pix does not return this header.
Midaz always includes the
X-Idempotency-Replayed header in the response (false for new requests, true for replays). Other services (Matcher, TED, Indirect Pix, and Reporter) only add this header when the response is a replay. An absent header means a new request. Direct Pix does not return this header. Its idempotency middleware replays the full response transparently without a replay indicator.Fees Engine, Tracer, Auth, and CRM do not currently support idempotency headers. Tracer validations are idempotent by
requestId instead. POST /v1/validations deduplicates on the body field and returns the cached result with HTTP 200 (HTTP 201 on first call). Auth token operations are inherently idempotent. CRM and onboarding entities rely on uniqueness constraints instead.FAQ
What happens if I don’t send an idempotency key?
What happens if I don’t send an idempotency key?
Midaz automatically generates one by computing a SHA-256 hash of the request body. Midaz therefore deduplicates identical request bodies sent to the same organization and ledger. You only need to provide a custom key if you want to control deduplication independently from the request body.
Can I reuse a key across different organizations or ledgers?
Can I reuse a key across different organizations or ledgers?
Yes. Midaz scopes idempotency keys per organization and ledger. The same key value used in different organizations or ledgers won’t conflict. However, within the same organization and ledger, each key must be unique per operation.
Can I reuse a key across different endpoints?
Can I reuse a key across different endpoints?
Midaz scopes idempotency keys per organization and ledger, not per endpoint. If you reuse the same key on a different endpoint within the same organization and ledger, you will receive the cached response from the original endpoint. Always use unique keys for each distinct operation.
What happens if I change the TTL on a retry?
What happens if I change the TTL on a retry?
Midaz uses only the TTL from the first request. Changing it later has no effect.
Will the replayed response always be identical?
Will the replayed response always be identical?
Yes. Midaz replays the full response, including status code (
201 Created), headers, and body, for completed requests.What’s the default TTL if I don’t send X-TTL?
What’s the default TTL if I don’t send X-TTL?
The default window is 300 seconds (5 minutes).
What happens if the original request fails?
What happens if the original request fails?
If the transaction fails due to validation errors or insufficient balance, Midaz deletes the idempotency key from cache. This allows you to fix the issue and retry with the same key.

