Skip to content
Idempotency
  1. Docs
  2. API
  3. Idempotency

Idempotency

Networks drop connections, and a call that builds a website can run for minutes. An Idempotency-Key makes any write safe to retry: the retry gets the first result, and the work happens — and is paid for — once.

#How it works

Send an Idempotency-Key header with any unique string — a UUID is ideal. If Attria has already seen that key from your workspace, it doesn't do the work again: it replays the result of the first request.

curl -X POST "https://app.attria.io/api/v1/studio/document/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "message": "A 10-slide seed pitch deck for Northwind",
    "auto": true
  }'
  • Turns are durable: if the first request is still running, a retry with its key returns the same turn instead of starting a second one.
  • Reusing a key with a different body is refused with 409 conflict — a key names one action, not a slot.
  • Every sample in these docs sends one on writes.

#When to send one

On every POST, PATCH and DELETE — anything that makes, changes or spends. GET requests change nothing, so they're always safe to repeat without one.

Make one key per operation, before the first attempt, and reuse it only for retries of that operation. A new key on a retry is a new request: it builds again and spends again.

#Repeating to check on work

Because a repeat with the same key never runs twice, some long jobs use it as their status check: a background agent run and a video content app both answer 202 first, and the same request with the same key returns the progress — then the finished result. See Jobs & streaming.

#A retry loop

// One key per operation, created BEFORE the first attempt and reused by every retry.
const key = crypto.randomUUID();

async function createDeck(attempt = 1): Promise<unknown> {
  try {
    const res = await fetch("https://app.attria.io/api/v1/studio/document/turns", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
        "Content-Type": "application/json",
        "Idempotency-Key": key,
      },
      body: JSON.stringify({ message: "A 10-slide seed pitch deck for Northwind", auto: true }),
    });
    if (res.status >= 500 && attempt < 4) return createDeck(attempt + 1);
    return await res.json();
  } catch (networkError) {
    if (attempt < 4) return createDeck(attempt + 1); // same key: replays, never repeats
    throw networkError;
  }
}