KBA caller-verification session errors
Knowledge-based authentication (KBA) challenges a live caller against facts on file for the call’s linked contact. Seven error codes fire across the start → verify → gate flow, and they split into two families: session and lookup errors (a session you named does not exist or can no longer accept answers; the call or contact behind it resolved to nothing) and gate errors (the verification itself refused to start or a guarded action has no verified session). This page lets a supervisor or integrator work either family end to end. The concept behind the flow lives on the KBA caller verification concept page; the happy-path walkthrough is the KBA caller-verification guide. Read this page when either of those surfaces returned an error instead of a session.1. The session state machine
A KBA session on the per-call ledger moves through three states:- pending — the start call issued the challenge; verify accepts answers and every mismatch burns one attempt.
- verified — every submitted factor matched. The session gates
sensitive actions for four hours from
verified_at; after that the status read computes asexpired, never as verified, and gated actions refuse again until a fresh session verifies. - failed — the attempt budget (three mismatches by default) ran out.
Failed is terminal: only a deliberate
restart: trueon start opens a new challenge.
kba_verification in the call
log’s metadata), so one call carries one session at a time, and start is
idempotent while the session is pending — a repeated start re-reads the
same questions and counters rather than minting a new session.
2. The seven codes
Neither error family is retryable without changing the request. Decode the code first.
The guard any sensitive endpoint (payment capture, PII disclosure, account
change) wires to refuse an unverified caller is what fires
KBA_VERIFICATION_REQUIRED; see section 5.
3. Session-not-found and session-not-active
KBA_SESSION_NOT_FOUND is almost always an integration ordering problem,
not a platform fault:
- Your integration submitted answers to a call that never had a start, or
post-surfaced a stale
session_idfrom an earlier session on the same call. The response message names the fix: start a session first. - The session expired — a
verifiedstatus persists as the ledger state, but four hours pastverified_atthe computed status isexpired, and most downstream gates stop honoring it. Open a fresh session; the caller is usually still on the line. If the integration keeps a session across long calls, refresh it at TTL boundaries rather than cachingsession_idforever. - On the stateless token pair, the equivalent failure is a verify call
with an expired or malformed
challenge_token— the challenge is single-use and five-minute-lived, so submit answers while the caller is on the line, never against a token carried between calls.
KBA_SESSION_NOT_ACTIVE says the session is already settled — it reached
verified or failed — and verify rejects any further answers. Read the
session state (GET /api/v1/voice/kba/:callId) before submitting; a
verified ledger means the gate should be passing, a failed ledger is
permanent until restart. Never retry the same answers against a settled
session — nothing changes.
4. Locked, insufficient-profile, and contact-lookup failures
Start rejects with one of four codes before any challenge issues.KBA_LOCKED (409) — the attempt budget ran out on a previous session,
so the ledger holds terminal failed. The only deliberate way past it is
POST /voice/kba/:callId/start with restart: true in the body:
/challenge spends against it — cycling the
challenge endpoint never resets the budget.
KBA_INSUFFICIENT_PROFILE_DATA (422) — the linked contact has fewer
than two verifiable facts on file. No retry of the same inputs passes:
challenge questions come from contact data, and thin data stays thin
across retries. Switch verification method:
- Agent judgement — agent reads an account-level fact the caller can confirm in the CRM, proceeds with a manual note on the call record.
- OTP send — run a verify profile’s delivery chain (SMS/email) and read a code back; see Verify OTP troubleshooting.
- Voice biometrics — if the contact enrolled a voiceprint, verify by phrase instead; see voice biometrics failures.
KBA_NO_CONTACT_LINKED and KBA_CONTACT_NOT_FOUND (both 422) — the
call carries no contact_id, or the linked contact no longer resolves
(deleted or unlinked after the call started). Both are lookup failures at
start time: link a contact to the call through the voice/call stack or
the CRM integration first, then start. KBA_NO_CONTACT_LINKED means “fix
your call-to-contact association”; KBA_CONTACT_NOT_FOUND means “the
association points to a contact that is gone.” The stateless pair
collapses the second one into its contact_not_found outcome on
/challenge.
5. The verification-required gate
Sensitive in-call actions refuse until a session verifies:- Payment capture — card read (DTMF or agent entry) is held.
- PII disclosure — tools that read contact or account details gate first.
- Account changes — address updates, plan changes, SIM swaps, and similar mutations.
403 KBA_VERIFICATION_REQUIRED with a
message that spells out the remediation (start → verify → retry). The
check is a read-only gate against the ledger’s computed status — it never
mutates the session, so it is cheap to call inline. When the gate fires
mid-flow:
- Read
GET /api/v1/voice/kba/:callId— if the ledger showsverified+expired, the four-hour TTL slid past; re-run the challenge. - Run start → verify while the caller is still on the line.
- Retry the original action once — never loop without the gate passing.
6. How the two surfaces differ
The stateful ledger and the stateless token pair carry the same verdict but address it differently, and the error meaning folds over accordingly:
Don’t mix the two on one call — the ledger’s per-session counter and the
token pair’s per-contact window are independent, and interleaving them
makes lockout behavior impossible to explain to a reviewer.
7. Escalation bundle
A session/lookup error you can’t clear with the steps above needs this in a ticket:- The
error.codeand the full JSON envelope. - The
meta.request_idoff the failing response. - The call id, the session id, and the start/verify timestamps off your integration log.
- The computed ledger state from
GET /api/v1/voice/kba/:callId(attach it — it proves which of the three states you hit).
Cross-links
- KBA caller verification concept — the model behind these states.
- KBA caller-verification guide — the happy-path walkthrough this page triages against.
- Verify OTP — the fallback when the profile is too thin.
- Voice biometrics failures — the enrolled-voiceprint fallback.
- Error Code Reference — the seven codes’ registry rows.