Verification API
OTP verification via WhatsApp/email and magic link verification with HMAC-SHA256 security.
Overview
The Verification API provides OTP-based and magic link verification for your users. It supports verification via WhatsApp and email channels, with fraud prevention and rate limiting built in.
Base URL
https://api.wacm.inAuthentication
The Verification API uses a custom API key authentication system with optional HMAC-SHA256 signature verification.
Required Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
| X-Public-Key | string | Required | Your API public key (can also be sent as ?public_key= query param) |
| X-Signature | string | Optional | HMAC-SHA256 signature (base64-encoded). Optional but recommended. |
| X-Timestamp | string | Optional | Unix epoch timestamp (required when X-Signature is provided). Must be within 5 minutes of server time. |
HMAC Signature Calculation
To compute the signature, construct a payload string and sign it with your API secret key:
const crypto = require('crypto');
function computeSignature(timestamp, method, path, body, secretKey) {
const payload = `${timestamp}.${method}.${path}.${body}`;
return crypto
.createHmac('sha256', secretKey)
.update(payload)
.digest('base64');
}
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = computeSignature(timestamp, 'POST', 'v1/verification/request', requestBody, secretKey);$timestamp = time();
$payload = $timestamp . '.' . $method . '.' . $path . '.' . $body;
$signature = base64_encode(hash_hmac('sha256', $payload, $secretKey, true));Security Note
The timestamp tolerance is 300 seconds (5 minutes). Requests with timestamps older than 5 minutes will be rejected. Always include the X-Signature and X-Timestamp headers for production use.
Request Verification
Initiate a verification request. This sends an OTP via the specified channel (WhatsApp or email) and returns a request_id for subsequent verification.
/v1/verification/requestRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| profile_id | string (UUID) | Required | UUID of the verification profile to use |
| identifier | string | Required | Phone number or email to verify |
| channel | string | Required | <code>whatsapp</code> or <code>email</code> |
| purpose | string | Required | Purpose code (1-50 chars, e.g., "LOGIN", "SIGNUP") |
| trust_key | string | Optional | Optional trust key (e.g., session ID, device ID) |
| captcha_token | string | Optional | CAPTCHA verification token |
| silent | boolean | Optional | Silent verification mode (no OTP sent) |
curl -X POST https://api.wacm.in/v1/verification/request \
-H "X-Public-Key: YOUR_PUBLIC_KEY" \
-H "X-Signature: COMPUTED_SIGNATURE" \
-H "X-Timestamp: 1721000000" \
-H "Content-Type: application/json" \
-d '{
"profile_id": "550e8400-e29b-41d4-a716-446655440000",
"identifier": "+1234567890",
"channel": "whatsapp",
"purpose": "LOGIN"
}'Response
{
"request_id": "660e8400-e29b-41d4-a716-446655440001",
"status": "pending",
"expires_at": "2026-07-14T10:15:00.000000Z"
}Note
The otp and magic_link fields are stripped from the response for security. The OTP is sent to the user via the specified channel.
Verify Code
Submit the OTP code received by the user to verify the request.
/v1/verification/verifyRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | Required | The request_id from the request verification step |
| code | string | Required | The OTP code entered by the user |
curl -X POST https://api.wacm.in/v1/verification/verify \
-H "X-Public-Key: YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_id": "660e8400-e29b-41d4-a716-446655440001",
"code": "123456"
}'Response
{
"verified": true,
"request_id": "660e8400-e29b-41d4-a716-446655440001",
"trust_key": "session_abc123",
"identifier": "+1234567890",
"channel": "whatsapp",
"verified_at": "2026-07-14T10:05:00.000000Z"
}{
"verified": false,
"request_id": "660e8400-e29b-41d4-a716-446655440001"
}Check Status
Check the current status of a verification request. Useful for polling verification status in real-time applications.
/v1/verification/status/{request_id}curl -H "X-Public-Key: YOUR_PUBLIC_KEY" \
https://api.wacm.in/v1/verification/status/660e8400-e29b-41d4-a716-446655440001Response
{
"status": "pending"
}{
"status": "verified",
"trust_key": "session_abc123",
"identifier": "+1234567890",
"channel": "whatsapp",
"verified_at": "2026-07-14T10:05:00.000000Z"
}Resend Code
Resend the OTP code for a pending verification request. The request must not have expired.
/v1/verification/resendRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | Required | The request_id to resend the code for |
curl -X POST https://api.wacm.in/v1/verification/resend \
-H "X-Public-Key: YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_id": "660e8400-e29b-41d4-a716-446655440001"
}'Response
{
"success": true,
"message": "Resend initiated"
}Magic Link Verification
Magic links allow users to verify by clicking a URL instead of entering an OTP. This endpoint is called when the user clicks the magic link in their email.
/v1/verification/magic/{request_id}/{token}Rate Limit
This endpoint is rate-limited to 10 requests per minute (no API key required).
On success, returns an HTML page with a success message. On failure, returns an HTML page with an error. The magic link token is verified against the pending verification request.
Data Model
VerificationProfile
Central entity that configures verification behavior. Has many API keys, templates, webhooks, and whitelists.
| Parameter | Type | Required | Description |
|---|---|---|---|
| uuid | string (UUID) | Optional | Auto-generated unique identifier (used as profile_id) |
| settings_json | object | Optional | Profile-specific settings (OTP length, expiry, etc.) |
VerificationApiKey
Stores API key pairs for authentication. Each key is scoped to a company and profile.
| Parameter | Type | Required | Description |
|---|---|---|---|
| public_key | string | Required | Public key used for authentication (X-Public-Key header) |
| secret_key | string | Required | Secret key used for HMAC signature computation |
| status | string | Required | <code>active</code> or <code>inactive</code> |
VerificationRequest
Tracks individual verification attempts with status, expiry, and metadata.
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | Required | Unique identifier for this verification request |
| status | string | Required | <code>pending</code>, <code>verified</code>, <code>expired</code>, <code>failed</code>, <code>blocked</code> |
| expires_at | datetime | Required | When the verification request expires |
| verified_at | datetime | Optional | When the code was successfully verified |
| metadata_json | object | Optional | Request metadata (IP, user agent, etc.) |
Error Responses
{
"error": "Validation failed",
"details": {
"profile_id": ["The selected profile id is invalid."],
"channel": ["The selected channel is invalid."]
}
}{
"error": "Too many verification attempts. Please try again later."
}Flowmaker Integration
The Verification API integrates with the AI Flow Builder through dedicated node types:
- Request Verification — Initiate verification from within a flow
- Verify Code — Verify a code submitted by the user
- Verification Status — Check the status of a verification request
See the AI Flow Builder documentation for details on using verification nodes in flows.
Related Endpoints
- Contacts API — Manage contacts that can be verified
- WhatsApp Business API — Send OTP via WhatsApp
- AI Flow Builder — Build verification flows visually