Skip to the content
Menu: Hiring

Hiring

Candidate screening: roles, invites, candidates and decisions.

GET/v1/invites/{id}

Get an invite

getInvitecandidates:readread: 600/min per keySince 2026-10-01

One invite, its status now and its link while it can be used.

Path parameters

  • idstringrequired

    Invite id (inv_…); the id without its prefix is accepted too.

Returns

200 The invite. data is Invite.

Fields of data
  • idstringrequired

    Invite id (inv_…).

    pattern `^inv_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired

    The portal whose door the link opens.

  • externalIdstring | nullrequired

    Your ATS's own id for the applicant, sent back on every candidate event.

  • metadatamap of stringrequired
  • namestring | nullrequired

    Null once the candidate's data was erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • status"invited" | "opened" | "started" | "completed" | "cancelled" | "expired"required

    invited → 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" | nullrequired
  • timing"open" | "deadline" | "scheduled"required
  • startAtstring (date-time) | nullrequired

    scheduled: the interview time.

  • opensAtstring (date-time) | nullrequired

    scheduled: when the link opens.

  • lateAtstring (date-time) | nullrequired

    scheduled: not started by then, the invite is cancelled as late.

  • deadlineAtstring (date-time) | nullrequired

    deadline: the interview must be started by then.

  • sentAtstring (date-time) | nullrequired

    When Zentiq last emailed it; null when the link was only copied.

  • openedAtstring (date-time) | nullrequired
  • startedAtstring (date-time) | nullrequired
  • completedAtstring (date-time) | nullrequired
  • cancelledAtstring (date-time) | nullrequired
  • candidateIdstring | nullrequired

    The candidate (cand_…) once their interview reached the hiring team.

  • linkstring | nullrequired

    The candidate's personal link while it can be used: a secret, give it only to them.

  • createdAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/invites/inv_123" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "id": "inv_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "portalId": "portal_cmfq2b7x10000abcd1234",
    "externalId": "…",
    "metadata": "…",
    "name": "Zoe"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
DELETE/v1/invites/{id}

Cancel an invite

cancelInvitecandidates:writewrite: 120/min per keySince 2026-10-01

Withdraws a waiting invite (invited or opened): its link stops working and nothing is sent to the candidate. Records candidate.invite_cancelled (reason withdrawn_by_team).

Path parameters

  • idstringrequired

    Invite id (inv_…); the id without its prefix is accepted too.

Returns

200 The invite, cancelled. data is Invite.

Fields of data
  • idstringrequired

    Invite id (inv_…).

    pattern `^inv_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired

    The portal whose door the link opens.

  • externalIdstring | nullrequired

    Your ATS's own id for the applicant, sent back on every candidate event.

  • metadatamap of stringrequired
  • namestring | nullrequired

    Null once the candidate's data was erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • status"invited" | "opened" | "started" | "completed" | "cancelled" | "expired"required

    invited → 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" | nullrequired
  • timing"open" | "deadline" | "scheduled"required
  • startAtstring (date-time) | nullrequired

    scheduled: the interview time.

  • opensAtstring (date-time) | nullrequired

    scheduled: when the link opens.

  • lateAtstring (date-time) | nullrequired

    scheduled: not started by then, the invite is cancelled as late.

  • deadlineAtstring (date-time) | nullrequired

    deadline: the interview must be started by then.

  • sentAtstring (date-time) | nullrequired

    When Zentiq last emailed it; null when the link was only copied.

  • openedAtstring (date-time) | nullrequired
  • startedAtstring (date-time) | nullrequired
  • completedAtstring (date-time) | nullrequired
  • cancelledAtstring (date-time) | nullrequired
  • candidateIdstring | nullrequired

    The candidate (cand_…) once their interview reached the hiring team.

  • linkstring | nullrequired

    The candidate's personal link while it can be used: a secret, give it only to them.

  • createdAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictrate_limitedserver_error

Events

candidate.invite_cancelled

Request

curl -X DELETE "https://app.zentiqai.com/v1/invites/inv_123" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "id": "inv_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "portalId": "portal_cmfq2b7x10000abcd1234",
    "externalId": "…",
    "metadata": "…",
    "name": "Zoe"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/roles/{id}/invites

List a role's invites

listInvitescandidates:readread: 600/min per keySince 2026-10-01

The role's invites, newest first, each with its status now and its link while it can be used.

Path parameters

  • idstringrequired

    Subject id (sub_…); the id without its prefix is accepted too.

Query parameters

  • limitinteger

    Page size, 1-200 (default 50).

  • cursorstring

    The nextCursor of the previous page.

  • statusstring

    invited, opened, started, completed, cancelled or expired (comma-separated).

  • externalIdstring

    Only the invites your ATS gave this id.

Returns

