Documentation Index
Fetch the complete documentation index at: https://docs.autousers.ai/llms.txt
Use this file to discover all available pages before exploring further.
Set the Idempotency-Key header on any retried POST so a network
hiccup never double-charges the team.
curl -X POST https://app.autousers.ai/api/v1/evaluations \
-H "Authorization: Bearer $AUTOUSERS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "name": "...", "type": "SSE", "...": "..." }'
If the request reaches us, we record the response. If you retry with the
same key within 24 hours, we replay the original response — same
status, same body, same X-Request-Id — without re-running the work.
Beta status (2026-05-04): the Idempotency-Key header is accepted but
enforcement is rolling out. During beta the server records keys but does not
yet replay; behaviour is “best-effort safe retries”. Watch the
Changelog.
When to use it
Any time the request mutates state and a retry could double-bill. In
practice that is:
| Route | Why idempotency matters |
|---|
POST /v1/evaluations | Creates an evaluation. Re-runs spawn duplicates. |
POST /v1/evaluations/{id}/ratings | Submits a rating. Re-submits skew agreement. |
POST /v1/evaluations/{id}/run-autousers | Queues paid autouser runs. The expensive one. |
POST /v1/api-keys | Mints a key. Re-mints leak credentials. |
POST /v1/autousers | Creates an autouser persona. |
POST /v1/templates | Creates a template / dimension. |
GET, PATCH, and DELETE are already idempotent at the protocol
level — Idempotency-Key is ignored.
- Up to 255 characters.
- We recommend a UUID v4 generated by your client per logical
request, not per HTTP attempt. A retry uses the same key.
- Scope: per team. Two teams using the same key string see independent
records.
import { randomUUID } from "node:crypto";
async function createEvaluationOnce(payload: unknown) {
const idempotencyKey = randomUUID();
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await fetch("https://app.autousers.ai/api/v1/evaluations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AUTOUSERS_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify(payload),
});
} catch (err) {
if (attempt === 2) throw err;
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
}
}
}
Mismatched bodies
If you replay a key with a different body, we 409:
{
"error": {
"message": "Idempotency-Key was previously used with a different request body.",
"type": "invalid_request_error",
"code": "idempotency_key_reused",
"request_id": "0192c7f8-..."
}
}
The check is a sha256 of the canonical request body. The cure is a new
key — pick one fresh UUID per logical request.
TTL
Records are kept 24 hours from first use, then garbage-collected.
After that the key is reusable. In practice, generate fresh keys; reuse
is for retries within a single workflow.
Combining with retries
Idempotency-Key and exponential backoff are complementary. The first
makes the server safe to retry; the second decides when.
import { randomUUID } from "node:crypto";
async function postIdempotent(path: string, body: unknown) {
const key = randomUUID();
for (let attempt = 0; attempt < 5; attempt++) {
const res = await fetch(`https://app.autousers.ai${path}`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AUTOUSERS_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": key,
},
body: JSON.stringify(body),
});
if (res.ok) return res.json();
if (res.status >= 500 || res.status === 429) {
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
continue;
}
throw new Error(`HTTP ${res.status}`);
}
}
Webhooks: idempotency on the receiver
Your webhook receiver should be idempotent too. Use the
Autousers-Event-Id header as the dedup key. See
Retry & replay.