Blog
Verification APIs compared for developers
Every verification API follows the same two-call pattern, but they differ in how they authenticate, fall back between channels, report results and let you test. This guide compares them from the code side and shows how to write an integration you can move to another provider later.
Last updated
The pattern every provider shares
Whichever provider you choose, the flow on your server looks like this:
- The user enters a phone number. Your server calls start verification with that number and gets back an identifier for the attempt.
- The provider generates a code and sends it.
- The user types the code. Your server calls check verification with the identifier, or the phone number, and the code.
- The provider answers whether the code is right, wrong, expired or out of attempts.
Your server never generates or stores the code. It keeps only the identifier from step 1, usually for a few minutes in the user's session.
How the main APIs differ
| Start | Check | Fallback between channels | |
|---|---|---|---|
| Twilio Verify | Create a Verification on a Verify Service | Create a Verification Check | Start a new verification on another channel |
| Vonage Verify v2 | Send a request with an ordered workflow of channels | Submit the code for the request ID | Automatic, through the workflow |
| Prelude | POST /v2/verification | POST /v2/verification/check | Automatic, across its routes |
| Plivo Verify | Create a verification session | Validate the code for the session | Voice after SMS |
| Sinch Verification | Start a verification with a method: SMS, flash call, call or data | Report the code or caller ID | You choose the method per request |
| Oxtro | POST /v1/otp/send | POST /v1/otp/verify | None: WhatsApp only |
A few details matter when you write the code.
Twilio Verify
You first create a Verify Service in the console, which holds settings such as code length and the name shown in the message. Every request then names that service. Authentication is HTTP Basic with your account SID and auth token, or an API key. A failed SMS does not switch channels on its own: your code calls start again with channel set to call or whatsapp. See the Verify API reference.
Vonage Verify v2
The start request carries a workflow array, for example WhatsApp then SMS then voice, and Vonage moves down the list until the user completes one. Verify v2 authenticates with a JWT bearer token, not the API key and secret of the older Verify API. Silent authentication, where the user's device opens a check URL over mobile data, must be the first step of a workflow. See the Verify getting started guide.
Prelude
Prelude's v2 API uses a bearer API key and two endpoints. Before sending, it runs a fraud check on each request and may decline to send, so your code needs to handle a blocked outcome as well as success and failure. Prelude publishes a migration guide from Twilio that maps one API onto the other. See the Verify documentation.
Plivo Verify
Plivo sends by SMS with voice as the fallback. Its Fraud Shield blocks suspected SMS pumping and returns error code 452 for blocked messages, which your code should treat as "do not retry". Verify must be enabled on your account first. See the Verify overview.
Sinch Verification
Sinch is built around its mobile SDKs as well as REST. With a flash call, the Android SDK reads the caller ID of the missed call and reports it, so the user types nothing. Data verification goes through the carrier and must be enabled by Sinch. See the Verification API reference.
Oxtro
Oxtro, our product, sends codes on WhatsApp from a number you link to your workspace, and uses a bearer API key with the otp:send and otp:verify scopes. A wrong code returns HTTP 400 with OTP_INVALID, OTP_EXPIRED or OTP_MAX_ATTEMPTS, not 200 with verified: false, so handle those as "not verified". The send endpoint accepts an Idempotency-Key header. See the OTP API reference.
Write the integration so you can switch
Providers change prices, coverage and terms. Keep the provider behind a small interface in your code so that changing it, or using two at once, is a contained change.
type StartResult = { attemptId: string; channel: string };
type CheckResult =
| { status: 'approved' }
| { status: 'wrong_code' | 'expired' | 'too_many_attempts' };
interface Verifier {
start(phone: string): Promise<StartResult>;
check(attemptId: string, code: string): Promise<CheckResult>;
}Each provider gets one adapter that maps its responses onto these few outcomes. Your sign-up and login code only ever sees Verifier. This also makes a fallback provider simple: if start on the first one throws, call the second.
Things to get right regardless of provider
- Normalise phone numbers to E.164 (
+213555123456) before you call any API. Most failed sends are badly formatted numbers. - Rate-limit on your side as well. Cap starts per phone number and per IP address, and put a CAPTCHA or bot check in front of the form. Provider limits protect the provider; yours protect your bill.
- Make starts idempotent. A double-clicked button should not send two codes. Use the provider's idempotency key if it has one, or deduplicate on your side.
- Return the same error for every failure. Do not tell an attacker whether a number exists in your system.
- Expire the attempt identifier with the session. Do not keep it in a URL or local storage.
- Log outcomes, not codes. Record which provider, channel, country and result. That is how you spot a delivery problem or a pumping attack early.
Testing
Use the provider's test credentials or test phone numbers in automated tests, so no real messages are sent and no money is spent. In your own tests, stub the Verifier interface. Before launch, test by hand on real phones in each country you serve.
Which one to pick
If you want the most channels from one vendor, start with Twilio Verify. If you want fallback handled in one request, Vonage. If fraud is your biggest risk, Prelude or Plivo. If you build a native mobile app and want the least typing, Sinch. If your users are on WhatsApp and you want codes to come from your own number, Oxtro. For a less code-focused overview, read the top 5 SMS verification providers.