Start a verification#
Create a verification for a destination phone number and select how the verification challenge is delivered. The response contains the verification identifier, initial status, expiration time, and delivery-method details when applicable.
For an approved request, the Verification API attempts to deliver the challenge by SMS or phone call.
Request#
HTTP method: POST
Path: /api/v1/verifications
Request body#
The request body contains a top-level data object. The following table lists the fields
accepted inside data and identifies which fields are required:
Field |
Type |
Required |
Description |
|---|---|---|---|
|
|
Yes |
Phone number to verify in E.164 format. The leading |
|
|
Yes |
The method used to deliver the verification challenge. Supported values are |
|
|
No |
Options for the |
|
Array of |
No |
Preferred message-template languages as BCP 47 tags, ordered from most to least
preferred. Tags are matched exactly, so |
|
|
No |
Android SMS Retriever application hash. It must contain exactly 11 characters from
|
|
|
No |
Options for the |
|
Array of |
No |
Preferred announcement languages as BCP 47 tags, ordered from most to least
preferred. These are the same tags with the same semantics as |
Response#
The endpoint returns JSON responses. When a verification is created, its
verification object appears under a top-level
data key. Errors that prevent a verification from being created appear under a
top-level errors array.
The following table lists the HTTP status codes returned by this endpoint:
Status |
Meaning |
|---|---|
|
The verification record was created. Inspect |
|
Authentication failed, credentials are missing or invalid, or the authentication mode is below the minimum configured for the OTP application. |
|
The account balance is insufficient to start a verification. |
|
Request validation failed. This includes an invalid destination, unsupported delivery method, or invalid delivery-method options. |
See Errors and status codes for the error response structure and available error codes.
Note
A 201 Created response confirms that the verification record was created. It does not
confirm that the challenge was delivered. An approved start normally has status
pending, and delivery can still fail later.
A request callback can deny the start before delivery.
A denied start can also return 201 Created with status denied and a matching
error_code. Always inspect both fields.
Examples#
The REST API examples use HTTP Basic authentication. See REST API authentication for credential and header requirements.
The SDK examples assume that the corresponding SDK is installed and initialized. See the Ruby SDK, iOS SDK, and Android SDK.
The identifiers, expiration times, and fees shown in the examples are illustrative.
REST API#
Send a POST request to create a verification. When the record is created, the response
returns a verification object containing its initial state under a top-level data key.
http
POST /api/v1/verifications HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
{
"data": {
"destination": "+4915112345678",
"delivery_method": "sms",
"sms": {
"languages": ["en-US"]
}
}
}
curl
curl -i -X POST https://verification.didww.com/api/v1/verifications -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"delivery_method": "sms", "destination": "+4915112345678", "sms": {"languages": ["en-US"]}}}' --user your_app_key:your_app_secret
response
HTTP/1.1 201 Created
Content-Type: application/json
{
"data": {
"id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
"destination": "4915112345678",
"delivery_method": "sms",
"fee": "0.06",
"status": "pending",
"error_code": null,
"error_detail": null,
"expires_at": "2026-07-15T10:02:00.000Z",
"sms": {
"template": "Your code is {{CODE}}",
"language": "en-US",
"interception_timeout": 120
}
}
}
http
POST /api/v1/verifications HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
{
"data": {
"destination": "+4915112345678",
"delivery_method": "callout",
"callout": {
"languages": ["de-DE"]
}
}
}
curl
curl -i -X POST https://verification.didww.com/api/v1/verifications -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"callout": {"languages": ["de-DE"]}, "delivery_method": "callout", "destination": "+4915112345678"}}' --user your_app_key:your_app_secret
response
HTTP/1.1 201 Created
Content-Type: application/json
{
"data": {
"id": "2b3c4d5e-6f70-4b3c-9d0e-1f2a3b4c5d6e",
"destination": "4915112345678",
"delivery_method": "callout",
"fee": "0.08",
"status": "pending",
"error_code": null,
"error_detail": null,
"expires_at": "2026-07-15T10:02:00.000Z",
"callout": {
"language": "de-DE"
}
}
}
Ruby SDK#
The Ruby SDK sends the request when start_verification(...) is called and returns a
verification object containing the initial state.
verification = client.start_verification(
destination: "+4915112345678",
delivery_method: "sms",
sms: {languages: ["en-US"]}
)
verification.id # => "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21"
verification.status # => "pending"
verification.pending? # => true
verification.sms_language # => "en-US"
verification = client.start_verification(
destination: "+4915112345678",
delivery_method: "callout",
callout: {languages: ["de-DE"]}
)
verification.id # => "2b3c4d5e-6f70-4b3c-9d0e-1f2a3b4c5d6e"
verification.status # => "pending"
verification.callout_language # => "de-DE"
iOS SDK#
The iOS SDK sends the request when start(...) is called and returns a Verification
containing the initial state.
let verification = try await client.start(
destination: "+4915112345678",
method: .sms,
sms: .init(languages: ["en-US"])
)
verification.id // "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21"
verification.status // .pending
let verification = try await client.start(
destination: "+4915112345678",
method: .callout,
callout: .init(languages: ["de-DE"])
)
verification.id // "2b3c4d5e-6f70-4b3c-9d0e-1f2a3b4c5d6e"
verification.status // .pending
Inspect verification.status before asking the user for a code. A denied start returns a
Verification with status .denied instead of throwing an HTTP error.
Android SDK#
The Android SDK returns a VerificationHandle. Calling start(...) does not send the
request. Collect handle.states exactly once to send the request and receive verification
state changes. After VerificationState.Starting, an approved start emits
VerificationState.AwaitingInput, which corresponds to the API status pending.
val handle = didww.start(
destination = "+4915112345678",
method = DeliveryMethod.SMS,
sms = SmsOptions(languages = listOf("en-US")),
)
val handle = didww.start(
destination = "+4915112345678",
method = DeliveryMethod.CALLOUT,
callout = CalloutOptions(languages = listOf("de-DE")),
)
Collect the returned handle from a ViewModel-scoped coroutine:
viewModelScope.launch {
handle.states.collect { state ->
when (state) {
is VerificationState.AwaitingInput ->
println("Verification ${state.verificationId} is pending")
is VerificationState.Denied ->
println(state.error?.detail ?: "Verification denied")
is VerificationState.SetupError ->
println("Configuration error: ${state.code}")
is VerificationState.Failed ->
println("Start failed: ${state.reason}")
else -> Unit
}
}
}