Secure Your Users with our multi-channel Verify API
Grow signups and keep accounts safe with one-time passcodes (OTPs) sent to your customers.
Channels: SMS · WhatsApp · Viber · Telegram
If the first channel is slow, we try the next one automatically so fewer people drop off.
*No credit card required. Get free Call & SMS credits on sign‑up.
+1,000 BUSINESSES USE SMS.to FOR THEIR NEEDS
Control Everything in One Place
Set your verification rules once and stay in control. Your team sees what happened in real time with webhooks and logs.

Choose channels and fallback
Pick SMS, WhatsApp, Viber or Telegram and set the order we try.
![]()
Set expiry and code format
Choose how long the code is valid and the length or format that fits your flow.
![]()
Use clear templates and language
Write a short message and select the language your customers expect.
![]()
Adjust per request when needed
Override any default for a test, a new region or a special flow.
We execute your rules in real time and stream events to your webhooks and logs so your team can trace each step.
Who Benefits and How
Why teams trust Verify API for the entire customer journey, from signups to account changes

One place to set your rules
Create a single Verify App to set your defaults. Pick your channel order, expiry time, code length or format, templates and language. Change any of these per request when you need to.
![]()
Smart fallback that saves time and money
If WhatsApp is not installed or fails to deliver, we try SMS. If Viber is blocked, we can try WhatsApp or Telegram.
You only pay for the channel that delivered and a Verify fee when the user verifies.
Many teams start with WhatsApp in high-penetration regions and use SMS as a universal safety net.
![]()
Clear data for your team
See webhooks, logs and charts for every verification. Support can check what happened. Product can see where users drop off. Engineering can tune timeouts and templates.
![]()
Built for both business and dev
Business owners get simple pricing rules and better completion. Developers get clean APIs, SDKs and examples. Everyone gets a faster path to a working 2FA flow.
Suitable for both greenfield projects and established platforms. Whether you’re adding 2FA to a new app or replacing in-house scripts, the verification api provides consistent responses, webhooks, and a dashboard your team can use without a manual.
How SMS.to Verify API works

Initiate a verification
Choose the channel order (for example, WhatsApp → SMS), OTP expiry, code length/format, message template, and locale. Set smart defaults in your Verify App. Change them on any single request for A/B tests, roll out by region, or handle a unique case.

Deliver & observe
We attempt the first channel and track delivery in real time. If delivery doesn’t happen within your timeout, we fall back automatically to the next channel. Your logs show the exact path taken - useful when support asks, “What happened to this user’s code?”

