Idempotent requests

Overview

To ensure that API requests are handled safely without accidental duplication, Zenskar supports idempotency. This is especially useful in scenarios where a network interruption occurs, and you are unsure if your request reached our servers. By retrying the request with the same idempotency key, you guarantee that the operation is performed only once.

🔖

Currently, idempotency is supported exclusively for Usage Event APIs. Support for other Zenskar APIs will be rolled out in a phased manner.


How idempotency works

To make an idempotent request, include a unique key in the Idempotency-Key header of your HTTP request.

  1. First Request: Zenskar processes the request normally and saves the resulting status code and response body.
  2. Subsequent Requests: If you send another request with the same Idempotency-Key, Zenskar skips processing and returns the cached response from the first successful execution.

Key lifecycle and TTL

  • TTL (time to live): Idempotency keys are stored for 24 hours. After 24 hours, a request with the same key will be treated as a new request.
  • Scope: Keys are scoped to your Organization. You cannot reuse a key across different organizations, but you should ensure uniqueness within your own environment.
  • Payload consistency: If you retry a request with the same key but change the request body, Zenskar will return an error to prevent accidental data mismatches.

Workflow diagram

The following diagram illustrates how Zenskar handles requests containing an idempotency key:

sequenceDiagram
    participant Client
    participant Zenskar API
    participant Cache

    Client->>Zenskar API: POST /usage/api_calls (Idempotency-Key: "unique-key-123")
    Zenskar API->>Cache: Check if "unique-key-123" exists
    
    alt Key not found
        Zenskar API->>Zenskar API: Process request & Save data
        Zenskar API->>Cache: Store Response (TTL 24h)
        Zenskar API-->>Client: 200 OK (Original Response)
    else Key found
        Cache-->>Zenskar API: Return Cached Response
        Zenskar API-->>Client: 200 OK (Cached Response)
    end

Example request

To report usage idempotently, add the Idempotency-Key header to your request. We recommend using a V4 UUID or another high-entropy string.

curl --location --request POST 'https://api.zenskar.com/usage/api_calls' \
--header 'organisation: 888ae523-9999-4ed7-85cc-6c0a54320568' \
--header 'x-api-key: <your-api-key>' \
--header 'Idempotency-Key: 7b8b8092-2374-42f0-928d-f5370d07412e' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "call_count": 5
    },
    "timestamp": "2025-12-17 02:52:04",
    "customer_id": "c02"
}'

Error handling and retries

Idempotency is a critical tool for building resilient integrations. Here is how to handle common scenarios:

Network timeouts

If a request times out or the connection is dropped before you receive a response, you can safely retry the exact same request with the same Idempotency-Key. If Zenskar received the first request, you will get the cached result. If we didn't, we will process it for the first time.

4xx and 5xx Errors

  • 4xx Errors: If a request fails with a validation error (e.g., 400 Bad Request), the idempotency key is generally not cached. You should fix the request payload and you can choose to use a new key or the same one depending on the fix.
  • 5xx Errors: If you receive a 500 Internal Server Error or 503 Service Unavailable, Zenskar does not cache the result. You should retry these requests with the same idempotency key.

Changing Request Parameters

If you send a request with an existing Idempotency-Key but change the request body (e.g., changing the call_count from 5 to 10), Zenskar will return a 400 error indicating a parameter mismatch. To send a different payload, you must use a different key.