Skip to content

Idempotency

Mutating endpoints (anything that creates a resource, charges credits, or starts a job) accept an Idempotency-Key header. Use it on every non-idempotent request you might retry.

  • Submitting POST /v1/code or any other coding/codebook write. A retry without an idempotency key can re-charge credits.
  • Creating projects, questions, or webhooks.
  • Anywhere your network layer auto-retries (e.g. a fetch wrapper with exponential backoff).

You don’t need an idempotency key on GET requests or on DELETE requests — they’re naturally idempotent on the server.

Terminal window
curl -X POST https://api.surveycoder.io/v1/code \
-H "x-api-key: $SCP_API_KEY" \
-H "Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" \
-H "Content-Type: application/json" \
-d '{ "question": "...", "responses": ["..."] }'

The server caches the response for 24 hours, keyed on (api_key, idempotency_key). Replaying the exact same request returns the cached response — same status code, same body, same request_id.

  1. Keys must be unique per logical request. A UUID v4 is the safest default.
  2. Keys are scoped per API key, not per org. Two keys can use the same idempotency key without conflict.
  3. The request body must match the original. If you reuse a key with a different body, the API returns VALIDATION_ERROR with message: "Idempotency-Key reused with different body".
  4. Keys expire after 24 hours. A 25-hour-later retry creates a new request.

Pair idempotency keys with bounded retries. We recommend at most 3 attempts on 5xx responses (or 429 with a Retry-After header):

async function codeWithRetry(payload: CodeRequest) {
const idempotencyKey = crypto.randomUUID();
let lastErr: unknown;
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await sc.code(payload, { idempotencyKey });
} catch (err) {
lastErr = err;
if (!isRetryable(err)) throw err;
await sleep(2 ** attempt * 1000); // 1s, 2s, 4s
}
}
throw lastErr;
}

isRetryable should return true for HTTP 429, 502, 503, 504, and network errors; false for 4xx errors that aren’t 429.