KBA caller verification
An inbound call reaches your contact center with a phone number — nothing more. Before an agent discusses account details, takes a payment, or changes anything on the account, someone has to answer: is this caller who the number’s contact profile says they are? Knowledge-based authentication (KBA) answers it by challenging the caller with questions drawn from facts already on file for the call’s linked contact — email, the last 4 digits of the phone number, the full name, the company name. Orbit ships KBA as a voice-pillar primitive, alongside the OTP-code model documented in Verification session lifecycle and enrolled-voiceprint matching in Voice biometrics. This page is the concept-level map: what a challenge is, which endpoints drive it, how the attempt budget behaves, and where the audit ledger lives.Why KBA exists
OTP verification proves someone controls a phone or email you can reach out-of-band — it dispatches a code on a second channel. Voice biometrics prove the caller sounds like an enrolled voiceprint. Neither fits the classic contact-center moment: the caller is already on the line, the agent needs a check now, and voiceprint enrollment or an SMS-capable number isn’t assumed. KBA fills that gap with evidence your CRM already holds. The agent reads two or three prompts aloud — “Can you confirm the email we have on file?”, “Can you confirm the last 4 digits of the phone number?”, “Can you confirm the full name on this account?”, “Can you confirm the company name?” — and submits the caller’s spoken answers. No new PII is collected: the expected answers come from the existing contact record linked to the call, and answers are never logged or audited verbatim, only per-factor pass/fail outcomes.The endpoint surface under /voice/kba
Two resource shapes sit under the same prefix. Pick the one that matches your agent workflow — both end in the same verified/not-verified gate.
Stateful per-call ledger. Useful when you want every start, attempt, and lockout readable on the call record itself:
Stateless signed-token pair. Useful when you’d rather round-trip a challenge token than address a call id:
Factor selection and question count
A challenge draws 2–3 questions from the on-file profile — a default of three where the data supports it. Factors that are empty on the contact record are skipped, and a contact with fewer than two verifiable fields can’t be meaningfully challenged at all: start returns a422 KBA_INSUFFICIENT_PROFILE_DATA, and the call needs an alternate verification method (agent judgement, a callback, an OTP send). The stateless pair defaults to date-of-birth and ZIP factors when your tenant configuration doesn’t pin a factor list.
The bounded attempt budget and lockout
Every mismatched submission burns one attempt against a bounded budget — three on the stateful ledger before the session flips failed; a configurable windowed count on the stateless pair (default five per contact). This counter is the brute-force guard on an identity gate, so submissions serialize correctly under concurrency: parallel guesses each consume their own attempt and trip the lockout on schedule rather than sharing a counter value. Exhaustion is terminal. On the stateful ledger the session sits infailed until you deliberately pass restart: true to start a fresh challenge — a stray retry can’t route around the lockout. On the stateless pair, repeated challenge issuance counts against the same per-contact budget, so cycling /challenge doesn’t reset it either.
Verified sessions, and what gates on them
A fully-matched submission opens a verified session. Reads compute the effective status at request time — a storedverified flag past its expiry reports as expired, never as verified — so stale rows can’t silently gate later actions. In the stateless pair the verify response hands back a session_token, and /session/check is the read-only gate payment, PII-disclosure, and account-change tools call before they proceed.
The migration-free ledger
The stateful session lives on the call record — in the call log’s metadata underkba_verification — rather than in a new table. This is Orbit’s extend-metadata pattern (the same one lightweight annotations like MCID use): a read-model cache on the existing call row, so the feature ships with no schema migration and everything stays inside your tenant schema. The cache-cell shape holds the session id, status, factor list, attempt counters, and the verified/failed timestamps.
Answers stay out of the record
Only outcomes are persisted or audited: which factor keys were checked, and the pass/fail result for each. Spoken answer values are never written to logs or the audit trail — KBA is a tenant-owned control over your call data, not a capture of new caller PII.Outbound signalling is never involved
KBA is read-and-compare over data already on file plus annotation of the call record. It originates no outbound call or message and touches no carrier leg, so all outbound traffic continues to exit only through the Devotel softswitch — the verification flow itself never wires a signaling path of its own.Challenge → verify with curl
The stateful ledger, end to end:session_id and the question set (factor + prompt pairs — the caller-facing text the agent reads aloud).
verified status comes back when every submitted factor matches; a mismatch returns per-factor results and the remaining attempt count, and the session locks when the budget runs out.
403 KBA_VERIFICATION_REQUIRED until the session verifies.
Where the how-to lives
- Verification session lifecycle — the OTP-code model for out-of-band proof of possession.
- Voice biometrics — enrolled-voiceprint matching for callers with a voiceprint on file.
- Voice call lifecycle — where the call record KBA annotates comes from.