Getting Started#
This guide walks you through creating an OTP application, generating API credentials, and running your first verification from start to finish. The walkthrough uses the sandbox environment so you can test the integration before moving it to production.
Choose an environment#
Create the OTP application and credentials in the same environment as the Verification API endpoint you plan to use:
Environment |
User Panel |
Verification API base URL |
Use |
|---|---|---|---|
Sandbox |
|
Integration testing |
|
Production |
|
Live verifications |
Important
Credentials are environment-specific. Use credentials from a sandbox OTP application with the sandbox API, and credentials from a production OTP application with the production API.
Before you begin#
An account in the selected environment is required. For testing, open the DIDWW Sandbox User Panel. For production, sign in to the DIDWW Production User Panel or create a DIDWW account.
Access to the corresponding User Panel is required to create an OTP application and copy its credentials.
A positive account balance is required for production. The verification fee is billed when a verification reaches
verified. SMS and call delivery costs are billed separately.A phone number you control is required when testing delivery through the production environment.
Step 1: Create an OTP application#
An OTP application groups the credentials and settings used by your verification requests. You need one before you can start verifications, because each request is tied to an OTP application key, secret, callback URL, and minimum authentication mode.
For this walkthrough, create the application in the DIDWW Sandbox User Panel.
Open the User Panel for your selected environment: use the DIDWW Sandbox User Panel for testing or the DIDWW Production User Panel for live verifications.
Expand OTP Verify.
Select Applications.
Click Create application.
Enter a name for the application.
Optionally, enter a description.
Set a callback URL if you plan to use
publicauthentication, including the iOS and Android SDK examples in this guide. The Verification API calls this URL so your backend can approve or reject each start request. The callback URL is optional forbasicandapplicationauthentication. See Callbacks.Select the minimum authentication mode required for requests to this OTP application:
Public: anyone with the credential key can call the OTP endpoint.
Basic: callers must use HTTP Basic authentication with the credential key as the username and the credential secret as the password.
Application: callers must sign each request with the credential secret.
Click Create to save the application.
Create an OTP application in the DIDWW Sandbox User Panel.#
Step 2: Get your API credentials#
Each OTP application has a key and a secret. The key identifies the OTP application
when you make verification requests. The secret is used for stronger authentication modes,
such as HTTP Basic or signed application authentication.
Copy the credentials from the OTP application in your selected environment. This walkthrough uses credentials created in the DIDWW Sandbox User Panel.
The REST API and Ruby SDK examples use both credentials with basic authentication. The
iOS and Android SDK examples use only the key with public authentication.
In OTP Verify > Applications, find the application you created.
In the Credentials column, copy the key and secret for that application. Use the copy icon to copy each value without revealing it on screen.
If you need to view the actual value before copying it, click the eye icon.
Warning
Treat the secret like a password. Store it securely and never expose it in client-side code or public repositories. If it is leaked, rotate it from the corresponding DIDWW User Panel.
Copy the key and secret from the Credentials column.#
Step 3: Start a verification#
Call the start endpoint with the destination number and delivery method. The examples use the sandbox environment and send an SMS code.
Note
The REST API and Ruby SDK examples use basic authentication. The iOS and Android SDK
examples use public authentication, which requires the callback URL configured in
Step 1. An OTP application with minimum auth mode public accepts both authentication
modes. All examples use credentials created in the DIDWW Sandbox User Panel.
http
POST /api/v1/verifications HTTP/1.1
Host: verification-sandbox.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-sandbox.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
}
}
}
Note
The Authorization header contains the Base64 encoding of key:secret. Most
HTTP clients build this header when you supply the key as the username and the
secret as the password.
Install the Ruby SDK, then create a sandbox client and start the verification:
require "didww/otp_verification"
client = DIDWW::OTPVerification::Client.new(
key: "your-app-key",
secret: "your-app-secret",
env: :sandbox
)
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
Install the iOS SDK, then create a sandbox client with public authentication and start the verification:
import DIDWWVerification
let client = VerificationClient(
environment: .sandbox,
auth: .public(appKey: "your-app-key")
)
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
Install the Android SDK. Inside an
AndroidViewModel, create a sandbox client with public authentication and start
collecting the verification states. Calling start(...) creates a handle. The
request is sent when handle.states is first collected.
import androidx.lifecycle.viewModelScope
import com.didww.android.sdk.verification.Auth
import com.didww.android.sdk.verification.DeliveryMethod
import com.didww.android.sdk.verification.Environment
import com.didww.android.sdk.verification.SmsOptions
import com.didww.android.sdk.verification.VerificationState
import com.didww.android.sdk.verification.all.DidwwVerification
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
val didww = DidwwVerification(
context = application,
auth = Auth.Public("your-app-key"),
environment = Environment.Sandbox,
)
val verificationState = MutableStateFlow<VerificationState>(
VerificationState.Starting,
)
val handle = didww.start(
destination = "+4915112345678",
method = DeliveryMethod.SMS,
sms = SmsOptions(languages = listOf("en-US")),
)
viewModelScope.launch {
handle.states.collect { verificationState.value = it }
}
Keep the returned id, verification, or handle, depending on your integration.
You need it to report the code and read the verification status in the next steps.
Step 4: Report the code#
When the user enters the code they received, submit it to the report endpoint:
http
PATCH /api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 HTTP/1.1
Host: verification-sandbox.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
{
"data": {
"delivery_method": "sms",
"code": "123456"
}
}
curl
curl -i -X PATCH https://verification-sandbox.didww.com/api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"code": "123456", "delivery_method": "sms"}}' --user your_app_key:your_app_secret
response
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
"destination": "4915112345678",
"delivery_method": "sms",
"fee": "0.06",
"status": "verified",
"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
}
}
}
verification = client.report_verification(
"0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
delivery_method: "sms",
code: "123456"
)
verification.status # => "verified"
verification.verified? # => true
let result = try await client.verify(
verification,
code: "123456"
)
result.status // .verified
Submit the code through the handle created in Step 3. The existing state collector receives the result.
handle.submit("123456")
A successful submission emits VerificationState.Submitting followed by
VerificationState.Verified. If the code is rejected, the flow returns to
VerificationState.AwaitingInput with lastError set.
A status of verified confirms the user controls the number. If the code is incorrect,
the report is rejected and the verification remains available for another attempt until the
attempt limit is reached. See Errors and status codes for
the exact limit and other status values.
Step 5: Check the status (optional)#
Read the current status of a verification at any time. REST, Ruby, and iOS make a status request. Android reads the latest state received by the collector created in Step 3.
http
GET /api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 HTTP/1.1
Host: verification-sandbox.didww.com
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
curl
curl -i -X GET https://verification-sandbox.didww.com/api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 -H "Accept: application/json" --user your_app_key:your_app_secret
response
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
"destination": "4915112345678",
"delivery_method": "sms",
"fee": "0.06",
"status": "verified",
"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
}
}
}
verification = client.get_verification("0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21")
verification.status # => "verified"
verification.verified? # => true
let current = try await client.status(verification)
current.status // .verified
Do not collect handle.states a second time. Read the latest value mirrored by the
collector created in Step 3:
when (val current = verificationState.value) {
is VerificationState.AwaitingInput -> println("pending")
is VerificationState.Verified -> println("verified")
is VerificationState.Denied -> println("denied")
is VerificationState.Failed -> println("failed")
is VerificationState.SetupError -> println("configuration error")
VerificationState.Expired -> println("expired")
else -> println("in progress")
}
Move to production#
After the sandbox flow works as expected, configure the integration separately for production:
Sign in to the DIDWW Production User Panel.
Create a new OTP application in the production account and configure its callback URL and minimum authentication mode.
Copy the key and secret from the production OTP application. Store them separately from the sandbox credentials.
Change the API or SDK environment from sandbox to production:
Integration
Sandbox
Production
REST API
https://verification-sandbox.didww.comhttps://verification.didww.comRuby SDK
env: :sandboxenv: :productionor omitenviOS SDK
environment: .sandboxenvironment: .productionAndroid SDK
environment = Environment.Sandboxenvironment = Environment.ProductionRun a controlled verification using a phone number you can access.
Warning
Production requests can contact real destinations and incur verification and delivery charges. Confirm that the production OTP application, credentials, callback URL, and API environment are configured together before sending requests.
Next steps#
Compare the delivery channels in Verification Methods.
Review the available authentication modes and choose the one that fits your integration in Authentication.
Gate verifications in real time with a request callback.
Review every field and status code in the API Reference.