200 A page of invites. A page: data is a list of Invite, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    Invite id (inv_…).

    pattern `^inv_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired

    The portal whose door the link opens.

  • externalIdstring | nullrequired

    Your ATS's own id for the applicant, sent back on every candidate event.

  • metadatamap of stringrequired
  • namestring | nullrequired

    Null once the candidate's data was erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • status"invited" | "opened" | "started" | "completed" | "cancelled" | "expired"required

    invited → 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" | nullrequired
  • timing"open" | "deadline" | "scheduled"required
  • startAtstring (date-time) | nullrequired

    scheduled: the interview time.

  • opensAtstring (date-time) | nullrequired

    scheduled: when the link opens.

  • lateAtstring (date-time) | nullrequired

    scheduled: not started by then, the invite is cancelled as late.

  • deadlineAtstring (date-time) | nullrequired

    deadline: the interview must be started by then.

  • sentAtstring (date-time) | nullrequired

    When Zentiq last emailed it; null when the link was only copied.

  • openedAtstring (date-time) | nullrequired
  • startedAtstring (date-time) | nullrequired
  • completedAtstring (date-time) | nullrequired
  • cancelledAtstring (date-time) | nullrequired
  • candidateIdstring | nullrequired

    The candidate (cand_…) once their interview reached the hiring team.

  • linkstring | nullrequired

    The candidate's personal link while it can be used: a secret, give it only to them.

  • createdAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/roles/sub_123/invites?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "inv_cmfq2b7x10000abcd1234",
      "roleId": "sub_cmfq2b7x10000abcd1234",
      "portalId": "portal_cmfq2b7x10000abcd1234",
      "externalId": "…",
      "metadata": "…",
      "name": "Zoe"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}
POST/v1/roles/{id}/invites

Invite candidates to a role

createInvitescandidates:writeheavy: 20/min per keyIdempotency-KeySince 2026-10-01

Personal links to the role's first-round interview, from your ATS with its own ids (externalId, metadata). The role must be published and pass the go-live check. At most 200 candidates (100 when Zentiq emails them); an address with an open invite for the role, one that completed its interview within the role's retention, or one listed twice is skipped with the reason. The links open the role's portal door. Records candidate.invited per invite.

Path parameters

  • idstringrequired

    Subject id (sub_…); the id without its prefix is accepted too.

Body

  • candidatesobject[]required

    At 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

    • namestringrequired

      2-120 characters

    • emailstringrequired

      at most 254 characters

    • phonestring | null
    • externalIdstring

      pattern `^[^\s@]{1,200}$`

    • metadatamap of string

      Your own data about the applicant, returned as it was: at most 20 string keys. Never sent by webhook.

  • timingInviteTimingrequired

    When candidates may take the interview: any time, by a deadline, or at a set time.

  • timeZonestring

    IANA time zone the emails' times read in (default Europe/London).

    at most 64 characters

  • sendboolean

    true: Zentiq emails each candidate their link (with a calendar file for a set time, and reminders). false (default): copy the links yourself.

  • portalIdstring

    The portal whose door the links open; default: the role's own (where it is published and open to visitors).

Returns

201 The invites made, each with its link, and those skipped. data is CreatedInvites.

Fields of data
  • createdInvite[]required
  • skippedobject[]required
    • emailstringrequired
    • externalIdstring | nullrequired
    • reason"open_invite" | "already_interviewed" | "listed_twice"required
    • messagestringrequired
  • emailobjectrequired
    • requestedbooleanrequired
    • sentintegerrequired
    • failedintegerrequired
    • queuedintegerrequired

      Still to go: sent straight after this answer.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error

Events

candidate.invited

Request

curl -X POST "https://app.zentiqai.com/v1/roles/sub_123/invites" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "candidates": [
    {
      "name": "Zoe",
      "email": "sam@example.com"
    }
  ],
  "timing": {
    "mode": "open"
  }
}'
Example answer
Response
{
  "data": {
    "created": [
      {
        "id": "inv_cmfq2b7x10000abcd1234",
        "roleId": "sub_cmfq2b7x10000abcd1234",
        "portalId": "portal_cmfq2b7x10000abcd1234",
        "externalId": "…",
        "metadata": "…",
        "name": "Zoe"
      }
    ],
    "skipped": [
      {
        "email": "sam@example.com",
        "externalId": "…",
        "reason": "open_invite",
        "message": "…"
      }
    ],
    "email": {
      "requested": true,
      "sent": 1,
      "failed": 1,
      "queued": 1
    }
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
POST/v1/candidates/{id}/decision

Record a person's decision

decideCandidatecandidates:writewrite: 120/min per keyIdempotency-KeySince 2026-10-01

The hiring team's decision on one candidate, made by the member named in decidedBy and carried by the key. 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. The member's own hiring access applies; the reviews the role asks for come first (a decline waits for at least one); a decline needs the member to have opened the candidate's interview or added their own review in Zentiq (409, details.reason: needs_open); an erased candidate can't be decided; the same decision and reason again changes nothing. There is no bulk decline. Records candidate.decided (the decision and reason code only).

Path parameters

  • idstringrequired

    Candidate id (cand_…); the id without its prefix is accepted too.

Body

  • decision"invite" | "hold" | "decline"required
  • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other"required

    must_haves, strong_answers, missing_must_have, stronger_candidate, more_evidence, withdrew or other (other needs a note).

  • notestring

    Kept for the hiring team; never given out through the API or webhooks.

    at most 600 characters

  • decidedBystringrequired

    The 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.

  • sendOutcomeEmailboolean

    Email the candidate the outcome, with their link to ask for a review.

Returns

200 The candidate with the decision recorded. data is CandidateWithHistory.

Fields of data
  • idstringrequired

    cand_…: the candidate's interview.

    pattern `^cand_.*`

  • sessionIdstringrequired

    Session id (sess_…).

    pattern `^sess_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired
  • inviteIdstring | nullrequired
  • externalIdstring | nullrequired

    Your ATS's id from the invite.

  • namestring | nullrequired

    Null once erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • interviewedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • minutesnumber | nullrequired
  • typedbooleanrequired

    They typed instead of speaking.

  • roundinteger | nullrequired
  • withdrawnbooleanrequired

    They chose to end the interview: never scored.

  • erasedbooleanrequired
  • erasedAtstring (date-time) | nullrequired
  • mustHaves"met" | "missed" | "unclear" | "none" | nullrequired

    The 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[]required

    Each requirement's result; never the answer. Empty once erased.

    • idstringrequired
    • metboolean | nullrequired
    • knockoutbooleanrequired
  • scorenumber | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • band"strong" | "possible" | "below" | "unscored" | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • rankinteger | nullrequired

    Place 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 | nullrequired

    The latest decision a person made; null while it awaits one.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

  • reviewsobjectrequired
    • countintegerrequired
    • requiredintegerrequired
    • recommendationsobject | nullrequired

      How many reviewers recommend advance, hold or do not advance. Only where the role shares scores (candidates.share_scores), and never once erased; else null.

      • advanceintegerrequired
      • holdintegerrequired
      • doNotAdvanceintegerrequired
  • holdbooleanrequired

    A legal hold keeps their data past the role's retention.

  • reviewRequestedbooleanrequired

    They asked for a review of the decision and no decision was recorded since.

  • retentionExpiresAtstring (date-time) | nullrequired

    When their data is erased (null while held or once erased).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • decisionsobject[]required

    Every decision recorded, newest first.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error

