One Time Passcode
Overview
One Time Passcode (OTP) confirms possession by delivering a 6-digit code to the user via SMS, email, or voice call. The user enters the code in your UI — the platform verifies it and returns an approve or deny decision.
OTP is a possession check, not an identity check. It confirms the user can access the registered phone number or email inbox at the moment of verification. Pair with an Authoritative Database or Phone Registration checker for identity assurance.
Level of Assurance
Medium — possession of the registered contact method confirmed at time of verification.
User Friction Level
Low — user receives a code and enters it. Most users complete in under 60 seconds.
End User Requirements
Access to the registered phone number (SMS or Voice) or email inbox; ability to receive the delivery and enter the code within the expiry window.
Speed
Real-time delivery; completion is user-dependent. Email delivery may be subject to provider latency or spam filtering.
Supported Countries
SMS and Voice: broad international coverage — contact your ID Dataweb team for country-specific availability. Email: global.
Use Cases
- Standalone possession check for account actions (password reset, account changes, step-up).
- Secondary factor when SMS Link tap is not suitable for the user environment.
- Re-authentication challenge for medium-risk sessions.
- Email OTP when a phone number is not available or email is the primary identifier.
How It Works
Your application calls the /otp endpoint to deliver a code to the user — the delivery method is controlled by the type parameter. The endpoint returns a session identifier (asi). The user enters the received code in your UI. Your application submits the code and session ID to /slverify — the platform compares the code and returns a policy decision.
Outcome:
- Correct code entered within expiry window:
policyDecision = approve - Incorrect code or expiry exceeded:
policyDecision = deny
When to Use Which Delivery Method
| Delivery | Use when |
|---|---|
| SMS | You have the user's phone number and want fast, familiar code delivery via text message |
| Phone number is not available, or email is the user's primary identifier | |
| Voice | SMS delivery is unreliable for the target population (e.g., older users, low-SMS regions, or as a fallback channel) |
Integration: Gateway (OIDC)
Standard OIDC flow. See Gateway (OIDC) Integration. Delivery and code collection are handled by the hosted UI.
OTP is configured at the workflow level. Contact your ID Dataweb team to enable it as a step and to select the delivery method.
Integration: ID Dataweb API
OTP uses a two-call flow: deliver the code to the user, then verify the code the user enters. The flow is identical for all three delivery methods — only the parameters differ.
API Prerequisites
sequenceDiagram
participant App as Your Application
participant IDW as ID Dataweb API
participant User as End User
App->>IDW: POST /token (apiKey:secret)
IDW-->>App: access_token
App->>IDW: GET /otp?type=sms|email|voice&...&apikey=...
IDW-->>App: asi (session ID) + status: SUCCESS
IDW-->>User: Code via SMS, Email, or Voice
Note over App,User: User receives code and enters it in your UI
App->>IDW: POST /slverify (asi + PINCode + contact attribute)
IDW-->>App: policyDecision (approve | deny)
API Reference
Step 1: Get a bearer token
const credentials = btoa(`${API_KEY}:${SHARED_SECRET}`);
const tokenRes = await fetch('https://api.preprod.iddataweb.com/v1/token', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials'
});
const { access_token } = await tokenRes.json();Step 2: Deliver the OTP
GET https://api.preprod.iddataweb.com/v1/otp
| Parameter | Required | Description |
|---|---|---|
type | Yes | "sms" |
dialCode | Yes | Country dial code (e.g., "1" for US) |
telephone | Yes | Phone number without dial code |
apikey | Yes | OTP step API key |
credential | No | User identifier for session correlation |
appID | No | Application identifier for reporting |
const params = new URLSearchParams({
type: 'sms',
dialCode: '1',
telephone: userPhoneNumber,
apikey: OTP_STEP_KEY,
credential: userCredential
});
const otpRes = await fetch(
`https://api.preprod.iddataweb.com/v1/otp?${params}`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
const { asi } = await otpRes.json();
// Store asi — required for /slverifyResponse (all delivery methods):
{
"responseCode": "200",
"errorDescription": null,
"asi": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "SUCCESS"
}Step 3: Verify the entered code
The user enters the received code into your UI. Submit it to /slverify with the session ID and the contact attribute matching your delivery method.
POST https://api.preprod.iddataweb.com/v1/slverify
const verifyRes = await fetch('https://api.preprod.iddataweb.com/v1/slverify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`
},
body: JSON.stringify({
asi: asi,
apikey: OTP_STEP_KEY,
credential: userCredential,
userAttributes: [
{
attributeType: 'PINCode',
values: {
pincode: userEnteredCode,
pinType: 'sms'
}
},
{
attributeType: 'InternationalTelephone',
values: {
dialCode: '1',
telephone: userPhoneNumber
}
}
]
})
});
const { policyDecision, forwardApiKey } = await verifyRes.json();Response:
{
"errorCode": "",
"errorDescription": "",
"transaction_id": "string",
"userAttributes": [],
"userAssertionList": [],
"mbun": "string",
"policyDecision": "approve | deny",
"forwardApiKey": "string"
}Step-by-step Setup
- Call
POST /tokento obtain a bearer token. - Call
GET /otp?type=sms|email|voice&...to deliver the code. Store the returnedasi. - Present a code entry UI to the user.
- On submission, call
POST /slverifywith theasi, the enteredpincode(withpinTypematching your delivery method), and the contact attribute (InternationalTelephonefor SMS/Voice;Emailfor Email). - Check
policyDecision:approve= possession confirmed;deny= incorrect code or expired session.
Configuration Options — API-specific
Content coming soon.
Policy Components & Assertions
| Assertion | Key | Applies to | What it checks |
|---|---|---|---|
| Phone OTP Possession Check | test.device | SMS, Voice | Confirms the phone number passed OTP verification — code entered correctly within the expiry window |
| Email OTP Possession Check | link.email_user | Confirms the email address passed OTP verification — code entered correctly within the expiry window |
For infrastructure-specific assertions (e.g., message delivery confirmation on AWS or Telesign variants), see the One Time Passcode Checker.
Error Handling & Troubleshooting
- Code not received (SMS/Voice): May be due to carrier filtering, invalid number format, or network delays. Retry the
/otprequest or prompt the user to check their connection. Ensuretelephoneis passed without the dial code anddialCodeis set separately. - Code not received (Email): Advise the user to check their spam folder. Retry the
/otprequest to resend. - Expired code: OTP codes have a fixed expiry window. If the user takes too long,
/slverifyreturnsdeny. Call/otpagain to send a fresh code — do not reuse the previousasi. - Incorrect code:
policyDecision = deny. Call/otpagain to start a new session. - Email possession vs. identity: Email OTP confirms inbox access only — it does not verify the address belongs to the claimed identity. Pair with Email Risk to assess address quality before sending the OTP.
Testing in Preproduction
Testing Options
- Gateway (Try Now): Run a workflow with OTP configured in the Admin Console — the hosted UI handles delivery and code entry.
- API: Use the OTP Postman Collection with your preproduction step key. Contact your ID Dataweb team for test credentials.
Test Credentials and Values
| Scenario | Input | Expected Result |
|---|---|---|
| Correct code | Enter the code received via SMS, Email, or Voice | approve |
| Wrong code | Enter an incorrect code | deny |
| Expired session | Wait past the OTP expiry window, then submit | deny |
Interpreting Results
policyDecision = approve — user entered the correct code and possesses the registered contact method.
policyDecision = deny — code was incorrect, expired, or the session was invalid. Re-initiate the flow from /otp.
Related Resources
→ SMS Link | → One Time Passcode Checker | → Email Risk | → Session Risk | → Gateway (OIDC) Integration
Updated 2 days ago
