Mono Colombia

Idempotency Keys

How to safely retry write requests without creating duplicates.

An idempotency key is a unique label your system attaches to a write request so that Mono can recognize a retry as the same operation rather than a new one. It works like an order number on a paper form: if you fax the same form twice by mistake, the receiving clerk sees the order number and only processes it once. Without an idempotency key, a network glitch on a transfer request could quietly create two transfers.

Use an idempotency key on every write request that moves money or creates a card, transfer, collection link, or payout. The cost of forgetting is a duplicated transaction; the cost of remembering is one extra header.

Before you start

This page assumes you have read Authentication and that you make POST, PUT, or PATCH requests against the Mono API. Idempotency does not apply to GET requests — those are already safe to retry by definition.

When to send it

Send an idempotency key whenever a retry of the same request must not produce a second side effect. In practice, this is every write request to Mono. Examples:

  • Creating a bank transfer.
  • Creating a collection link.
  • Creating a card.
  • Triggering a payout.
  • Submitting an outgoing Bre-B transfer.

You can also send one on requests that are theoretically safe to retry (such as updates that converge to the same state). It is never wrong to include the header.

How to send it

Add the X-Idempotency-Key header to your request. The value is a string you generate, unique per logical operation, up to 255 characters.

curl https://api.cuentamono.com/v1/bank_transfers \
  -H "Authorization: Bearer $MONO_API_KEY" \
  -H "X-Idempotency-Key: payroll-2026-05-06-emp-1042" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1500000,
    "currency": "COP",
    "routing": "turbo",
    "destination": { ... }
  }'

Choosing a good key

A good idempotency key is deterministic for a given logical operation and opaque to humans. Recommended formats:

  • A UUID v4 generated once per logical operation and stored alongside the operation in your database. Persist the key before the first attempt so retries reuse it.
  • A composite of identifiers your system already controls — for example transfer:${order_id} for a per-order transfer. Avoid timestamps unless you control them precisely; clocks drift across retries.

What to avoid:

  • Reusing the same key for different operations. Mono will treat the second one as a duplicate and reply with the cached first response, which is almost certainly not what you want.
  • Generating a fresh key on each retry. That defeats the entire point — retries become new operations.
  • Including secrets or PII in the key. Keys appear in logs and dashboards.

What Mono does with it

When Mono receives a request with an idempotency key, it looks the key up in its short-term store:

  1. First time seen — Mono executes the request, stores the response, and returns it.
  2. Already seen, same payload — Mono returns the stored response without executing the request again. Your retry is safe.
  3. Already seen, different payload — Mono rejects the request with 409 Conflict. This protects you from a programming bug where two unrelated operations accidentally share a key.

Cached responses are retained for 24 hours from the first request. After that the key is forgotten and a fresh request with the same key starts a new operation.

When retries make sense

Retry on transient failures only — network timeouts, 502, 503, 504. Do not retry on 400, 401, 403, 404, or 422; those indicate the request is wrong, and retrying will not change the answer.

Use exponential backoff with jitter, and cap the retry budget. A common pattern: 3 retries, starting at 1s, doubling each time, with 0–500ms jitter.

Common mistakes

MistakeSymptomFix
Generating a new key on each retryDuplicate transfers, double charges.Generate the key once, store it, reuse it on retry.
Reusing a key across logical operationsSecond operation returns the first one's response.Make the key unique per operation.
Sending the key only on retries, not the first attemptThe first attempt has no protection.Always send the key on the first attempt.
Relying on idempotency for GET retriesNo effect.GET is already idempotent; the header is ignored.

Next steps

On this page