号码检查、OTP、身份核验:各自回答什么问题?

先在免费沙盒中跑通流程,再准备生产接入。

统计选择在本站复用,可随时关闭;账号关联另行同意。

号码检查、OTP、身份核验:各自回答什么问题?

注册流程里有一个手机号字段,团队中有人要求对它进行“验证”。这个词其实包含三个不同的问题。号码检查描述的是号码本身:格式是否正确、是否有效,以及可能属于哪种线路。OTP 检验的是正在输入的人此刻能否通过某个渠道收到验证码。身份核验评估的是关于某个人的身份声明。三者都不能替代彼此的答案:移动线路不能说明号码归谁所有,验证码送达不能确立身份,Approved 的身份结果本身也不授予任何权限。本文帮助你判断注册任务需要哪一种证明,并展示 GridZen 可下载的合成示例如何把三者分开处理。

curl https://gridzen.ai/console/api/quickstart/trial \
  -H 'Content-Type: application/json' \
  -d '{"task": "signup_phone", "scenario": "success"}'

接入指南

决策:先明确问题,再选择证明

首先写下注册这一步必须确认什么。如果只是想在创建账户前拦截输入错误和格式不正确的号码,你需要的是号码属性。如果需要确认这个人能在该号码上收到消息,你需要的是渠道访问证明,也就是通过你自己运营的服务商发送 OTP。如果后续操作(例如允许卖家上架商品)取决于这个人是谁,你需要通过托管引导流程核验身份声明,然后再应用你自己的业务规则。常见的错误是把较弱的信号当作较强的信号:把有效的手机号当作归属证明,或者把 Approved 当作权限。每种证明都有各自的失败模式、重试方式和负责方,因此应把它们放在独立的字段和独立的代码路径中。

可下载示例实际实现了什么

指南中的 verification_delivery 示例是一个无依赖的 Python 3.10+ 脚本,不需要凭据,也不发起任何网络调用。它的 phone 命令有四个分支:normal、unknown、provider_failure 和 otp。identity 命令使用本地 SQLite 文件保存夹具会话和事件。每个输出都带有 mode: synthetic_fixture。phone 各分支始终返回 otp_sent: false 和 live_line_type_available: false。identity 路径只接受来源为 fixture_callback 的合成事件,没有生产环境的签名验证器。它记录的任何权限都只是本地夹具标记,每次读取身份状态都会返回 live_permission_changed: false。这个四分支下载示例与匿名的三场景 HTTP 试用是两回事,不要把其中一个的结果当成另一个的结果。本文中超出上述输出的其他内容,都是为你自己的代码提出的应用设计建议。

假设示例:卖家注册

设想一个假设的 B2B 交易平台。新卖家输入手机号。normal 分支返回 state: simulated、valid: true、line_type: mobile 和 next: continue_customer_policy。对你的设计来说,这只说明号码看起来可用,并不涉及归属或可达性。如果团队需要渠道访问证明,otp 分支会明确回答:state: unsupported、valid: null、line_type: null、next: customer_otp_provider。验证码必须由你自己的 OTP 服务商发送。之后,在卖家可以上架商品之前,identity 路径会创建一个会话。创建步骤返回 state: simulated、session: fixture-session、一个位于 example.invalid 的 hosted_link、link_executable: false 以及 next: send_real_provider_link_only_after_authorization。一个 policy 为 true 的合成 Approved 事件返回 status: approved、deadline: 60、permission_granted: true 和 grant_count: 1。在这个流程中,号码检查结果、OTP 结果和身份状态各自保存在独立字段中。

由调用方负责的失败处理

号码结果为未知并不等于拒绝。unknown 分支返回 state: unknown,next 为 review_or_existing_otp。provider_failure 分支返回同样的 unknown 状态,next 为 bounded_retry_then_review。你的设计应限制重试次数,然后把注册转入人工审核,而不是静默拦截。在身份这一侧,重复事件不会改变任何内容:输出仍为 approved,grant_count 为 1。随后到达的 Declined 事件被视为更正,会把 status 设为 declined、permission_granted 设为 false,而 grant_count 仍为 1。如果在截止时间前没有收到决定,recover 会把处于 pending、review 或 unknown 的会话标记为 expired,并返回 permission_granted: false、grant_count: 0、next: review_or_authorized_provider_refresh 和 provider_polled: false。过期在本地完成,recover 从不联系服务商。会话或 tenant/subject 绑定不匹配的事件会以 BINDING_MISMATCH 被拒绝。读取不存在的会话会返回 SESSION_NOT_FOUND。

真实路由的限制

截至 2026-10-17,符合条件的美国和英国企业可以自助注册免费的基础号码路由。它只检查格式和有效性,每个已验证的企业域名最多 10 次请求,不请求线路类型、号码归属、可达性或 OTP 发送。另有托管身份核验试用,需要单独接受 Didit 附加条款,限额为每个已验证的企业域名 2 次请求、共享终身总量 10 次请求。新获批的用户以及客户随后的业务操作,尚未经过端到端验证。合成夹具中的权限不是真实的业务权限,匿名试用也不代表生产环境批准。

验收清单

运行全部四个 phone 分支,确认每个分支输出的 state、valid、line_type 和 next 与上文完全一致,并且每次都是 otp_sent: false。确认你的注册流程把号码属性、OTP 结果和身份状态分别存放在独立字段中。确认 unknown 和 provider_failure 会进入有上限的重试或人工审核,绝不会自动拒绝。运行 python3 -m unittest -v test_delivery,确认重复事件、更正、过期和绑定错误等用例全部通过。确认没有任何代码路径会因夹具值或仅凭 Approved 授予真实权限。在处理任何真实用户之前,另行选择经过授权的真实 OTP 或身份核验路由。如果这些检查符合你的任务需求,下一步可以保存一个沙盒请求。

运行已检查的模拟示例

下载并解压 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/phone-otp-identity/ https://gridzen.ai/guides/current-capabilities/ 依据已检查的来源快照与本地模拟;建议的业务规则属于设计建议,不代表已证明的生产行为。内容使用 AI 辅助写作,并经过独立审稿。

另行体验三种沙盒结果 创建账号,继续项目接入

下载不等于运行成功;本地示例与在线沙盒分别测试。

接入你的应用

运行三种模拟结果 · 需要接入帮助

连接免费沙盒账号

号码基础有效性不证明持有权或送达,不提供短信验证码。业务放行由你的系统判断。