Skip to main content

Idempotent Requests

The Magnolia API supports idempotency for all authenticated POST and PATCH requests using the Idempotency-Key header, following the established draft RFC.

Why Use Idempotent Requests?

Idempotency prevents duplicate operations when network issues or timeouts occur. For example:

  • Network timeout: Your request succeeds on the server, but you never receive the response
  • Retry logic: Your application automatically retries failed requests
  • User error: A user clicks "Submit" multiple times

With idempotent requests, retrying with the same Idempotency-Key will return the same result without creating duplicates.

Which Methods Support Idempotency?

HTTP MethodIdempotency SupportNotes
POST✅ Supported via Idempotency-Key headerRequired for safe retries
PATCH✅ Supported via Idempotency-Key headerRequired for safe retries
GET✅ Inherently idempotentNo header needed
DELETE✅ Inherently idempotentNo header needed

How to Make an Idempotent Request

1. Generate a Unique Key

Generate a random, unique key for your request. A UUID v4 is recommended:

Example: 550e8400-e29b-41d4-a716-446655440000

2. Add the Header

Include the Idempotency-Key header with your request:

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

3. Make Your Request

Perform your POST or PATCH request normally. If you retry with the same key, you'll get the same response.

Best Practices

1. Generate Keys Client-Side

Always generate idempotency keys on the client side. This ensures you have the same key available for retries.

// Good: Generate once, reuse for retries
const idempotencyKey = crypto.randomUUID();
await retryableRequest(data, idempotencyKey);

// Bad: Generate new key on each retry
await retryableRequest(data, crypto.randomUUID());

2. Store Keys for Long Operations

For long-running operations, store the idempotency key alongside the operation:

// Store the key with the pending operation
const operation = {
id: 'op_123',
data: accountData,
idempotencyKey: crypto.randomUUID(),
status: 'pending'
};
await saveToDatabase(operation);

// Use the stored key for retries
await createAccount(operation.data, operation.idempotencyKey);

3. Use Unique Keys Per Operation

Never reuse idempotency keys across different operations:

// Good: Different operations, different keys
const key1 = crypto.randomUUID();
await createAccount(accountData, key1);

const key2 = crypto.randomUUID();
await createContact(contactData, key2);

// Bad: Reusing the same key
const key = crypto.randomUUID();
await createAccount(accountData, key);
await createContact(contactData, key); // Don't do this!

4. Handle Key Expiration

Idempotency keys expire after 24 hours. If an operation might take longer than 24 hours, be prepared to generate a new key:

const MAX_KEY_AGE = 24 * 60 * 60 * 1000; // 24 hours in milliseconds

function shouldRegenerateKey(keyTimestamp) {
return Date.now() - keyTimestamp > MAX_KEY_AGE;
}

How It Works

When you send a request with an Idempotency-Key:

  1. First request: The server processes the request and stores the result with the key
  2. Duplicate request: If you retry with the same key within 24 hours, the server returns the stored result without reprocessing
  3. After 24 hours: The key expires and a new request would be processed as new

Important Notes

  • Optional but recommended: Using idempotency keys is currently optional but highly recommended for production applications
  • Expiration: Keys expire after 24 hours in all environments
  • Only for mutations: Use idempotency keys only for POST and PATCH requests
  • Case-sensitive: Idempotency keys are case-sensitive
  • Maximum length: Keys can be up to 255 characters (UUID v4 is 36 characters)

Learn More

For more details on the idempotency standard, see draft-ietf-httpapi-idempotency-key-header-06.