Events

candidate.decided

Request

curl -X POST "https://app.zentiqai.com/v1/candidates/cand_123/decision" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "decision": "invite",
  "reason": "must_haves",
  "decidedBy": "usr_123"
}'
Example answer
Response
{
  "data": {
    "id": "cand_cmfq2b7x10000abcd1234",
    "sessionId": "sess_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "portalId": "portal_cmfq2b7x10000abcd1234",
    "inviteId": "inv_cmfq2b7x10000abcd1234",
    "externalId": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/candidates/{id}

Get a candidate

getCandidatecandidates:readread: 600/min per keySince 2026-10-01

One candidate with their decision history. Never their answers, a summary, notes, review reasons, integrity flags or recordings here: a hiring system reads the interview itself with GET /candidates/{id}/interview (a key an owner or admin gave interview content, every read logged). Reading it here does not count as opening their 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.

Path parameters

  • idstringrequired

    Candidate id (cand_…); the id without its prefix is accepted too.

Returns

200 The candidate. data is CandidateWithHistory.

Fields of data
  • idstringrequired

    cand_…: the candidate's interview.

    pattern `^cand_.*`

  • sessionIdstringrequired

    Session id (sess_…).

    pattern `^sess_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired
  • inviteIdstring | nullrequired
  • externalIdstring | nullrequired

    Your ATS's id from the invite.

  • namestring | nullrequired

    Null once erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • interviewedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • minutesnumber | nullrequired
  • typedbooleanrequired

    They typed instead of speaking.

  • roundinteger | nullrequired
  • withdrawnbooleanrequired

    They chose to end the interview: never scored.

  • erasedbooleanrequired
  • erasedAtstring (date-time) | nullrequired
  • mustHaves"met" | "missed" | "unclear" | "none" | nullrequired

    The 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[]required

    Each requirement's result; never the answer. Empty once erased.

    • idstringrequired
    • metboolean | nullrequired
    • knockoutbooleanrequired
  • scorenumber | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • band"strong" | "possible" | "below" | "unscored" | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • rankinteger | nullrequired

    Place 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 | nullrequired

    The latest decision a person made; null while it awaits one.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

  • reviewsobjectrequired
    • countintegerrequired
    • requiredintegerrequired
    • recommendationsobject | nullrequired

      How many reviewers recommend advance, hold or do not advance. Only where the role shares scores (candidates.share_scores), and never once erased; else null.

      • advanceintegerrequired
      • holdintegerrequired
      • doNotAdvanceintegerrequired
  • holdbooleanrequired

    A legal hold keeps their data past the role's retention.

  • reviewRequestedbooleanrequired

    They asked for a review of the decision and no decision was recorded since.

  • retentionExpiresAtstring (date-time) | nullrequired

    When their data is erased (null while held or once erased).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • decisionsobject[]required

    Every decision recorded, newest first.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/candidates/cand_123" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "id": "cand_cmfq2b7x10000abcd1234",
    "sessionId": "sess_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "portalId": "portal_cmfq2b7x10000abcd1234",
    "inviteId": "inv_cmfq2b7x10000abcd1234",
    "externalId": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/candidates/{id}/compliance

Get a candidate's US hiring record

getCandidateCompliancecandidates:readread: 600/min per keySince 2026-10-01

The US hiring pack (switch hiring.us_compliance, off by default; on Pro and up): the rules the pack applies to the candidate's role now, the notices the candidate read before the interview (kind, version and a fingerprint of the exact text) with when they agreed, their separate consent for Illinois, how New York City's notice reached them in time, and their requests. consent is null for an interview started before the pack was on. Never a candidate's message, an open-door request's contact details, a legal hold's reason or any demographic answer. Zentiq gives no legal advice.

Path parameters

  • idstringrequired

    Candidate id (cand_…); the id without its prefix is accepted too.

Returns

200 The candidate's record. data is CandidateCompliance.

Fields of data
  • candidateIdstringrequired

    Candidate id (cand_…).

    pattern `^cand_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • laws("illinois" | "nyc" | "colorado")[]required

    The US hiring rules the pack applies to the role now: illinois, nyc, colorado.

  • consentobject | nullrequired

    What 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) | nullrequired

      When the candidate agreed to take part and started.

    • shownAtstring (date-time) | nullrequired

      When the page with the notices was made for them.

    • noticesobject[]required
      • kind"aivia" | "nyc" | "colorado"required
      • versionstringrequired
      • fingerprintstringrequired

        SHA-256 of the notice's exact text as shown.

    • illinoisConsentbooleanrequired

      They gave the separate consent to the AI analysing their interview (Illinois).

  • nycNoticeobject | nullrequired

    New York City: how the notice reached the candidate at least 10 business days before the interview.

    • via"posting" | "invite_email" | "invite_link" | "door_email"required

      posting (the date your job posting gave it), invite_email, invite_link or door_email.

    • noticeAtstring (date-time) | nullrequired
    • postedOnstring (date) | nullrequired
  • requestsCandidateRequest[]required

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/candidates/cand_123/compliance" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "candidateId": "cand_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "laws": [
      "illinois"
    ],
    "consent": {
      "at": "2026-09-25T12:00:00.000Z",
      "shownAt": "2026-09-25T12:00:00.000Z",
      "notices": [
        {
          "kind": "aivia",
          "version": "…",
          "fingerprint": "…"
        }
      ],
      "illinoisConsent": true
    },
    "nycNotice": {
      "via": "posting",
      "noticeAt": "2026-09-25T12:00:00.000Z",
      "postedOn": "2026-09-25"
    },
    "requests": [
      {
        "id": "creq_cmfq2b7x10000abcd1234",
        "kind": "deletion",
        "status": "open",
        "roleId": "sub_cmfq2b7x10000abcd1234",
        "candidateId": "cand_cmfq2b7x10000abcd1234",
        "inviteId": "inv_cmfq2b7x10000abcd1234"
      }
    ]
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/candidates/{id}/interview

Get a candidate's interview

getCandidateInterviewcandidates:readcandidates:interviewsheavy: 20/min per keySince 2026-10-01

The interview for your hiring system: each must-have and interview question with the candidate's answer and what the platform found in it (verdict, marks, a note), the written summary, strengths and concerns, the evidence it quotes, the transcript (the AI interviewer and the candidate, turn by turn), whether they asked for an adjustment (never which one), their request for a review, the reviews as a reviewer who hasn't added one sees them (blind review hides them), and when it happened. A candidate under 18 or anything that is not a candidate's interview is 404; an erased candidate, a deleted interview and one the candidate ended themselves are 410 gone (details.reason: erased, deleted, withdrawn). Numbers (score, band, rank, marks, verdicts, competency scores, reviewers' ratings) are given only where the role shares scores (switch candidates.share_scores, off by default); otherwise they are null and scoresShared is false. Only with a key an owner or admin made in Zentiq with "Interview content (hiring)" ticked (candidates:interviews, which a key never passes on and a connected app or assistant never holds). Every read is logged on the candidate as opened by the API key, and the hiring team sees it in the candidate's history. It never counts as a person having opened the interview: a decline still needs one. Never: reviewers' or deciders' notes, the details of integrity moments or of the report's flags (their counts only), the recording (whether there is one only). A candidate under 18, a practice or mock interview and a builder's preview are never served. The practice question is never in the transcript. Webhooks carry no words: on candidate.screened, fetch the interview here. 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.

