Choose who generates and verifies the OTP
WhatsOS-generated OTP: use the verification flow below. Send your own OTP: your software generates and verifies the code; WhatsOS delivers it using your existing API key and template.
Create your project and key
Open your OTP workspace and select a test project. Create a scoped API key and store the secret on your backend. Test and live projects use separate credentials.
Test delivery is simulated. No WhatsApp message is sent, and the verification code is 123456. Use a fictional number while building your integration.
| Scope | Permission |
|---|---|
otp:send | Create and resend verification codes |
otp:verify | Check a submitted code |
otp:read | Read delivery and verification status |
otp:cancel | Cancel a verification |
Keep API keys out of browser JavaScript, public repositories and mobile binaries. Your application calls your backend; your backend calls WhatsOS.
Open your OTP workspaceSend an OTP
Request a code for the user's phone number. Use an opaque reference to associate the request with the action in your application.
/verificationsotp:sendcurl -X POST 'https://whatsos.com/api/v1/otp/verifications' \
-H 'Authorization: Bearer YOUR_SERVER_API_KEY' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: login-send-001' \
-d '{
"to": "+12025550123",
"purpose": "login",
"reference": "opaque-action-session",
"locale": "en_US"
}'Save the returned verification_id against your server-side action session. A 202 response means the request is queued; it does not mean the message was delivered.
Use a unique idempotency key for each operation. If the request times out, retry with the same key and body. Examples use placeholder credentials and a fictional phone number.
Verify the user's code
Pass the code entered by the user and the verification_id you saved. Use a new idempotency key for this check operation.
/verifications/{id}/checkotp:verifycurl -X POST 'https://whatsos.com/api/v1/otp/verifications/VERIFICATION_ID/check' \
-H 'Authorization: Bearer YOUR_SERVER_API_KEY' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: login-check-001' \
-d '{"code":"123456"}'Require verified: true and status: verified from a successful check. Bind that result to the original recipient, purpose and action session before logging the user in.
A fresh check after consumption returns 409. Retrying the original successful operation returns its recorded result. Your backend must also deduplicate its own login or business action.
Handle status, expiry and resend
Delivery and verification are separate events. Read both statuses to understand the result of an OTP request.
curl 'https://whatsos.com/api/v1/otp/verifications/VERIFICATION_ID' \
-H 'Authorization: Bearer YOUR_SERVER_API_KEY'Tracks message delivery through the provider.
Tracks the verification challenge and its outcome.
| Operation | Endpoint and behavior |
|---|---|
| GET | /verifications/{id}Read status with |
| POST | /verifications/{id}/resendReplace the previous challenge after the 30-second cooldown. Requires |
| POST | /verifications/{id}/cancelInvalidate the challenge. Requires |
Save the new verification_id returned by resend, replacing the previous ID in your server-side action session. Resend and cancel use an empty JSON object and a fresh idempotency key. Codes expire five minutes after creation. Five wrong checks lock a challenge; shared request limits survive resends.
Receive signed events
Add an HTTPS destination under Webhooks in the OTP dashboard. Events report verification success, expiry or lock, and message delivery or failure.
- Read
X-WhatsOS-Timestampand reject timestamps outside a five-minute tolerance. - Compute HMAC-SHA256 over
timestamp + '.' + rawBodyusing your webhook secret. - Prefix the hex digest with
sha256=and compare it withX-WhatsOS-Signatureusing a constant-time comparison. - Deduplicate
X-WhatsOS-Event-Id. Return a 2xx response after durable processing.
Use the original raw request body for signature verification. Callbacks may arrive more than once, retry for up to 24 hours and be replayed after failure. A delivered message is never proof of a verified recipient.
Move from sandbox to live
Complete your sender setup before switching your integration to live credentials.
- Connect your production WhatsApp business number.
- Select an approved authentication template with a Copy code button and five-minute expiry text.
- Complete sender and template readiness checks.
- Activate your subscription and enable the live project when service activation is available.
- Use live API keys and run a controlled test for a recipient who requested the code.
Payment does not complete business onboarding or guarantee template approval. Business app coexistence is available only for eligible numbers. Test keys cannot send through live projects.
REFERENCE
Errors & retries
Inspect the response error code and message. Preserve your operation key when retrying the same request.
| Status | What to check |
|---|---|
400 | Invalid input. Check your request body and headers. |
401 | Invalid or missing API key. |
403 | Scope, quota or setup does not allow this operation. |
404 | The verification was not found in this project. |
409 | State or idempotency conflict. Inspect the returned error. |
429 | Rate limit reached. Honor Retry-After. After a definitive rejection, start a new attempt with a new idempotency key. |
503 | Temporary unavailability. Retry with the same operation key. |
YOUR SERVICE
No transaction charges from WhatsOS.
Your annual licence includes OTP API access, with no additional WhatsOS fee for each OTP transaction. New live requests require a current subscription.
Renewal is manual, with no automatic debit. Existing projects retain their agreed billing terms; your workspace shows the applicable price. See the pricing page for the current package, GST and renewal total.
View current pricingNEXT STEP
Try it in your sandbox.
Create a test key and follow the request examples.