Skip to main content
This guide walks you through the complete OTP flow — from obtaining your API key to sending a code and verifying it — using nothing but curl. By the end, you’ll have made real API calls and understand the shape of every response you’ll encounter in production.
The OTP code itself is never returned in API responses — it’s delivered directly to the user through the chosen channel.
1

Get your API key

Every request to the OTP.ID API must include a Bearer API key. To obtain yours:
  1. Log in to your dashboard at https://otp.id.
  2. Navigate to Settings → API Keys.
  3. Copy your key — you’ll pass it in the Authorization header of every request.
Your API key looks like this: otpid_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeep it secret. Never commit it to source control or expose it in client-side code.
2

Send an OTP via WhatsApp

Call POST /v3/request to have OTP.ID generate a code and deliver it to your user over WhatsApp. Pass the destination number in E.164 format (digits only, no + prefix) and a brand name that will appear in the message.
A successful response looks like this:
Save the otp_id — you’ll need it in the next two steps. The expires_at field tells you when the code stops being valid. price is the amount deducted from your balance (in the smallest currency unit), and last_balance is your remaining prepaid balance after this send.
Pass an external_id field in your request body to make sends safely retriable. If you call POST /v3/request again with the same external_id, OTP.ID returns the original OTP record instead of creating a duplicate. See the idempotency guide for details.
3

Verify the OTP

Once your user submits the code they received, call POST /v3/verify with the otp_id from the previous step and the code the user entered.
Successful verification — the code matches:
Code mismatch — the user entered the wrong code:
A mismatch returns HTTP 200 with verified: false — it is a valid, expected outcome, not an API error. Only check data.verified to decide whether to grant access.
Other possible values for reason include "expired" (the OTP window has passed) and "already_verified" (the code was already used).
4

Check transaction status

For polling-based flows — or when you want to inspect a past OTP record — call GET /v3/otp/{otp_id} with the OTP’s ID.
The response includes the full OTP record with its current status:
Common status values are sent, delivered, verified, expired, and failed. For real-time notifications without polling, configure an otp.verified webhook in your dashboard instead.

Next Steps

You’ve completed the full OTP flow. Here’s where to go deeper:
  • Authentication — understand API key scoping and how to handle auth errors.
  • Channels — learn when to use SMS, Email, Missed Call, or WhatsApp Inbound instead of WhatsApp outbound.
  • Webhooks — set up the otp.verified event to receive async verification results.
  • API Reference — see the full schema for every request and response field.