Skip to main content
The Phone Verification feature emits warnings whenever a risk signal fires on the OTP flow or the number itself: a known bad number, a VoIP or disposable line, an OTP attempt cap, or a hit against another user’s session. This page lists every code, what triggers it, and how to configure the workflow response.

Overview

Warnings are tagged with feature PHONE. They appear under phone_verifications[].warnings[] in GET /v3/session/{sessionId}/decision/ and follow the standard warning object shape (feature, risk, additional_data, log_type, short_description, long_description, node_id). Each warning is also routed into the per-session log so it surfaces in the Business Console under the Phone section. Some warnings are hard auto-decline triggers — they always set the feature status to Declined. Others map to a configurable action (DECLINE, REVIEW, or NO_ACTION, depending on the setting) defined in your workflow settings, so the same risk code may decline one workflow while only flagging another.

Auto-decline conditions

The following warnings always decline the Phone Verification step regardless of configuration, and always carry log_type: "error":
  • VERIFICATION_CODE_ATTEMPTS_EXCEEDED — the user exhausted an OTP attempt cap: by default 2 wrong code submissions (phone_max_check_attempts) or more than 2 OTP sends (phone_max_retries), both tunable per workflow node. The standalone phone API allows 3 code attempts.
  • PHONE_NUMBER_IN_BLOCKLIST — the number is in your blocklist managed via the Lists API, or it matches a blocklisted session.
HIGH_RISK_PHONE_NUMBER — the delivery provider’s anti-fraud layer refusing to send the OTP (Blocked send) — declines by default but is no longer unconditional: see high_risk_phone_action below.

Configurable risks

Each of the following risks maps to a workflow setting you can configure to DECLINE, REVIEW, or NO_ACTION (the default — the warning is recorded without affecting the status). The configured action also sets the warning’s log_type: DECLINEerror, REVIEWwarning, NO_ACTIONinformation. Duplicate detection runs within your application across KYC, KYB, and standalone API phone verifications, and groups sessions by vendor_data — sessions sharing the same vendor_data are treated as one end-user and are excluded from match results. Leave vendor_data empty and every session is treated as a distinct user.

Blocked sends

HIGH_RISK_PHONE_NUMBER follows the same pattern with a narrower choice set, because a send the provider refused cannot be approved: The setting is applied only when every high-risk block on the step carries additional_data.risk_factors of exactly ["device_attribute"] — the provider’s “this device looks suspicious” signal, which is what fires on ordinary mobile lines. Any other risk factor, any mix that merely includes device_attribute, or a block with no risk factors at all declines regardless of the setting. The blocking reason (repeated_attempts, suspicious, or spam) is a separate field, returned in additional_data.blocked_reason. Independently of the setting, a number on a phone allowlist created via the Lists API is never auto-declined for a blocked send: the step goes to In Review, the warning carries log_type: "warning", and additional_data.phone_number_in_allowlist is true.

Verification attempt limits

The Phone Verification feature applies a hard cap on OTP attempts to prevent abuse:
  • Code-entry attempts — Default 2 wrong submissions (phone_max_check_attempts) before the step finalizes as Declined with VERIFICATION_CODE_ATTEMPTS_EXCEEDED. The standalone phone API allows 3 code attempts per verification.
  • Send attempts — Default 2 sends in total (phone_max_retries): the initial send plus one resend. A further send request finalizes the step and raises VERIFICATION_CODE_ATTEMPTS_EXCEEDED.
  • OTP validity — A pending OTP is valid for 5 minutes from the first send; retries do not extend the window.
Both caps are tunable per workflow node. Independently of these caps, the delivery provider’s anti-fraud layer can block a send outright (reason repeated_attempts, suspicious, or spam) — that raises HIGH_RISK_PHONE_NUMBER, not the attempts warning.

Warnings produced

Cross-session matches

When a number is detected on other sessions or on your blocklist, those hits also appear under phone_verifications[].matches[] (capped at 5 entries). Each match carries session_id, session_number, vendor_data, verification_date, phone_number, status, is_blocklisted, api_service, and a source of session (another session with the same number, any status) or list_entry (a synthetic blocklist hit prepended to the array). If the current number is on your phone allowlist, Didit keeps the match evidence but emits PHONE_NUMBER_IN_ALLOWLIST instead of applying the duplicate-phone action. See the Phone Verification report for the full match schema.

Example

A blocked send (HIGH_RISK_PHONE_NUMBER) on a VoIP number, with voip_number_action configured to REVIEW:

Warning types

Each risk is assigned a severity based on your application’s configuration. Severities fall into three categories: