The page describes how to safely retry POST requests to the Mipise Payment Services API without creating duplicate resources.
🌐 Introduction
Every POST endpoint of the MPS API accepts an optional Idempotency-Key HTTP header. Include it
on any request that mutates state — creation, transfer, mandate, and so on — so that a network
timeout or an ambiguous 5xx response never turns into a duplicate resource.
A retry with the same
Idempotency-Keyand the same body within 7 days replays the exact
response of the original call — same status code, same body — even if the original call had
returned an error. One key identifies one business intent.
🔑 Header Format
The key is a client-generated string with these constraints:
- Length: 8 to 255 characters.
- Charset:
[A-Za-z0-9_-:.]. - Recommended: a UUID v4 generated on your side.
A malformed key returns 400 with the bad_request error code. Generate your key before
sending the request and persist it locally until you receive a definitive response (2xx or 4xx).
♻️ Lifecycle of a Key
The server treats a key as one of five states:
- First call — the request is processed normally and the response (status + body) is stored
server-side for 7 days. - Replay (same key + same body) — MPS returns the original response as-is, plus two response
headers:Idempotency-Status: replayandIdempotency-Replayed-At: <ISO 8601>. - Replay with a different body —
422 validation_failed. Idempotency keys must uniquely
identify a single business intent; generate a new key. - Concurrent replay —
409 conflict. A previous call with the same key is still being
processed. Retry after a short back-off. - After 7 days — the key is purged and can be reused for a new intent.
5xxresponses do not consume the key. You can retry the exact same request until success.
🎯 Scope
Idempotency records are scoped by (agent, HTTP method, path). Two different agents may safely use
the same string on the same endpoint. The same agent may reuse a key on two different endpoints —
they are treated as independent intents.
UUIDs in the URL are normalized before scoping.
POST /platforms/A/pay_outsandPOST /platforms/B/pay_outsshare the same scope for a given agent.
📦 Example Flow
The client sends a first POST with an idempotency key:
curl -X POST https://sandbox.mipisepaymentservices.com/api/platforms/018f.../pay_outs \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9b6e1f3a-2a14-4c12-9a3a-ce3f7a3a1b21" \
-d '{"pay_out": {"amount": 10000, "currency": "EUR"}}'MPS creates the pay-out and returns 201 Created with a body like:
{
"uuid": "e2a1-...",
"object": "financial_request",
"amount": 10000,
"currency": "EUR"
}The client's network drops before the response arrives. It replays the exact same request with the
same Idempotency-Key. MPS recognizes the replay and returns the same 201 Created and the same
JSON body, plus two extra response headers: Idempotency-Status: replay and
Idempotency-Replayed-At set to the current UTC timestamp.
Same UUID — no duplicate pay-out was created.
On
409 conflict, retry after 1 – 5 seconds — the first call is still running server-side.
🚫 Reused Key with a Different Body
Sample error response:
{
"success": false,
"error": {
"code": "validation_failed",
"message": "Idempotency-Key reused with different payload.",
"details": {}
},
"meta": { "timestamp": "2026-07-02T08:12:33Z" }
}Fix: generate a new Idempotency-Key for the corrected request. Reusing the same key across
different intents is treated as a client bug.
✅ Client-Side Recommendations
- Persist the key — generate it before sending, keep it locally until you receive a
2xxor
4xx. - Retry safely on 5xx or timeout — reuse the same key with an exponential back-off (e.g. up to
60 s). - Retry on 409 — back off 1 – 5 s, then reuse the same key.
- One key = one intent — never reuse a key across two independent operations.
- Regenerate on 422 — if the server rejects your body (validation, mismatch), generate a fresh
key for the corrected request.
Idempotency is optional. Requests without an
Idempotency-Keyheader are processed with the
historical (non-idempotent) semantics — you get the current behaviour, unchanged.