Concepts
Idempotency keys
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.
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 happens | You get |
|---|---|
| First request | It runs; the result is stored for the key |
| Same key, same request, finished | The 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 running | 409 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 saved | The 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#
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.