Path parameters

  • idstringrequired

    Candidate id (cand_…); the id without its prefix is accepted too.

Returns

200 The interview (the read is logged). data is CandidateInterview.

Fields of data
  • idstringrequired

    Candidate id (cand_…).

    pattern `^cand_.*`

  • sessionIdstringrequired

    Session id (sess_…).

    pattern `^sess_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired
  • inviteIdstring | nullrequired
  • externalIdstring | nullrequired

    Your ATS's id from the invite.

  • namestring | nullrequired
  • emailstring | nullrequired
  • phonestring | nullrequired
  • locationstring | nullrequired
  • titlestringrequired

    The job, as the interview named it.

  • roundinteger | nullrequired
  • versioninteger | nullrequired

    The version of the role the interview ran on.

  • level"relaxed" | "standard" | "rigorous" | nullrequired

    How demanding the interview was set to be (the same for every candidate of the role).

  • panelbooleanrequired

    Two AI interviewers took turns.

  • typedbooleanrequired

    They typed instead of speaking.

  • practiceQuestionbooleanrequired

    It opened with an unscored practice question. Its answer is never kept, never in the transcript and never marked.

  • startedAtstring (date-time) | nullrequired
  • endedAtstring (date-time) | nullrequired
  • interviewedAtstring (date-time)required

    When it ended and reached the hiring team.

  • minutesnumber | nullrequired
  • scoresSharedbooleanrequired

    The role shares scores (candidates.share_scores): the numbers below are filled in.

  • scorenumber | nullrequired
  • band"strong" | "possible" | "below" | "unscored" | nullrequired
  • rankinteger | nullrequired

    Place by score among the role's candidates in the same round (1 = highest).

  • mustHaves"met" | "missed" | "unclear" | "none"required
  • requirementsobject[]required

    The must-have questions, with their answers.

    • idstringrequired
    • questionstringrequired
    • answerstring | nullrequired

      Their answer in a few words, as the interview heard it; null when it was never answered.

    • metboolean | nullrequired

      Whether it meets the requirement (decided in code); null when unclear: a person checks it.

    • knockoutbooleanrequired

      A must-have: not meeting it is flagged to the hiring team, never acted on.

    • whystring | nullrequired

      Why the role needs it, as the role says.

  • questionsobject[]required

    The interview questions, in order, with the answers and what the platform found in them.

    • idstring | nullrequired

      The question's id in the role's question set.

    • nintegerrequired

      Its number in the interview ("Question 2 of 5").

      at least 1

    • questionstringrequired
    • answerstring | nullrequired

      What 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"required
    • verdict"right" | "partial" | "not-yet" | nullrequired

      How the answer compares with what the role looks for. Only where the role shares scores.

    • marksnumber | nullrequired

      Marks given. Only where the role shares scores.

    • outOfnumber | nullrequired

      The marks the question carries.

    • notestring | nullrequired

      A short note on the answer, as the report wrote it.

    • redFlagboolean | nullrequired

      The answer showed one of the question's red flags (for a person to check). Only where the role shares scores.

    • hintsintegerrequired

      Hints the interviewer gave on it.

  • summarystring | nullrequired

    The written summary for the hiring team.

  • strengthsstring[]required
  • concernsstring[]required

    Where the evidence was thin.

  • competenciesobject[]required

    The role's competencies with their score (0-100) where there was evidence and the role shares scores.

    • idstringrequired
    • labelstringrequired
    • weightnumberrequired
    • scorenumber | nullrequired
  • evidenceobject[]required

    What the report quotes from the interview, by competency.

    • competencyIdstringrequired
    • quotestring | nullrequired

      Their own words.

    • notestring | nullrequired
  • transcriptobjectrequired
    • keptbooleanrequired

      false when the role keeps no transcripts (then turns is empty).

    • turnsobject[]required
      • speaker"ai" | "candidate"required

        ai: Zentiq's AI interviewer; candidate: the person.

      • namestring | nullrequired

        Which AI interviewer spoke, when two took turns; else null.

      • textstringrequired
      • offsetMsinteger | nullrequired

        Milliseconds from the start of the interview, when known.

  • adjustmentsobjectrequired

    Whether 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 | nullrequired

    They asked for a review of the decision (from the link in an outcome email); open until a person decides again.

    • requestedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • messagestring | nullrequired
    • openbooleanrequired
  • reviewsobjectrequired
    • countintegerrequired
    • requiredintegerrequired

      Reviews a decision waits for (candidates.reviews_required).

    • blindbooleanrequired

      Blind review (candidates.blind_review): each reviewer sees the others' reviews only after adding their own.

    • hiddenBy"blind_review" | "scores_not_shared" | nullrequired

      Why items is null: the role's blind review, or its scores aren't shared.

    • itemsobject[] | nullrequired

      Each reviewer's recommendation and ratings, never their notes. Null while hidden.

  • integrityobjectrequired

    Moments a recorded interview noted for a person to watch (how many, of which kinds), never part of the score. Their details stay in Zentiq.

    • countintegerrequired
    • kindsobject[]required
      • kind"face_out_of_view" | "another_person" | "left_page" | "pasted_text" | "camera_off" | "microphone_off" | "connection_dropped"required
      • countintegerrequired
  • flagsobjectrequired

    Things the report asks a person to look at; their words stay in Zentiq.

    • countintegerrequired
  • recorded"audio" | "audio_video" | nullrequired

    A recording exists (watch it in Zentiq); it is never given out.

  • decisionobject | nullrequired

    The latest decision a person made; null while it awaits one.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundgonerate_limitedserver_errorupstream_error

Request

curl "https://app.zentiqai.com/v1/candidates/cand_123/interview" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "id": "cand_cmfq2b7x10000abcd1234",
    "sessionId": "sess_cmfq2b7x10000abcd1234",
    "roleId": "sub_cmfq2b7x10000abcd1234",
    "portalId": "portal_cmfq2b7x10000abcd1234",
    "inviteId": "inv_cmfq2b7x10000abcd1234",
    "externalId": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/roles/{id}/candidates

List a role's candidates

listCandidatescandidates:readread: 600/min per keySince 2026-10-01

Everyone who took the role's interview. Where the role shares scores (switch candidates.share_scores, off by default), each carries score, band and rank and sort=rank puts the highest score first; otherwise those are null and the list sorts by interview date. Never answers, summaries, notes, review reasons, integrity flags, recordings or an adjustment's kind here: a hiring system reads those with GET /roles/{id}/interviews (a key an owner or admin gave interview content). 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.

Path parameters

  • idstringrequired

    Subject id (sub_…); the id without its prefix is accepted too.

Query parameters

  • limitinteger

    Page size, 1-200 (default 50).

  • cursorstring

    The nextCursor of the previous page.

  • bandstring

    Only where the role shares scores (candidates.share_scores).

  • decisionstring

    awaiting (no decision yet), invite, hold or decline.

  • mustHavesstring

    One or more of met, missed, unclear, none, comma-separated.

  • roundstring

    latest, all (the default) or a round number: scores compare only within a round.

  • interviewedAfterstring

    ISO 8601 date and time.

  • updatedAfterstring

    Only candidates with anything new since (a decision, a review, an erasure): for syncing.

  • sort"rank" | "interviewed" | "name"

    rank (best score first; only where the role shares scores, else by interview date), interviewed or name.

  • order"asc" | "desc"

    rank: asc (1 first, the default); interviewed: desc (newest first, the default); name: asc.

Returns

200 A page of candidates. A page: data is a list of Candidate, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    cand_…: the candidate's interview.

    pattern `^cand_.*`

  • sessionIdstringrequired

    Session id (sess_…).

    pattern `^sess_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired
  • inviteIdstring | nullrequired
  • externalIdstring | nullrequired

    Your ATS's id from the invite.

  • namestring | nullrequired

    Null once erased.

  • emailstring | nullrequired
  • phonestring | nullrequired
  • interviewedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • minutesnumber | nullrequired
  • typedbooleanrequired

    They typed instead of speaking.

  • roundinteger | nullrequired
  • withdrawnbooleanrequired

    They chose to end the interview: never scored.

  • erasedbooleanrequired
  • erasedAtstring (date-time) | nullrequired
  • mustHaves"met" | "missed" | "unclear" | "none" | nullrequired

    The 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[]required

    Each requirement's result; never the answer. Empty once erased.

    • idstringrequired
    • metboolean | nullrequired
    • knockoutbooleanrequired
  • scorenumber | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • band"strong" | "possible" | "below" | "unscored" | nullrequired

    Only where the role shares scores, and never once erased; else null.

  • rankinteger | nullrequired

    Place 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 | nullrequired

    The latest decision a person made; null while it awaits one.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

  • reviewsobjectrequired
    • countintegerrequired
    • requiredintegerrequired
    • recommendationsobject | nullrequired

      How many reviewers recommend advance, hold or do not advance. Only where the role shares scores (candidates.share_scores), and never once erased; else null.

      • advanceintegerrequired
      • holdintegerrequired
      • doNotAdvanceintegerrequired
  • holdbooleanrequired

    A legal hold keeps their data past the role's retention.

  • reviewRequestedbooleanrequired

    They asked for a review of the decision and no decision was recorded since.

  • retentionExpiresAtstring (date-time) | nullrequired

    When their data is erased (null while held or once erased).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/roles/sub_123/candidates?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "cand_cmfq2b7x10000abcd1234",
      "sessionId": "sess_cmfq2b7x10000abcd1234",
      "roleId": "sub_cmfq2b7x10000abcd1234",
      "portalId": "portal_cmfq2b7x10000abcd1234",
      "inviteId": "inv_cmfq2b7x10000abcd1234",
      "externalId": "…"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}
