Making retries safe
In real-world systems, failed API requests are common. Maybe a network timeout occurs. Maybe your service goes down right after sending a request. In these cases, it’s natural to retry, but how can you be sure Midaz won’t process the same operation twice? That’s where idempotency keys come in. 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, already completed, or still being processed. This protects your system from duplicates while giving you full control over your retry strategy.Idempotency in Midaz
Midaz uses idempotency keys to make sure operations are safe to retry, and never processed more than once. To do that, your request must include two headers: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.
- When a new key arrives, Midaz marks it as
pending
, processes the request, and stores the full response in cache. - If the same key is used again within the TTL window:
- If the operation is still running, Midaz returns a
409 Conflict
withX-Idempotency-Replayed: false
. - If it’s done, Midaz returns the exact same response, including headers and body, with
X-Idempotency-Replayed: true
.
- If the operation is still running, Midaz returns a
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, processes the request, stores the response, and returns it with
X-Idempotency-Replayed: false
. - If the key already exists:
- If the operation is still running, Midaz returns a
409 Conflict
withX-Idempotency-Replayed: false
. - If the operation is complete, Midaz skips execution and returns the cached response with
X-Idempotency-Replayed: true
.
- If the operation is still running, Midaz returns a
Example request
Here’s how to send an idempotent request to create a transaction:Key generation
You generate theX-Idempotency
key on your side. The key should be deterministic, meaning if the same operation is retried, the key remains the same.
A simple and effective strategy is to create a hash based on the key fields that define the operation. For example:
- Transaction amount
- Source and destination
- Asset code
Preventing entity duplication
For some endpoints, you don’t need idempotency keys to avoid duplication. Midaz enforces uniqueness constraints on critical resources like Accounts and Ledgers. If you attempt to create an entity with a name that already exists, the system blocks the request and returns a descriptive error. This ensures that your data remains clean, unambiguous, and easy to manage, even when multiple services are operating in parallel or when retries occur automatically.FAQ
What happens if I don’t send an idempotency key?
What happens if I don’t send an idempotency key?
Midaz treats the request as new every time. This means retries may result in duplicated operations.
Can I reuse a key across endpoints?
Can I reuse a key across endpoints?
No. Keys should be scoped to a single operation and endpoint.
What happens if I change the TTL on a retry?
What happens if I change the TTL on a retry?
Only the TTL from the first request is used. 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 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), but you can customize it up to your allowed limit per endpoint.