如何在 Twilio OTP 验证被拦截时收到短信通知?
可以实现,但需要自行连接错误监控和短信发送
使用 Twilio Verify 时,可以在后端捕获验证请求的错误,再通过 Programmable Messaging 向自己的手机发送通知。对于请求提交后才出现的失败,还需要补充事件监控。
Twilio 不同通知入口的触发条件和提供的信息各不相同,需要组合使用。仅开启某个通知选项,无法保证所有拦截都逐条发送短信,且每条都包含号码和错误码。
为什么需要区分不同的失败阶段?
你的需求是每次拦截都通知,不限定错误原因,并在通知中带上目标号码和错误码。实现时需要区分以下情况:
- API 立即拒绝请求:后端可以从请求参数取得目标号码,从 Twilio 返回的异常取得错误码。
- 请求受理后发送失败:最初的 API 调用可能成功,需要通过后续事件或日志发现失败。
- 网络超时等结果不明的情况:应用没有收到明确响应,不能直接认定 Twilio 已拦截,也可能没有 Twilio 错误码。
例如,60410 表示验证发送尝试被拦截。Fraud Guard 文档说明,这类拦截会出现在错误日志中。Fraud Guard 自带的是邮件通知,文档没有承诺逐次发送短信并附带号码和错误码。60410 错误说明、Verify Fraud Guard
第一步:在调用 Verify 的后端捕获错误
对于立即返回的错误,后端比较容易同时取得号码和错误码。不要只判断 60410,否则会漏掉其他原因造成的拒绝。
下面的 Node.js 示例会对创建验证请求时的所有异常发送短信,其中也包括参数错误等非拦截异常。因此,短信使用“请求异常”描述,避免误判。
先安装 SDK:
npm install twilio
代码示例:
const twilio = require('twilio');
const client = twilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
async function sendAdminAlert(targetNumber, error) {
const errorCode = error.code ?? '未提供';
return client.messages.create({
from: process.env.TWILIO_ALERT_FROM,
to: process.env.ADMIN_PHONE_NUMBER,
body: [
'Twilio Verify 请求异常',
`目标号码:${targetNumber}`,
`错误码:${errorCode}`
].join('\n')
});
}
async function startVerification(targetNumber) {
try {
return await client.verify.v2
.services(process.env.TWILIO_VERIFY_SERVICE_SID)
.verifications.create({
to: targetNumber,
channel: 'sms'
});
} catch (error) {
try {
await sendAdminAlert(targetNumber, error);
} catch (alertError) {
// 告警失败不能覆盖原始验证错误。
console.error('管理员短信提交失败', {
code: alertError.code ?? null,
message: alertError.message
});
}
throw error;
}
}
module.exports = { startVerification };
环境变量需要分别提供账户凭据、Verify Service SID、管理员手机号,以及用于发送告警短信的发件号码。电话号码使用 E.164 格式;告警发件号码需要具备相应短信发送能力。Verify Service SID 不能直接作为短信的 from。
上述调用方式分别对应官方的 Verifications API 和 Messages API。示例只处理创建验证请求时抛出的异常,不包含异步失败,也没有实现生产环境的持久化队列。
如果业务还调用了 OTP 校验接口,应在该调用入口加入相同的异常采集逻辑。如果只希望通知已确认的拦截,应根据实际错误码及其官方含义筛选,不要把所有异常都归为拦截。
第二步:补充 Twilio 侧的错误和异步事件
使用 Debugging Events Webhook 接收错误日志
Twilio 支持配置 Debugging Events Webhook,将 Debugger 中产生的错误和警告发送到你的后端。后端收到事件后,可以调用同一个短信发送函数。Debugging Events Webhook 文档
处理时需要注意:
- 请求体使用
application/x-www-form-urlencoded,其中的Payload还需要按 JSON 解析。 - 错误码位于解析后的
Payload.error_code。 resource_sid、service_sid可用于识别相关资源。附加信息因事件而异,不能假定每条事件都有目标号码。- 根据事件提供的资源 SID,结合本地保存的请求记录补齐目标号码;无法关联时,应明确标记号码未知。
- 验证
X-Twilio-Signature,并过滤与 Verify 无关的错误,尤其是告警短信自身的发送错误,避免循环告警。
这个入口可以补充已进入 Debugger 的错误,但不能保证所有 Verify 拦截都会产生字段齐全的通知。
使用 Verify Message Status Stream 监控投递失败
对于已经受理、随后发送失败的验证消息,可以通过 Event Streams 配置 Webhook,订阅以下事件:
com.twilio.accountsecurity.verify.message.failed
com.twilio.accountsecurity.verify.message.undelivered
官方 Message Status Stream 的数据包含 to、verification_sid、attempt_sid 和 message_status 等字段。当前列出的字段中没有通用错误码字段,不能假定事件里一定存在 error_code。需要错误码时,应结合能够取得的错误日志进一步关联;没有取得就注明未提供。Message Status Stream 文档
FAILED 和 UNDELIVERED 表示消息发送或投递失败,并不自动等于 Twilio 风控拦截。建议在短信中保留实际事件状态,避免混淆原因。
能否只在控制台配置?
如果只需要按错误数量触发通知,可以考虑 Twilio Alarms。它支持邮件或 Webhook,按指定时间窗口内的错误数量阈值触发;短信仍需由 Webhook 后端发送。它是阈值告警,不能直接视为逐条验证失败通知。Alarms 文档
对于“每次都通知,并带上对应号码和错误码”的要求,优先采用后端采集,再补充 Twilio 事件和日志。
上线前需要处理哪些细节?
- 保存关联记录:调用前保存内部请求 ID 和目标号码,成功后补存 Twilio 返回的 SID,方便关联后续事件。
- 去重与重试:同一次失败可能被 API 异常捕获和 Webhook 同时发现。持久化告警记录并去重,使用队列重试短信发送,避免重复通知或遗漏。
- 保留真实状态:没有错误码时写“未提供”,网络超时写“请求结果未知”,不要自行填入某个拦截错误码。
- 监控告警通道:短信创建成功不等于已经送达。如果告警也依赖同一个 Twilio 账户,账户级故障可能同时影响 OTP 和告警,应保留邮件等备用通知方式。
- 控制短信内容:只包含排查所需的号码、错误码和关联 ID,不发送 OTP、Auth Token 或完整请求内容。告警短信也会产生相应费用。
备注:内容仅供参考。
