PAYATHON 2026

如何在 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 文档

处理时需要注意:

  1. 请求体使用 application/x-www-form-urlencoded,其中的 Payload 还需要按 JSON 解析。
  2. 错误码位于解析后的 Payload.error_code。
  3. resource_sid、service_sid 可用于识别相关资源。附加信息因事件而异,不能假定每条事件都有目标号码。
  4. 根据事件提供的资源 SID,结合本地保存的请求记录补齐目标号码;无法关联时,应明确标记号码未知。
  5. 验证 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 或完整请求内容。告警短信也会产生相应费用。

备注:内容仅供参考。