Schemas
Every object the API takes and answers with. New fields can appear at any time: ignore the ones you don't know.
AddMembershipInput
role"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"requiredOWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullworkspaceIdstring | nullgradeBandstring | nullageBand"18+" | null
AgentAnswer
One written answer from a business's public website assistant.
answerstringrequiredThe assistant's written answer, from what the business has told it. Email addresses, phone numbers and payment or identity numbers are removed.
urlstringrequiredThe assistant's own page, where a person can talk to it, book or reach the team.
aiGeneratedtruerequiredAlways true: the answer is AI-generated (EU AI Act Article 50(2)). Say so when you pass it on.
AgentAskInput
questionstringrequiredOne question, up to 800 characters. Leave out people's names and contact details: email addresses, phone numbers and payment or identity numbers are removed before it is read.
1-800 characters
ApiKey
An API key. The secret is never returned after creation.
idstringrequiredAPI key id (
key_…).pattern `^key_.*`
namestringrequiredprefixstringrequiredThe key's first characters, as shown in the console.
scopesstring[]requiredThe scopes as set on the key; [] or ["*"] is full access (sensitive scopes are added by name).
apiVersion"2026-07-08" | "2026-10-01"requiredThe contract the key speaks.
createdBystring | nullrequiredWho made it: a member (
usr_…) or a key (key_…); null for older keys.lastUsedAtstring (date-time) | nullrequiredrevokedAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
AssessmentCompletedData
A scored attempt completed; the final result once a person has decided it.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullpassedboolean | nullpercentnumber | nullmarksnumber | nulloutOfnumber | nullpassMarknumber | nullquestionSetobject | nullidstring | nulltitlestring | null
humanReviewboolean | nullreviewboolean | nullcriticalFailboolean | nulldifficultystring | nullfinalboolean | nullaiobject | nullpassedboolean | nullpercentnumber | nullmarksnumber | null
decisionstring | nullvoidedboolean | nullreviewedboolean | null
AssignmentCompletedData
A person completed assigned work.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullassignmentIdstring | nulltitlestring | nullminutesnumber | nullpassboolean | null
AssignmentCreatedData
Work was assigned.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullassignmentIdstring | nulltitlestring | nulllearnersinteger | nulldueAtstring | nullminutesnumber | nullskillsstring[] | nullfocusobject | nullkindstring | nullidstring | nulltitlestring | null
difficultystring | nulltargetnumber | null
AssignmentStartedData
A person started assigned work.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullassignmentIdstring | null
AttemptGrantedData
A person was given one more scored attempt.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreportIdstring | nullincompleteboolean | null
AttestationRecordedData
A person confirmed an attestation before a completion.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullquestionSetobject | nullidstring | nulltitlestring | null
versioninteger | nulldocumentIdsstring[] | null
Avatar
A face a persona can wear: from the library, or your organisation's own.
idstringrequiredAvatar id (
av_…).pattern `^av_.*`
namestringrequiredkind"builtin" | "custom"requiredbuiltin: Zentiq's library; custom: your organisation's own.
genderstring | nullrequiredA library face's gender (female, male); null for your own pictures.
ageBandstring | nullrequiredA library face's age band (20s, 30s, 40s, 50s, 60s); null for your own.
heritagestring | nullrequiredA library face's heritage (white, black, indian, chinese, korean, japanese, thai, hispanic, middleeastern, mixed); null for your own.
previewUrlstring | nullrequiredThe picture. A library face is public (usable in an <img>); your own needs your API key (or a console sign-in).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
aiGeneratedtruerequiredAlways true: this avatar's video and voice in every session are AI-generated, and so is its picture unless it is a photo you uploaded (EU AI Act Article 50(2)).
AvatarInput
Exactly one of imageBase64 or imageUrl, and consent: whose face it is and that they agreed, or subject "generated" for a face made by AI.
namestringDefault "Custom avatar".
imageBase64stringThe picture as a data:image/… URI (PNG, JPEG or WebP).
imageUrlstring (uri)Or a public https address to fetch it from (6 MB at most).
Consent to clone a real person's voice or to make an avatar from their picture. Recorded with who confirmed it (the API key), when, a hashed IP address, the exact wording and its version. The organisation's owners can export records and withdraw them; a withdrawn voice or face stops starting new sessions.
BookingRequestedData
A website visitor asked for a booking: contact details, the service and time asked for, and their consent.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullsummarystring | nullneedstring | nullbudgetstring | nulltimelinestring | nullcontactobject | nullnamestring | nullemailstring | nullphonestring | nullcompanystring | nullrolestring | nullpreferredTimestring | nulllocationstring | nullreferencestring | null
consentobject | nullpurposestring | nullmarketingboolean | nulltextstring | nullversioninteger | nullatstring | nullgivenboolean | null
promisestring | nulldueAtstring | nulldepartmentstring | nullverifiedboolean | nullportalIdstring | nullservicestring | nullwhenstring | nullstatusstring | nullinboxItemIdstring | null
Candidate
A candidate: someone who took a role's interview. A person decides every outcome: scores and bands are a sorting aid for the hiring team, never a verdict, and no decision is made automatically.
idstringrequiredcand_…: the candidate's interview.pattern `^cand_.*`
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
roleIdstringrequiredSubject id (
sub_…).portalIdstring | nullrequiredinviteIdstring | nullrequiredexternalIdstring | nullrequiredYour ATS's id from the invite.
namestring | nullrequiredNull once erased.
emailstring | nullrequiredphonestring | nullrequiredinterviewedAtstring (date-time)requiredISO 8601 UTC timestamp.
minutesnumber | nullrequiredtypedbooleanrequiredThey typed instead of speaking.
roundinteger | nullrequiredwithdrawnbooleanrequiredThey chose to end the interview: never scored.
erasedbooleanrequirederasedAtstring (date-time) | nullrequiredmustHaves"met" | "missed" | "unclear" | "none" | nullrequiredThe must-have requirements: all met, one missed, unclear (a person checks), or none set. Flagged for a person, never acted on. Null once erased.
requirementsobject[]requiredEach requirement's result; never the answer. Empty once erased.
idstringrequiredmetboolean | nullrequiredknockoutbooleanrequired
scorenumber | nullrequiredOnly where the role shares scores, and never once erased; else null.
band"strong" | "possible" | "below" | "unscored" | nullrequiredOnly where the role shares scores, and never once erased; else null.
rankinteger | nullrequiredPlace by score among the role's candidates in the same round (1 = highest; erased and withdrawn candidates hold no place); only where the role shares scores.
decisionobject | nullrequiredThe latest decision a person made; null while it awaits one.
value"invite" | "hold" | "decline"requireddecline is shown to people as "not progressing".
reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequiredThe reason code from the fixed list (a note is never given out).
decidedAtstring (date-time)requiredISO 8601 UTC timestamp.
decidedByobject | nullrequiredThe member who decided (never an API key).
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
reviewsobjectrequiredcountintegerrequiredrequiredintegerrequiredrecommendationsobject | nullrequiredHow many reviewers recommend advance, hold or do not advance. Only where the role shares scores (candidates.share_scores), and never once erased; else null.
advanceintegerrequiredholdintegerrequireddoNotAdvanceintegerrequired
holdbooleanrequiredA legal hold keeps their data past the role's retention.
reviewRequestedbooleanrequiredThey asked for a review of the decision and no decision was recorded since.
retentionExpiresAtstring (date-time) | nullrequiredWhen their data is erased (null while held or once erased).
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
CandidateCompliance
A candidate's US hiring record: the notices they read, their consent and their requests.
candidateIdstringrequiredCandidate id (
cand_…).pattern `^cand_.*`
roleIdstringrequiredSubject id (
sub_…).laws("illinois" | "nyc" | "colorado")[]requiredThe US hiring rules the pack applies to the role now: illinois, nyc, colorado.
consentobject | nullrequiredWhat the candidate read and agreed to at the start; null for an interview started before the pack was on for the role.
atstring (date-time) | nullrequiredWhen the candidate agreed to take part and started.
shownAtstring (date-time) | nullrequiredWhen the page with the notices was made for them.
noticesobject[]requiredkind"aivia" | "nyc" | "colorado"requiredversionstringrequiredfingerprintstringrequiredSHA-256 of the notice's exact text as shown.
illinoisConsentbooleanrequiredThey gave the separate consent to the AI analysing their interview (Illinois).
nycNoticeobject | nullrequiredNew York City: how the notice reached the candidate at least 10 business days before the interview.
via"posting" | "invite_email" | "invite_link" | "door_email"requiredposting (the date your job posting gave it), invite_email, invite_link or door_email.
noticeAtstring (date-time) | nullrequiredpostedOnstring (date) | nullrequired
CandidateDecisionInput
A person's decision on one candidate. A person decides every outcome: scores and bands are a sorting aid for the hiring team, never a verdict, and no decision is made automatically.
decision"invite" | "hold" | "decline"requiredreason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other"requiredmust_haves, strong_answers, missing_must_have, stronger_candidate, more_evidence, withdrew or other (other needs a note).
notestringKept for the hiring team; never given out through the API or webhooks.
at most 600 characters
decidedBystringrequiredThe member who made the decision (
usr_…). Their own hiring access applies, and a decline needs them to have opened the interview or reviewed it in Zentiq.sendOutcomeEmailbooleanEmail the candidate the outcome, with their link to ask for a review.
CandidateInterview
A candidate's interview for your hiring system: every read is logged on the candidate. A person decides every outcome: scores and bands are a sorting aid for the hiring team, never a verdict, and no decision is made automatically.
idstringrequiredCandidate id (
cand_…).pattern `^cand_.*`
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
roleIdstringrequiredSubject id (
sub_…).portalIdstring | nullrequiredinviteIdstring | nullrequiredexternalIdstring | nullrequiredYour ATS's id from the invite.
namestring | nullrequiredemailstring | nullrequiredphonestring | nullrequiredlocationstring | nullrequiredtitlestringrequiredThe job, as the interview named it.
roundinteger | nullrequiredversioninteger | nullrequiredThe version of the role the interview ran on.
level"relaxed" | "standard" | "rigorous" | nullrequiredHow demanding the interview was set to be (the same for every candidate of the role).
panelbooleanrequiredTwo AI interviewers took turns.
typedbooleanrequiredThey typed instead of speaking.
practiceQuestionbooleanrequiredIt opened with an unscored practice question. Its answer is never kept, never in the transcript and never marked.
startedAtstring (date-time) | nullrequiredendedAtstring (date-time) | nullrequiredinterviewedAtstring (date-time)requiredWhen it ended and reached the hiring team.
minutesnumber | nullrequiredscoresSharedbooleanrequiredThe role shares scores (candidates.share_scores): the numbers below are filled in.
scorenumber | nullrequiredband"strong" | "possible" | "below" | "unscored" | nullrequiredrankinteger | nullrequiredPlace by score among the role's candidates in the same round (1 = highest).
mustHaves"met" | "missed" | "unclear" | "none"requiredrequirementsobject[]requiredThe must-have questions, with their answers.
idstringrequiredquestionstringrequiredanswerstring | nullrequiredTheir answer in a few words, as the interview heard it; null when it was never answered.
metboolean | nullrequiredWhether it meets the requirement (decided in code); null when unclear: a person checks it.
knockoutbooleanrequiredA must-have: not meeting it is flagged to the hiring team, never acted on.
whystring | nullrequiredWhy the role needs it, as the role says.
questionsobject[]requiredThe interview questions, in order, with the answers and what the platform found in them.
idstring | nullrequiredThe question's id in the role's question set.
nintegerrequiredIts number in the interview ("Question 2 of 5").
at least 1
questionstringrequiredanswerstring | nullrequiredWhat they said after the interviewer read the question, up to the next one, from the transcript; null when it can't be told or nothing is kept.
status"answered" | "skipped" | "asked"requiredverdict"right" | "partial" | "not-yet" | nullrequiredHow the answer compares with what the role looks for. Only where the role shares scores.
marksnumber | nullrequiredMarks given. Only where the role shares scores.
outOfnumber | nullrequiredThe marks the question carries.
notestring | nullrequiredA short note on the answer, as the report wrote it.
redFlagboolean | nullrequiredThe answer showed one of the question's red flags (for a person to check). Only where the role shares scores.
hintsintegerrequiredHints the interviewer gave on it.
summarystring | nullrequiredThe written summary for the hiring team.
strengthsstring[]requiredconcernsstring[]requiredWhere the evidence was thin.
competenciesobject[]requiredThe role's competencies with their score (0-100) where there was evidence and the role shares scores.
idstringrequiredlabelstringrequiredweightnumberrequiredscorenumber | nullrequired
evidenceobject[]requiredWhat the report quotes from the interview, by competency.
competencyIdstringrequiredquotestring | nullrequiredTheir own words.
notestring | nullrequired
transcriptobjectrequiredkeptbooleanrequiredfalse when the role keeps no transcripts (then
turnsis empty).turnsobject[]requiredspeaker"ai" | "candidate"requiredai: Zentiq's AI interviewer; candidate: the person.
namestring | nullrequiredWhich AI interviewer spoke, when two took turns; else null.
textstringrequiredoffsetMsinteger | nullrequiredMilliseconds from the start of the interview, when known.
adjustmentsobjectrequiredWhether they asked for an adjustment during the interview: make sure it was given. Never which one, nor why (it can reveal a disability): that stays with the hiring team in Zentiq.
requestedbooleanrequired
reviewRequestobject | nullrequiredThey asked for a review of the decision (from the link in an outcome email); open until a person decides again.
requestedAtstring (date-time)requiredISO 8601 UTC timestamp.
messagestring | nullrequiredopenbooleanrequired
reviewsobjectrequiredcountintegerrequiredrequiredintegerrequiredReviews a decision waits for (candidates.reviews_required).
blindbooleanrequiredBlind review (candidates.blind_review): each reviewer sees the others' reviews only after adding their own.
hiddenBy"blind_review" | "scores_not_shared" | nullrequiredWhy
itemsis null: the role's blind review, or its scores aren't shared.itemsobject[] | nullrequiredEach reviewer's recommendation and ratings, never their notes. Null while hidden.
integrityobjectrequiredMoments a recorded interview noted for a person to watch (how many, of which kinds), never part of the score. Their details stay in Zentiq.
countintegerrequiredkindsobject[]requiredkind"face_out_of_view" | "another_person" | "left_page" | "pasted_text" | "camera_off" | "microphone_off" | "connection_dropped"requiredcountintegerrequired
flagsobjectrequiredThings the report asks a person to look at; their words stay in Zentiq.
countintegerrequired
recorded"audio" | "audio_video" | nullrequiredA recording exists (watch it in Zentiq); it is never given out.
decisionobject | nullrequiredThe latest decision a person made; null while it awaits one.
value"invite" | "hold" | "decline"requireddecline is shown to people as "not progressing".
reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequiredThe reason code from the fixed list (a note is never given out).
decidedAtstring (date-time)requiredISO 8601 UTC timestamp.
decidedByobject | nullrequiredThe member who decided (never an API key).
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
CandidateRequest
A candidate's request under the US hiring pack. Their message and contact details stay in Zentiq.
idstringrequiredCandidate request id (
creq_…).pattern `^creq_.*`
kind"deletion" | "alternative" | "review" | "correction"requireddeletion (their interview, any recording and every copy), alternative (another way to be assessed, or an accommodation), review (a person to review a decision) or correction (their data corrected).
status"open" | "paused" | "done"requiredopen; paused while a legal hold keeps the interview (the candidate was told); done once answered, or (a deletion) once the interview was erased.
roleIdstringrequiredSubject id (
sub_…).candidateIdstring | nullrequiredThe candidate whose interview it is about; null before an interview (an invitation) or from the door.
inviteIdstring | nullrequiredsource"link" | "interview" | "door" | "outcome_email"requiredlink: the candidate's own page; door: the interview's page; outcome_email: the review link in an outcome email.
requestedAtstring (date-time)requiredISO 8601 UTC timestamp.
dueAtstring (date-time)requiredWhen the hiring team is asked to have answered: 30 days for a deletion, a review or a correction, 14 for another way.
autoDeleteAtstring (date-time) | nullrequiredA deletion the role carries out automatically: when (day 30), unless a person acts first or a legal hold is on.
overduebooleanrequiredoutcomestring (one of 10) | nullrequiredWhat happened, once done: deleted, deleted_automatically, alternative_offered, accommodation_given, not_possible, withdrawn_by_candidate, decision_stands, decision_changed, data_corrected or nothing_to_correct.
resolvedAtstring (date-time) | nullrequired
CandidateWebhookData
A candidate event's data: ids, the role, the portal, a status and timestamps only. Never a name, an email, answers, notes, ratings or scores.
eventIdstring | nullrequiredstatusstring | nullrequiredcandidateIdstring | nullrequiredsessionIdstring | nullrequiredinviteIdstring | nullroleIdstring | nullrequiredrolestring | nullportalIdstring | nulldecisionstring | nullrecommendationstring | nullreasonstring | nullby"team" | "candidate" | nullreviewerIdstring | nullofferIdstring | nullslotIdstring | nulltimingstring | nullstartAtstring | nullopensAtstring | nulllateAtstring | nulldeadlineAtstring | nullrescheduledboolean | nulloccurredAtstring | nullrequiredexternalIdstring | nullresentboolean | null
CandidateWithHistory
A candidate with their decision history. A person decides every outcome: scores and bands are a sorting aid for the hiring team, never a verdict, and no decision is made automatically.
idstringrequiredcand_…: the candidate's interview.pattern `^cand_.*`
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
roleIdstringrequiredSubject id (
sub_…).portalIdstring | nullrequiredinviteIdstring | nullrequiredexternalIdstring | nullrequiredYour ATS's id from the invite.
namestring | nullrequiredNull once erased.
emailstring | nullrequiredphonestring | nullrequiredinterviewedAtstring (date-time)requiredISO 8601 UTC timestamp.
minutesnumber | nullrequiredtypedbooleanrequiredThey typed instead of speaking.
roundinteger | nullrequiredwithdrawnbooleanrequiredThey chose to end the interview: never scored.
erasedbooleanrequirederasedAtstring (date-time) | nullrequiredmustHaves"met" | "missed" | "unclear" | "none" | nullrequiredThe must-have requirements: all met, one missed, unclear (a person checks), or none set. Flagged for a person, never acted on. Null once erased.
requirementsobject[]requiredEach requirement's result; never the answer. Empty once erased.
idstringrequiredmetboolean | nullrequiredknockoutbooleanrequired
scorenumber | nullrequiredOnly where the role shares scores, and never once erased; else null.
band"strong" | "possible" | "below" | "unscored" | nullrequiredOnly where the role shares scores, and never once erased; else null.
rankinteger | nullrequiredPlace by score among the role's candidates in the same round (1 = highest; erased and withdrawn candidates hold no place); only where the role shares scores.
decisionobject | nullrequiredThe latest decision a person made; null while it awaits one.
value"invite" | "hold" | "decline"requireddecline is shown to people as "not progressing".
reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequiredThe reason code from the fixed list (a note is never given out).
decidedAtstring (date-time)requiredISO 8601 UTC timestamp.
decidedByobject | nullrequiredThe member who decided (never an API key).
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
reviewsobjectrequiredcountintegerrequiredrequiredintegerrequiredrecommendationsobject | nullrequiredHow many reviewers recommend advance, hold or do not advance. Only where the role shares scores (candidates.share_scores), and never once erased; else null.
advanceintegerrequiredholdintegerrequireddoNotAdvanceintegerrequired
holdbooleanrequiredA legal hold keeps their data past the role's retention.
reviewRequestedbooleanrequiredThey asked for a review of the decision and no decision was recorded since.
retentionExpiresAtstring (date-time) | nullrequiredWhen their data is erased (null while held or once erased).
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
decisionsobject[]requiredEvery decision recorded, newest first.
value"invite" | "hold" | "decline"requireddecline is shown to people as "not progressing".
reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequiredThe reason code from the fixed list (a note is never given out).
decidedAtstring (date-time)requiredISO 8601 UTC timestamp.
decidedByobject | nullrequiredThe member who decided (never an API key).
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
CaseLink
A personal link one customer was sent about their case. Never the case's details or the link's address: those went to the customer only.
idstringrequiredCase link id (
clk_…).pattern `^clk_.*`
portalIdstringrequiredPortal id (
portal_…).referencestringrequiredkind"case" | "order" | "claim" | "appointment" | "ticket" | "booking" | "application" | "renewal"requiredcustomerIdstringrequiredYour own id for the customer.
status"active" | "expired" | "revoked" | "used_up"requiredactive: it opens; expired: past expiresAt; revoked: switched off; used_up: every conversation it may start has started.
opensintegerrequiredConversations started from it so far.
maxOpensintegerrequiredexpiresAtstring (date-time)requiredISO 8601 UTC timestamp.
revokedAtstring (date-time) | nullrequiredlastOpenedAtstring (date-time) | nullrequiredemailedAtstring (date-time) | nullrequiredWhen your team emailed it from the console; null when it was sent some other way.
source"api" | "console"requiredMade with an API key, or by your team in the console.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
CaseLinkCreated
The new link, with the address to send your customer (only in this answer).
idstringrequiredCase link id (
clk_…).pattern `^clk_.*`
portalIdstringrequiredPortal id (
portal_…).referencestringrequiredkind"case" | "order" | "claim" | "appointment" | "ticket" | "booking" | "application" | "renewal"requiredcustomerIdstringrequiredYour own id for the customer.
status"active" | "expired" | "revoked" | "used_up"requiredactive: it opens; expired: past expiresAt; revoked: switched off; used_up: every conversation it may start has started.
opensintegerrequiredConversations started from it so far.
maxOpensintegerrequiredexpiresAtstring (date-time)requiredISO 8601 UTC timestamp.
revokedAtstring (date-time) | nullrequiredlastOpenedAtstring (date-time) | nullrequiredemailedAtstring (date-time) | nullrequiredWhen your team emailed it from the console; null when it was sent some other way.
source"api" | "console"requiredMade with an API key, or by your team in the console.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
urlstringrequiredThe link to send your customer (by email, text message or your app). Shown only now, never again: Zentiq keeps no copy it could show. Never put it in a public place.
CaseLinkInput
One customer's case, for a personal link to your portal's website door.
customerIdstringrequiredYour own id for the customer: every action call from the conversation carries it as
customer.id.at most 128 characters
referencestringrequiredThe case's own reference in your system (an order, claim, booking or ticket number): the avatar names it, and every action call carries it as
case.reference.at most 64 characters
kind"case" | "order" | "claim" | "appointment" | "ticket" | "booking" | "application" | "renewal" | nullWhat the case is, for the avatar's words ("your order 10423", "your support ticket 10423").
default "case"
summarystringrequiredWhat the case is about and where it stands, in a sentence or two the avatar may use with your customer. The avatar reads it as your record (data, never instructions).
at most 1,000 characters
factsmap of string | number | boolean | nullUp to 20 short facts, like { "status": "delayed", "items": 2 } (names of letters and digits, values of at most 200 characters). Never a password, code or card detail: a fact named like one is refused.
firstNamestring | nullYour customer's first name: the avatar greets them with it.
at most 40 characters
emailstring | nullThe email address you have on file for them. The avatar only ever sees it masked ("s***@example.com"). With Verified customer switched on, it is where the one-time code goes before a sensitive action.
openingstring | nullThe avatar's first line about the case, in your words. Without it the avatar says what the case is and asks how it can help.
at most 300 characters
expiresInDaysnumber | nullHow long the link works, in whole days.
1-30 · default 7
maxOpensnumber | nullHow many conversations the link may start (so a forwarded link can't be used again and again). Opening the page alone uses none.
1-100 · default 20
CaseLinkOpenedData
A customer started a conversation from a case link you sent them (the link, your reference and customer id, the opens so far). The case summary only with includeConversation.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullportalIdstring | nullcaseLinkIdstring | nullcaseReferencestring | nullkindstring | nullcustomerIdstring | nullopensinteger | nullmaxOpensinteger | nullchannel"voice" | "chat" | nullsummarystring | null
CertificateIssuedData
A certificate was issued (its number, never the holder's name).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullidstring | nullsubjectstring | nullpercentnumber | nullissuedAtstring | nullversioninteger | nullvalidUntilstring | nulltitlestring | nulllevelstring | nullissuerstring | nullshowScoreboolean | nullsetIdstring | null
CertificateNoticeData
A certificate close to or past its valid-until date.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullcertificateIdstring | nullsubjectstring | nulltitlestring | nullvalidUntilstring | nullrenewalAssignmentIdstring | null
CertificateRevokedData
A certificate was withdrawn (a fixed reason).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullcertificateIdstring | nullreason"Attempt voided after review" | "Result changed after review" | null
ChatTurnInput
One message of the chat so far.
role"visitor" | "agent" | "bot"requiredWho said it: the customer (
visitor), a person on your team (agent) or your chat bot (bot).textstringrequiredWhat they said: plain text.
at most 4,000 characters
atstring | number | nullWhen it was said: an ISO 8601 date and time (or seconds since 1970).
CompletionRecordedData
A completion record was written for a confirmed pass.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullkindstring | nullpercentnumber | nullpassMarknumber | nullversioninteger | nullsetIdstring | nullsetTitlestring | nullattemptinteger | nullstartedAtstring | nullendedAtstring | nullcompletedAtstring | nulldocumentsobject[] | nulldocumentsHashstring | nullreviewedboolean | nullreviewerIdstring | nulldecisionstring | nulldecidedAtstring | null
CompletionWithdrawnData
A completion was withdrawn (a fixed reason).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreason"Attempt voided after review" | "Result changed after review" | null
Connection
One of the organisation's connected systems. Never a key or a token.
idstringrequiredConnection id (
conn_…).kind"mcp" | "calcom" | "hubspot" | "shopify" | "google_calendar" | "microsoft_calendar" | "slack" | "zapier"requirednamestringrequiredThe system, in words.
labelstringrequiredstatus"pending" | "active" | "failing" | "reconnect"requiredstatusWordsstringrequiredsecretHintstringrequiredThe last four characters of its key, like "…4f2a" ("" when there is none): the only part of a key ever shown.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
lastUsedAtstring (date-time) | nullrequiredhealthobjectrequiredcallsintegerrequiredsuccessRatenumber | nullrequiredCalls the system answered, as a share of all (0 to 1); null before the first.
p50Msinteger | nullrequiredThe median time of the latest calls, in ms.
lastErrorobject | nullrequiredcodestringrequiredwordsstringrequiredatstring | nullrequired
detailsmap of string | number | booleanrequiredWhat isn't secret: the server's host, the shop, the event type, the calendar.
ConnectionCreated
One of the organisation's connected systems. Never a key or a token.
authorizeUrlstring | nullrequiredFor a sign-in: where an owner approves it, signed in to the console. null when it is connected already.
ConnectionDeleted
Disconnected: the connection and its key are deleted.
idstringrequiredactionsOffintegerrequiredActions that used it, now switched off.
ConnectionFailedData
One of your connected systems started failing (its id, kind, an error code and the HTTP status): its actions tell visitors they can't do that just now. Never its key or anything it sent back.
connectionIdstring | nullkindstring | nullerrorCodestring | nullstatusinteger | null
ConnectionInput
A system to connect, and what it needs.
kind"mcp" | "calcom" | "hubspot" | "shopify" | "google_calendar" | "microsoft_calendar" | "slack" | "zapier"requiredWhich system.
labelstring | nullA plain name (never a key).
at most 60 characters
urlstring | nullmcp: the server's public https MCP address (standard port; private and local addresses are refused).
auth"none" | "bearer" | "oauth" | nullmcp: how it signs in.
oauth: the answer'sauthorizeUrlis where an owner approves it, signed in to the console.tokenstring | nullmcp (bearer), hubspot (a private app's access token) or shopify (an older app's Admin API access token, made in the Shopify admin before 2026). Write-only: checked, sealed in the vault and never returned (only a masked hint).
apiKeystring | nullcalcom: a Cal.com API key. Write-only: checked, sealed in the vault and never returned (only a masked hint).
eventTypeIdstring | number | nullcalcom: the event type's number.
timeZonestring | nullcalcom, google_calendar, microsoft_calendar: an IANA time zone, like America/New_York.
shopstring | nullshopify: the shop's address, like your-shop.myshopify.com.
clientIdstring | nullshopify: a Dev Dashboard app's Client ID (the app's Settings), with clientSecret instead of token. Zentiq asks Shopify for the app's 24-hour tokens itself (the client credentials grant: the store must be in the app's own Shopify organisation).
at most 100 characters
clientSecretstring | nullshopify: a Dev Dashboard app's Client secret, with clientId. It also verifies the order notifications Shopify sends for order emails. Write-only: checked, sealed in the vault and never returned (only a masked hint).
apiSecretstring | nullshopify with token: the older app's API secret key, which only order emails need (Shopify signs its order notifications with it). Write-only: checked, sealed in the vault and never returned (only a masked hint).
propertiesstring | string[] | nullhubspot: the contact properties the avatar may read (HubSpot's own names).
calendarIdstring | nullgoogle_calendar: which calendar ("primary" unless named).
hoursmap of string | nullgoogle_calendar, microsoft_calendar: opening hours per day, like { "mon": "09:00-17:00" } (a day left out is closed).
slotMinutesnumber | nulllengthMinutesnumber | nulltitlestring | nullgoogle_calendar, microsoft_calendar: a booking's title.
at most 60 characters
ConnectionList
onbooleanrequiredThe organisation's actions.connectors switch: off, nothing connected is used and nothing new can be connected.
ConnectionTest
A read-only call that proves it still works.
okbooleanrequiredwordsstringrequiredOne of the organisation's connected systems. Never a key or a token.
Consent
Consent to clone a real person's voice or to make an avatar from their picture. Recorded with who confirmed it (the API key), when, a hashed IP address, the exact wording and its version. The organisation's owners can export records and withdraw them; a withdrawn voice or face stops starting new sessions.
attestedtruerequiredYou confirm the person agreed (or, with subject "generated", that the face is not a real person).
subject"myself" | "someone_else" | "generated"requiredWhose face or voice it is. "generated" is for a face made by AI; a voice can't be generated.
subjectNamestringRequired with subject "someone_else": the person's name.
2-120 characters
textVersionstringOptional. When sent it must be the current wording version, or the request is refused with consent_outdated.
ConsentRecordedData
Consent was recorded for a membership (who recorded it, never their address).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullbystring | null
ConversationRatedData
A visitor rated a conversation (the comment only with includeConversation). Never a candidate's.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullratingnumber | nullcommentstring | null
CreatedInvites
The invites made, each with its link, and the candidates skipped with why.
skippedobject[]requiredemailstringrequiredexternalIdstring | nullrequiredreason"open_invite" | "already_interviewed" | "listed_twice"requiredmessagestringrequired
emailobjectrequiredrequestedbooleanrequiredsentintegerrequiredfailedintegerrequiredqueuedintegerrequiredStill to go: sent straight after this answer.
CreateInvitesInput
Invite candidates to a role's first-round interview.
candidatesobject[]requiredAt most 200, or 100 when Zentiq emails them. An address with an open invite for the role, one that completed the interview within its retention, or one listed twice is skipped.
at most 200 items
namestringrequired2-120 characters
emailstringrequiredat most 254 characters
phonestring | nullexternalIdstringpattern `^[^\s@]{1,200}$`
metadatamap of stringYour own data about the applicant, returned as it was: at most 20 string keys. Never sent by webhook.
When candidates may take the interview: any time, by a deadline, or at a set time.
timeZonestringIANA time zone the emails' times read in (default Europe/London).
at most 64 characters
sendbooleantrue: Zentiq emails each candidate their link (with a calendar file for a set time, and reminders). false (default): copy the links yourself.
portalIdstringThe portal whose door the links open; default: the role's own (where it is published and open to visitors).
CreatePersonInput
externalIdstring | nullYour own id for the person: the sync key. A repeat with it returns the same person.
emailstring (email) | nullWithout an externalId, the person is found or added by email. An email another account already has is refused (409).
namestring | nullrole"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"requiredOWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullworkspaceIdstring | nullA workspace admin's subject.
gradeBandstring | nullageBand"18+" | nullloginCardboolean | nullA learner without an email gets a login card (needs accounts without email switched on).
CreateUnitInput
namestringrequired1-80 characters
parentIdstring | nullkindstring | nullclass, team, group, department, region, school or club (default: the organisation's).
gradeBandstring | nullleaderobject | nullInvites the unit's leader by email (takes a staff seat).
emailstring (email)required
CustomerToken
A short-lived identity token for one signed-in customer.
tokenstringrequiredzct1.…: for this portal and one conversation only. Give it to the website widget or a conversation's start; never put it in a URL.
expiresAtstring (date-time)requiredISO 8601 UTC timestamp.
CustomerTokenInput
The customer signed in on your website.
customerIdstringrequiredYour own id for the signed-in customer: sent to your system as customer.id on every call.
at most 128 characters
namestring | nullShown to them as "Signed in as …".
at most 80 characters
emailstring | nullauthTimenumber | nullWhen they signed in, seconds since 1970 (within the last 30 days).
ttlSecondsnumber | nullHow long the token lasts, in seconds. At most 900: a longer one is cut to 900 (expiresAt says when).
at least 30 · default 600
contactobject | nullVerified customer: the contact on record, where Zentiq sends a one-time code before a sensitive action (when the organisation switches it on). Signed into the token; never shown to the avatar, the conversation or a log, only as a masked read-back ("s***@example.com"). Use the address you would send a password reset to.
emailstring | nullThe customer's email address on record: where a one-time code is sent.
Dashboard
A Workspaces portal: the front door (address, sign-in methods) and its subjects, each built from a template.
idstringnamestringslugstringstatus"draft" | "published" | "archived"welcomestring | nulladdressstringWhere people open it: /d/<org>/<slug>, or the verified custom domain.
loginMethods("email" | "login_card" | "class_code" | "visitor")[]personaIdstring | nullsubjectsobject[]idstringnamestringtypestringThe template's blueprint key.
statusstring
createdAtstring (date-time)updatedAtstring (date-time)publishRefusedstringOnly on a publish that was refused (POST /portals with publish: true, POST /portals/{id}/publish): what to finish before the portal can go live. The portal stays a draft.
DashboardInput
namestringrequiredat most 80 characters
templatesstring[]requiredTemplate keys from GET /portals/templates.
at most 12 items
personaIdstringA persona of yours to serve every subject; omitted = the portal gets its own.
welcomestringat most 160 characters
loginMethods("email" | "login_card" | "class_code" | "visitor")[]publishbooleantrue publishes it once it passes the go-live check; otherwise, or when the check refuses it (see publishRefused), it stays a draft.
default false
DashboardPersona
namestringfacestring | nullvoicestring | nullaccentstring | nullgreetingstring | nullcharacterstringreadybooleantrue once it has a face and a voice: people can talk to it.
DashboardTemplate
keystringgroup"Learn" | "Train" | "Serve" | "Assess"labelstringdescriptionstringavailablebooleanWhether it can be built today.
Deleted
deletedbooleanidstring
DeliveryList
Type: object[]
Document
A document in a knowledge pack.
idstringrequiredDocument id (
doc_…).pattern `^doc_.*`
knowledgeBaseIdstringrequiredKnowledge base id (
kb_…).pattern `^kb_.*`
namestringrequiredtypestring | nullrequiredpdf, txt, md, docx, csv, url or text.
bytesinteger | nullrequiredstatus"processing" | "ready" | "failed"requiredprocessing until it has been read; then ready, or failed.
chunkCountinteger | nullrequiredHow many passages were read from it, once ready.
errorstring | nullrequiredWhen failed: one plain sentence (the file couldn't be read, took too long, reading is unavailable, or it couldn't be processed).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
DocumentInput
A document from an address ({ url }) or as text ({ text }): exactly one.
urlstring (uri)A public https address to fetch and read (25 MB at most; every redirect is checked too).
textstringText to read (1 MB at most).
at most 1,048,576 characters
namestringat most 200 characters
DocumentUpload
A document as a file.
filestring (binary)requiredpdf, txt, md, docx or csv; 25 MB at most.
namestring
DoorReadiness
openbooleanrequiredtextstringrequiredThe readiness line, in plain words ("Public page open").
fix"publish" | "visitors" | "organisation" | nullrequiredWhat to do when it is closed: publish the portal, open it to visitors, or let outside people in (the organisation's public website switch).
DownloadUrl
Where to download the original file, for a few minutes.
urlstringrequiredA short-lived signed address of the original file.
expiresAtstring (date-time)requiredISO 8601 UTC timestamp.
Duo
A duo of the organisation's.
idstringrequiredDuo id (
duo_…).pattern `^duo_.*`
personaIdstringrequiredThe persona sessions and portals use (its name is "A & B").
pattern `^pa_.*`
source"library" | "generated" | "composed" | "upload"requiredWhere its picture came from.
libraryKeystring | nullrequiredThe ready-made duo it was copied from.
peopleobject[]requirednamestringrequiredgender"female" | "male"requiredrolestring | nullrequiredTheir part in the conversation, in a few words.
voiceIdstring | nullrequired
relationshipstring | nullrequiredstatus"draft" | "ready_for_render" | "registering" | "testing" | "live" | "needs_changes" | "failed"requireddraft, then ready_for_render once published; registering and testing on the render side; live when its test run passed, or needs_changes / failed.
statusWordsstringrequiredWhere it is, in one plain sentence.
previewUrlstring | nullrequiredIts picture (your API key reads it: it is the organisation's own avatar).
languagesstring[]requiredThe languages a duo speaks (the ten codes GET /languages marks
duo).testReasonsstring[]requiredWhy its test run didn't pass, in plain words (needs_changes, failed).
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
aiGeneratedtruerequiredAlways true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).
DuoAccess
What the organisation may do with duos now.
builderOpenbooleanrequiredDuos are open to the organisation (while not, every other /duos operation is 404).
canUsebooleanrequiredThe plan uses ready-made duos.
canBuildbooleanrequiredThe plan builds its own duos.
upgradeobject | nullrequiredThe plan that would add what's missing, and the words for it; null when nothing is.
planstringrequiredmessagestringrequired
DuoInput
A new duo, as a draft.
source"library"requiredA copy of one of Zentiq's ready-made duos (your own duos come in a later release).
libraryKeystringrequiredFrom GET /duos/library.
EmbedToken
A one-time sign-in for one of your users.
tokenstringrequiredFive minutes, single use.
expiresAtstring (date-time)requiredISO 8601 UTC timestamp.
urlstringrequiredOpens the portal as that person (a full page).
embedUrlstringrequiredWhat an iframe mounts (
zentiq-embed.js,@zentiq/react's<ZentiqPortal>).
EmbedTokenInput
The person your backend signs in.
externalUserIdstringrequiredYour own id for this person: the same person as
POST /peoplewith thisexternalId.1-120 characters
namestringat most 80 characters
emailstringat most 200 characters
role"learner" | "leader" | "observer"Default
learner. A leader takes a staff seat.unitIdstringTheir team or class (
unit_…).unitNamestringOr a group by name, made under the portal's team on first sight.
1-80 characters
gradeBandstringat most 8 characters
consentobject{ by: "organisation" }: your organisation attests the consent a young learner needs (recorded as yours; needspeople:writeas well). Without it, a learner under the consent age waits for a guardian's consent.by"organisation"required
Error
The error envelope. The request id is in the X-Request-Id header.
errorobjectrequiredcodestring (one of 33)requiredWhat went wrong, from the error catalogue.
messagestringrequiredPlain English, safe to show an admin.
paramstringThe input at fault, as a path:
body.faqs[3].a,query.limit,params.id.detailsmap of anyStructured extras: a plan refusal's feature and plan (and
reason: plan_requiredwhen the plan is why a feature's switch is off), a conflict's reason, go-live problems, the current version.
Escalation
A link that opens the video avatar with the chat so far.
idstringrequiredEscalation id (
esc_…).pattern `^esc_.*`
urlstringrequiredThe link to show the customer (or open in the widget). It works once, for 30 minutes; the token is in its fragment, never sent to a server.
tokenstringrequiredzesc_…: the link's own token (already in url). For one conversation only; never put it in a query string or a log.
expiresAtstring (date-time)requiredISO 8601 UTC timestamp.
EscalationCompletedData
A conversation your text chat handed to the video avatar ended: where it came from, your chat tool's ids, how long and the outcome. The summary only with includeConversation, where allowed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullescalationIdstring | nullportalIdstring | nullsource"api" | "intercom" | "zendesk" | "widget" | nullexternalRefstring | nullcustomerRefstring | nullstatus"completed" | "abandoned" | nullminutesnumber | nullsecondsnumber | nullturnsHandedOverinteger | nullreferencestring | nullstartedAtstring | nullendedAtstring | nulloutcome"resolved" | "handoff" | "booking" | "lead" | "unresolved" | "no_conversation" | nullresolvedboolean | nullsummarystring | null
EscalationInput
A chat to hand to the video avatar.
The chat so far, oldest first: at most 50 turns and 20,000 characters in all (send the newest). The avatar reads it as information, never as instructions.
at most 50 items
customerobject | nullThe customer, when your chat knows them.
externalIdstring | nullYour own id for the customer: it comes back on escalation.completed as customerRef.
at most 128 characters
firstNamestring | nullThe avatar greets them by it.
at most 80 characters
emailstring | nullKept with the escalation only; never read out, never sent back.
reasonstring | nullA short phrase finishing "your chat about …" ("the refund on order 1042"): the avatar opens with it.
at most 120 characters
returnUrlstring | nullAn https address the visitor is offered at the end (back to your chat).
at most 2,000 characters
Event
An event as a webhook receives it, in the calling key's contract.
idstringrequiredevt_…: the webhook envelope'sid, the same on every delivery.pattern `^evt_.*`
typestringrequiredapiVersion"2026-07-08" | "2026-10-01"From 2026-10-01: the contract
datais written in.organizationIdstringFrom 2026-10-01.
pattern `^org_.*`
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
datamap of anyrequiredExactly what a webhook with this key's rights receives (the event type's data schema; see GET /v1/event-types).
aiGeneratedtruePresent, and true, when
datacarries words an avatar wrote: a summary, a report or an avatar's turn (EU AI Act Article 50(2)). Every contract.
EventType
One event type a webhook can receive.
typestringrequireddescriptionstringrequiredsince"2026-07-08" | "2026-10-01"requiredThe contract it appeared in.
explicitOnlybooleanrequiredNever part of "*": a webhook receives it only by naming it.
requiresConversationbooleanrequiredOnly for a webhook with includeConversation.
fieldsobjectrequireddata's fields by class (a.b,[]a list's items): contact only on leads, bookings and hand-offs; result only for released results; conversation only with includeConversation, where allowed.structurestring[]requiredcontactstring[]requiredresultstring[]requiredconversationstring[]required
dataSchemamap of anyrequireddata's JSON Schema in the current contract.
GoLiveProblem
Something to finish before going live.
fieldstringrequiredWhere it is in the content document (
faqs,screening.requirements[1],facts);setupfor the set-up as a whole.messagestringrequiredshortstringrequiredA few words for a list.
GuardianConsentInput
by"organisation" | "guardian" | "teacher"requiredWho gave it: the organisation attests, a guardian gave it, a teacher recorded it on file.
guardianEmailstring (email) | nullKept on the place as evidence; never sent in any event or webhook.
methodstringrequiredHow it was given: school_form, in_person, email, …
1-40 characters
evidenceRefstring | nullYour own reference to the evidence.
HandoffJoinedData
Someone from your team joined a website visitor's live conversation as themselves (their user id, how they joined).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullportalIdstring | nullstaffUserIdstring | nullvia"console" | "email" | "api" | nullstaffCountinteger | null
HandoffLeftData
Someone from your team left a website visitor's live conversation: how long they were in it, and whether the assistant carried on or the conversation ended.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullportalIdstring | nullstaffUserIdstring | nullsecondsinteger | nullnext"stayed" | "resumed" | "ended" | null
HandoffRequestedData
A website visitor asked for a person: their contact details, what they need and their consent. The summary and reason only with includeConversation.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullsummarystring | nullneedstring | nullbudgetstring | nulltimelinestring | nullcontactobject | nullnamestring | nullemailstring | nullphonestring | nullcompanystring | nullrolestring | nullpreferredTimestring | nulllocationstring | nullreferencestring | null
consentobject | nullpurposestring | nullmarketingboolean | nulltextstring | nullversioninteger | nullatstring | nullgivenboolean | null
promisestring | nulldueAtstring | nulldepartmentstring | nullverifiedboolean | nullportalIdstring | nullreasonstring | nullintentstring | nullinboxItemIdstring | null
HandoffUpdatedData
A website visitor's request for a person gained their contact details after it was sent (they agreed and said how to reach them later in the conversation): the same fields as handoff.requested, with the same reference.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullsummarystring | nullneedstring | nullbudgetstring | nulltimelinestring | nullcontactobject | nullnamestring | nullemailstring | nullphonestring | nullcompanystring | nullrolestring | nullpreferredTimestring | nulllocationstring | nullreferencestring | null
consentobject | nullpurposestring | nullmarketingboolean | nulltextstring | nullversioninteger | nullatstring | nullgivenboolean | null
promisestring | nulldueAtstring | nulldepartmentstring | nullverifiedboolean | nullportalIdstring | nullreasonstring | nullintentstring | nullinboxItemIdstring | null
Health
The API is up.
status"ok"requiredversion"v1"required
InboxItem
A website visitor's request the team acts on: a lead, a booking request or a hand-off (one per conversation).
idstringrequiredinb_…: the visitor's conversation (webhooks'inboxItemId).pattern `^inb_.*`
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
portalIdstring | nullrequiredThe portal the visitor came through, when known.
subjectIdstring | nullrequiredsubjectstring | nullrequiredThe subject's name when the request came in.
referencestring | nullrequiredThe reference the visitor was given.
receivedAtstring (date-time)requiredWhen the conversation's first request came in.
kinds("lead" | "booking" | "handoff")[]requiredprimary"lead" | "booking" | "handoff"requiredWhat the item is mainly about: a booking, else a lead, else a hand-off.
status"new" | "contacted" | "confirmed" | "closed"requiredstatusAtstring (date-time) | nullrequiredstatusByobject | nullrequiredWho moved it last: a member, or an API key (yours included, so a sync can ignore its own changes).
type"user" | "api_key"requiredidstringrequiredusr_…orkey_….
notestring | nullrequiredThe team's note with the latest status.
overduebooleanrequireddueAtstring (date-time) | nullrequiredWhen the visitor was promised an answer by.
promisestring | nullrequiredWhat the visitor was told about when they would hear back.
contactobject | nullrequiredThe details the visitor gave, with their consent, for this request; payment and identity numbers are masked. Never an under-18's.
namestring | nullrequiredemailstring | nullrequiredphonestring | nullrequiredcompanystring | nullrequiredrolestring | nullrequiredlocationstring | nullrequiredpreferredTimestring | nullrequiredreferencestring | nullrequired
teamstring | nullrequiredThe team it went to.
leadobject | nullrequiredbandstring | nullrequiredpointsnumber | nullrequired
bookingobject | nullrequiredA booking request: nothing is in a calendar until someone confirms it with the visitor.
servicestring | nullrequiredwhenstring | nullrequired
consentobject | nullrequiredWhat the visitor agreed to: to be contacted about this request, never marketing.
purposestring | nullrequiredmarketingfalserequiredversioninteger | nullrequiredatstring (date-time) | nullrequiredgivenboolean | nullrequired
verifiedboolean | nullrequiredfalse: some of the request was read only from the visitor's page (it could be made up); null: recorded before Zentiq checked.
removedFieldsstring[]requiredDetails the visitor had removed; delete them from your records too.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
needstring | nullWhat they need, in their words. Only for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).budgetstring | nullOnly for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).timelinestring | nullOnly for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).summarystring | nullThe conversation's summary. Only for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).reasonstring | nullWhy they asked for a person. Only for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).answersmap of string | nullA lead's answers to the qualification questions. Only for a key holding
transcripts:read, and never from an under-18's, a candidate's or a safety-flagged conversation (absent otherwise).
InboxItemUpdate
Move a request on. Records lead.updated or booking.updated with by = this key.
status"new" | "contacted" | "confirmed" | "closed"requirednotestringThe team's note with the new status (at most 500 characters).
at most 500 characters
expectedStatus"new" | "contacted" | "confirmed" | "closed"The status you last saw: when it has changed since, nothing changes (409 conflict,
details.currentStatus).
InboxMoveData
A website visitor's request moved on in the inbox: its status, the one before, and who moved it.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullrequeststring | nullstatusstring | nullpreviousstring | nullbyobject | nulltype"user" | "api_key" | nullidstring | null
Invite
A personal invitation to a role's first-round interview.
idstringrequiredInvite id (
inv_…).pattern `^inv_.*`
roleIdstringrequiredSubject id (
sub_…).portalIdstring | nullrequiredThe portal whose door the link opens.
externalIdstring | nullrequiredYour ATS's own id for the applicant, sent back on every candidate event.
metadatamap of stringrequirednamestring | nullrequiredNull once the candidate's data was erased.
emailstring | nullrequiredphonestring | nullrequiredstatus"invited" | "opened" | "started" | "completed" | "cancelled" | "expired"requiredinvited → opened → started → completed; or cancelled (by the team, rescheduled, or a missed set time) or expired (a passed deadline).
cancelReason"late" | "withdrawn_by_team" | "rescheduled" | nullrequiredtiming"open" | "deadline" | "scheduled"requiredstartAtstring (date-time) | nullrequiredscheduled: the interview time.
opensAtstring (date-time) | nullrequiredscheduled: when the link opens.
lateAtstring (date-time) | nullrequiredscheduled: not started by then, the invite is cancelled as late.
deadlineAtstring (date-time) | nullrequireddeadline: the interview must be started by then.
sentAtstring (date-time) | nullrequiredWhen Zentiq last emailed it; null when the link was only copied.
openedAtstring (date-time) | nullrequiredstartedAtstring (date-time) | nullrequiredcompletedAtstring (date-time) | nullrequiredcancelledAtstring (date-time) | nullrequiredcandidateIdstring | nullrequiredThe candidate (
cand_…) once their interview reached the hiring team.linkstring | nullrequiredThe candidate's personal link while it can be used: a secret, give it only to them.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
InviteTiming
When candidates may take the interview: any time, by a deadline, or at a set time.
mode"scheduled"requireddeadlineAtstring (date-time)30 minutes to 90 days from now.
startAtstring (date-time)In the future, within 90 days.
earlyMinutesintegerscheduled: how early the link opens (default 10).
0-120
lateMinutesintegerscheduled: how late a start may be before the invite is cancelled (default 15).
1-120
JobCompletedData
A long-running job finished (the drafts it wrote, by id).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nulljobIdstring | nulltypestring | nullstatusstring | nullsubjectIdsstring[] | null
KeyInput
namestringUp to 60 characters. Default "API key".
scopesstring[]Scope names, or ["*"] (the default, [] means the same) for full access. A key can only give scopes it holds itself.
at most 64 items
apiVersion"2026-07-08" | "2026-10-01"The contract the new key speaks. Default: the contract of this request.
KeyList
Type: ApiKey[]
KeyRevoked
The key stops working on its next request.
revokedtruerequiredidstringrequiredAPI key id (
key_…).pattern `^key_.*`
KeyWithSecret
A new key, with its secret (shown once).
idstringrequiredAPI key id (
key_…).pattern `^key_.*`
namestringrequiredprefixstringrequiredThe key's first characters, as shown in the console.
scopesstring[]requiredThe scopes as set on the key; [] or ["*"] is full access (sensitive scopes are added by name).
apiVersion"2026-07-08" | "2026-10-01"requiredThe contract the key speaks.
createdBystring | nullrequiredWho made it: a member (
usr_…) or a key (key_…); null for older keys.lastUsedAtstring (date-time) | nullrequiredrevokedAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
keystringrequiredThe full key. Returned once: store it now.
KnowledgeBase
A knowledge pack: documents an avatar answers from once attached to its persona.
idstringrequiredKnowledge base id (
kb_…).pattern `^kb_.*`
namestringrequireddocumentCountintegerrequiredIts documents (not deleted ones).
readyCountintegerrequiredIts documents that have been read: the ones the avatar answers from.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
KnowledgeBaseInput
A knowledge pack's name.
namestringrequiredat most 200 characters
KnowledgeDocumentFailedData
A knowledge document could not be read; errorCode says why.
documentIdstring | nullknowledgeBaseIdstring | nullerror"The document could not be read. Check that it is a readable PDF, Word, text, Markdown or CSV file." | "No text was found in the document. If it is a scan or a picture, upload a version with text you can select." | "Processing the document took too long. Try a smaller file." | "Document processing is unavailable right now. Try again later." | "The document could not be processed." | nullerrorCode"unreadable" | "empty" | "timeout" | "unavailable" | "failed" | null
KnowledgeDocumentProcessedData
A knowledge document was read and is ready.
documentIdstring | nullknowledgeBaseIdstring | nullchunkCountinteger | null
KnowledgeGapData
The assistant couldn't answer some questions (the questions only with includeConversation).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullsourcestring | nullreferencestring | nullquestionsstring[] | null
Language
A language from the catalogue.
codestringrequiredBCP-47 code: what the API takes and returns.
namestringrequiredEnglish name.
nativeNamestringrequiredIts own name.
duobooleanrequiredA duo (two people in one conversation) speaks it: ten languages do.
duoNamestring | nullrequiredHow a duo shows it (a duo has one Portuguese); null when a duo doesn't speak it.
betabooleanrequiredOffered to one avatar in beta (Cantonese).
Languages
The language catalogue, the voice engines and the accent keys.
Every language an avatar speaks, from the catalogue: one avatar any of them, a duo the ten flagged
duo.enginesobjectrequiredThe two voice engines.
A voice engine. The voice decides which one a persona runs on: see
Voice.engine.A voice engine. The voice decides which one a persona runs on: see
Voice.engine.
accentsobject[]requiredValues for
settings.accentthat speak English with the accent of another language.keystringrequiredlabelstringrequired
LeadCapturedData
A website visitor left their details as a lead: contact details, the lead's band and their consent. The summary only with includeConversation.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreferencestring | nullsummarystring | nullneedstring | nullbudgetstring | nulltimelinestring | nullcontactobject | nullnamestring | nullemailstring | nullphonestring | nullcompanystring | nullrolestring | nullpreferredTimestring | nulllocationstring | nullreferencestring | null
consentobject | nullpurposestring | nullmarketingboolean | nulltextstring | nullversioninteger | nullatstring | nullgivenboolean | null
promisestring | nulldueAtstring | nulldepartmentstring | nullverifiedboolean | nullportalIdstring | nullleadBandstring | nullpointsnumber | nullanswersmap of string | nullinboxItemIdstring | null
LearnerSignedInData
A learner signed in to a portal.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullmethodstring | nullportalIdstring | null
LibraryDuo
One of Zentiq's ready-made duos.
keystringrequiredWhat POST /duos takes as
libraryKey.titlestringrequiredscenariostring | nullrequiredpeopleobject[]requiredThe person on the left, then the one on the right.
namestringrequiredgender"female" | "male"requiredrolestring | nullrequiredTheir part in the conversation, in a few words.
relationshipstring | nullrequiredcouple, colleagues, family or panel.
previewUrlstringrequiredTheir picture (public).
aiGeneratedtruerequiredAlways true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).
LoginCard
How a learner without an email signs in.
usernamestringrequiredorgCodestringrequiredpinstringrequiredShown once, never again: print or hand it over now.
MasteryUpdatedData
A person's level on a skill moved.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullskillstring | nulltopicstring | nullbeforenumber | nullafternumber | nullconfidencenumber | null
Me
The calling key, its organisation, plan and limits.
organizationobjectrequiredidstringrequiredOrganisation id (
org_…).pattern `^org_.*`
displayNamestringrequiredThe name the organisation chose for the API (never an internal workspace name).
planstringrequiredThe plan's code (free, starter, plus, pro, business, enterprise).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
planobjectrequiredkeystringrequirednamestringrequiredincludedMinutesnumber | nullrequiredThe plan's minutes this cycle; null on an unlimited account.
featuresstring[]requiredThe plan's features that are on (dashboards.serve, embed.website, api.access, …).
limitsobjectrequiredmaxConcurrentSessionsinteger | nullrequiredLive sessions at once; null = no limit.
activeSessionsintegerrequiredminutesRemainingnumber | nullrequiredMinutes the account can still spend (and within its own monthly API cap); null = unlimited.
rateLimitsobjectrequiredThe rate limits this key works within (RateLimit-* headers on every answer).
windowSecondsintegerrequiredperKeyobjectrequiredRequests per window, by operation class (each operation's class is in the reference as x-zentiq-rate-class).
readintegerrequiredwriteintegerrequiredliveintegerrequiredheavyintegerrequiredsearchintegerrequired
perOrganizationobjectrequiredShared by all of the organisation's keys.
readintegerrequiredwriteintegerrequiredliveintegerrequiredheavyintegerrequiredsearchintegerrequired
apiKeyobjectrequiredidstringrequiredAPI key id (
key_…).pattern `^key_.*`
namestring | nullrequiredprefixstringrequiredThe key's first characters, as shown in the console.
scopesstring[]requiredThe key's scopes as set on it; [] or ["*"] is full access.
effectiveScopesstring[]requiredEvery scope the key holds, after full access and the implied scopes of keys made before 2026-10-01.
fullAccessbooleanrequiredapiVersion"2026-07-08" | "2026-10-01"requiredThe contract the key is pinned to (Zentiq-Version may ask for a newer one).
lastUsedAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
MemberAddedData
Someone was added to the organisation.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullrolestring | nullmethodstring | nullgradeBandstring | nullstatusstring | null
MemberRemovedData
Someone was removed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullrolestring | nullscopestring | nullrolesstring[] | nullteamsstring[] | nullaccountDeactivatedboolean | null
Membership
A person's place: a role at a unit or at the organisation level.
idstringrequiredMembership id (
mbr_…).pattern `^mbr_.*`
personIdstringrequiredPerson id (
usr_…).pattern `^usr_.*`
rolestringrequiredOne of the member roles.
unitIdstring | nullrequiredThe unit it is held at; null at the organisation level.
workspaceIdstring | nullrequiredA workspace admin's subject (
sub_…; bare for keys on 2026-07-08).statusstringrequiredactive, waiting_consent (a child's place waiting for a parent's consent) or disabled.
gradeBandstring | nullrequiredageBand"18+" | nullrequired"18+": an adult learner, who starts without a parent's or guardian's consent.consentAtstring (date-time) | nullrequiredconsentBy"organisation" | "guardian" | "teacher" | nullrequiredWho gave a learner's consent: the organisation, a guardian or a teacher (never their details).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
MemberStateData
A member, or one of their places, switched off or on.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullscopestring | nullrolesstring[] | nullmembershipIdstring | nullrolestring | null
MemberUpdatedData
A member's role or unit changed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullmembershipIdstring | nullfromobject | nullrolestring | nullunitIdstring | null
toobject | nullrolestring | nullunitIdstring | null
MemoryWrittenData
The platform noted something for a person's next session (what kind, never the note).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullkindstring | nullsourcestring | nullskillstring | nullcharsinteger | null
Person
Someone in the organisation: a member, a learner, a parent.
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for the person (the sync key), when you gave one.
namestringrequiredemailstring | nullrequiredNull for a login card or a person known only by your id.
loginNamestring | nullrequiredA login card's sign-in name (
<organisation code>/<username>).lastSignInAtstring (date-time) | nullrequireddisabledbooleanrequiredSwitched off: no sign-in anywhere; their places keep their own status.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Persona
An avatar people talk to: a face, a voice, a character and what it knows.
idstringrequiredPersona id (
pa_…).pattern `^pa_.*`
namestringrequiredsystemPromptstringrequiredgreetingstring | nullrequiredavatarIdstring | nullrequiredvoiceIdstring | nullrequiredBehaviour settings.
knowledgePersonaKnowledge | nullrequiredcastobjectrequiredWho the avatar is: one person, or a duo (two people in one conversation).
kind"single" | "duo"requiredpeopleobject[]requiredOne person, or a duo's two, by name.
namestringrequired
duoIdstring | nullrequiredThe duo (GET /duos/{id}) when it is one made from /duos; null otherwise.
avatarAvatar | nullrequiredvoiceVoice | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
PersonaInput
A new persona.
namestringrequiredat most 200 characters
systemPromptstringrequiredThe character: who they are, what they help with, how they behave.
at most 16,000 characters
greetingstring | nullThe first thing they say.
at most 2,000 characters
avatarIdstringAvatar id (
av_…).voiceIdstringVoice id (
vo_…).voiceProfileIdstringdeprecatedDeprecated: use
voiceId.settingsPersonaSettingsInputBehaviour settings to set (see PersonaSettings).
Deprecated: use
settings.knowledgeobject | nullbaseIdsstring[]requiredKnowledge base ids (
kb_…), 1 to 20.topKnumberminScorenumbermaxCharsnumber
PersonaKnowledge
The knowledge packs attached to a persona: the avatar answers from them.
baseIdsstring[]requiredtopKintegerrequiredminScorenumberrequiredmaxCharsinteger
PersonaPatch
What to change; what isn't sent stays as it is.
namestringat most 200 characters
systemPromptstringThe character: who they are, what they help with, how they behave.
at most 16,000 characters
greetingstring | nullThe first thing they say.
at most 2,000 characters
avatarIdstringAvatar id (
av_…).voiceIdstringVoice id (
vo_…).voiceProfileIdstringdeprecatedDeprecated: use
voiceId.settingsPersonaSettingsInputBehaviour settings to set (see PersonaSettings).
Deprecated: use
settings.knowledgeobject | nullbaseIdsstring[]requiredKnowledge base ids (
kb_…), 1 to 20.topKnumberminScorenumbermaxCharsnumber
PersonaSettings
Behaviour settings.
engine"premier" | "global"requiredThe voice engine the persona runs on, decided by its voice: premier for your organisation's cloned voices, global for the studio voices.
globalVoicestringDeprecated: present when
engineis global. Choose a voice byvoiceId.languagestringrequiredThe language it speaks first: a code from GET /languages.
languageMode"follow" | "fixed"requiredfollow: it answers in the language people speak to it (starting in
language); fixed: it keeps tolanguage.accentstringrequiredAn accent for English, in words ("Scottish") or a key from GET /languages
accents; "" for none.voice_accentstringrequiredA studio voice's English accent variant (neutral is American).
skipGreetingbooleanrequiredinterruptiblebooleanrequiredPeople can talk over it.
ccbooleanrequiredCaptions shown by default.
companystringrequiredgreet_mode"single" | "rotate" | "ai"requiredgreetingsstring[]requiredidle_actionsbooleanrequiredSmall natural movements between turns.
display_mode"half_body" | "presenter" | "full_body"requiredHow the camera frames it.
hand_motionbooleanrequiredHand gestures while speaking.
visionbooleanrequiredIt may see the user's camera, when the user allows it.
vision_safe_modebooleanrequiredSeeing, without reading emotions.
ai_disclosurebooleanrequiredAlways true: every avatar tells people it's an AI (EU AI Act Article 50(1)), and it can't be switched off.
ai_disclosure_textstringrequiredYour own wording for the AI disclosure (it always says it's an AI); "" for the standard one, "You're speaking with an AI avatar."
PersonaSettingsInput
Behaviour settings to set (see PersonaSettings).
languagestring | nullA code or a name from GET /languages (a duo: one of its ten).
languageMode"follow" | "fixed" | nullfollow: answer in the language people speak; fixed: keep to
language(the default).accentstring | nullAn accent for English, in words, or a key from GET /languages
accents(longer is cut at 60).at most 60 characters
voice_accent"neutral" | "amgen" | "valley" | "south" | "rp" | "brixton" | "transat" | "aussie" | nullskipGreetingboolean | nullinterruptibleboolean | nullccboolean | nullcompanystring | nullat most 80 characters
greet_mode"single" | "rotate" | "ai" | nullgreetingsstring[] | nullOpening lines to choose from (the first 10, each cut at 200).
at most 10 items
idle_actionsboolean | nulldisplay_mode"half_body" | "presenter" | "full_body" | nullhand_motionboolean | nullvisionboolean | nullvision_safe_modeboolean | nullai_disclosureboolean | nullAlways true: every avatar tells people it's an AI (EU AI Act Article 50(1)), and it can't be switched off. Accepted for compatibility; false is ignored, and the persona reads back true.
ai_disclosure_textstring | nullYour own wording for the AI disclosure. It must still say plainly that it's an AI ("AI", or "artificial intelligence" in the avatar's language), or the request is refused (400 invalid_request). "" = the default, "You're speaking with an AI avatar."
at most 140 characters
engine"premier" | "global"deprecatedRead-only from 2026-10-01 (ignored): the voice decides the engine. Choose a voice by
voiceId.globalVoicestringdeprecatedRead-only from 2026-10-01 (ignored). Keys on 2026-07-08 may still name a studio voice here when they send no
voiceId.
PersonCreated
The person, and a new login card's PIN once.
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for the person (the sync key), when you gave one.
namestringrequiredemailstring | nullrequiredNull for a login card or a person known only by your id.
loginNamestring | nullrequiredA login card's sign-in name (
<organisation code>/<username>).lastSignInAtstring (date-time) | nullrequireddisabledbooleanrequiredSwitched off: no sign-in anywhere; their places keep their own status.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
loginCardLoginCard | nullrequiredOnly on the answer that made the card; never replayed.
Portal
A portal: its doors, how people sign in, who speaks, and its subjects.
idstringrequiredPortal id (
portal_…).namestringrequiredslugstringrequiredstatus"draft" | "published" | "archived"requireddraftuntil published; people only reach a published portal.group"learn" | "train" | "serve" | "assess" | "mixed" | nullrequiredIts subjects' group,
mixedwhen they differ; null without subjects.welcomestring | nullrequiredaddressstringrequiredWhere people open it: the sign-in page, or the verified custom domain.
addressesobjectrequiredmembersstringrequiredThe sign-in page (
/d/<org>/<portal>).visitorsstring | nullrequiredThe visitor page (
/v/<org>/<portal>) when a subject opens to visitors; null otherwise.embedstringrequiredWhat an iframe mounts, with
?t=<embed token>.
loginMethods("email" | "login_card" | "class_code" | "visitor")[]requiredunitIdstring | nullrequiredThe team or class it is for; null = the whole organisation.
personaIdstring | nullrequiredWho speaks on it.
brandobjectrequiredprimarystring | nullrequired#rrggbblogoUrlstring | nullrequiredmode"light" | "dark" | "system" | nullrequired
domainobject | nullrequiredThe organisation's own address for it, when one is set.
namestringrequiredverifiedbooleanrequiredverifiedAtstring (date-time) | nullrequired
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
publishRefusedstringOnly when a publish was asked for and the go-live check refused it (
POST /portalswithpublish: true;POST /portals/{id}/publishfor keys on 2026-07-08): what to finish first. The portal stays a draft.
PortalCreatedData
A portal was created.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullportalIdstring | nullnamestring | nullslugstring | nullsubjectsstring[] | nullviastring | null
PortalDoors
Every way in to a portal.
membersobjectrequiredurlstringrequiredThe sign-in page.
loginMethods("email" | "login_card" | "class_code" | "visitor")[]requiredunitIdstring | nullrequired
The visitors' door: people come in without signing in.
embedobjectrequiredurlstringrequiredWhat an iframe mounts, with
?t=and a token fromPOST /portals/{id}/embed-tokens.scriptstringrequiredThe snippet for a signed-in embed (your backend gets the token).
customDomainobject | nullrequirednamestringrequiredverifiedbooleanrequiredverifiedAtstring (date-time) | nullrequired
PortalGoLive
What stops the portal going live, subject by subject.
readybooleanrequiredPublishing would go through.
Worth fixing; never a refusal.
PortalGoLiveProblem
Something a subject still needs before the portal goes live.
fieldstringrequiredWhere it is in the content document (
faqs,screening.requirements[1],facts);setupfor the set-up as a whole.messagestringrequiredshortstringrequiredA few words for a list.
subjectIdstring | nullrequiredThe subject it is about; null for something about the whole portal: its actions (
fieldisactions) or its rehearsal before go-live (fieldisrehearsal).subjectNamestringrequired
PortalInput
A new portal. It starts as a draft.
namestringrequired1-80 characters
templatesstring[]Template keys from
GET /portals/templates; one subject each.at most 12 items
templatestringdeprecatedOne template (the 2026-07-08 form of
templates).1-60 characters
personaIdstringA persona of yours to speak on every subject; left out = the portal gets its own.
unitIdstring | nullThe team or class it is for; left out or null = the whole organisation.
welcomestring | nullloginMethods("email" | "login_card" | "class_code" | "visitor")[]publishbooleanPublish it once it passes the go-live check (needs
portals:publish); otherwise it stays a draft andpublishRefusedsays why.
PortalPersona
Who speaks on a portal.
idstringrequiredPersona id (
pa_…).pattern `^pa_.*`
namestringrequiredfacestring | nullrequiredThe face's name.
voicestring | nullrequiredThe voice's name.
avatarIdstring | nullrequiredvoiceIdstring | nullrequiredaccentstring | nullrequiredgreetingstring | nullrequiredcharacterstringrequiredlanguagestringrequiredThe language it speaks (a name from
GET /languages): English unless set.readybooleanrequiredIt has a face and a voice: people can talk to it.
PortalPersonaUpdate
What to change about who speaks. A new face of the other gender brings a matching voice unless one is given.
avatarIdstringA face (
av_…) fromGET /avatars.voiceIdstringA voice (
vo_…) fromGET /voices.facestringdeprecatedA library face by first name ("Marcus"). Prefer
avatarId.at most 40 characters
voicestringdeprecatedA studio voice by name ("James"). Prefer
voiceId.at most 40 characters
accentstringIn plain words ("British").
at most 60 characters
characterstringWho they are and how they behave, word for word (up to 4,000 characters; longer is 413).
greetingstringTheir first line (up to 300 characters).
namestringUp to 80 characters.
languagestringThe language it speaks: a name or code from
GET /languages("German", "es"); one it doesn't know is400. A duo speaks one of its ten.at most 80 characters
PortalSubject
A subject on a portal.
idstringrequiredSubject id (
sub_…).namestringrequiredtemplatestringrequiredThe template it was built from (
customfor one written for the organisation).typestringrequiredThe same as
template(its name in the 2026-07-08 contract).kind"tutor" | "roleplay" | "assessor" | "service"requiredWhat the avatar does:
tutorteaches,roleplayplays someone to practise with,assessorasks and scores,servicetalks to website visitors.group"learn" | "train" | "serve" | "assess"requiredscreeningbooleanrequiredA candidate screening role.
status"draft" | "published" | "archived"requiredhasDraftbooleanrequiredA draft version waits to be published (
POST /subjects/{id}/publish).
PortalTemplate
A template a portal's subjects are built from.
keystringrequiredWhat
POST /portalstakes intemplates.group"Learn" | "Train" | "Serve" | "Assess"requiredlabelstringrequireddescriptionstringrequiredavailablebooleanrequiredIt can be built today.
kind"tutor" | "roleplay" | "assessor" | "service"requiredWhat the avatar does:
tutorteaches,roleplayplays someone to practise with,assessorasks and scores,servicetalks to website visitors.duobooleanrequiredWritten for two people in one conversation (needs a duo).
requiresstring[]requiredThe plan features it needs (its portal family, candidate screening, ready-made duos).
includedInPlanbooleanrequiredThe organisation's plan has every feature it needs.
PortalUpdate
The fields to change.
namestring1-80 characters
welcomestring | nullloginMethods("email" | "login_card" | "class_code" | "visitor")[]Adding
visitoropens it to visitors: needsportals:publish, and runs the go-live check on a published portal.unitIdstring | nullpersonaIdstringOne of your personas to speak on it instead of its own.
brandobjectprimarystring | null#rrggbbor a colour name (green); null goes back to the organisation's colour.mode"light" | "dark" | "system" | nullhideZentiqBadgeboolean | nullHonoured when the plan includes removing the badge.
PortalUpdatedData
A portal changed (which fields).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullportalIdstring | nullpersonaIdstring | nullfieldsstring[] | nullstatusstring | nullviastring | nulladdedstring | nullremovedstring | number | boolean | nulldomainstring | nulldomainVerifiedstring | nullallowedOriginsstring[] | nullloginMethodsstring[] | nulltoolstring | null
PracticeStartedData
A person started a practice attempt.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullportalIdstring | null
ReportProducedData
A session's report is ready: numbers once released; its words only with includeConversation, where allowed. Never for a candidate.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullkindstring | nullsummarystring | nulloverallnumber | nullscorenumber | nullpracticeboolean | nullpassedboolean | nullpercentnumber | nullscenarioobject | nullidstring | nulltitlestring | null
questionSetobject | nullidstring | nulltitlestring | null
difficultystring | nullheldboolean | nullscreeningboolean | nullprovisionalboolean | nullfinalboolean | nullreportobject | nullkindstring | nullsummarystring | nullscoresmap of number | nulloverallnumber | nullstrengthsstring[] | nullworkOnstring[] | nullnextstring | nullbetterstring[] | nullmasteryobject[] | nulldeliveryobject | nulllearnerWordsinteger | nullavatarWordsinteger | nulltalkSharenumber | nullquestionsAskedinteger | nullfillerWordsinteger | nullfillerPerHundrednumber | nulllongestTurnWordsinteger | nullturnsinteger | nullpaceWpmnumber | nulltopFillersobject[] | null
assessmentobject | nullpassedboolean | nullpercentnumber | nullmarksnumber | nulloutOfnumber | nullpassMarknumber | nullpracticeboolean | nullreviewboolean | nullhumanReviewboolean | nullcertificateboolean | nullcriticalFailboolean | nullitemsobject[] | null
visitorobject | nullintentstring | nulltopicsstring[] | nullansweredobject[] | nullconsentboolean | nullhandoffobject | nullbookingobject | nullleadScorestring | nullresolvedboolean | nullpointsnumber | nullunansweredstring[] | nullforgottenstring[] | null
outcomeobject | nullagreedboolean | nullscorenumber | nullissuesobject[] | null
criticalobject[] | nullpracticeNotestring | nullomittedstring[] | nullscenarioobject | nullidstring | nulltitlestring | null
questionSetobject | nullidstring | nulltitlestring | null
difficultystring | null
ResponseTimes
How long the avatar took to start answering each turn, measured in the person's browser from when they stopped speaking or sent a typed line to the avatar's first sound. Only where the organisation measures response times (Settings, Features: "Measure how fast the avatar answers"), and only on Zentiq's own session pages (a portal's sessions, your website avatar's conversations): a session your own app shows isn't timed, and a builder's preview never is.
p50MsintegerrequiredThe typical wait in milliseconds: half the answers started sooner.
p90MsintegerrequiredNine answers in ten started within this many milliseconds.
maxMsintegerrequiredThe slowest answer's wait, in milliseconds.
turnsintegerrequiredHow many turns were timed. Turns that couldn't be timed fairly (talking over each other, a page in the background, a reconnect) aren't counted.
Result
A session's result: numbers only (never the summary, feedback, evidence, answers, flags or notes). Practice attempts, candidates' interviews and other job interviews are never results here.
idstringrequiredres_+ the session's id.pattern `^res_.*`
sessionIdstring | nullrequiredportalIdstring | nullrequiredThe portal it was started from (
portal_…; bare for keys on 2026-07-08).subjectIdstring | nullrequiredsub_…(bare for keys on 2026-07-08).subjectNamestring | nullrequiredkindstring | nullrequiredWhat the subject is: assessor, roleplay, tutor, …
personobject | nullrequiredidstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for them; only for a key holding people:read.
unitIdstring | nullrequiredstartedAtstring (date-time) | nullrequiredendedAtstring (date-time) | nullrequireddurationSecondsinteger | nullrequiredscoredbooleanrequiredA scored attempt (an assessment); its numbers follow the released rule.
release"not_scored" | "awaiting_review" | "reviewers_only" | "voided" | "released"requirednot_scored (a role-play, a lesson: its numbers are the report's); awaiting_review (a reviewer still decides it); reviewers_only (results go to the person through a reviewer only); voided; released.
scorenumber | nullrequired0-100: the released percent of a scored attempt, else the report's overall. Null while not released.
percentnumber | nullrequiredpassedboolean | nullrequiredpassMarknumber | nullrequiredscenarioobject | nullrequiredidstringrequiredtitlestringrequired
questionSetobject | nullrequiredidstringrequiredtitlestringrequired
difficultystring | nullrequiredcategoriesobject[]requiredThe rubric's categories with evidence, 0-100. Empty while not released.
idstringrequiredlabelstringrequiredscorenumberrequired
reviewobject | nullrequiredA reviewer's decision; null while the result is held for a reviewer or kept from the person (it would say pass or fail).
decisionstring | nullrequiredconfirm, pass, not_yet or void.
decidedAtstring (date-time)requiredISO 8601 UTC timestamp.
reviewerobject | nullrequiredidstringrequiredPerson id (
usr_…).pattern `^usr_.*`
correctedbooleanrequiredThe reviewer corrected marks.
contestobject | nullrequiredThe person asked for another look (never their words).
atstring (date-time)requiredISO 8601 UTC timestamp.
openbooleanrequired
certificateobject | nullrequiredThe certificate; null while the result is held for a reviewer or kept from the person.
idstringrequiredCertificate id (
cert_…).pattern `^cert_.*`
numberstringrequiredstatus"valid" | "expired" | "withdrawn"requiredvalidUntilstring | nullrequiredverifyUrlstringrequired
completionobject | nullrequiredThe completion record; null while the result is held for a reviewer or kept from the person.
status"recorded" | "withdrawn"requiredatstring (date-time)requiredISO 8601 UTC timestamp.
reportAvailablebooleanrequiredA written report exists (GET /results/{id}/report, with transcripts:read, where the rules allow the words).
erasedbooleanrequiredThe retention job took the conversation's words out.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
ResultContestedData
A person asked for their result to be looked at again.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullpercentnumber | nullpassedboolean | nullquestionSetobject | nullidstring | nulltitlestring | null
ResultReport
The report's words, where the conversation's rules allow them.
resultIdstringrequiredResult id (
res_…).pattern `^res_.*`
summarystring | nullrequiredstrengthsstring[]requiredworkOnstring[]requirednextstring | nullrequired
ReviewCompletedData
A person decided a result under review.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nulldecisionstring | nullpassedboolean | nullvoidedboolean | nullpercentnumber | nullmarksnumber | nulloutOfnumber | nullpassMarknumber | nullaiobject | nullpassedboolean | nullpercentnumber | nullmarksnumber | null
reviewerIdstring | nullreportIdstring | nullcontestedboolean | nullbeforeboolean | nullfinalboolean | nullincompleteboolean | null
ReviewRequestedData
A result waits for a person's review (why, never the score).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullreasonstring | nullpassMarknumber | null
Role
A screening role: the subject candidates are interviewed on.
idstringrequiredThe role is a screening subject (
sub_…); edit its content through /subjects/{id}/content.titlestringrequiredThe job being hired for (the screening block's role), or the subject's name while it has none.
subjectNamestringrequiredlocationstring | nullrequiredmarket"us" | "uk" | "eu" | nullrequiredWhere the role hires (its own, or the organisation's country): us, uk or eu. Null while unpublished.
status"draft" | "published" | "archived"requiredportalIdsstring[]requiredtimingobject | nullrequiredThe role's default timing for new invites; null when it sets none.
mode"open" | "deadline" | "scheduled"requireddeadlineDaysinteger | nullrequiredearlyMinutesinteger | nullrequiredlateMinutesinteger | nullrequired
closesOnstring (date) | nullrequiredApplications close at the end of this day (the role's time zone); no invite may start after it.
bandsobject | nullrequiredThe score bands the hiring team sorts by (a sorting aid, never a verdict).
strongnumberrequiredpossiblenumberrequired
roundsobject[]requiredRounds of the interview candidates took: scores compare only within a round.
roundintegerrequiredat least 1
versionintegerrequiredThe first published version of the role in this round.
at least 1
changed("set" | "questions" | "level" | "bands" | "mustHaves")[]requiredWhat changed from the round before: the question set, the questions, the level, the bands or the must-haves.
latestRoundinteger | nullrequiredreviewsRequiredintegerrequiredReviews a decision waits for (switch candidates.reviews_required); a decline waits for at least one.
blindReviewbooleanrequiredshareScoresbooleanrequiredSwitch candidates.share_scores: whether candidates' score, band and rank are given out through the API. Off by default. Never by webhook.
holdbooleanrequiredA legal hold is on the whole role: nothing about its candidates is erased while it is on.
doorobject | nullrequiredThe interview link a job advert carries (a portal's visitor door), open once it is published and open to visitors.
portalIdstringrequiredPortal id (
portal_…).urlstringrequiredopenbooleanrequired
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
SayInput
textstringrequiredUp to 2,000 characters.
interruptboolean | nullCut off any speech in progress first (default true).
languagestring | nullThe line's language: one of GET /languages. Default: the session's.
turnIdstring | nullExternal turn mode: the turn this line answers.
eventIdstring | nullExternal turn mode: makes a redelivered line idempotent.
endSessionboolean | nullExternal turn mode: end the session after this line.
ScoreRecordedData
A released score for a person's session.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullscorenumber | nullscoresmap of number | null
SearchInput
What to look for.
querystringrequiredat most 4,096 characters
topKintegerHow many passages (default 5).
1-50
minScorenumberLeave out passages below this similarity (0-1, default 0).
0-1
SearchResult
The closest passages, best first.
resultsobject[]requireddocumentIdstringrequiredDocument id (
doc_…).pattern `^doc_.*`
textstringrequiredscorenumberrequired0-1 similarity (higher is closer).
metadataobjectrequiredpageinteger | nullrequired
Session
A live conversation with a persona.
idstringrequiredSession id (
sess_…).pattern `^sess_.*`
personaIdstring | nullrequiredThe persona that spoke (
pa_…).status"ACTIVE" | "COMPLETED" | "ABANDONED"requiredACTIVE while live; COMPLETED or ABANDONED once ended.
sourcestringrequiredWhere it started: api, portal, visitor, playground, demo or guide.
turnModestring | nullrequiredexternalwhen your app owns every avatar turn (autoRespond false); null otherwise.autoRespondbooleanrequiredFalse when the avatar only speaks the lines your app sends (POST /sessions/{id}/say).
roomstring | nullrequiredThe realtime room, while it has one.
minutesBillednumber | nullrequiredMinutes charged once the session ended; null while live.
startedAtstring (date-time)requiredISO 8601 UTC timestamp.
endedAtstring (date-time) | nullrequireddurationinteger | nullrequiredSeconds, once ended.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
modestringrequiredAVATAR (a talking avatar), VOICE_CALL or CHAT (typed).
subjectIdstring | nullrequiredThe portal subject it ran in (
sub_…; bare for keys on 2026-07-08); null for a persona session.kind"persona" | "subject" | "visitor"requiredA persona session (your app's, or the console's), a lesson or role-play in a subject, or a website visitor's conversation.
aiGeneratedtruerequiredAlways true: the avatar's video, voice and words are AI-generated (EU AI Act Article 50(2)). Keep this marker with the content when you store or pass it on.
responseTimesResponseTimes | nullrequiredHow fast the avatar started answering, once the session ended; null when it wasn't measured.
SessionAnalytics
Only recorded data: speech-recognition, model and speech-synthesis timings and interruptions are not recorded and are listed in notRecorded.
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
statusstringrequiredsourcestringrequireddurationobjectrequiredsecondsintegerrequiredlivebooleanrequiredstartedAtstring (date-time)requiredISO 8601 UTC timestamp.
endedAtstring (date-time) | nullrequired
billingobjectrequiredratenumberrequiredbilledSecondsintegerrequiredbilledMinutesnumberrequiredledgerobjectrequiredThe minutes ledger entries for this session.
chargedSecondsintegerrequiredabsorbedSecondsintegerrequiredunmeteredSecondsintegerrequiredwallSecondsintegerrequiredentriesintegerrequired
turnsobjectrequiredtotalintegerrequireduserintegerrequiredavatarintegerrequired
talkShareobjectrequiredmethod"word_timings" | "word_count" | nullrequiredusernumber | nullrequiredavatarnumber | nullrequireduserWordsintegerrequiredavatarWordsintegerrequireduserSpeechMsinteger | nullrequiredavatarSpeechMsinteger | nullrequired
timingobjectrequiredturnTimestampsbooleanrequiredwordTimingsbooleanrequireduserToAvatarMsobject | nullrequiredTime between a person's turn being recorded and the avatar's reply being recorded. Not a pure response latency: turns are timestamped when they are stored.
medianintegerrequiredp90integerrequiredsamplesintegerrequired
turnsobject[]requiredindexintegerrequiredrole"user" | "avatar"requiredspeakerstringA duo's speaker.
atMsinteger | nullrequiredwordsintegerrequiredspeechMsinteger | nullrequiredsincePreviousMsinteger | nullrequired
interruptionsanyrequiredNot recorded yet.
clientMetricsobject | nullrequiredpaceWpmnumber | nullrequiredtalkListenRationumber | nullrequiredfillerWordsPerMinutenumber | nullrequired
candidatebooleanrequiredA candidate's screening interview: report and summary are always null.
reportobject | nullrequiredkindstring | nullrequiredsummarystring | nullrequiredscorenumber | nullrequiredoverallnumber | nullrequiredpercentnumber | nullrequiredpassedboolean | nullrequiredproducedAtstring (date-time)requiredISO 8601 UTC timestamp.
summarystring | nullrequireddisclosureobject | nullrequiredrequiredboolean | nullrequiredtextstring | nullrequiredmethodstring | nullrequiredrecordedAtstring (date-time)requiredISO 8601 UTC timestamp.
notRecordedstring[]requiredaiGeneratedtruerequiredAlways true: the avatar's video, voice and words are AI-generated (EU AI Act Article 50(2)). Keep this marker with the content when you store or pass it on.
SessionAnalyticsSummary
The short analytics GET /sessions/{id} carries.
durationSecondsintegerrequiredbilledMinutesnumberrequiredbilledSecondsintegerrequiredbillingRatenumberrequiredBillable seconds per wall-clock second, fixed when the session started.
turnCountintegerrequiredtalkShareobjectrequiredusernumber | nullrequiredavatarnumber | nullrequired
summarystring | nullrequiredThe report's short summary, or a transcript summary already made in the portal: conversation words, so only where the transcript may be read (never a candidate's interview, a young learner's conversation or a website visitor's who said they are under 18).
scorenumber | nullrequiredThe report's score, when it has one.
SessionDetail
A session with its short analytics (the full breakdown is GET /sessions/{id}/analytics).
idstringrequiredSession id (
sess_…).pattern `^sess_.*`
personaIdstring | nullrequiredThe persona that spoke (
pa_…).status"ACTIVE" | "COMPLETED" | "ABANDONED"requiredACTIVE while live; COMPLETED or ABANDONED once ended.
sourcestringrequiredWhere it started: api, portal, visitor, playground, demo or guide.
turnModestring | nullrequiredexternalwhen your app owns every avatar turn (autoRespond false); null otherwise.autoRespondbooleanrequiredFalse when the avatar only speaks the lines your app sends (POST /sessions/{id}/say).
roomstring | nullrequiredThe realtime room, while it has one.
minutesBillednumber | nullrequiredMinutes charged once the session ended; null while live.
startedAtstring (date-time)requiredISO 8601 UTC timestamp.
endedAtstring (date-time) | nullrequireddurationinteger | nullrequiredSeconds, once ended.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
modestringrequiredAVATAR (a talking avatar), VOICE_CALL or CHAT (typed).
subjectIdstring | nullrequiredThe portal subject it ran in (
sub_…; bare for keys on 2026-07-08); null for a persona session.kind"persona" | "subject" | "visitor"requiredA persona session (your app's, or the console's), a lesson or role-play in a subject, or a website visitor's conversation.
aiGeneratedtruerequiredAlways true: the avatar's video, voice and words are AI-generated (EU AI Act Article 50(2)). Keep this marker with the content when you store or pass it on.
responseTimesResponseTimes | nullrequiredHow fast the avatar started answering, once the session ended; null when it wasn't measured.
analyticsSessionAnalyticsSummary | nullrequired
SessionEndedData
A session ended, once: its length and minutes. Its summary only with includeConversation, where allowed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullpersonaIdstring | nulldurationSecondsnumber | nullbilledMinutesnumber | nullreasonstring | nullminutesnumber | nullsecondsnumber | nullstatusstring | nullcompletedAssignmentsstring[] | nullscorenumber | nullselfboolean | nullwithheldboolean | nullwithdrawnboolean | nullincompleteboolean | nullunverifiedboolean | nullreapedboolean | nullvoidedboolean | nullsummarystring | null
SessionStartedData
A live session started: an API session, or a member's session on a portal (never its plan).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullpersonaIdstring | nullidentitystring | nullworkspaceNamestring | nullselfboolean | nullportalIdstring | nullkindstring | nullfocusstring | nulldifficultystring | nullbootstrapboolean | nullassignmentsstring[] | null
SessionToken
What your app needs to join the session.
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
sessionTokenstringrequiredShort-lived client token (15 minutes) for the realtime room.
urlstringrequiredThe realtime transport URL.
roomstringrequiredpersonaobjectrequiredidstringrequiredPersona id (
pa_…).pattern `^pa_.*`
namestringrequiredThe name the avatar hears. Only a duo's carries " & " ("Mark & Susan"); a single persona named "Smith & Jones" comes back as "Smith and Jones".
disclosureobjectrequiredThe AI disclosure (EU AI Act Article 50): keep
labelvisible on or next to the avatar's video for the whole session and showtextat its start. Recorded against the session.requiredbooleanrequiredAlways true: the AI disclosure can't be switched off.
textstringrequiredThe notice to show when the session starts, in the session's language (the persona's own wording when it has one).
labelstringrequiredThe short label to keep on or right next to the avatar's video for the whole session, in the session's language (the persona's own wording when it has one). The browser and React SDKs draw it for you.
languagestringrequiredThe language of
labelandtext, as a code.display"whole_session"requiredWhen the label shows: for the whole session.
rulestringrequiredWhat your app must do, in plain words: keep the label visible for the whole session and show the notice at the start. You may restyle or move it, never remove, hide or cover it.
ownLabelbooleanrequiredTrue only when an owner of your organisation has confirmed, in the console, that your app shows its own AI label for the whole of every session. Only then may the SDKs' own label be hidden.
ccbooleanrequiredThe persona's caption preference. The transcript always streams on the data topic "chat"; cc is a render hint.
aiGeneratedtruerequiredAlways true: the avatar's video, voice and words are AI-generated (EU AI Act Article 50(2)). Keep this marker with the content when you store or pass it on.
SessionTokenInput
personaIdstringrequiredThe persona to start (
pa_…).identitystring | nullYour end user's id (optional): the participant identity in the room.
languagestring | nullPer-session spoken-language override: one of GET /languages, as a code or the name.
languageMode"follow" | "fixed" | nullHow this session keeps its language:
followswitches to the person's language when they use another;fixedanswers in the session's language anyway. Default: the persona's own setting.overridesobject | nullsystemPromptstring | nullReplaces the persona's prompt for this session (up to 16,000 characters).
greetingstring | nullReplaces the greeting (up to 2,000 characters); an empty string means no greeting.
variablesmap of any | null
autoRespondboolean | nullfalse: your app owns every avatar turn; the avatar only speaks the greeting and the lines you send with say.
turnModeobject | null{ mode: "external" }is the same as autoRespond false.modestring
SessionTranscriptReadyData
A session's whole transcript can be read with GET /v1/sessions/{id}/transcript (ids only; only where the API may read it).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullpersonaIdstring | null
SettingChangedData
A switch changed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullkeystring | nullscopeTypestring | nullscopeIdstring | nullfromstring | number | boolean | nulltostring | number | boolean | nulllockedboolean | null
SetupPlan
What to build for a goal. POST /portals with the template builds it.
templatestringrequiredA key from
GET /portals/templates, orcustomwhen nothing there fits.fit"exact" | "close" | "none"requiredHow well the template fits;
nonegoes withcustom.customKind"service" | "tutor" | "roleplay" | "assessor"For
custom: what the avatar mostly does.templateLabelstringrequiredportalNamestringrequiredaudiencestringrequiredWho the avatar talks to, in plain words.
orgType"company" | "school" | "tutoring" | "individual" | "family" | "other"requiredsummarystringrequired
SetupPlanInput
goalstringrequired1-600 characters
StaffToken
What your helpdesk needs to join the visitor's call as the member, as themselves.
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
staffTokenstringrequiredShort-lived client token (15 minutes) for the realtime room, as the person: microphone and camera, no data channel.
urlstringrequiredThe realtime transport URL.
roomstringrequiredidentitystringrequiredThe person's identity in the room:
staff-<userId>-<random>, with the attribute zq_role=staff.userIdstringrequiredPerson id (
usr_…).pattern `^usr_.*`
handedOverbooleanrequiredTrue when this person is the first from the team in the call: the avatar says who joined and what the visitor needs, then goes quiet until the team has left.
StaffTokenInput
userIdstring | nullThe member who joins. A member's own key (made by them in the console) joins as them and may leave this out; only a full-access key may name another member.
SteerInput
systemPromptstring | nulllanguagestring | nullOne of GET /languages (a duo's: one of the ten it speaks).
variablesmap of any | null
Subject
A subject: what an avatar teaches, practises, assesses or answers, on one or more portals.
idstringrequiredSubject id (
sub_…).namestringrequiredtemplatestringrequiredThe template it was built from (
customfor one written for the organisation).kind"tutor" | "roleplay" | "assessor" | "service"requiredgroup"learn" | "train" | "serve" | "assess"requiredscreeningbooleanrequiredA candidate screening role (its invites and candidates are under /roles).
status"draft" | "published" | "archived"requireddraftuntil it (or its portal) is published.liveVersionintegerrequiredThe version sessions run; 0 when there is none.
draftVersioninteger | nullrequiredA pending draft to publish; null when there is none.
languagesstring[]requiredLanguage codes (
GET /languages).visitorLanguage"follow" | "listed" | "english" | nullrequiredA website subject: whether it follows the visitor's language, keeps to
languages, or speaks English. Null for any other.unitIdstring | nullrequiredportalIdsstring[]requiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
SubjectAssessment
How a structured assessment runs. On a write, the fields sent replace theirs.
questionsintegerrequiredHow many questions one attempt asks.
passMarknumberrequiredtimedSecondsintegerfeedback"after-each" | "at-end"requiredhintsbooleanhintCostnumberfactCheckedbooleanpurposestringWhat the assessment is for, in the notice people confirm before a scored attempt.
contactstringWho people ask for an adjustment or about a result.
review"borderline" | "all"certificatebooleanhumanReviewbooleanretakeAfterDaysintegerretakeLimitobjectattemptsintegerrequiredwithinDaysintegerrequired
contestDaysintegerpracticeModebooleanreportstringrequiredWhat the report contains.
SubjectAssessmentInput
How a structured assessment runs. On a write, the fields sent replace theirs.
questionsintegerHow many questions one attempt asks.
1-80
passMarknumber0-100
timedSecondsinteger | nullfeedback"after-each" | "at-end"hintsboolean | nullhintCostnumber | nullfactCheckedboolean | nullpurposestring | nullcontactstring | nullreview"borderline" | "all" | nullcertificateboolean | nullhumanReviewboolean | nullretakeAfterDaysinteger | nullretakeLimitobject | nullattemptsintegerrequired1-20
withinDaysintegerrequired1-1,095
contestDaysinteger | nullpracticeModeboolean | nullreportstringWhat the report contains.
1-600 characters
SubjectBookableService
Something visitors can ask to book.
idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
namestringrequiredminutesintegerrequireddetailsstringleadTimeHoursintegerhoursstring
SubjectBookableServiceInput
Something visitors can ask to book.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
namestringrequired1-80 characters
minutesintegerrequired5-480
detailsstring | nullleadTimeHoursinteger | nullhoursstring | null
SubjectContent
A subject's content, one section per thing a business edits. Sections that don't apply to the subject's kind are left out; a section that applies but isn't set is null (objects) or [] (lists).
namestringrequiredaudiencestring | nullrequiredlanguagesstring[]requiredgradeBandany[] | nullrequiredtopicsSubjectTopic[]framestring | nullscenariosSubjectScenario[]questionsSubjectQuestion[]questionSetsSubjectQuestionSet[]rubricSubjectRubricHow conversations are marked. On a write, the fields sent replace theirs.
assessmentSubjectAssessmentHow a structured assessment runs. On a write, the fields sent replace theirs.
serviceSubjectServiceHow a website conversation runs. On a write, the fields sent replace theirs.
faqsSubjectFaq[]departmentsSubjectDepartment[]hoursSubjectHours | nulllocationsSubjectLocation[]servicesSubjectBookableService[]qualificationSubjectQualification[]leadScoringSubjectLeadScoring | nullsafetyLinesSubjectSafetyLines | nullwidgetSubjectWidgetA website widget's subject: set through
PUT /personas/{id}/widget. Read-only here: a write may only send it back as it is.screeningSubjectScreeningA candidate screening role. On a write, the fields sent replace theirs.
SubjectContentDraft
The draft saved, and whether it could go live.
versionintegerrequiredThe version shown; its
ETagis"v<version>".livebooleanrequiredIt is what sessions run.
basedOninteger | nullrequiredThe version it was saved over; null for the first.
A subject's content, one section per thing a business edits. Sections that don't apply to the subject's kind are left out; a section that applies but isn't set is null (objects) or [] (lists).
goLiveobjectrequiredreadybooleanrequiredWorth fixing; never a refusal.
SubjectContentSet
The sections to change. A list replaces the whole list; an object section changes only the fields sent (null clears an optional one); facts also takes { key: value }. A document read with GET can be sent back as it is.
namestring1-80 characters
audiencestring | nulllanguagesstring[]at most 50 items
gradeBandany[] | nullfactsSubjectFactInput[] | map of stringEither the whole list of facts (replacing it), or
{ key: value }to set values by key.topicsSubjectTopicInput[]at most 500 items
framestring | nullscenariosSubjectScenarioInput[]at most 60 items
questionsSubjectQuestionInput[]at most 300 items
questionSetsSubjectQuestionSetInput[]at most 40 items
rubricSubjectRubricInputHow conversations are marked. On a write, the fields sent replace theirs.
assessmentSubjectAssessmentInputHow a structured assessment runs. On a write, the fields sent replace theirs.
serviceSubjectServiceInputHow a website conversation runs. On a write, the fields sent replace theirs.
at most 100 items
departmentsSubjectDepartmentInput[]at most 20 items
hoursSubjectHoursInput | nulllocationsSubjectLocationInput[]at most 10 items
servicesSubjectBookableServiceInput[]at most 30 items
qualificationSubjectQualificationInput[]at most 15 items
leadScoringSubjectLeadScoringInput | nullsafetyLinesSubjectSafetyLinesInput | nullwidgetSubjectWidgetInputA website widget's subject: set through
PUT /personas/{id}/widget. Read-only here: a write may only send it back as it is.screeningSubjectScreeningInputA candidate screening role. On a write, the fields sent replace theirs.
SubjectContentUpdate
Sections to change. Always saved as a draft; publish it with POST /subjects/{id}/publish.
The sections to change. A list replaces the whole list; an object section changes only the fields sent (null clears an optional one);
factsalso takes{ key: value }. A document read with GET can be sent back as it is.notestringKept with the version.
at most 200 characters
baseVersionintegerThe version your change is based on (or send
If-Match: "v<n>"); a newer one is409 version_conflict.at least 1
SubjectContentVersion
One version of a subject's content.
versionintegerrequiredThe version shown; its
ETagis"v<version>".livebooleanrequiredIt is what sessions run.
basedOninteger | nullrequiredThe version it was saved over; null for the first.
A subject's content, one section per thing a business edits. Sections that don't apply to the subject's kind are left out; a section that applies but isn't set is null (objects) or [] (lists).
SubjectDepartment
A team visitors can be passed to.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
namestringrequiredhandlesstringrequiredcontactstringphonestringemailstringhoursstringA set of opening hours, by its id in
hours.sets.callbackPromisestringcallbackWithinHoursinteger
SubjectDepartmentInput
A team visitors can be passed to.
idstring | nullnamestringrequired1-80 characters
handlesstringrequired1-400 characters
contactstring | nullphonestring | nullemailstring | nullhoursstring | nullcallbackPromisestring | nullcallbackWithinHoursinteger | null
SubjectDraftSavedData
A subject's draft version was saved.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullversioninteger | nullviastring | null
SubjectFact
A fact about the organisation that the subject's content uses.
keystringrequiredFills
{{key}}wherever the subject's content says it.labelstringrequiredvaluestringrequiredThe organisation's own value; "" = not filled in yet.
helpstringkeepbooleanA method or guardrail default the organisation keeps until it writes its own.
perPersonbooleanEach person gives their own value on the start screen (the role an interview is for).
SubjectFactInput
A fact about the organisation that the subject's content uses.
keystringrequiredFills
{{key}}wherever the subject's content says it.1-40 characters · pattern `^[a-z][a-z0-9_]*$`
labelstring1-80 characters
valuestringrequiredThe organisation's own value; "" = not filled in yet.
0-2,000 characters
helpstring | nullkeepboolean | nullperPersonboolean | null
SubjectFaq
An approved answer to a question visitors ask.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
qstringrequiredThe question, as visitors ask it.
askstring[]Other ways visitors ask it (any language).
astringrequiredThe approved answer.
linkstringthenstringWhat to do after answering:
offer_handoff:<team>,start_booking:<service>.
SubjectFaqInput
An approved answer to a question visitors ask.
idstring | nullqstringrequiredThe question, as visitors ask it.
1-300 characters
askstring[] | nullastringrequiredThe approved answer.
1-1,200 characters
linkstring | nullthenstring | null
SubjectGoLive
Whether a version of the subject can go live, and what to finish first.
versionintegerrequiredThe version checked.
readybooleanrequiredWorth fixing; never a refusal.
SubjectHours
Opening hours the assistant can reason about. On a write, the fields sent replace theirs.
timezonestringrequiredAn IANA time zone, like
America/New_York.bankHolidays"england-and-wales" | "scotland" | "northern-ireland" | "us-common" | "us-federal" | "none"setsmap of objectrequiredOpening hours by set id (
main,sales). A day left out on a write is closed.closuresobject[]datestringrequiredlabelstringrequiredsetsstring[]
SubjectHoursInput
Opening hours the assistant can reason about. On a write, the fields sent replace theirs.
timezonestringAn IANA time zone, like
America/New_York.1-60 characters
bankHolidays"england-and-wales" | "scotland" | "northern-ireland" | "us-common" | "us-federal" | "none" | nullsetsmap of objectOpening hours by set id (
main,sales). A day left out on a write is closed.closuresobject[] | null
SubjectLeadScoring
How a lead is banded. On a write, the fields sent replace theirs.
hotstringrequiredwarmstringrequiredcoldstringrequiredhotAtintegerwarmAtinteger
SubjectLeadScoringInput
How a lead is banded. On a write, the fields sent replace theirs.
hotstring1-500 characters
warmstring1-500 characters
coldstring1-500 characters
hotAtinteger | nullwarmAtinteger | null
SubjectLocation
Where the business is.
namestringrequiredaddressstringrequiredmapUrlstringparkingstringaccessstring
SubjectLocationInput
Where the business is.
namestringrequired1-80 characters
addressstringrequired1-300 characters
mapUrlstring | nullparkingstring | nullaccessstring | null
SubjectPublish
What to publish.
versionintegerThe version to publish (default: the newest, the pending draft). An older one is brought back as the newest.
at least 1
newRoundbooleanA screening role that keeps candidates: changes to how candidates compare start a new round (otherwise
409 conflict, reasonround_locked).
SubjectQualification
A question asked about an enquiry before it goes to the team.
idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
questionstringrequiredfieldstring (one of 11)whystringpointsmap of integerPoints per kind of answer, for the lead score.
SubjectQualificationInput
A question asked about an enquiry before it goes to the team.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
questionstringrequired1-300 characters
fieldstring (one of 11) | nullwhystring | nullpointsmap of integer | null
SubjectQuestion
A question people are asked (the answer key is the organisation's own content).
idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
textstringrequiredtopicstringcompetencystringThe rubric category it measures.
difficulty"easy" | "medium" | "hard"format"open" | "short" | "scenario" | "choice"optionsstring[]followUpsstring[]followUpsRigorousstring[]twiststringlookForstring[]redFlagsstring[]anchorsobject1string3string5string
notestringmodelAnswerstringacceptedstring[]marksintegertimeSecondsintegercriticalbooleanpinned"first" | "last"
SubjectQuestionInput
A question people are asked (the answer key is the organisation's own content).
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
textstringrequired1-600 characters
topicstring | nullcompetencystring | nulldifficulty"easy" | "medium" | "hard" | nullformat"open" | "short" | "scenario" | "choice" | nulloptionsstring[] | nullfollowUpsstring[] | nullfollowUpsRigorousstring[] | nulltwiststring | nulllookForstring[] | nullredFlagsstring[] | nullanchorsobject | null1string | null3string | null5string | null
notestring | nullmodelAnswerstring | nullacceptedstring[] | nullmarksinteger | nulltimeSecondsinteger | nullcriticalboolean | nullpinned"first" | "last" | null
SubjectQuestionSet
A named group of questions.
idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
titlestringrequireddescriptionstringquestionIdsstring[]requiredorder"fixed" | "shuffled"requiredLeft out on a write:
fixed.askintegerlevel"easy" | "medium" | "hard" | "mixed"region"uk" | "us" | "intl"The country the content is written for:
ukorus, orintlfor a law module's version for everywhere outside the UK; left out = anywhere.hiddenbooleanformstringintensity"relaxed" | "standard" | "rigorous"assessmentobjectmode"scored" | "practice" | "either"passMarknumbertimedSecondsintegerfeedback"after-each" | "at-end"hintsbooleanhintCostnumberreview"borderline" | "all"certificateboolean
SubjectQuestionSetInput
A named group of questions.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
titlestringrequired1-80 characters
descriptionstring | nullquestionIdsstring[]requiredat most 80 items
order"fixed" | "shuffled"Left out on a write:
fixed.askinteger | nulllevel"easy" | "medium" | "hard" | "mixed" | nullregion"uk" | "us" | "intl" | nullhiddenboolean | nullformstring | nullintensity"relaxed" | "standard" | "rigorous" | nullassessmentobject | nullmode"scored" | "practice" | "either" | nullpassMarknumber | nulltimedSecondsinteger | nullfeedback"after-each" | "at-end" | nullhintsboolean | nullhintCostnumber | nullreview"borderline" | "all" | nullcertificateboolean | null
SubjectQuestionsTranslate
The language to translate the subject's questions into.
languagestringrequiredA name or code from
GET /languages("German", "es"): the portal's language.1-80 characters
SubjectQuestionsTranslated
A draft with the subject's questions in another language, to check and publish.
versionintegerrequiredThe draft that holds the translated questions.
languagestringrequiredThe language's name.
translatedintegerrequiredHow many questions were translated.
SubjectRubric
How conversations are marked. On a write, the fields sent replace theirs.
scalenumberrequiredcategoriesobject[]requiredWeights add up to 1.
idstringrequiredlabelstringweightnumberrequirednotestringanchorsmap of string
masteredAtnumberrequiredcriticalobject[]idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
labelstringrequiredcapnumbercategoriesmap of numberwhen"beyond_walk_away"
SubjectRubricInput
How conversations are marked. On a write, the fields sent replace theirs.
scalenumbercategoriesobject[]Weights add up to 1.
at most 50 items
idstring1-60 characters
labelstring | nullweightnumberrequired0-1
notestring | nullanchorsmap of string | null
masteredAtnumbercriticalobject[] | null
SubjectSafetyLines
The organisation's exact safety wording. On a write, the fields sent replace theirs.
emergencystringcrisisstringchildstringdomesticAbusestringcannotSpeakstring
SubjectSafetyLinesInput
The organisation's exact safety wording. On a write, the fields sent replace theirs.
emergencystring | nullcrisisstring | nullchildstring | nulldomesticAbusestring | nullcannotSpeakstring | null
SubjectScenario
A role-play scenario: the avatar plays the counterpart.
idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
titlestringrequiredcontextstringThe situation, shown to the person before they start.
counterpartstringrequiredWho the avatar plays, shown to the person.
privatestringThe counterpart's hidden brief: never shown to the person.
goalstringrequiredopeningstringdifficulty"easy" | "medium" | "hard" | "any"requiredLeft out on a write:
any.skillsstring[]successstringminutesintegeraudienceBriefstringaudienceQuestionsobjecteasystring[]requiredmediumstring[]requiredhardstring[]required
traineeBriefstringsensitivebooleanhiddenbooleanKept but never offered: a sensitive situation written for another industry, until it is rewritten for this business and checked.
contentNotestringissuesobject[]idstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
labelstringrequiredunitstringbetter"high" | "low"requiredhigh= the trainee wants a bigger number;low= a smaller one.targetnumberrequiredwalkAwaynumberrequiredcounterpartLimitnumberThe counterpart's real limit: never shown to the trainee.
weightnumber
SubjectScenarioInput
A role-play scenario: the avatar plays the counterpart.
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
titlestringrequired1-80 characters
contextstring | nullcounterpartstringrequiredWho the avatar plays, shown to the person.
1-400 characters
privatestring | nullgoalstringrequired1-300 characters
openingstring | nulldifficulty"easy" | "medium" | "hard" | "any"Left out on a write:
any.skillsstring[] | nullsuccessstring | nullminutesinteger | nullaudienceBriefstring | nullaudienceQuestionsobject | nulleasystring[]requiredat most 8 items
mediumstring[]requiredat most 8 items
hardstring[]requiredat most 8 items
traineeBriefstring | nullsensitiveboolean | nullhiddenboolean | nullcontentNotestring | nullissuesobject[] | null
SubjectScreening
A candidate screening role. On a write, the fields sent replace theirs.
rolestringrequiredThe job title.
locationstringintrostringrequiredWhat candidates read before they start.
noticestringrequiredcapture("name" | "email" | "phone" | "location")[]requiredrequirementsobject[]requiredidstringrequiredThe item's id within this subject: letters, numbers, dots, dashes or underscores.
questionstringrequiredAsked word for word near the start.
kind"yes_no" | "choice" | "number" | "text"requiredoptionsstring[]meetsobjectThe answer that meets it: one of
anyOf(yesfor yes/no), or a range; left out = recorded, not judged.anyOfstring[]minnumbermaxnumber
knockoutbooleanNot meeting it is flagged to the hiring team; a person decides.
whystring
setIdstringThe question set the interview uses.
uncheckedstring[]Questions written for the role by Magic Setup that no person has checked yet: the role can't go live until this is empty. Send [] once they are checked.
bandsobjectrequiredstrongnumberrequiredpossiblenumberrequired
humanContactstringrequiredWho candidates contact for adjustments or a person instead.
adjustmentsstringrequiredretentionDaysintegerrequiredclosesOnstringtimingobjectmode"open" | "deadline" | "scheduled"requireddeadlineDaysintegerearlyMinutesintegerlateMinutesinteger
recording"transcript" | "audio" | "audio_video"cameraOptionalbooleanopenDoorbooleanintensity"relaxed" | "standard" | "rigorous"style"structured" | "natural"bookingUrlstringhiringForstringoutcomeEmailsobjectinvitestringholdstringdeclinestring
market"us" | "uk" | "eu"usStatestringnycbooleantimeZonestring
SubjectScreeningInput
A candidate screening role. On a write, the fields sent replace theirs.
rolestringThe job title.
2-120 characters
locationstring | nullintrostringWhat candidates read before they start.
10-1,200 characters
noticestring10-1,500 characters
capture("name" | "email" | "phone" | "location")[]at most 4 items
requirementsobject[]at most 10 items
idstringThe item's id within this subject: letters, numbers, dots, dashes or underscores.
at most 60 characters · pattern `^[A-Za-z0-9][A-Za-z0-9._-]*$`
questionstringrequiredAsked word for word near the start.
3-300 characters
kind"yes_no" | "choice" | "number" | "text"requiredoptionsstring[] | nullmeetsobject | nullanyOfstring[] | nullminnumber | nullmaxnumber | null
knockoutboolean | nullwhystring | null
setIdstring | nulluncheckedstring[] | nullbandsobjectstrongnumberrequired0-100
possiblenumberrequired0-100
humanContactstringWho candidates contact for adjustments or a person instead.
0-300 characters
adjustmentsstring5-600 characters
retentionDaysinteger7-1,461
closesOnstring | nulltimingobject | nullmode"open" | "deadline" | "scheduled"requireddeadlineDaysinteger | nullearlyMinutesinteger | nulllateMinutesinteger | null
recording"transcript" | "audio" | "audio_video" | nullcameraOptionalboolean | nullopenDoorboolean | nullintensity"relaxed" | "standard" | "rigorous" | nullstyle"structured" | "natural" | nullbookingUrlstring | nullhiringForstring | nulloutcomeEmailsobject | nullinvitestring | nullholdstring | nulldeclinestring | null
market"us" | "uk" | "eu" | "US" | "UK" | "EU" | nullusStatestring | nullnycboolean | nulltimeZonestring | null
SubjectService
How a website conversation runs. On a write, the fields sent replace theirs.
goalstringrequiredopeningstringoutOfHoursOpeningstringhelpsWithstring[]capture(string (one of 11))[]requiredThe details the avatar may ask a visitor for, with consent.
captureRulesmap of stringHow to ask for each detail, by capture field.
consentstringrequiredprivacyNoticeUrlstringneverCollectstring[]handoffstringrequiredhandoffRulesobjectofferAfterUnansweredintegeralwaysHandoffTopicsstring[]urgentTopicsstring[]emergencyTopicsstring[]staffSummarystring
bookingbooleanbookingRulesstringoutOfHoursstringescalateOnstring[]closedScreenstringendobjectnextStepsmap of stringratingPromptstringthanksLinestring
SubjectServiceInput
How a website conversation runs. On a write, the fields sent replace theirs.
goalstring1-300 characters
openingstring | nulloutOfHoursOpeningstring | nullhelpsWithstring[] | nullcapture(string (one of 11))[]The details the avatar may ask a visitor for, with consent.
at most 11 items
captureRulesmap of string | nullconsentstring1-400 characters
privacyNoticeUrlstring (uri) | nullneverCollectstring[] | nullhandoffstring1-400 characters
handoffRulesobject | nullofferAfterUnansweredinteger | nullalwaysHandoffTopicsstring[] | nullurgentTopicsstring[] | nullemergencyTopicsstring[] | nullstaffSummarystring | null
bookingboolean | nullbookingRulesstring | nulloutOfHoursstring | nullescalateOnstring[] | nullclosedScreenstring | nullendobject | nullnextStepsmap of string | nullratingPromptstring | nullthanksLinestring | null
SubjectTopic
A curriculum topic.
idstringrequiredtitlestringdescriptionstringgradeany[][lowest, highest]grade, 1 to 12.skillsstring[]requiredThe skills this topic trains (the rubric and the start screen refer to them). Left out on a write: kept as they are.
prerequisitesstring[]sourceHintstringWhich of the organisation's documents covers it.
keyPointsstring[]What the avatar teaches first, in plain language.
checkliststring[]region"uk" | "us" | "intl"The country the content is written for:
ukorus, orintlfor a law module's version for everywhere outside the UK; left out = anywhere.
SubjectTopicInput
A curriculum topic.
idstring1-60 characters
titlestring | nulldescriptionstring | nullgradeany[] | nullskillsstring[]The skills this topic trains (the rubric and the start screen refer to them). Left out on a write: kept as they are.
at most 50 items
prerequisitesstring[] | nullsourceHintstring | nullkeyPointsstring[] | nullcheckliststring[] | nullregion"uk" | "us" | "intl" | null
SubjectVersion
A stored version of a subject's content.
versionintegerrequiredlivebooleanrequireddraftbooleanrequiredThe pending draft.
notestring | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
createdByobjectrequiredtype"user" | "api_key" | "system"requiredidstring | nullrequiredusr_…orkey_…; null for the system.
SubjectWidget
A website widget's subject: set through PUT /personas/{id}/widget. Read-only here: a write may only send it back as it is.
emailstringWhere visitors' requests are emailed.
SubjectWidgetInput
A website widget's subject: set through PUT /personas/{id}/widget. Read-only here: a write may only send it back as it is.
emailstring | null
Transcript
The turn-by-turn transcript.
sessionIdstringrequiredSession id (
sess_…).pattern `^sess_.*`
keptbooleanrequiredTrue when the turns are the whole transcript; false when the session's subject keeps nothing (no turns).
aiGeneratedtruerequiredAlways true: the avatar's video, voice and words are AI-generated (EU AI Act Article 50(2)). Keep this marker with the content when you store or pass it on.
TranscriptFinalData
One finished turn of a session the API started, with its words. Needs includeConversation.
sessionIdstring | nullrole"user" | "assistant" | nulltextstring | nulltsnumber | null
TranscriptTurn
One turn as recorded: ts (when it was stored), speaker for a duo, words with timings when speech recognition gave them.
rolestringrequireduser or assistant (the avatar); a duo's turns carry
speaker.textstringrequiredaiGeneratedbooleanrequiredTrue for the avatar's turns (AI-generated words, EU AI Act Article 50(2)); false for what the person said.
Unit
A class, team or group in the organisation's tree.
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
UnitCreatedData
A unit was created.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullnamestring | nullkindstring | nullparentIdstring | nullleaderUserIdstring | null
UnitDeletedData
A unit was deleted.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullnamestring | nullmovedTostring | nullsubTeamsinteger | nullportalsinteger | nullsubjectsinteger | nullassignmentsinteger | nullmembershipsRemovedinteger | null
UnitRenamedData
A unit was renamed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullfromstring | nulltostring | nullduplicateNameboolean | null
UnitSwitchData
A unit switched off or on, with everything below it.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullnamestring | nullunitsBelowinteger | nullstillOffBecauseOfAParentboolean | null
UnitUpdatedData
A unit was moved or changed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullparentIdstring | nullsortOrdernumber | nullgradeBandstring | null
UnitWritten
A unit as created or changed.
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
duplicateNameobject | nullrequiredAnother unit at the same level already has this name (allowed, flagged).
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
namestringrequired
UpdateMembershipInput
role"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"OWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullgradeBandstring | nullageBand"18+" | null"18+"marks an adult learner (a place waiting for consent is switched on); null clears it.status"active" | "disabled"Switch this place off or on. A place waiting for consent turns active only through guardian consent.
UpdateSubjectInput
namestring1-80 characters
unitIdstring | nullThe unit it belongs to; null: the organisation level.
visitorLanguage"follow" | "listed" | "english" | nullA website subject only: follow the visitor's language, keep to its
languages(listed), or English only; null goes back to the organisation's own setting.
UpdateUnitInput
namestring1-80 characters
parentIdstring | nullMove it under another unit; null moves it to the top level.
sortOrderintegergradeBandstring | nullnull clears it.
disabledbooleanSwitch it (and everything below it) off or on. Nothing is deleted.
UpgradeRequired
A plan refusal for keys on the 2026-07-08 contract. From 2026-10-01 it is an Error with code upgrade_required and details: { feature, plan, limit, reason }.
error"upgrade_required"requiredfeaturestringrequiredplanstring | nullrequiredmessagestringrequiredlimitnumberreason"plan_required"The feature's switch is off because the plan doesn't include it (
plannames the plan that does).
Usage
Session time for the period, with the plan and minutes from the account's minutes. There is no overage: when minutes run out, new sessions can't start until more are added.
planobjectrequiredkeystringrequiredfree, starter, plus, pro, business or enterprise.
namestringrequiredintervalstringrequiredmonth or year.
unlimitedbooleanrequiredAn unlimited account has no minute counts (the minute fields are null).
includedMinutesinteger | nullrequiredThe plan's minutes this cycle.
minutesUsednumberrequiredSession time in the period, in minutes.
remainingMinutesinteger | nullrequiredEvery minute the account can still spend: plan, minute packs and bonus.
cycleobjectrequiredstartstring (date-time)requiredISO 8601 UTC timestamp.
endstring (date-time)requiredISO 8601 UTC timestamp.
minutesobject | nullrequiredplanIncludedintegerrequiredplanUsedintegerrequiredplanLeftintegerrequiredpurchasedLeftintegerrequiredMinute packs; they never expire.
bonusLeftintegerrequiredtotalLeftintegerrequired
periodobjectrequiredstartstring (date-time)requiredISO 8601 UTC timestamp.
endstring (date-time)requiredISO 8601 UTC timestamp.
sessionCountintegerrequiredbySourceobjectrequiredportalnumberrequiredapinumberrequired
byDayobject[]requireddatestringrequiredYYYY-MM-DD (UTC).
minutesnumberrequiredsessionsintegerrequired
byPersonaobject[]requiredpersonaIdstringrequiredPersona id (
pa_…).pattern `^pa_.*`
personaNamestringrequiredminutesnumberrequiredsessionsintegerrequired
UsageThresholdData
The organisation's minutes crossed a warning level.
thresholdstring | nullminutesLeftnumber | nullplanMinutesnumber | nullplanUsedPercentnumber | nullrenewsOnstring | null
VisitorDetailRemovedData
A website visitor asked for details to be forgotten: which fields to delete from your systems.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullfieldsstring[] | null
VisitorsDoor
The visitors' door: people come in without signing in.
urlstring | nullrequiredThe visitor page to hand out (or the custom domain that leads there); null when no subject opens to visitors.
openbooleanrequiredVisitors can come in now.
readinessDoorReadiness | nullrequiredNull when no subject opens to visitors (a website assistant or a screening role).
allowedOriginsstring[]requiredThe only websites that may show the visitor page in a frame and start conversations from it; [] = any.
scriptstring | nullrequiredThe snippet that puts the visitor page on your website.
VisitorsDoorUpdate
allowedOriginsstring[]Website addresses (
https://www.example.com); [] allows any website again.at most 20 items
openbooleantrueopens the portal to visitors (needsportals:publish; runs the go-live check on a published portal, and lets outside people in);falsecloses it.
VisitorSessionEndedData
A website visitor's conversation ended (never a candidate's interview).
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullworkspaceNamestring | nullminutesnumber | nullsecondsnumber | nullstatusstring | nullscreeningboolean | nulltypedboolean | nullrestartedboolean | nullwithdrawnboolean | nullunverifiedboolean | nullreapedboolean | nullhandoffboolean | nullbookingboolean | nullresolvedboolean | null
Voice
A voice. One voice speaks every language in languages in its own timbre: choose a voice for how it sounds.
idstringrequiredVoice id (
vo_…).pattern `^vo_.*`
namestringrequiredlanguagestringrequiredIts default language (a catalogue code).
languagesstring[]requiredThe languages this voice is promised in, as catalogue codes (GET /languages): every catalogue language for a studio voice, the ten marked for duos for a cloned voice. Set the language on the persona or the session, not by choosing another voice.
engine"premier" | "global"requiredThe voice engine a persona speaking with this voice runs on: global for the studio voices, premier for cloned voices.
genderstring | nullrequiredfemale or male for a studio voice; null when not known.
kind"builtin" | "custom"requiredbuiltin: a studio voice; custom: your organisation's clone.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
VoiceCloneCompletedData
A cloned voice is ready to use.
voiceIdstring | nullnamestring | null
VoiceCloneInput
Clone a voice from a short sample, with the consent of the person it belongs to.
namestringDefault "My voice".
audioBase64stringrequired10 to 60 seconds of clean speech: base64, or a data:audio/… URI (25 MB at most).
formatstringThe sample's format when it isn't in the data URI.
Consent to clone a real person's voice or to make an avatar from their picture. Recorded with who confirmed it (the API key), when, a hashed IP address, the exact wording and its version. The organisation's owners can export records and withdraw them; a withdrawn voice or face stops starting new sessions.
VoiceEngine
A voice engine. The voice decides which one a persona runs on: see Voice.engine.
namestringrequiredlanguageCountintegerrequiredHow many catalogue languages this engine's voices are promised in.
voiceCloningbooleanrequireddefaultbooleanrequiredThe studio voices run on it.
notestringrequired
Webhook
A signed webhook. Deliveries: X-Zentiq-Signature: sha256=HMAC(secret, "<X-Zentiq-Timestamp>.<body>"), retried for about two days; never redirected.
idstringrequiredWebhook id (
wh_…).pattern `^wh_.*`
urlstringrequiredWhere deliveries go: a public https address, checked again before every attempt.
descriptionstring | nullrequiredeventsstring[]requiredThe event types it receives; ["*"] = every type except transcript.final, which must be named.
includeConversationbooleanrequiredSend conversation words to this webhook where Zentiq's privacy rules allow them: transcript.final (sessions your app started through the API, and only when named in
events), session.ended's and report.produced's summaries, report feedback lines and quotes, a visitor's own words (need, budget, timeline, a lead's answers, a hand-off's summary and reason), a rating's comment, knowledge.gap's questions and case_link.opened's case summary. Never from a child's, a candidate's (any hiring session), a practice, a held or a safety-flagged session. Off by default. Turning it on needs a key holdingtranscripts:read; every change is recorded in the organisation's activity log. Refused, and off, while the organisation has zero data retention on.activebooleanrequiredFalse while switched off, and after three days of failed deliveries (then
pausedAtsays when).pausedAtstring (date-time) | nullrequiredWhen it was paused after failing every delivery for three days; PATCH { active: true } resumes it.
apiVersion"2026-07-08" | "2026-10-01"requiredThe contract its deliveries are written in (the creating key's; PATCH to move it).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
WebhookDeleted
deletedtruerequiredidstringrequiredWebhook id (
wh_…).pattern `^wh_.*`
WebhookDelivery
One event's delivery to one webhook, with its last attempt.
idstringrequiredwhd_…(sent as X-Zentiq-Delivery-Id). Keys on the 2026-07-08 contract receive the id without its prefix.webhookIdstringrequiredWebhook id (
wh_…).pattern `^wh_.*`
eventIdstring | nullrequiredThe event delivered (
evt_…, the envelope'sid); null for deliveries logged before the outbox.eventstringrequiredThe event's type.
state"pending" | "retrying" | "delivered" | "failed"requiredpending (the first attempt is under way), retrying (the next attempt is at
nextAttemptAt), delivered, failed (no attempt left, or closed: seeerrorCode).attemptsintegerrequiredstatusinteger | nullrequiredThe HTTP status of the last attempt; null when none was reached.
okbooleanrequiredresponseMsinteger | nullrequirederrorCodestring | nullrequiredWhy the last attempt failed or the delivery closed: http_status, redirect, timeout, network, address_refused, internal_error, webhook_inactive, webhook_paused, unsubscribed, withdrawn, event_gone.
nextAttemptAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredISO 8601 UTC timestamp.
WebhookEnvelope
Every webhook's body (2026-10-01). Verify X-Zentiq-Signature before trusting it; de-duplicate by id.
idstringrequiredThe event's id (
evt_…), stable across retries.typestringrequiredapiVersion"2026-07-08" | "2026-10-01"requiredorganizationIdstringrequiredorg_…createdAtstring (date-time)requireddataobjectrequiredaiGeneratedtruePresent, and true, when
datacarries words an avatar wrote: a summary, a report or an avatar's turn (EU AI Act Article 50(2)). Every contract.
WebhookEvent
The JSON body of every webhook delivery (headers X-Zentiq-Signature, X-Zentiq-Timestamp, X-Zentiq-Event). Every event's data is an allowlist: ids, statuses, timestamps, counts and the organisation's own short names. Conversation words (transcript.final's text, summaries, report feedback and quotes, a visitor's questions and answers, a rating's comment, knowledge.gap's questions) go only to a webhook with includeConversation on, and never from a child's, a candidate's, a practice, a held or a safety-flagged session; without it they are null (transcript.final is not sent). lead.captured, booking.requested and handoff.requested carry the visitor's contact details (captured: name, email, phone, company, role, location, preferred time, reference), their consent and a booking's service and when, for your own CRM; what they described in their own words (captured.need, budget, timeline, a lead's answers, a hand-off's reason) goes only with includeConversation. Never sent: safety flags (safety.flagged is not delivered, and reports carry no flags or flag counts), admin notes, a candidate's scores or bands, results that are held for review, kept from the person or voided (score, percent, passed and marks are null), a practice attempt's score, the minor flag, a session's plan, people's names and notes.
idstringrequiredtypestringrequiredcreatedAtstring (date-time)requireddataobjectrequired
WebhookInput
A new webhook.
urlstringrequiredA public https address. Private and local addresses are refused; redirects are never followed.
at most 2,048 characters
eventsstring[]Event types, or ["*"] (the default). transcript.final needs
includeConversation: true.at most 100 items
descriptionstringat most 200 characters
includeConversationbooleanSend conversation words to this webhook where Zentiq's privacy rules allow them: transcript.final (sessions your app started through the API, and only when named in
events), session.ended's and report.produced's summaries, report feedback lines and quotes, a visitor's own words (need, budget, timeline, a lead's answers, a hand-off's summary and reason), a rating's comment, knowledge.gap's questions and case_link.opened's case summary. Never from a child's, a candidate's (any hiring session), a practice, a held or a safety-flagged session. Off by default. Turning it on needs a key holdingtranscripts:read; every change is recorded in the organisation's activity log. Refused, and off, while the organisation has zero data retention on.
WebhookList
Type: Webhook[]
WebhookPatch
What to change on a webhook; anything left out stays.
urlstringat most 2,048 characters
eventsstring[]at most 100 items
descriptionstring | nullactivebooleantrue resumes a paused webhook (its failing run starts again); false switches it off.
apiVersion"2026-07-08" | "2026-10-01"Move its deliveries to another contract.
includeConversationbooleanSend conversation words to this webhook where Zentiq's privacy rules allow them: transcript.final (sessions your app started through the API, and only when named in
events), session.ended's and report.produced's summaries, report feedback lines and quotes, a visitor's own words (need, budget, timeline, a lead's answers, a hand-off's summary and reason), a rating's comment, knowledge.gap's questions and case_link.opened's case summary. Never from a child's, a candidate's (any hiring session), a practice, a held or a safety-flagged session. Off by default. Turning it on needs a key holdingtranscripts:read; every change is recorded in the organisation's activity log. Refused, and off, while the organisation has zero data retention on.
WebhookTestData
A test ping, sent only to the webhook it was asked for.
eventIdstring | nullwebhookIdstring | null
WebhookWithSecret
A webhook just made, with its signing secret (shown once).
idstringrequiredWebhook id (
wh_…).pattern `^wh_.*`
urlstringrequiredWhere deliveries go: a public https address, checked again before every attempt.
descriptionstring | nullrequiredeventsstring[]requiredThe event types it receives; ["*"] = every type except transcript.final, which must be named.
includeConversationbooleanrequiredSend conversation words to this webhook where Zentiq's privacy rules allow them: transcript.final (sessions your app started through the API, and only when named in
events), session.ended's and report.produced's summaries, report feedback lines and quotes, a visitor's own words (need, budget, timeline, a lead's answers, a hand-off's summary and reason), a rating's comment, knowledge.gap's questions and case_link.opened's case summary. Never from a child's, a candidate's (any hiring session), a practice, a held or a safety-flagged session. Off by default. Turning it on needs a key holdingtranscripts:read; every change is recorded in the organisation's activity log. Refused, and off, while the organisation has zero data retention on.activebooleanrequiredFalse while switched off, and after three days of failed deliveries (then
pausedAtsays when).pausedAtstring (date-time) | nullrequiredWhen it was paused after failing every delivery for three days; PATCH { active: true } resumes it.
apiVersion"2026-07-08" | "2026-10-01"requiredThe contract its deliveries are written in (the creating key's; PATCH to move it).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
secretstringrequiredThe signing secret: returned once, at creation.
Widget
A persona's website widget.
personaIdstringrequiredPersona id (
pa_…).pattern `^pa_.*`
existsbooleanrequiredThe widget has been set up (the first PUT makes it).
onbooleanrequiredSwitched on.
livebooleanrequiredSwitched on and showing: its public door is open and it has websites to show on.
How the widget shows on your pages.
labelstringrequiredThe button's words as visitors see them.
allowedOriginsstring[]requiredThe websites that may show it (every other website gets nothing).
requestEmailstring | nullrequiredWhere visitors' messages and requests go.
templatestring | nullrequiredWhat its conversations are set up as: support-agent or receptionist.
What it needs before it goes live, in order.
documentsintegerrequiredDocuments it answers from (the persona's knowledge).
answersintegerrequiredApproved answers of its own.
publicIdstring | nullrequiredThe widget's public id (
<organisation>/w-…): all the snippet names.snippetstring | nullrequiredThe code to paste into your pages, as the layout needs it.
configUrlstring | nullrequiredWhere a website reads the widget's public settings (for your own button).
portalIdstring | nullrequiredIts hidden website-assistant portal (never listed by GET /portals).
subjectIdstring | nullrequiredIts subject: edit its answers through /subjects/{id}/content.
outOfDatebooleanrequiredThe persona's first line or languages changed since the widget was saved; any PUT brings them over.
WidgetInput
What to change; the first PUT makes the widget. What isn't sent stays as it is.
purpose"support" | "reception"What its conversations are set up as when it is first made: support (a support agent) or reception (a receptionist).
layout"floating" | "inline"floating (a button in a corner) or inline (inside your page).
initialState"minimized" | "expanded"minimized or expanded ("minimised" is read too).
position"bottom-right" | "top-right" | "bottom-left" | "top-left"A floating widget's corner ("right" and "left" read as the bottom ones).
labelstring | nullThe button's words (null or "" for "Talk to <name>").
at most 40 characters
accentstringThe button's colour, #rrggbb.
start"voice" | "chat"The panel opens ready to talk (voice) or to type (chat).
allowedOriginsstring[]Replaces the websites that may show it, such as https://www.example.com (20 at most).
at most 20 items
requestEmailstring | nullWhere visitors' messages and requests go; null clears it.
onbooleanSwitch it on (needs the portals:publish scope and what
stepslists) or off (its door closes at once).
WidgetLook
How the widget shows on your pages.
layout"floating" | "inline"requiredfloating: a button in a corner of every page; inline: the panel inside an element of your page.
initialState"minimized" | "expanded"requiredminimized: the button only until a visitor clicks; expanded: the panel opens with the page (nothing listens until a visitor presses Talk).
position"bottom-right" | "top-right" | "bottom-left" | "top-left"requiredThe corner a floating widget sits in.
labelstringrequiredThe button's own words; "" for "Talk to <name>".
accentstringrequiredThe button's colour, #rrggbb.
start"voice" | "chat"requiredThe panel opens ready to talk, or ready to type.
WidgetSaved
The widget as saved.
personaIdstringrequiredPersona id (
pa_…).pattern `^pa_.*`
existsbooleanrequiredThe widget has been set up (the first PUT makes it).
onbooleanrequiredSwitched on.
livebooleanrequiredSwitched on and showing: its public door is open and it has websites to show on.
How the widget shows on your pages.
labelstringrequiredThe button's words as visitors see them.
allowedOriginsstring[]requiredThe websites that may show it (every other website gets nothing).
requestEmailstring | nullrequiredWhere visitors' messages and requests go.
templatestring | nullrequiredWhat its conversations are set up as: support-agent or receptionist.
What it needs before it goes live, in order.
documentsintegerrequiredDocuments it answers from (the persona's knowledge).
answersintegerrequiredApproved answers of its own.
publicIdstring | nullrequiredThe widget's public id (
<organisation>/w-…): all the snippet names.snippetstring | nullrequiredThe code to paste into your pages, as the layout needs it.
configUrlstring | nullrequiredWhere a website reads the widget's public settings (for your own button).
portalIdstring | nullrequiredIts hidden website-assistant portal (never listed by GET /portals).
subjectIdstring | nullrequiredIts subject: edit its answers through /subjects/{id}/content.
outOfDatebooleanrequiredThe persona's first line or languages changed since the widget was saved; any PUT brings them over.
saidstringrequiredWhat happened, in one sentence.
WidgetStep
One thing the widget needs before it can go live.
key"websites" | "email" | "knowledge" | "organisation" | "setup"requireddonebooleanrequiredtitlestringrequiredfixstringrequiredWhat to do, in one sentence; "" when done.
WidgetUpdatedData
A persona's website widget was switched on or off, or changed.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullpersonaIdstring | nullonboolean | nullliveboolean | null
WorkspaceCreatedData
A subject was created.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullnamestring | nullblueprintKeystring | null
WorkspacePublishedData
A subject's version went live.
eventIdstring | nullorganizationIdstring | nullworkspaceIdstring | nullunitIdstring | nulluserIdstring | nullsessionIdstring | nullblueprintVersioninteger | nullversioninteger | null