Verification channels

WhatsApp & Email OTP verification

Verify phone-number or email ownership with secure six-digit one-time passwords. Create an OTP-only key or add these channels to a KYC key.

During API creation choose KYC, WhatsApp OTP only, Email OTP only, or WhatsApp + Email OTP. OTP-only keys cannot call KYC verification endpoints.

Official Meta API only
WhatsApp uses an approved authentication template through Meta's Cloud API. Live sending requires the platform's Meta phone-number ID, access token and approved template. No third-party WhatsApp provider is involved.

WhatsApp: send and verify

POST/v1/phone-verifications
POST/v1/phone-verifications/:id/verify

Use an international E.164 number and a fresh Idempotency-Key for every new OTP request. A same-key retry returns the original request instead of sending another message or charging twice.

send-whatsapp-otp.sh
curl -X POST https://api.okias.io/v1/phone-verifications \
  -H "Authorization: Bearer $OKIAS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+923001234567" }'

A successful live response has status: SENT, an OTP id, an expiry time and credits_charged: 10. SENT means Meta accepted the request—not that the handset delivered or read it.

verify-whatsapp-otp.sh
curl -X POST https://api.okias.io/v1/phone-verifications/$OTP_ID/verify \
  -H "Authorization: Bearer $OKIAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'

Email: send and verify

POST/v1/email-verifications
POST/v1/email-verifications/:id/verify

Email OTP costs 1 credit when the transactional email provider accepts the live message. Verification is free and codes expire after ten minutes.

email-otp.sh
curl -X POST https://api.okias.io/v1/email-verifications \
  -H "Authorization: Bearer $OKIAS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com" }'

# Verify with the returned id
curl -X POST https://api.okias.io/v1/email-verifications/$OTP_ID/verify \
  -H "Authorization: Bearer $OKIAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'

PHP example

Keep the OKIAS key in your server environment—never in browser or mobile-app code.

send-otp.php
<?php
$ch = curl_init('https://api.okias.io/v1/phone-verifications');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('OKIAS_API_KEY'),
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['phone_number' => '+923001234567']),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
if ($status >= 400) {
    throw new RuntimeException($result['error']['message'] ?? 'OTP request failed');
}
$otpId = $result['id'];

Billing and retries

RequestCredits
Live WhatsApp OTP accepted by Meta10
Live Email OTP accepted by the email provider1
Provider rejection or transport failure at send time0
OTP verification or status lookup0
Sandbox OTP0

Live requests reserve the channel price before contacting the provider. Acceptance captures it; initial send failure releases it automatically. A later WhatsApp delivery failure does not reverse an already accepted send.

Sandbox integration
An ok_test_ key never calls Meta or SMTP and never charges credits. Responses include sandbox_otp_code: 123456.

Meta delivery-status webhook

Configure this callback URL in the Meta WhatsApp app to receive sent, delivered, read and delivery-failed updates:

Meta callback URL
https://api.okias.io/v1/webhooks/meta/whatsapp
  • Set a long random WHATSAPP_WEBHOOK_VERIFY_TOKEN in OKIAS and the same value in Meta's Verify Token field.
  • Configure WHATSAPP_APP_SECRET from the Meta app. OKIAS verifies every POST with X-Hub-Signature-256.
  • Subscribe to WhatsApp messages webhook field. Invalid signatures are rejected and raw OTP/message content is not logged.

OTP status responses can progress from SENT to DELIVERED and READ. Duplicate or out-of-order callbacks cannot move a verified OTP backward.

Security controls

  • One request per destination and API key every 60 seconds.
  • Six-digit cryptographically random live codes and a five-attempt limit.
  • WhatsApp codes expire after five minutes; email codes after ten minutes.
  • Plaintext codes and full destinations are not stored in OTP records.
  • OTP records are isolated to the account and API key that created them.
  • Disabled channels return 403 PHONE_VERIFICATION_NOT_ENABLED or 403 EMAIL_VERIFICATION_NOT_ENABLED.

Next steps