GET/v1/roles/{id}/interviews

List a role's interviews

listRoleInterviewscandidates:readcandidates:interviewsheavy: 20/min per keySince 2026-10-01

The role's interviews, oldest first by when each reached the hiring team, for syncing your hiring system: since gives only those after a moment, and nextCursor goes on from the last page. Each item is the whole interview, as GET /candidates/{id}/interview gives it. Erased and withdrawn candidates are never listed, and an interview that is never served is left out, so a page can hold fewer than limit and still have a nextCursor. Numbers (score, band, rank, marks, verdicts, competency scores, reviewers' ratings) are given only where the role shares scores (switch candidates.share_scores, off by default); otherwise they are null and scoresShared is false. Only with a key an owner or admin made in Zentiq with "Interview content (hiring)" ticked (candidates:interviews, which a key never passes on and a connected app or assistant never holds). Every read is logged on the candidate as opened by the API key, and the hiring team sees it in the candidate's history. It never counts as a person having opened the interview: a decline still needs one. Never: reviewers' or deciders' notes, the details of integrity moments or of the report's flags (their counts only), the recording (whether there is one only). A candidate under 18, a practice or mock interview and a builder's preview are never served. The practice question is never in the transcript. Webhooks carry no words: on candidate.screened, fetch the interview here. 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.

