# Idempotency and retries ## The SDK does not retry for you No `RatepayClient` operation retries automatically, every call makes exactly one HTTP request. If that request fails at the transport level or the server returns 5xx, you get a `RatepayNetworkException` and it's your integration's decision whether, and how, to retry. ## Idempotency Every operation method takes a trailing `idempotencyKey: String?` parameter. Pass a **stable, caller-chosen key that's the same across retries of the same logical request**, and the API can recognize a retried request as a duplicate rather than double-processing it (e.g. double-authorizing, double-capturing). ```java Java String idempotencyKey = "authorize-" + orderId; // stable per logical attempt, reused on retry try { AuthorizeOutcome outcome = client.authorize(request, idempotencyKey); } catch (RatepayNetworkException e) { // safe to retry with the SAME idempotencyKey AuthorizeOutcome retried = client.authorize(request, idempotencyKey); } ``` ```kotlin Kotlin val idempotencyKey = "authorize-$orderId" // stable per logical attempt, reused on retry val outcome = try { client.authorize(request, idempotencyKey) } catch (e: RatepayNetworkException) { // safe to retry with the SAME idempotencyKey client.authorize(request, idempotencyKey) } ``` Passing null does not give you retry-safety When you pass `null` (or omit the parameter in Kotlin), the SDK auto-generates a key with its internal random generator, which returns a fresh random UUID **on every call**. It is not derived from the request body, so two calls with `null` get two different keys, even with byte-for-byte identical bodies, and the API treats them as two separate requests. A retry without an explicit key is therefore **not** deduplicated, which is not what you want for retries. Always pass your own stable key when retrying.