Skip to content

Concepts

Idempotency keys

On this page

Networks fail. When a write times out you can't tell whether it happened. Send an Idempotency-Key header with every write, and retrying is always safe: Bizisy applies the request at most once.

Shell
curl https://api.bizisy.com/v1/org/people.hire \
  -H "Authorization: Bearer $BIZISY_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f6c2b8e-6a43-4f3e-9d1e-0b8a3c1f2d77" \
  -d '{"given_name":"Bea","family_name":"Santos","work_email":"bea@acme.com","title":"Designer","start_date":"2026-11-02"}'

How it works#

  • The key: any string of 1–255 visible ASCII characters. Use a new UUID per logical request, and the same one for its retries.
  • For 24 hours, retrying with the same key and the same request never applies it twice: you get the first result back, with the header Idempotent-Replayed: true.
  • Keys belong to the API key that sent them: two integrations can't collide.
  • Reads and dry runs ignore the header (they're safe to repeat anyway).
  • The header works on the REST API with an API key. MCP tool calls don't take it: assistants preview first and read before retrying.

Every case#

What happensYou get
First requestIt runs; the result is stored for the key
Same key, same request, finishedThe stored result, Idempotent-Replayed: true
Same key, different request (another action or input)409 conflict: "already used for a different request"
Same key while the first is still running409 conflict: retry in a few seconds
The first ended in a client error (4xx)The same error again: fix the request and use a new key
The first ended in a server error (5xx)The key is released: retry with the same key
Bizisy can't tell whether the first was savedThe same 409 on every retry: read the current state instead of repeating

A request still running after 10 minutes is treated as crashed, and its key can be used again.

Results that are never stored#

Some results hold a secret or personal data: an invite link, a webhook signing secret, a person's details. Those are never stored for replay. A retry of a completed request then gets 409 conflict saying it already completed, with a link to its entry in Activity in details.view_url, instead of the result. The API reference marks these actions under Retries. Results larger than 512 KB aren't stored either.

In your client#

JavaScript
import { randomUUID } from 'node:crypto';

async function hire(person) {
  const key = randomUUID(); // one per logical request, reused by every retry
  for (let attempt = 1; ; attempt++) {
    const res = await fetch('https://api.bizisy.com/v1/org/people.hire', {
      method: 'POST',
      headers: { Authorization: `Bearer ${process.env.BIZISY_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': key },
      body: JSON.stringify(person),
    });
    // Retry only what can succeed later: server errors and the rate limit.
    if (res.status < 500 && res.status !== 429) return res.json();
    if (attempt === 5) throw new Error(`gave up after ${attempt} attempts: ${res.status}`);
    const wait = Number(res.headers.get('retry-after') ?? 2 ** attempt);
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
}

Retry 5xx and 429 with the same key. Don't loop on other 4xx: a 409 on a retry means the first attempt is still running (wait a few seconds) or its outcome can't be replayed (read the current state).

Something missing or wrong on this page? Write to hello@bizisy.com.

Developer docs