Idempotency Keys

Idempotency keys let you safely retry requests without creating duplicate renders. Send an Idempotency-Key header with a unique value — if the same key is sent again within 24 hours, PixDoc returns the cached result instead of re-rendering.

Idempotency keys are available on all plans, including Free. They are a reliability feature designed to make your integration more robust.

How to Use

Add an Idempotency-Key header to any PDF or screenshot request. The value should be a unique string that identifies the logical operation.

curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: invoice-1234-v1" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Invoice #1234</h1>"}'

Response Headers

Every response to a request with an Idempotency-Key header includes these additional headers:

HeaderDescription
X-CacheHIT if the result was served from cache, MISS if a new render was performed
X-Idempotency-KeyEchoes back the idempotency key you sent

Behavior

ScenarioResult
First request with a keyRenders normally, returns X-Cache: MISS
Same key within 24 hoursReturns cached result, X-Cache: HIT, no re-render, no quota consumed
Different keyNew render (treated as a separate request)
No headerNormal render, backward compatible (no caching)
Key for an in-progress renderReturns 409 Conflict — retry after the first request completes

Cached responses don't count against your render quota. If you retry a request with the same idempotency key, only the first render is billed.

Best Practices

  • Use deterministic keys scoped to the logical operation. For example, invoice-{id}-{version} ensures the same invoice version always returns the same result.
  • Use UUIDs for one-off requests when you just need safe retries: const key = crypto.randomUUID().
  • Keys are scoped per user. Different API keys belonging to the same user share the same idempotency namespace.
  • 24-hour window. After 24 hours, the cached result expires and the same key triggers a new render.
  • Don't reuse keys for different content. If you change the request body but keep the same key, you'll get the original cached result back.

Retry Example

Here's a pattern for safely retrying failed requests:

async function renderPdfWithRetry(html, idempotencyKey, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
  try {
    const response = await fetch("https://pixdoc.dev/api/v1/pdf", {
      method: "POST",
      headers: {
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
        "Idempotency-Key": idempotencyKey,
      },
      body: JSON.stringify({ html }),
    });

    if (response.status === 409) {
      // Key is being processed — wait and retry
      await new Promise(r => setTimeout(r, 2000));
      continue;
    }

    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.blob();
  } catch (err) {
    if (attempt === maxRetries - 1) throw err;
    await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
  }
}
}

// Safe to call multiple times — only renders once
const pdf = await renderPdfWithRetry(
"<h1>Invoice #1234</h1>",
"invoice-1234-v1"
);

Key Format

Idempotency keys must be strings between 1 and 255 characters. We recommend one of these formats:

  • Entity-scoped: invoice-{id}-v{version}, report-{id}-{date}
  • UUID: 550e8400-e29b-41d4-a716-446655440000
  • Composite: {user-id}:{operation}:{timestamp}