Path parameters

  • idstringrequired

    Subject id (sub_…); the id without its prefix is accepted too.

Query parameters

  • limitinteger

    Page size, 1-50 (default 20): each item is a whole interview.

  • cursorstring

    The nextCursor of the previous page.

  • sincestring

    Only interviews that reached the hiring team after this moment (ISO 8601): for syncing. Oldest first.

Returns

200 A page of interviews (each read is logged). A page: data is a list of CandidateInterview, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    Candidate id (cand_…).

    pattern `^cand_.*`

  • sessionIdstringrequired

    Session id (sess_…).

    pattern `^sess_.*`

  • roleIdstringrequired

    Subject id (sub_…).

  • portalIdstring | nullrequired
  • inviteIdstring | nullrequired
  • externalIdstring | nullrequired

    Your ATS's id from the invite.

  • namestring | nullrequired
  • emailstring | nullrequired
  • phonestring | nullrequired
  • locationstring | nullrequired
  • titlestringrequired

    The job, as the interview named it.

  • roundinteger | nullrequired
  • versioninteger | nullrequired

    The version of the role the interview ran on.

  • level"relaxed" | "standard" | "rigorous" | nullrequired

    How demanding the interview was set to be (the same for every candidate of the role).

  • panelbooleanrequired

    Two AI interviewers took turns.

  • typedbooleanrequired

    They typed instead of speaking.

  • practiceQuestionbooleanrequired

    It opened with an unscored practice question. Its answer is never kept, never in the transcript and never marked.

  • startedAtstring (date-time) | nullrequired
  • endedAtstring (date-time) | nullrequired
  • interviewedAtstring (date-time)required

    When it ended and reached the hiring team.

  • minutesnumber | nullrequired
  • scoresSharedbooleanrequired

    The role shares scores (candidates.share_scores): the numbers below are filled in.

  • scorenumber | nullrequired
  • band"strong" | "possible" | "below" | "unscored" | nullrequired
  • rankinteger | nullrequired

    Place by score among the role's candidates in the same round (1 = highest).

  • mustHaves"met" | "missed" | "unclear" | "none"required
  • requirementsobject[]required

    The must-have questions, with their answers.

    • idstringrequired
    • questionstringrequired
    • answerstring | nullrequired

      Their answer in a few words, as the interview heard it; null when it was never answered.

    • metboolean | nullrequired

      Whether it meets the requirement (decided in code); null when unclear: a person checks it.

    • knockoutbooleanrequired

      A must-have: not meeting it is flagged to the hiring team, never acted on.

    • whystring | nullrequired

      Why the role needs it, as the role says.

  • questionsobject[]required

    The interview questions, in order, with the answers and what the platform found in them.

    • idstring | nullrequired

      The question's id in the role's question set.

    • nintegerrequired

      Its number in the interview ("Question 2 of 5").

      at least 1

    • questionstringrequired
    • answerstring | nullrequired

      What 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"required
    • verdict"right" | "partial" | "not-yet" | nullrequired

      How the answer compares with what the role looks for. Only where the role shares scores.

    • marksnumber | nullrequired

      Marks given. Only where the role shares scores.

    • outOfnumber | nullrequired

      The marks the question carries.

    • notestring | nullrequired

      A short note on the answer, as the report wrote it.

    • redFlagboolean | nullrequired

      The answer showed one of the question's red flags (for a person to check). Only where the role shares scores.

    • hintsintegerrequired

      Hints the interviewer gave on it.

  • summarystring | nullrequired

    The written summary for the hiring team.

  • strengthsstring[]required
  • concernsstring[]required

    Where the evidence was thin.

  • competenciesobject[]required

    The role's competencies with their score (0-100) where there was evidence and the role shares scores.

    • idstringrequired
    • labelstringrequired
    • weightnumberrequired
    • scorenumber | nullrequired
  • evidenceobject[]required

    What the report quotes from the interview, by competency.

    • competencyIdstringrequired
    • quotestring | nullrequired

      Their own words.

    • notestring | nullrequired
  • transcriptobjectrequired
    • keptbooleanrequired

      false when the role keeps no transcripts (then turns is empty).

    • turnsobject[]required
      • speaker"ai" | "candidate"required

        ai: Zentiq's AI interviewer; candidate: the person.

      • namestring | nullrequired

        Which AI interviewer spoke, when two took turns; else null.

      • textstringrequired
      • offsetMsinteger | nullrequired

        Milliseconds from the start of the interview, when known.

  • adjustmentsobjectrequired

    Whether 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 | nullrequired

    They asked for a review of the decision (from the link in an outcome email); open until a person decides again.

    • requestedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • messagestring | nullrequired
    • openbooleanrequired
  • reviewsobjectrequired
    • countintegerrequired
    • requiredintegerrequired

      Reviews a decision waits for (candidates.reviews_required).

    • blindbooleanrequired

      Blind review (candidates.blind_review): each reviewer sees the others' reviews only after adding their own.

    • hiddenBy"blind_review" | "scores_not_shared" | nullrequired

      Why items is null: the role's blind review, or its scores aren't shared.

    • itemsobject[] | nullrequired

      Each reviewer's recommendation and ratings, never their notes. Null while hidden.

  • integrityobjectrequired

    Moments a recorded interview noted for a person to watch (how many, of which kinds), never part of the score. Their details stay in Zentiq.

    • countintegerrequired
    • kindsobject[]required
      • kind"face_out_of_view" | "another_person" | "left_page" | "pasted_text" | "camera_off" | "microphone_off" | "connection_dropped"required
      • countintegerrequired
  • flagsobjectrequired

    Things the report asks a person to look at; their words stay in Zentiq.

    • countintegerrequired
  • recorded"audio" | "audio_video" | nullrequired

    A recording exists (watch it in Zentiq); it is never given out.

  • decisionobject | nullrequired

    The latest decision a person made; null while it awaits one.

    • value"invite" | "hold" | "decline"required

      decline is shown to people as "not progressing".

    • reason"must_haves" | "strong_answers" | "missing_must_have" | "stronger_candidate" | "more_evidence" | "withdrew" | "other" | nullrequired

      The reason code from the fixed list (a note is never given out).

    • decidedAtstring (date-time)required

      ISO 8601 UTC timestamp.

    • decidedByobject | nullrequired

      The member who decided (never an API key).

      • idstringrequired

        Person id (usr_…).

        pattern `^usr_.*`

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_errorupstream_error