Verify the code
Your user enters the code. You call the verification API to check it. You’ll also receive delivery and verification webhooks, plus searchable logs and charts. The result includes the channel that ultimately delivered, timestamps, and a verification status you can trust in downstream systems.
Best-practice fraud controls
- Add rate limits for user, IP and device.
- Use shorter expiry for risky actions.
- Use Home Location Register (HLR) or Mobile Number Portability (MNP) lookup to keep numbers clean.
- Add a simple human check (like CAPTCHA) on repeat attempts.
Key Features
Multi-channel delivery
(SMS, WhatsApp, Viber, Telegram)
Reach users on the app they open.
Single source of truth
Smart fallback orchestration
Per-request overrides
Client-generated OTP (optional)
Bring your own code; we’ll handle delivery, limits, and verification
Telemetry that matters
Localization & templates
Statistics & charts
Pricing:
What You Pay and When
How billing works
OTT channels (WhatsApp, Viber, Telegram)
You pay the channel fee only if it delivers, and the Verify fee only when the OTP is verified.
SMS
You pay the SMS send fee when we send it, even if it is not delivered.
You pay the Verify fee only when the OTP is verified.
Skipped channels
If a channel is not attempted, you do not pay for it.
Failed delivery
For OTT: no channel fee if it does not deliver.
For SMS: the send fee still applies even if delivery fails.
Experimenting with new channel orders won’t surprise you with extra costs if they don’t deliver.
Examples
- India (WhatsApp delivered) → Pay WhatsApp send + Verify success fee
- Egypt (WhatsApp timed out → SMS delivered) → Pay SMS send + Verify success fee
- Poland (no delivery) → No Verify success fee; skipped/failed channels not charged (except SMS)
- Germany (SMS delivered, user never entered code) → channel fee charged; no success fee
Compare WhatsApp→SMS versus SMS-only for your regions.
Our graphs show your potential savings and completion gains.
If you already use multiple channels, we also show how much you saved
versus SMS-only.
Verify API For Developers
Ship your first OTP in minutes. Use our sms verification api with clear responses and webhook events.
Prefer SDKs? Use Node, Python, PHP, Java, or Go. A Postman collection and a copy‑paste quickstart help you verify the flow quickly.
Note on code samples: The live page shows SMS API examples by default. For exact Verify API endpoints and parameters, follow the Read Docs link.
curl --location 'https://verifyapi.sms.to/api/v1/verifications/create' \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
}'
'https://verifyapi.sms.to/api/v1/verifications/create',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
}',
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer ',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
var https = require('follow-redirects').https;
var fs = require('fs');
var options = {
'method': 'POST',
'hostname': 'verifyapi.sms.to',
'path': '/api/v1/verifications/create',
'headers': {
'Authorization': 'Bearer ',
'Content-Type': 'application/json'
},
'maxRedirects': 20
};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", function (error) {
console.error(error);
});
});
var postData = JSON.stringify({
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
});
req.write(postData);
req.end();
require "uri"
require "json"
require "net/http"
url = URI("https://verifyapi.sms.to/api/v1/verifications/create")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer "
request["Content-Type"] = "application/json"
request.body = JSON.dump({
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
})
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("verifyapi.sms.to")
payload = json.dumps({
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
})
headers = {
'Authorization': 'Bearer ',
'Content-Type': 'application/json'
}
conn.request("POST", "/api/v1/verifications/create", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n \"guid\": \"3-1748345-bcef-0342-6bef5c26-04f64e7\",\n \"recipient\": \"+35799999999999\",\n \"reference\": \"d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0\",\n \"code\": \"123456\",\n \"callback_url\": \"https://abc.sms/message/callback\",\n \"channels\": [\n {\n \"channel\": \"viber\",\n \"sender_id\": \"SMSTO\",\n \"priority\": 1,\n \"expiry_time\": 30\n },\n {\n \"channel\": \"whatsapp\",\n \"priority\": 2,\n \"expiry_time\": 30\n },\n {\n \"channel\": \"sms\",\n \"priority\": 3,\n \"expiry_time\": 30\n }\n ]\n}");
Request request = new Request.Builder()
.url("https://verifyapi.sms.to/api/v1/verifications/create")
.method("POST", body)
.addHeader("Authorization", "Bearer ")
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://verifyapi.sms.to/api/v1/verifications/create"
method := "POST"
payload := strings.NewReader(`{
"guid": "3-1748345-bcef-0342-6bef5c26-04f64e7",
"recipient": "+35799999999999",
"reference": "d36f6c45-2bd3-4eee-b7c1-d9f81e65efb0",
"code": "123456",
"callback_url": "https://abc.sms/message/callback",
"channels": [
{
"channel": "viber",
"sender_id": "SMSTO",
"priority": 1,
"expiry_time": 30
},
{
"channel": "whatsapp",
"priority": 2,
"expiry_time": 30
},
{
"channel": "sms",
"priority": 3,
"expiry_time": 30
}
]
}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Authorization", "Bearer ")
req.Header.Add("Content-Type", "application/json")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
GET API KEY →
What to do with Verify API today

Complete account sign-ups with fewer drop offs
Reduce abandonment with short, localized templates and the channel your audience prefers. A common setup is WhatsApp → SMS for high-penetration markets.
![]()
Protect logins with 2FA
Use short lived codes and stricter limits. Pick the fastest channel first for your users, while keeping them safe.
![]()
Secure high-risk actions
For password resets, payouts, or policy changes, use stricter limits and secure templates. Confirm in a second channel if needed.
![]()
Confirm phone number changes
When users update their number, run a quick verify OTP before you overwrite the primary contact.
Why multi-channel helps: Coverage, cost, and completion.
If the first channel is slow or blocked for a user, we fall back to the next one.
This keeps the journey moving without manual retries.
Seamless Integrations
With Your Favorite Tools
SMS integrations for your preferred platform
Compliance & security
What Our Users Say
Start sending OTPs in minutes
Ready to try the sms verification api?
Start free or book a quick call to map out your channel order and rollout plan.
We can share quick start guidance and sample requests and responses so your team can test end-to-end in your own environment.
Learn how we collect and use your information by visiting our Privacy Notice
FAQ
(Verification API essentials)
It is a simple way to add phone verification to your app. You send a request. We send a one-time code by SMS. You confirm the code with one quick check.
Initiate with your channel order, then call the verify endpoint with the verification_id and the user’s code. Webhooks confirm delivery and success.
Yes. You can supply your own code; we’ll deliver it and handle the verification step.
- OTT channels (WhatsApp, Viber, Telegram): you pay the channel fee only if it delivers, and the Verify fee only when the OTP is verified.
- SMS: you pay the SMS send fee when we send it, even if it is not delivered. You pay the Verify fee only when the OTP is verified.
- Skipped channels: if a channel is not attempted, you do not pay for it.
You only pay for the channel that delivered and a Verify fee when the OTP is successfully verified. Skipped or failed channels are not charged.
We focus on phone verification. For ID documents and KYC, you can use your own provider on your platform.
We make this easy by sending delivery and verification events to your webhooks, so you can trigger KYC checks in the same flow. OTP confirms phone possession. For identity verification or KYC, we can integrate with your existing provider or recommend a partner.
No. If nothing delivers or the code isn’t verified, you don’t pay the Verify success fee.
Absolutely. Many teams verify phone numbers during profile edits, two-step approvals, high-risk transactions, and device pairing.
Yes for SMS and Viber. You can use your own templates and languages. For WhatsApp and Telegram, the channel requires a standard OTP text. We follow those rules and cannot change them. Keep messages short so users spot the code quickly.