Send Phone Code
Send a one-time passcode (OTP) to a phone number over WhatsApp, SMS, or another supported channel, then verify it with POST /v3/phone/check/.
How send and check pair up. Verification state is keyed by your application plus the E.164 phone_number — the check call does not take request_id. Each new send creates a pending verification that lives for 5 minutes: call the check with the same number and the code the user received before the window closes. Calling send again for the same number while a verification is pending re-sends a code for that same verification (status: "Retry", same request_id). At most one retry is attached this way (two sends total); a further send starts a fresh verification with a new request_id. The 5-minute window is measured from the first send and is not extended by retries.
Delivery channels. options.preferred_channel selects the channel (whatsapp by default; sms, telegram, voice, rcs, viber, and zalo are also supported). When the preferred channel is unavailable for the destination country or number, delivery automatically falls back to SMS — the send still reports Success, and the channel actually used is reported by the check response (phone.verification_method and the lifecycle events).
Send statuses. Success — OTP sent for a new verification; Retry — OTP re-sent for the pending verification; Blocked — the anti-fraud layer refused to send (see reason, e.g. repeated_attempts, suspicious, spam). A Blocked send immediately finalizes the verification as Declined with a high-risk warning, so a follow-up check returns Expired or Not Found.
Billing. The price depends on the destination country and the channel that actually delivers the message — see Phone Verification Pricing. Only Blocked sends are guaranteed free: any other unbilled send attempt is charged at verification finalization or expiration, even if delivery was never confirmed or the delivery provider reported the message undeliverable. Checks are always free. As an anti-abuse measure, phone verification is disabled until your organization’s first top-up (403).
Session persistence. Every new verification is persisted as an API-type session: request_id is a real session id you can pass to GET /v3/session/{sessionId}/decision/, the verification appears in the Business Console, and status.updated webhooks fire as it progresses.
Sandbox. Sandbox API keys skip delivery and billing: after request validation (malformed input still returns 400), the endpoint returns a static Success payload with a random request_id; no message is sent and nothing is persisted. Use code 123456 on the sandbox check.
Authentication. Send your application’s API key in the x-api-key header. Missing or invalid credentials return 403 ({"detail": "You do not have permission to perform this action."}) — this API never returns 401.
Rate limits. Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints, plus an anti-abuse cap of 4 send attempts per phone number per hour; exceeding either returns 429.
Authorizations
Body
Recipient phone number in E.164 format — leading + and country code (e.g., +14155552671). Numbers are validated and normalized to E.164; unparseable or invalid numbers return 400 with a phone_number field error.
20"+14155552671"
OTP delivery options. All fields are optional.
Optional device and network signals about the end user, forwarded to the anti-fraud layer to improve detection of abusive or automated traffic. All fields are optional.
Optional caller-controlled identifier (your internal user id, an email, a UUID, etc.) persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console. Use it to correlate Didit's request_id with your user record.
Optional free-form JSON object persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console.
Response
Send acknowledged. Inspect status: Success and Retry mean a code is on its way; Blocked means the anti-fraud layer refused and the verification is already finalized as Declined. request_id is the persisted session id (same id on a Retry).
Session id of the verification. A Retry send returns the same request_id as the original send. This id appears in the Business Console, is returned again by a finalized POST /v3/phone/check/, and can be passed to GET /v3/session/{sessionId}/decision/.
Success — OTP sent to a new verification. Retry — OTP re-sent for the pending verification created by a previous send. Blocked — the anti-fraud layer refused to send; the verification is immediately finalized as Declined and nothing is billed.
Success, Retry, Blocked Why a send was Blocked (e.g., repeated_attempts, suspicious, spam). null on Success and Retry.
Echo of the vendor_data stored on the session (from the first send).
Echo of the metadata stored on the session (from the first send).