Idempotency and retries
A network can fail after Zentiq has done what you asked but before the answer reaches you. Retrying a GET, PUT, PATCH or DELETE is always safe. Retrying a POST that creates something (a persona, a webhook, a session) could create it twice, unless you send an Idempotency-Key.
How it works#
Send a unique string (up to 255 characters; a UUID is ideal) in the Idempotency-Key header, and send the same key when you retry the same request:
curl -X POST https://app.zentiqai.com/v1/knowledge/bases \
-H "Authorization: Bearer $ZENTIQ_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1c2b8e-2f4a-4c1e-9d7a-0b6c5e4d3a21" \
-d '{ "name": "Help centre" }'- The first success is kept for 24 hours. A retry with the same key and the same request gets that answer again, with
Idempotency-Replayed: true, and nothing is done twice. - The same key with a different request is
409 idempotency_conflict: use a new key for a new request. - A retry while the first is still running is
409 idempotency_in_progress, withRetry-After: wait, then retry. - A failed first attempt isn't kept: a retry after a failure runs again.
Keys are per API key: two integrations can't collide.
Which operations take it#
- POST
/v1/avatarsBring your own avatar picture - POST
/v1/voicesClone a voice - POST
/v1/personasCreate a persona - POST
/v1/sessions/tokensStart a live session (mint a client token) - POST
/v1/webhooksCreate a webhook - POST
/v1/keysMint an API key - POST
/v1/knowledge/basesCreate a knowledge pack - POST
/v1/knowledge/bases/{id}/documentsAdd a document (a file, an address or text) - POST
/v1/portalsBuild a portal from templates - POST
/v1/setup/planPlan a portal from one sentence - POST
/v1/portals/{id}/publishPublish a portal - POST
/v1/duosAdd a ready-made duo - POST
/v1/duos/{id}/publishPublish a duo - POST
/v1/portals/{id}/case-linksSend a customer a link to their case - POST
/v1/subjects/{id}/publishPublish a subject's content - POST
/v1/unitsAdd a unit (a class, team or group) - POST
/v1/roles/{id}/invitesInvite candidates to a role - POST
/v1/candidates/{id}/decisionRecord a person's decision
These are safe to repeat by their own input (the same externalId gives back the same record), and their answer is never stored:
In the SDKs#
The SDKs send an Idempotency-Key with every operation above and reuse it when they retry, so their own retries are always safe. To make your retries safe (a job that restarts, a queue that redelivers), pass a key you keep with the job:
// The SDK sends an Idempotency-Key with every creating call that takes one (the reference marks them) and reuses it
// when it retries. To make your own retries safe across restarts, pass a key you store with the job:
const pack = await zentiq.createKnowledgeBase({ name: "Help centre" }, { idempotencyKey: "import-2026-10-01-help-centre" });Speaking into a live session#
POST /v1/sessions/{id}/say takes its own eventId in the body instead: in external turn mode, a line sent again with the same eventId is spoken once (see Bring your own brain).