Limits and paging
Rate limits#
Every operation belongs to a class, shown in the reference. Requests are counted per key and per organisation (an organisation's keys share its budget), across all of Zentiq's servers, in one-minute windows:
| Class | Per key, a minute | Per organisation, a minute | Used by |
|---|---|---|---|
| read | 600 | 1,200 | Reading: lists and single records (59 operations) |
| write | 120 | 240 | Creating, changing and deleting (49 operations) |
| live | 30 | 60 | Starting a live session (2 operations) |
| heavy | 20 | 40 | Work that takes a while: cloning a voice, planning or filling a portal, exports, candidates' interviews (6 operations) |
| search | 120 | 240 | Searching knowledge (2 operations) |
| address | 600 a minute from one address, whatever the key | Every request | |
Every answer carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets), for whichever of your key's or your organisation's limits is closer. Past it, the answer is 429 rate_limited with Retry-After: wait that many seconds. GET /v1/me lists your limits under rateLimits.
Live sessions and minutes#
- At once: a plan (or an owner, under Plan & billing) can cap how many live sessions run at the same time. Past it, starting one is
429 concurrency_limit; end one first.GET /v1/meshowslimits.maxConcurrentSessionsandlimits.activeSessions. - Minutes are prepaid, shared by the console and the API. With none left (or past the organisation's own monthly cap), starting a session is
402 insufficient_minutes.GET /v1/usageshows minutes used and left, and theusage.thresholdwebhook warns you as they run low. - Plan features: a session that needs something the plan doesn't include is
403 feature_not_in_plan; a paused account is403 account_paused.
Pages#
Lists answer one page at a time:
limit: how many items, 1 to 200 (default 50);cursor: thenextCursorof the page before;nextCursoris null on the last page.
A page can hold fewer than limit items and still have a nextCursor: keep going until it is null. Lists are newest first, unless an operation offers order=asc. A cursor belongs to its list and its filters: use it with the same query.
// One page at a time…
const first = await zentiq.listPersonas({ limit: 50 });
if (first.nextCursor) await zentiq.listPersonas({ limit: 50, cursor: first.nextCursor });
// …or every item, fetching pages as you go.
for await (const persona of zentiq.paginate("listPersonas", { limit: 100 })) console.log(persona.id, persona.name);Syncing what changed#
To keep your own system in step, ask only for what changed since your last run:
- lists that offer
updatedAfter(an ISO time; the reference shows which, results and inbox items among them) give only what changed after it; - the event log,
GET /v1/events, takesafter(an event id) withorder=asc, andfrom/to: every event your webhooks were offered, with the same ids, so you can catch up after an outage.
Editing at the same time#
Subject content is saved as versions. Reading it gives its version (and an ETag); send it back as baseVersion (or If-Match) when you save, and a save made on top of an older version than the current one is refused with 409 version_conflict and details.currentVersion, instead of overwriting someone's work. Without one, the last save wins.
Work that takes a while#
Reading a document into a knowledge pack, or checking that a duo renders before it goes live, takes longer than a request. The operation answers at once (a document's status is processing), and the event says when it is done (knowledge.document.processed); or poll the resource. The SDKs' waitUntilReady does the polling for you.
Sizes#
A request, a file or a field that is too large is 413 too_large (on the 2026-07-08 contract, 413 invalid_request). The reference gives each field's limits.