这个号码开通了 WhatsApp 吗?注册时的电话检查能说明什么、不能说明什么
有一个公开问题问道:在通过 WhatsApp Cloud API 发送消息之前,如何判断一个电话号码是否开通了 WhatsApp。我们无法代表该平台作答,也不代表提问者,本文内容也不会改变 WhatsApp 的任何行为。对小型 B2B 团队而言,与之相邻的决策范围更窄:当注册表单收集到一个号码时,在尝试通过任何渠道联系这个号码之前,你的应用究竟可以得出什么结论?本文运行经过检查的四分支合成电话示例,说明它的任何输出都无法证明号码在某个消息应用中存在、能够触达,或归填写者所有,并提出代码应如何为每种结果安排后续路由。
curl https://gridzen.ai/console/api/quickstart/trial \
-H 'Content-Type: application/json' \
-d '{"task": "signup_phone", "scenario": "success"}'问题与你需要做的决策
你的团队想给新用户发送引导消息,于是有人提议在注册阶段过滤掉没有开通 WhatsApp 的号码。一种很有诱惑力的设计是:调用电话检查,把通过视为“可以通过 WhatsApp 触达”,其他任何结果都作为拒绝用户的理由。这种设计把三个问题混为一谈:号码格式是否正确、是否有效?它可能属于哪种线路类型?某个具体的消息应用能否把消息送达填写号码的人?电话检查最多只能回答前两个问题。某个消息服务能否送达,只能通过该渠道本身、依照其公开文档中的规则来了解,而且通常要等到实际尝试投递时才能知道。 因此,真正要做的决策不是“如何用电话检查识别 WhatsApp”,而是注册流程应如何处理每一种电话检查结果,以及针对特定渠道的投递尝试应放在流程中的哪个位置。这套路由属于拟议的应用设计。下文介绍的 fixture 只演示这套路由必须处理的输入和输出。
已检查示例实际实现了什么
可下载的示例在 Python 3.10 及以上版本中离线运行,不需要凭据,也不发起任何网络调用。其中的 phone 任务只接收一个输入 branch,返回以下字段:mode、branch、state、valid、line_type、next、otp_sent 和 live_line_type_available。在所有分支中,mode 都是 synthetic_fixture,otp_sent 都是 false,live_line_type_available 也都是 false。 输出中没有任何关于 WhatsApp 或其他消息应用的字段,也没有可触达性或号码归属的字段。normal 分支中 line_type 的值 mobile 只是模拟数据。当前免费的 Basic Lookup 路由不请求线路类型,也不检查号码归属、可触达性或 OTP 投递。即使线路类型确实是 mobile,也不代表该号码已在某个应用中注册。请不要把这个四分支示例与另一个独立的匿名 HTTP 试用混淆,后者只包含三个场景。
假设场景与预期的 fixture 输出
假设:某团队的注册表单收到四个号码。开发者在接触任何真实服务之前,把每个号码映射到一个分支,用来测试路由逻辑。 normal 分支返回 state 为 simulated,valid 为 true,line_type 为 mobile,next 为 continue_customer_policy。建议处理方式:把号码作为联系字段接受,由你自己的策略决定之后是否尝试发送消息。不要把该用户标记为“可通过 WhatsApp 触达”。 unknown 分支返回 state 为 unknown,valid 为 null,line_type 为 null,next 为 review_or_existing_otp。建议处理方式:不要拒绝用户,而是转入人工审核,或使用你已经在运行的 OTP 流程。 provider_failure 分支返回 state 为 unknown,valid 为 null,line_type 为 null,next 为 bounded_retry_then_review。建议处理方式:按固定的较少次数重试,之后转入审核。永远不要无限期地阻塞注册。 otp 分支返回 state 为 unsupported,valid 为 null,line_type 为 null,next 为 customer_otp_provider。建议处理方式:交给你现有的 OTP 服务商。fixture 本身不会发送任何验证码,otp_sent 始终为 false。
渠道投递尝试应放在哪里
如果业务目标是通过某个具体应用给用户发消息,应把投递当作之后单独进行的一步,遵循该平台的文档、同意要求和响应处理方式。把投递结果记录为独立的状态,例如根据渠道的反馈记为已尝试、已送达或失败,并与电话检查的字段分开保存。投递失败不应把 valid 改写为 false,号码有效也不应被存成“已开通 WhatsApp”。把这些状态分开,才能让之后回退到短信、邮件或人工审核的过程清晰明确、可以测试。以上是设计建议,fixture 并没有实现或测试任何消息渠道。
你的代码必须负责的失败处理
fixture 只给出下一步的名称,执行这些步骤是调用方的职责。传入无法识别的分支会抛出 UNSUPPORTED_FIXTURE,你的测试框架应把它当作测试错误处理,而不是对用户的判定。valid 为 null 表示没有结论,并不表示号码无效。重试必须有次数上限,并记录每条路由是由哪个分支产生的。工程测试只覆盖模拟的状态转换,不能证明生产环境中一定成功。真实路由是否可用需要另行确认,合成结果也永远不会授予真实的业务权限。
验收清单
在集成之前,请逐项确认:四个分支都能运行,输出与上文所列字段完全一致;unknown 和 provider_failure 都不会导致自动拒绝;otp 分支会交给你的服务商处理,系统中没有任何地方在等待一个 fixture 从未发送的验证码;所有存储的字段都不声称号码在消息应用中存在、归填写者所有或可以触达;投递结果保存在独立的状态中;重试有次数上限,最终转入审核;在确认获得授权的真实路由之前,每条记录都保留 mode 为 synthetic_fixture。全部通过后,再决定是否为免费的 Basic Lookup 路由保存一个沙盒请求,同时记住该路由不会返回线路类型。
运行已检查的模拟示例
下载并解压 https://gridzen.ai/downloads/verification-delivery.zip,进入 verification_delivery,用 Python 3.10+ 运行。此本地示例不联网;独立身份实验请使用新的数据库。
python3 delivery.py phone --branch unknown
python3 delivery.py phone --branch provider_failure来源与范围
https://gridzen.ai/guides/signup-phone-check/ https://gridzen.ai/guides/current-capabilities/ 依据已检查的来源快照与本地模拟;建议的业务规则属于设计建议,不代表已证明的生产行为。内容使用 AI 辅助写作,并经过独立审稿。
下载不等于运行成功;本地示例与在线沙盒分别测试。