Concepts & how things work
The reference tells you what to send. This page explains why — how a call moves through verification, what enrolling a voice actually does, and what each response property means.
The call lifecycle
A reseller works inbound calls for a child institution. Each call is identified by a voiceId — Pindrop's identifier for that call's audio, and the handle you pass to every call-scoped endpoint.
- Assign — POST
/external/calls/assignlinks an inbound call (by phone number or existingvoiceId) to a member (personId) and returns thevoiceId. - Queue — GET
/external/calls/queuelists calls awaiting verification, with optional search and date filters. - Inspect — GET
/external/calls/{voiceId}/detailsreturns the full call record: enrollment/verification flags, risk, and the Pindrop event log. - Decide — POST
…/enrollto accept the caller's voice, or POST…/reject-voiceto reject it.
How voice enrollment works
Enrolling a voice (POST /external/calls/{voiceId}/enroll) is how a reseller manually authenticates a caller and tells Pindrop to trust and keep that caller's voiceprint. A single call does several things atomically:
- Records a verification for the member, tagged with the
validationTypeyou supplied (voice, OTP, KBA, …). - Tells Pindrop the interaction succeeded — it sends account-interaction feedback keyed by the account alias
{institutionKey}-{personId}against thisvoiceId, with statusSUCCESSFUL. This is what lets Pindrop enroll and reuse the voiceprint on future calls. - Applies the “Green Manual Authentication” policy to the call. This signals to Pindrop's call-end webhook that the enrollment should be preserved even if an automated voice-match rule would otherwise reject it.
- Writes two activity records —
AcceptCallerVoice(the reseller explicitly accepted the voice) andFullAuthentication(the caller is fully authenticated). TheFullAuthenticationactivity is what stops the call-end webhook from discarding the voiceprint.
After a successful enroll, the member's voiceprint is trusted in Pindrop and future calls from that member can be voice-authenticated automatically — no further manual verification needed.
curl -X POST https://api.getconfirmed.org/external/calls/<voiceId>/enroll \
-H "SsoToken: <sso-token>" \
-H "InstitutionKey: acme-cu" \
-H "RequestedBy: jdoe" \
-H "Content-Type: application/json" \
-d '{ "personId": "00123", "validationType": "VoiceAuth", "notes": "Verified by agent" }'
→ { "success": true }
Voice authentication thresholds
Separately from the manual /enroll flow above, Pindrop runs its own passive voice biometrics on call audio. Two distinct checks govern this — one for creating a voiceprint (enrollment) and one for matching against an existing voiceprint (verification). Both require a low device risk_rating.
| Scenario | Required conditions | Result |
|---|---|---|
| New enrollment (first voiceprint for a member) |
voiceStrength = 100 and risk_rating = low |
Pindrop applies its “Basic Enrollment Speech” enrollment policy, which flips successfulVoiceEnrollment = true on that phone call. |
| Voice verification (against an existing enrollment) |
voiceScore ≥ 50 and risk_rating = low |
The call is treated as voice-verified. |
| Enrollment discarded (low liveness) |
liveness score is > 0 and < 30 |
Confirm does not enroll the caller's voice — the audio is most likely synthetic or recorded. successfulVoiceEnrollment stays false. |
When Pindrop's liveness detection returns a low score (greater than 0 and under 30), the caller's voice is treated as probably a clone, deepfake, or playback and is not enrolled even if it would otherwise meet the enrollment threshold. The same low-liveness signal also drives the new Red Low Liveness authentication policies described under Interpreting the validation status.
voiceStrength
voiceStrength is the signal that gates a new enrollment (it must reach 100). It is not currently exposed through the Pindrop API, so it is not returned on the call-detail response — only its effect is observable, via successfulVoiceEnrollment flipping to true once enrollment succeeds.
The numeric voiceScore (and the underlying device/voice signals) is only present on Pindrop's call_end and call.enrollment_update webhook events — it is not available mid-call, so it is unreliable as a live decision signal. Pindrop already bakes these scores and thresholds into the policies it returns. Drive your business logic off metaData.pindropPolicies, never off the raw scores. See the next section for how to turn those policies into a status.
Rejecting & un-enrolling a voice
POST /external/calls/{voiceId}/reject-voice is the inverse. It notifies Pindrop of a FAILED interaction, records a RejectCallerVoice activity, and — importantly — un-enrolls every prior manual authentication for that member: each earlier FullAuthentication activity is moved to FullAuthenticationUnenrolled, so Pindrop discards the previously trusted voiceprint. Use it when a caller's identity can't be trusted.
Call detail properties
Selected fields returned by GET /external/calls/{voiceId}/details. The reference lists the full schema; these are the ones whose meaning isn't obvious.
| Property | Meaning |
|---|---|
voiceId | Pindrop's identifier for the call audio; the handle used by all call-scoped endpoints. |
personId / valueForCore | The matched member id and the core system's internal identifier for that member. |
isVoiceEnrolled | A voiceprint exists in Pindrop for this member. |
isVoiceVerified | The voice was verified on this call. |
isVoiceMismatch | The caller's voice did not match the enrolled voiceprint — a fraud signal. |
successfulVoiceEnrollment | Pindrop's enrollment-update webhook confirmed the voiceprint was enrolled on this call. |
isHighRiskDevice | Pindrop's device analysis flagged the originating device as high risk. |
status | The current activity status of the call (see the table below). |
hasVoiceMatchValidationRule | The institution's active validation rule includes a voice-match requirement. |
metaData.pindropPolicies | Policies applied to the call, e.g. "Green Manual Authentication". |
pindropEvents | The full event log received from Pindrop's webhooks for this call. |
Interpreting the validation status
Our own dashboard shows the agent a single color-coded validation status for each call — a traffic-light that tells them how to proceed. That status is derived entirely from metaData.pindropPolicies (the policies Pindrop applied to the call). If you build your own agent UI, reproduce the same logic so your status matches ours.
The rule is a simple case-insensitive keyword match with a fixed precedence — the first rule that matches wins:
| # | If any policy contains… | Status | What it means for the agent |
|---|---|---|---|
| 1 | green |
Fully Authenticated Device & Voice Match |
Voice (and device) matched. Proceed with assisting the caller. Shows as “Device & Voice Match” when the institution also has a voice-match validation rule (hasVoiceMatchValidationRule). |
| 2 | gray |
High Risk Device | Spoofing, SIM-swap, suspicious VoIP, or other device/network signals. Proceed with caution and ask further verification questions. |
| 3 | red (but not answered) |
High Risk Caller | The voice does not match previous records — a high-risk / fraud signal. Policies that also contain answered are excluded here, because the caller passed knowledge-based questions. |
| 4 | Account Not Enrolled (e.g. “Yellow/Blue Low Risk Account Not Enrolled”) |
First Time Caller | No previous voiceprint exists. No fraud detected — proceed to knowledge-based questions and/or send an MFA code. |
| 5 | anything else (default) | Voice Pending No Identity Claim |
The account is enrolled but the voice hasn't matched yet. Shows as “No Identity Claim” for the Yellow Low Risk No ID Claim policy. Continue verifying — voice results may still resolve to green. |
Matching on the color keyword (rather than a fixed set of boolean fields) lets Confirm introduce new policies driven by new business rules without any code or schema changes — the new policy just needs the right color word in its name. For example, at launch we didn't offer our liveness / deepfake-detection product (Pulse); once we added it, we were able to introduce new Red policies based on liveness scores, and they began surfacing as “High Risk Caller” automatically — no code change required. If you mirror this keyword approach on your side, your UI inherits new policies the same way.
When Pindrop's liveness detection scores a call's audio as low (greater than 0 and under 30) and the liveness reason is not ambient — i.e. the signal looks like a synthetic or recorded voice rather than just background noise — Confirm applies one of the following policies. All three contain red, so they map to High Risk Caller via rule 3 above with no extra handling on your side:
| Policy name | Applied when |
|---|---|
Red Low Liveness No ID Claim | Low liveness and no personId (identity claim) was provided. |
Red Low Liveness Account Enrolled | Low liveness and the claimed personId is already voice-enrolled. |
Red Low Liveness Account Not Enrolled | Low liveness and the claimed personId is not yet voice-enrolled. |
Ambient noise is excluded. If Pindrop attributes the low liveness score to ambient conditions (a TV, radio, or other background noise), none of these policies are applied — a noisy line is not treated as fraud.
Two more states are not driven by a policy string — they're behavioural:
| Status | When |
|---|---|
| Loading | The initial state before Pindrop's verification results have arrived for the call. |
| No Voice Match | A Voice Pending (yellow) call that never resolved to green. Our dashboard re-polls …/details for a short while; if the voice still hasn't matched it settles on “No Voice Match”. This is not necessarily fraud — it can be a cold, a noisy line, etc. — but the account was enrolled and the voice didn't match. |
A status of Voice Pending means Pindrop is still evaluating. Re-fetch GET /external/calls/{voiceId}/details until the status resolves (to green) or the call ends. As above, base every decision on metaData.pindropPolicies — not on the raw scores in pindropEvents.
Activity status reference
The status on a call (and on individual activity records) is one of the following.
| Status | Meaning |
|---|---|
| FullAuthentication | Caller fully authenticated (by voice or another method). |
| FullAuthenticationUnenrolled | A previous full authentication that has since been rejected / un-enrolled. |
| AcceptCallerVoice | The caller's voice was explicitly accepted. |
| RejectCallerVoice | The caller's voice was explicitly rejected. |
| RejectCallerVoiceFromValidationRule | An automated validation rule rejected the voice. |
| VoiceMismatch | The voice did not match the enrolled voiceprint. |
| AnsweredQuestions | The caller passed knowledge-based authentication (KBA). |
| MFAValidated | Multi-factor authentication passed. |
| VoiceOptIn / VoiceOptOut | The caller opted in / out of voice authentication. |
| CallStarted / CallEnded | Call lifecycle markers. |
Validation types
The validationType you send when enrolling records how the caller was verified.
| Value | Meaning |
|---|---|
VoiceAuth | Verified by voice biometrics. |
OneTimePasswordAuth | Verified with a one-time passcode. |
KnowledgeBasedAuth | Verified via knowledge-based questions. |
NoAuth | No additional authentication performed. |
Other | Any other verification method. |