SMS 验证 API 指南 2026:Twilio, Vonage, MessageBird, Plivo
什么是短信验证 API?
短信验证 API 的作用只有一个:向手机号码发送一次性密码 (OTP),并确认用户是否正确输入。这是表面上的描述。有趣的部分在于其背后的一切。
一个真正的验证 API 处理五件您不想自己构建的事情:
- 运营商路由。 不同国家通过不同的运营商路由短信,每个运营商都有自己的延迟、失败率和成本。
- 限流和欺诈检测。 一个好的 API 会在明显的滥用模式(同一 IP 请求 200 个验证码、连续的手机号码、已知的临时运营商)影响您的账单之前将其阻止。
- 国家合规性。 印度需要 DLT 注册。法国会阻止字母数字发件人 ID。德国有自己的发件人 ID 规则。API 会为您处理这些。
- 验证码生成和验证。 一些 API 允许您自带验证码。其他 API 则在它们的服务器上生成和验证验证码,这可以从您的代码库中消除一类定时攻击。
- 用于状态更新的网络钩子。 当消息被拒收时,您需要在几秒钟内知道,而不是等到用户抱怨。
三个主要用途是:注册时的 OTP 交付、登录时的双因素身份验证以及高风险交易确认。大多数团队对这三者使用相同的 API。一些较大的团队会将其分散到不同的提供商以实现冗余,我们稍后会讨论这一点。
为什么使用专用的短信验证 API?
您可以自己构建。我们不会假装不是这样。您可以与运营商聚合商签订直接合同,设置自己的 SMPP 网关,并自行编写验证码生成器。我们见过团队这样做。我们也见过这些团队在十八个月后悄悄地迁移到 Twilio。
以下是为什么大多数团队付费使用托管 API 的原因:
运营商关系比代码更重要。 Twilio 与全球数百家运营商有直接的合作关系。Vonage (前身为 Nexmo) 自 2010 年以来一直在做这件事。这些关系需要真金白银,并且需要数年时间来建立。您无法在周末复制它们。
欺诈是一个不断变化的靶子。 通话欺诈攻击(也称为短信泵浦)每季度给真实企业造成数十万美元的损失。模式是:攻击者利用您的注册表单向低量国家的付费号码发送验证码,然后运营商将短信成本的一部分返还给攻击者。主要的 API 花费了数年时间来调整对此的检测。
合规性是您无法忽视的税。 仅印度的 DLT 注册就需要数周时间,并且需要当地的法律实体。如果您有任何法国用户,法国的 CNIL 规则将适用。API 提供商会为您处理这些,即使您没有意识到。
交付质量取决于热线。 “热线”是一种高优先级运营商路径,可在五秒内发送消息。冷线可能需要几分钟或静默失败。通过 API 购买热线访问权限比直接协商要便宜得多。
因此,除非您每月处理超过一百万次验证并且拥有专门的基础设施团队,否则数学表明:使用 API。问题是哪个。
2026 年排名前 5 的短信验证 API
我们针对每个提供商进行了相同的测试流程:向美国、印度、德国和巴西的号码发送 OTP,然后在我们的后端验证验证码。我们在 2026 年 3 月的 30 天窗口内,每个提供商、每个国家进行了 100 次验证。以下是我们发现的结果。
1. Twilio Verify
Twilio 是默认选择是有原因的。他们的 Verify API 是专门为 OTP 流程设计的,独立于其通用的可编程消息 API。这种分离很重要,因为它为您提供了固定的每次验证价格,而不是按每条出站短信加上每条入站网络钩子付费。
每次验证定价: 每次成功验证 0.05 美元(美国),国际上 0.07-0.20 美元,某些国家/地区还需支付运营商费用。这是大多数开发者关心的价格。
我们喜欢的地方: SDK 的人体工程学无与伦比。他们的文档是黄金标准。通道回退(短信到语音到电子邮件)开箱即用。在我们的测试窗口期间,他们的欺诈检测捕获了两次短信泵浦尝试,而无需我们进行任何配置。
我们不喜欢的地方: 国际线路上的价格上涨。印度、印度尼西亚和巴西的成本明显高于宣传的价格。在某些市场,运营商费用可能会使您的账单翻倍。
最适合: 美国流量为主的客户,重视文档的团队,任何需要语音回退的用户。
2. Vonage Verify (原 Nexmo)
Vonage 在这个领域的时间比几乎任何人都长。他们的 Verify API 非常成熟,文档齐全,并且包含服务器上的内置 PIN 码检查。您无需在数据库中存储 OTP,这可以从您的安全模型中消除一类存储攻击。
每次验证定价: 每次成功验证 0.062 美元(美国),国际上也有类似的阶梯定价。在大多数我们测试过的市场中,他们的定价比 Twilio 更接近固定价格。
我们喜欢的地方: 双因素结账流程干净利落。他们包含三次重试尝试在同一验证费用内,而 Twilio 不包含。他们的支持团队确实会回答技术问题。
我们不喜欢的地方: 他们的仪表板看起来像是 2018 年最后一次重新设计。Node.js SDK 在 Promise 拒绝方面存在一些粗糙之处。网络钩子签名在 2024 年初不一致,但现在似乎已修复。
最适合: 希望获得固定国际费率且不想自行管理 OTP 存储的团队。
3. MessageBird (现为 Bird)
MessageBird 在 2023 年更名为 Bird,并重建了其开发者平台。新的 API 更简洁,但也是一个不断变化的目标。在我们的测试期间,我们遇到了两次重大更改。
每次验证定价: 根据国家/地区,每次验证 0.04-0.08 美元。纸面上是最便宜的选择之一。
我们喜欢的地方: 他们的 Flow Builder 允许非技术团队成员在不重新部署的情况下调整验证流程。欧洲运营商线路非常出色(他们最初是一家荷兰公司)。我们审计过的 GDPR 策略是最彻底的。
我们不喜欢的地方: 自更名以来,API 的稳定性一直很差。文档在某些地方落后于实际 API。一些旧的端点已被弃用,但没有明确的迁移路径。
最适合: 欧盟流量为主的客户,需要开箱即用的 GDPR 友好默认设置的团队。
4. Plivo
Plivo 将自己定位为 Twilio 的经济实惠替代品,具有类似的功能集。在我们的测试中,这大致是准确的,尽管存在一些实际的权衡。
每次验证定价: 每次验证 0.045 美元(美国),国际上为分级费率。通常是高流量的最便宜选择。
我们喜欢的地方: 对于大多数美国和欧盟流量,价格确实比 Twilio 低。他们的余额系统很干净。他们的支持团队在工作时间内一小时内回复。API 设计几乎是 Twilio 的克隆,这使得迁移几乎无痛。
我们不喜欢的地方: 在我们的测试中,印度和巴西的交付率明显低于 Twilio。他们的欺诈检测捕获的明显攻击较少。验证 API 比其他 API 年轻,因此仍然会出现一些边缘情况。
最适合: 对成本敏感且流量主要在美国或欧盟的团队。
5. Sinch
Sinch 是企业级选项。他们收购了 Inteliquent、MessageMedia 和其他几家运营商,这使他们在其他所有人都支付高价的市场中拥有直接线路。他们的定价反映了这种定位。
每次验证定价: 定制企业定价,通常根据数量承诺,每次验证 0.04-0.10 美元。在没有销售电话的情况下很难评估。
我们喜欢的地方: 运营商关系是真实的。印度的交付率是我们测得的最好的。在我们的测试中,他们的语音回退质量优于 Twilio。
我们不喜欢的地方: 没有透明的定价。自助注册比竞争对手更粗糙。他们的 API 比其他 API 有更多的遗留问题。
最适合: 具有高流量且有耐心进行谈判的企业团队。
短信验证 API 定价比较
以下是典型的 2026 年费率的并排比较。所有价格均为每次成功验证(美国线路),截至 2026 年 4 月 1 日。国际费率因国家/地区而异。
| 提供商 | 美国费率 | 欧盟平均 | 印度 | 巴西 | 最低充值 |
|---|---|---|---|---|---|
| Twilio Verify | $0.05 | $0.07 | $0.18 | $0.14 | $20 |
| Vonage Verify | $0.062 | $0.075 | $0.16 | $0.13 | $10 |
| Bird (MessageBird) | $0.04 | $0.06 | $0.20 | $0.15 | $20 |
| Plivo | $0.045 | $0.065 | $0.22 | $0.17 | $25 |
| Sinch | $0.04-$0.10 | 因情况而异 | $0.11 | $0.12 | 企业级 |
需要注意两点。首先,宣传的美国费率本身具有误导性。如果您有任何有意义的国际流量,国家/地区的特定费率比美国价格更重要。其次,印度和巴西的定价差异很大。如果您以这两个市场为目标,请在承诺之前进行自己的测试。
对于每月处理 100,000 次验证、其中 60% 为美国、30% 为欧盟、10% 为世界其他地区的团队来说,实际月成本在 5,200 美元到 7,800 美元之间,具体取决于您选择的提供商。一旦包含失败率,最便宜的选项并不总是总成本最低的。
代码示例:发送 OTP
以下是三种语言中三个提供商的相同工作流程。它们的结构足够相似,通常可以通过更改端点 URL 和参数名称在它们之间移植代码。
Node.js 与 Twilio Verify
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const verifyServiceSid = process.env.TWILIO_VERIFY_SERVICE_SID;
const client = require('twilio')(accountSid, authToken);
async function sendVerification(phoneNumber) {
try {
const verification = await client.verify.v2
.services(verifyServiceSid)
.verifications
.create({ to: phoneNumber, channel: 'sms' });
return { success: true, status: verification.status };
} catch (error) {
console.error('Twilio verification failed:', error.message);
return { success: false, error: error.message };
}
}
async function checkVerification(phoneNumber, code) {
const result = await client.verify.v2
.services(verifyServiceSid)
.verificationChecks
.create({ to: phoneNumber, code });
return result.status === 'approved';
}
关于此代码的一些说明。verifyServiceSid 在 Twilio 控制台中创建一次,并用于每次验证。状态字段返回 pending、approved、canceled 或 failed。显式处理每一种。不要假设 success 意味着 approved。
Python 与 Vonage Verify
import os
import vonage
client = vonage.Client(
key=os.environ['VONAGE_API_KEY'],
secret=os.environ['VONAGE_API_SECRET']
)
verify = vonage.Verify(client)
def send_verification(phone_number, brand_name='YourApp'):
response = verify.start_verification(
number=phone_number,
brand=brand_name,
code_length=6,
pin_expiry=300
)
if response['status'] == '0':
return {'success': True, 'request_id': response['request_id']}
return {'success': False, 'error': response.get('error_text')}
def check_verification(request_id, code):
response = verify.check(request_id, code=code)
return response['status'] == '0'
Vonage 使用 request_id 作为验证句柄,而不是手机号码。将其与用户记录一起存储在您的会话或数据库中。pin_expiry 以秒为单位;我们使用 300(5 分钟),这与大多数应用程序向用户显示的相符。
PHP cURL 与 MessageBird (Bird)
<?php
$accessKey = getenv('BIRD_ACCESS_KEY');
$workspaceId = getenv('BIRD_WORKSPACE_ID');
function sendVerification($phoneNumber) {
global $accessKey, $workspaceId;
$url = "https://nest.messagebird.com/workspaces/{$workspaceId}/channels/sms/verify";
$payload = json_encode([
'recipient' => $phoneNumber,
'codeLength' => 6,
'expiry' => 300
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: AccessKey ' . $accessKey,
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($statusCode === 201) {
return ['success' => true, 'data' => json_decode($response, true)];
}
return ['success' => false, 'error' => $response];
}
Bird API 需要工作区 ID 作为 URL 路径,这是从旧的 MessageBird 端点最近的一次更改。如果您从旧版 API 迁移,这是最常见的陷阱。
用于交付状态的网络钩子设置
发送 OTP 是工作的一半。另一半是知道它是否真的送达了。每个主要的 API 都支持用于交付状态的网络钩子,但实现细节有所不同。
以下是一个通用的 Express.js 网络钩子处理程序,可作为任何提供商的起点:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/sms-status', express.json(), (req, res) => {
const signature = req.headers['x-provider-signature'];
const expectedSignature = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expectedSignature) {
return res.status(401).send('Invalid signature');
}
const { messageId, status, errorCode, phoneNumber } = req.body;
switch (status) {
case 'delivered':
logSuccess(messageId);
break;
case 'failed':
handleFailure(messageId, errorCode, phoneNumber);
break;
case 'undelivered':
retryWithFallbackChannel(phoneNumber);
break;
default:
console.log(`Unhandled status: ${status}`);
}
res.status(200).send('OK');
});
我们在生产环境中使用网络钩子时遵循一些规则。始终验证签名;未经身份验证的网络钩子端点是一个敞开的大门。始终快速返回 200,即使您的处理需要更长时间;将实际工作排队到后台作业中。幂等性很重要,因为提供商会在超时时重试。
速率限制和重试策略
速率限制是大多数团队受挫的地方。这是我们使用的模式。
每个手机号码的速率限制。 在任何 10 分钟内,同一手机号码最多发送 3 次 OTP。这可以阻止意外的请求循环和大多数随意滥用。
每个 IP 的速率限制。 在任何 5 分钟内,同一 IP 最多发送 10 次 OTP 请求。足够宽松,不会破坏共享办公室,足够严格,可以减缓注册机器人。
每个账户的速率限制。 如果一个用户账户在 24 小时内有超过 5 次验证失败,则锁定该账户并要求通过电子邮件重置。这是我们交付的最有效的防滥用措施。
重试时的指数退避。 如果 API 返回 5xx 错误,请在 1 秒后重试一次,然后在 4 秒后重试一次,然后放弃。不要重试 4xx 错误;它们几乎总是永久性的。
以下是实际情况:
async function sendWithRetry(phoneNumber, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const result = await sendVerification(phoneNumber);
if (result.success) return result;
if (result.statusCode >= 400 && result.statusCode < 500) {
return result;
}
} catch (error) {
if (attempt === maxAttempts) throw error;
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
错误处理:交付失败和国家/地区禁令
每个短信 API 返回错误的格式略有不同,但常见的失败模式是普遍的。以下是如何处理它们。
无效的手机号码格式。 立即将错误返回给用户。不要重试。不要浪费 API 积分。
号码处于“请勿打扰”列表。 用户运营商已将该号码标记为已选择退出营销短信。一些 API 允许您将消息标记为交易性以绕过此限制;其他则需要运营商手动干预。实际上,回退到电子邮件或语音通道。
国家/地区受限。 一些国家/地区(古巴、伊朗、朝鲜、克里米亚部分地区)在制裁名单上。您的 API 将拒绝发送。在注册时检测到此情况,并将用户引导至电子邮件验证。
运营商过滤。 运营商静默丢弃了消息。您将收不到交付回执。在验证尝试上设置 90 秒超时;如果未收到验证码,请提示用户重试或切换通道。
余额不足。 您的预付费信用已用完。在余额剩余 20% 时设置警报,而不是在零时。我们以痛苦的方式学到了这一点。
成本优化策略
一旦您达到实际流量,每次验证的成本就会成为一个真实的条目。以下是我们行之有效的策略。
缓存成功的验证。 如果用户在 30 天前验证了他们的手机号码,现在只是重新登录,您不需要新的 OTP。使用长期有效的身份验证令牌,仅在可疑活动时重新验证。
在成本较高的市场使用语音回退。 在某些地区(尤其是非洲和中东部分地区),语音验证可能比短信便宜。为每个国家/地区配置通道偏好。
运行多提供商故障转移。 一个主提供商和一个次要提供商。如果主提供商返回错误或在 30 秒内未交付,则使用次要提供商重试。成本开销很小,成功率提升是真实的。我们在测试市场中测量了 4-6% 的提升。
尽早协商批量定价。 大多数提供商从每月约 10,000 次验证开始提供批量折扣。折扣很少宣传。去问问。
阻止您不服务的付费国家/地区。 在您的注册表单上设置国家/地区允许列表。如果您是仅限美国的产品的,阻止 200 多个国家/地区是免费的欺诈减少。短信泵浦攻击利用了这个漏洞。
值得了解的 Twilio Verify 替代方案
我们上面重点介绍了五大巨头,因为它们是最常被问到的。但短信验证市场比人们意识到的要提供更多选择,其中一些根据您的用例值得再次考虑。
对于开发者友好的免费套餐,可以尝试 Termii(非常适合非洲市场)或 Telnyx(以美国为主,具有运营商级路由)。对于纯粹的 API 简单性,Authy(现为 Twilio 的一部分)仍然是最简洁的仅限 2FA 的选项。对于自托管,Apache APISIX 有一个验证插件,可与大多数主要的短信网关配合使用。
对于面向消费者的虚拟号码,VerifySMS 是我们构建的。我们不是 API;我们是一款 iOS 应用,适用于需要手机号码接收验证码而无需暴露真实号码的用户。如果您正在构建一个身份验证流程,而您的用户不断抱怨提供他们的个人号码,请将我们的链接发送给他们。
您应该自己构建短信验证吗?
我们大约每季度都会收到高级工程师的这个问题。答案几乎总是“否”,但这是诚实的版本。
如果您应该自己构建:您有一个专门的基础设施团队,您每月处理超过 500 万次验证,您在至少三个目标市场拥有直接的运营商关系,并且您拥有处理您运营的每个司法管辖区的合规性的法律资源。否则,数学就不成立。
自己构建的隐藏成本是合规性维护、欺诈检测调整以及 24/7 运营商升级。这至少需要三名工程师。每位工程师的综合成本为 20 万美元,在发送第一条短信之前,纯粹的开销为每年 60 万美元。与 Twilio 的盈亏平衡点大约在每月 5 万美元的 API 支出。
常见问题解答
短信验证 API 和短信网关有什么区别?
短信网关向手机号码发送通用短信。验证 API 是一种更高级别的服务,它在短信网关之上处理 OTP 生成、验证、重试逻辑和欺诈检测。您可以使用网关进行验证,但需要自己构建 OTP 层。
我可以在不破坏用户流程的情况下切换短信验证提供商吗?
是的,但要计划一个过渡期。最干净的方法是将提供商抽象到您自己的内部 API 之后,这样您的面向用户的代码只知道您的验证服务,而不了解底层提供商。我们通过这样做,在零用户可见停机的情况下,在 Twilio 和 Vonage 之间迁移了生产流量。
如何防止我的注册表单遭受短信泵浦攻击?
三件事:阻止来自您不服务的国家的注册,按 IP 和手机号码进行速率限制,并为新用户在手机号码输入字段上实现 CAPTCHA。这种组合可以消除 95% 以上的泵浦攻击。如果您已经受到攻击,请立即升级到您的提供商的欺诈团队;他们可以在几小时内将目标运营商列入黑名单。
如果我的用户有身份验证器应用程序,我还需要短信 API 吗?
对于大多数产品来说,是的。短信仍然是新用户摩擦最低的第二因素,而且许多用户没有安装身份验证器应用程序。有效的模式是:在注册时提供短信验证以降低摩擦,然后在用户第一周内提示用户升级到身份验证器应用程序或通行密钥。短信成为账户恢复的后备。
如果验证码在我的过期窗口之后到达会怎样?
API 将在验证检查时拒绝迟到的验证码。用户需要请求新的验证码。我们将过期时间设置为 5 分钟,这对于大多数用户找到手机来说足够长,并且足够短以限制重放攻击。如果您设置的时间太长(超过 15 分钟),则会带来真正的安全风险;如果您设置的时间太短(少于 90 秒),您的支持工单将激增。
如何在不花费真实验证码的情况下在我的 CI 流水线中测试短信验证?
每个主要的 API 都有沙盒或测试模式。Twilio 有一个神奇的测试手机号码,始终返回成功。Vonage 在验证调用中有一个测试模式标志。Bird 有一个沙盒工作区。在 CI 中使用这些;切勿在自动化测试中对生产号码运行真实验证。
底线
如果您想要最简单的解决方案且您的流量以美国为主,请选择 Twilio Verify。如果您想要固定的国际定价和服务器端 OTP 存储,请选择 Vonage。如果您专注于欧盟且关心 GDPR 默认设置,请选择 Bird。如果您对价格敏感且流量主要在美国或欧盟,请选择 Plivo。如果您是企业级用户且有耐心进行谈判,请选择 Sinch。
如果您正在构建面向消费者的身份验证,而您的用户不断询问如何验证账户而无需提供他们的个人手机号码,那么这就是 VerifySMS 填补的空白。我们不与上述 API 竞争;我们处于方程的另一端,为您的用户提供一个干净的手机号码来接收您的验证码。
无论您选择哪条路线,首先要做的是针对您的实际流量组合运行一个 30 天的测量窗口。宣传价格是最容易比较的数字,也是总成本最差的预测指标。最适合您的提供商是在您的真实市场中成功率最高的提供商,而不是标价最低的。
构建一次,每月测量一次,并每十二个月重新评估一次选择。短信市场变化的速度比大多数人意识到的要快。