Request

curl "https://app.zentiqai.com/v1/roles/sub_123/interviews?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "cand_cmfq2b7x10000abcd1234",
      "sessionId": "sess_cmfq2b7x10000abcd1234",
      "roleId": "sub_cmfq2b7x10000abcd1234",
      "portalId": "portal_cmfq2b7x10000abcd1234",
      "inviteId": "inv_cmfq2b7x10000abcd1234",
      "externalId": "…"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}
GET/v1/roles/{id}/requests

List a role's candidate requests

listRoleRequestscandidates:readread: 600/min per keySince 2026-10-01

The US hiring pack (switch hiring.us_compliance, off by default; on Pro and up): candidates' requests for a role under Illinois', New York City's or Colorado's rules, newest first, each with its due date and outcome: deletion (their interview, any recording and every copy; due in 30 days, carried out automatically on day 30 where the role says so, paused while a legal hold is on), alternative (another way to be assessed, or an accommodation; 14 days), review and correction (30 days). The hiring team answers them in Zentiq. Never a candidate's message, an open-door request's contact details, a legal hold's reason or any demographic answer. Zentiq gives no legal advice.

Path parameters

  • idstringrequired

    Subject id (sub_…); the id without its prefix is accepted too.

Query parameters

  • limitinteger

    Page size, 1-200 (default 50).

  • cursorstring

    The nextCursor of the previous page.

  • statusstring

    open, paused (a legal hold keeps the interview) or done (comma-separated).

  • kindstring

    deletion, alternative, review or correction (comma-separated).

