Idempotency and Retries

The journey from a partner application to the local document management system passes through several stages. Any one of them can temporarily lose a message, which is why at-least-once delivery is used throughout. To prevent this from resulting in duplicate imports, there is the Idempotency-Key.

The guarantee is simple: A request with the same key will be executed at most once – no matter how many times it is sent.

The Key

POST /v1/dms/documents
Authorization: Bearer eyJ...
Idempotency-Key: import-schriftsatz-2026-0042-001
Content-Type: application/json
Property Rule
Header Idempotency-Key
Allowed characters Letters, digits, and ., _, and -
Length 1 to 128 characters
Required? No. Without a key, the call behaves like a regular request.
Recommended for All mutating calls: import, new version, reassignment

A violation of the character set or length rules is rejected with 400 – intentionally, so that an application relying on idempotency immediately knows its key was not accepted.

A suitable value is a random identifier (such as a GUID) or a string derived from the business operation. The only requirement is: one key per business operation, and the same key on every retry.

What Happens on a Retry

Unlike some other APIs, the original result is not cached and not returned again. Instead, the API reports the duplicate attempt as such:

State of the original request Response to the retry
Still in progress 504 IDEMPOTENCY_KEY_INFLIGHT_TIMEOUT – it did not complete in time. Try again later.
Completed or permanently failed 409 IDEMPOTENCY_KEY_REUSED – the request will not be executed again.
Temporarily failed The retry is executed normally.
Rejected unprocessed by the connector (502 CONNECTOR_DEADLINE_EXCEEDED) The retry is executed normally – the first attempt had no effect.

Important for implementation. A 409 IDEMPOTENCY_KEY_REUSED is not an error with the request. It simply means: "This request has already been processed." It does not indicate whether it succeeded. The application must determine the actual outcome on its own – for operations that return 202 Accepted, via the operation query GET /v1/platform/operations/{operationId}; otherwise, through a business-level check (does the document already exist in the target case file?).

Two Pitfalls to Be Aware Of

The Key Is Unaware of the Request Body

Only the key is evaluated – not the request body. If the same key is used with a different body, it is treated as a retry and rejected. The second body will not be silently executed, but the contradiction will not be reported as such either.

Rule: Every new request always gets a new key. Even if only a single field was corrected.

A Key Cannot Be Reused After a Correction

If an import fails due to an incorrect field and the field is corrected, that is a new request. Using the old key would cause the corrected request to be rejected as a duplicate.

Retry Strategy

Recommendations by HTTP status:

Response Retry? Approach
2xx No –
4xx except 408, 425, 429 No Fix the request first
408 Timeout Yes Exponential backoff: 1 s, 2 s, 4 s, 8 s, then give up
425 Too Early Yes Same as above
429 Too Many Requests Yes Follow Retry-After exactly
502, 503, 504 Yes Exponential backoff with jitter: start at 1 s, cap at 60 s, give up after approximately 10 minutes
No response (network) Yes Same as 5xx

Retry-After always takes precedence. If the response specifies a wait time – as it does for 429 and 503 – that value applies instead of the cap in the table above. For TENANT_OVERLOADED, for example, that is 120 seconds.

This page is the authoritative source for retry behavior. The per-error-code recommendations in Error Codes refer back to it; where the two appear to conflict, the recommendation for the specific error code takes precedence.

The jitter is not a minor detail – it matters: without it, all waiting applications would hammer the service at the same moment once an outage ends.

The Idempotency-Key remains the same across all attempts for a given request.

The Special Case: No Response Received

This is the exact scenario idempotency exists for: the request may have arrived and been processed, but the response was lost. The application has no way to tell the difference.

With a key, retrying is safe:

  • The request did not arrive → it will be executed now.
  • The request arrived and is still running → 504 IDEMPOTENCY_KEY_INFLIGHT_TIMEOUT.
  • The request arrived and completed → 409 IDEMPOTENCY_KEY_REUSED, and the application determines the outcome via the operation query.

In none of these three cases will a duplicate document be created.

What Idempotency Does Not Do

  • No ordering guarantee. Two requests with different keys may be processed in any order. If ordering matters, you must serialize on your end or use the result of the first request as input to the second.
  • No unlimited validity. See the section below – after roughly five minutes, a key expires.
  • No protection against a logically incorrect request. Idempotency guards against duplicate execution, not against a business operation that was wrong to begin with.

How Long a Key Remains Valid

A key is retained for approximately five minutes. After that, it is no longer known to the API.

This is the most important number on this page, because the consequences are significant: A retry after this deadline has passed will be executed as a normal request – it is no longer treated as a retry. For an import, this means a second document will be created.

Two rules follow from this:

  • Complete all retries for a given request within a few minutes. The recommended cap of approximately ten minutes from the table above is already too long to rely on idempotency at the end of that window.
  • Do not blindly retry after a long interruption. If a request is picked up again hours later – for example, after an application restart – you must first perform a business-level check to determine whether it has already been executed. For an import, that means listing the documents in the target case file and checking.

Including a Correlation ID

Independently of the idempotency key, every request should include its own correlation ID:

X-Correlation-Id: 9f3a2b7c4d1e5081

Allowed characters are letters, digits, and ., _, and -, up to 64 characters. If no ID is provided, or an invalid one is sent, the API generates one automatically.

Where the ID appears in the response depends on the outcome:

Outcome Where the ID appears
Success In the X-Correlation-Id response header
Error Only in the error response body, in the correlationId field – the header is absent in this case

The reason is technical: error handling rebuilds the response from scratch, discarding any headers that were already set. For integrations, this means: in the event of an error, read the ID from the response body, not the header. Relying on the header will leave you without an ID precisely when you need one most.

This ID is the thread connecting all logs all the way through to the firm. It should be recorded in the partner application's logs so it is readily available if a question arises.

Further Reading

------------------------------------------------------------------------------------------------------------------
This article has been automatically translated by an AI and may therefore contain errors.

Related to