Verify API
Multi-channel OTP/2FA verification service.
Channels: SMS, Voice (TTS), and Email
Quick Start:
# SMS
curl -X POST https://api.wayscloud.services/v1/verify/start \
-H "X-API-Key: wayscloud_verify_xxx" \
-H "Content-Type: application/json" \
-d '{"channel": "sms", "recipient": "+4712345678", "locale": "no"}'
# Voice (TTS call)
curl -X POST https://api.wayscloud.services/v1/verify/start \
-H "X-API-Key: wayscloud_verify_xxx" \
-H "Content-Type: application/json" \
-d '{"channel": "voice", "recipient": "+4712345678", "locale": "no"}'
# Email
curl -X POST https://api.wayscloud.services/v1/verify/start \
-H "X-API-Key: wayscloud_verify_xxx" \
-H "Content-Type: application/json" \
-d '{"channel": "email", "recipient": "user@example.com", "locale": "no"}'
# Check code
curl -X POST https://api.wayscloud.services/v1/verify/check \
-H "X-API-Key: wayscloud_verify_xxx" \
-H "Content-Type: application/json" \
-d '{"session_id": "...", "code": "123456"}'Channel Details:
| Channel | Recipient | Sender |
|---|---|---|
sms | Phone (E.164) | Configurable alphanumeric |
voice | Phone (E.164) | +47 21 53 50 30 |
email | Email address | Verified domain or WAYSCloud default |
Pricing: 1.25 NOK per session + delivery (SMS ~0.35 NOK, Voice ~0.50 NOK, Email included)
Security:
- Codes hashed with SHA256 (never stored in plaintext)
- Max 5 attempts per session
- TTL: 60-900 seconds (configurable)
- Tenant isolation
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/verify/start | Start verification |
POST | /v1/verify/check | Check verification code |
GET | /v1/verify/status/{session_id} | Get session status |
DELETE | /v1/verify/sessions/{session_id} | Cancel session |
POST /v1/verify/start
Start verification
Start a new verification session and send code via SMS, voice call, or email.
Example Request (SMS)
{
"channel": "sms",
"recipient": "+4712345678",
"code_length": 6,
"ttl_seconds": 300,
"client_reference": "signup-user-42",
"locale": "no"
}Example Request (Voice)
{
"channel": "voice",
"recipient": "+4712345678",
"locale": "no"
}Example Request (Email)
{
"channel": "email",
"recipient": "user@example.com",
"locale": "no"
}Parameters
| Field | Required | Default | Description |
|---|---|---|---|
channel | No | sms | Channel: sms, voice, or email |
recipient | Yes | - | Phone (E.164) for SMS/Voice, email for Email |
code_length | No | 6 | Code length (4-8 digits) |
ttl_seconds | No | 300 | Session TTL in seconds (60-900) |
client_reference | No | - | Your reference for tracking |
locale | No | en | Message language: en, no, nb, sv, da, fi |
metadata | No | - | Custom metadata object (stored, not processed) |
client_ip | No | - | End-user IP for risk scoring. If provided, ip_risk is included in response |
Channel Notes
SMS: Requires sender name configured in dashboard settings.
Voice: Caller ID +47 21 53 50 30. Code read twice. Languages: en, no, sv, da, fi.
Email: From-address is your verified domain or no-reply@wayscloud.net. Verify domain via Domain Verification API to use custom from-address.
Request Body:
| Field | Type | Description |
|---|---|---|
channel | string | Verification channel Values: sms, voice, email |
recipient | string | Required. Phone (E.164) or email address |
code_length | integer | Verification code length |
ttl_seconds | integer | Session TTL in seconds |
client_reference | string | Your tracking reference (e.g., signup-123) |
locale | string | Message language Values: en, no, nb, sv, da, fi |
metadata | object | Custom metadata (stored, not processed) |
client_ip | string | End-user IP for risk scoring. If provided, ip_risk is included in response |
Response:
| Field | Type | Description |
|---|---|---|
session_id | string | |
status | string | Values: pending, delivered |
channel | string | Values: sms, voice, email |
expires_at | string | |
created_at | string | |
ip_risk | object | IP risk assessment (only if client_ip provided) |
Example:
curl -X POST https://api.wayscloud.services/v1/verify/start \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'POST /v1/verify/check
Check verification code
Verify the code entered by the user.
Example Request
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"code": "123456",
"client_ip": "203.0.113.42"
}The client_ip is optional. If provided, the response includes ip_risk with threat assessment data.
Error Codes
| Error | HTTP | Meaning | User Action |
|---|---|---|---|
invalid_code | 200 | Wrong code entered | Show remaining attempts |
session_expired | 200 | Session TTL exceeded | Start new verification |
max_attempts_exceeded | 200 | 5 attempts used | Start new verification |
session_not_found | 404 | Invalid session ID | Check session_id |
voice_no_answer | 200 | Voice call not answered | Try SMS or retry |
voice_busy | 200 | Phone line busy | Retry later |
Sessions are automatically locked after 5 failed attempts.
Request Body:
| Field | Type | Description |
|---|---|---|
session_id | string | Required. Session ID from /start response |
code | string | Required. Verification code entered by user |
client_ip | string | End-user IP for risk scoring |
Response:
| Field | Type | Description |
|---|---|---|
status | string | Values: verified, pending, failed, expired |
verified_at | string | |
error | string | Error code if failed |
attempts_remaining | integer | Remaining attempts |
ip_risk | object | IP risk assessment (only if client_ip provided) |
Example:
curl -X POST https://api.wayscloud.services/v1/verify/check \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'GET /v1/verify/status/
Get session status
Get current status of a verification session.
Response Fields
| Field | Description |
|---|---|
session_id | Unique session identifier |
channel | Channel used: sms or voice |
status | Current status |
recipient | Full phone number |
attempt_count | Number of /check attempts made |
max_attempts | Maximum allowed attempts (5) |
client_reference | Your tracking reference |
Status Values
pending- Session created, delivery in progressdelivered- Code sent/played to recipientverified- Successfully verified ✓failed- Max attempts or delivery failedexpired- Session TTL exceededcancelled- Manually cancelled
Response:
| Field | Type | Description |
|---|---|---|
session_id | string | |
channel | string | Values: sms, voice, email |
status | string | Values: pending, delivered, verified, failed, expired, cancelled |
recipient | string | |
created_at | string | |
expires_at | string | |
delivered_at | string | |
verified_at | string | |
attempt_count | integer | |
max_attempts | integer | |
client_reference | string | |
error_message | string | Error details if failed |
Example:
curl https://api.wayscloud.services/v1/verify/status/{session_id} \
-H "X-API-Key: YOUR_API_KEY"DELETE /v1/verify/sessions/
Cancel session
Cancel a pending or delivered verification session. Cannot cancel verified, failed, or expired sessions.
Example:
curl -X DELETE https://api.wayscloud.services/v1/verify/sessions/{session_id} \
-H "X-API-Key: YOUR_API_KEY"