Returns

200 A page of requests. A page: data is a list of CandidateRequest, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    Candidate request id (creq_…).

    pattern `^creq_.*`

  • kind"deletion" | "alternative" | "review" | "correction"required

    deletion (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"required

    open; paused while a legal hold keeps the interview (the candidate was told); done once answered, or (a deletion) once the interview was erased.

  • roleIdstringrequired

    Subject id (sub_…).

  • candidateIdstring | nullrequired

    The candidate whose interview it is about; null before an interview (an invitation) or from the door.

  • inviteIdstring | nullrequired
  • source"link" | "interview" | "door" | "outcome_email"required

    link: the candidate's own page; door: the interview's page; outcome_email: the review link in an outcome email.

  • requestedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • dueAtstring (date-time)required

    When 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) | nullrequired

    A deletion the role carries out automatically: when (day 30), unless a person acts first or a legal hold is on.

  • overduebooleanrequired
  • outcomestring (one of 10) | nullrequired

    What 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

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/roles/sub_123/requests?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "creq_cmfq2b7x10000abcd1234",
      "kind": "deletion",
      "status": "open",
      "roleId": "sub_cmfq2b7x10000abcd1234",
      "candidateId": "cand_cmfq2b7x10000abcd1234",
      "inviteId": "inv_cmfq2b7x10000abcd1234"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}
GET/v1/roles

List screening roles

listRolescandidates:readread: 600/min per keySince 2026-10-01

The organisation's screening roles (subjects candidates are interviewed on), newest first, with their doors, review settings and whether they share scores.

Query parameters

  • limitinteger

    Page size, 1-200 (default 50).

  • cursorstring

    The nextCursor of the previous page.

  • portalIdstring

    Only the roles on this portal.

  • statusstring

    draft, published or archived (comma-separated).

Returns

200 A page of roles. A page: data is a list of Role, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    The role is a screening subject (sub_…); edit its content through /subjects/{id}/content.

  • titlestringrequired

    The job being hired for (the screening block's role), or the subject's name while it has none.

  • subjectNamestringrequired
  • locationstring | nullrequired
  • market"us" | "uk" | "eu" | nullrequired

    Where the role hires (its own, or the organisation's country): us, uk or eu. Null while unpublished.

  • status"draft" | "published" | "archived"required
  • portalIdsstring[]required
  • timingobject | nullrequired

    The role's default timing for new invites; null when it sets none.

    • mode"open" | "deadline" | "scheduled"required
    • deadlineDaysinteger | nullrequired
    • earlyMinutesinteger | nullrequired
    • lateMinutesinteger | nullrequired
  • closesOnstring (date) | nullrequired

    Applications close at the end of this day (the role's time zone); no invite may start after it.

  • bandsobject | nullrequired

    The score bands the hiring team sorts by (a sorting aid, never a verdict).

    • strongnumberrequired
    • possiblenumberrequired
  • roundsobject[]required

    Rounds of the interview candidates took: scores compare only within a round.

    • roundintegerrequired

      at least 1

    • versionintegerrequired

      The first published version of the role in this round.

      at least 1

    • changed("set" | "questions" | "level" | "bands" | "mustHaves")[]required

      What changed from the round before: the question set, the questions, the level, the bands or the must-haves.

  • latestRoundinteger | nullrequired
  • reviewsRequiredintegerrequired

    Reviews a decision waits for (switch candidates.reviews_required); a decline waits for at least one.

  • blindReviewbooleanrequired
  • shareScoresbooleanrequired

    Switch candidates.share_scores: whether candidates' score, band and rank are given out through the API. Off by default. Never by webhook.

  • holdbooleanrequired

    A legal hold is on the whole role: nothing about its candidates is erased while it is on.

  • doorobject | nullrequired

    The interview link a job advert carries (a portal's visitor door), open once it is published and open to visitors.

    • portalIdstringrequired

      Portal id (portal_…).

    • urlstringrequired
    • openbooleanrequired
  • createdAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

Errors

invalid_requestunauthorizedforbiddenupgrade_requiredrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/roles?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "sub_cmfq2b7x10000abcd1234",
      "title": "…",
      "subjectName": "…",
      "location": "…",
      "market": "us",
      "status": "draft"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}