线索验证流程:用号码查询 API 跨渠道校验号码

发布于 2026年8月23日 · 更新于2026年10月9日

大多数线索名单都比看起来「脏」。输入错误、空号,以及根本不在你打算使用的渠道上的联系人,都会侵蚀营销 ROI。线索验证流程的做法是:在花钱触达之前,先对每个号码做校验和补全。你可以用同一个账户、同一个 API 密钥下的号码查询 API 搭建这样一套流程。

本文给出一个实用的设计:五个阶段、一段可运行的 Python 管道、评分规则、刷新节奏,以及最容易造成损失的几个错误。

管道总览

  1. 把每个号码归一化成同一种格式。
  2. 去重,避免对同一个联系人重复校验。
  3. 在对你的市场重要的各个渠道上校验注册状态。
  4. 只对通过校验的号码做补全。
  5. 评分并分流,把每个联系人导向确认可用的渠道。

顺序很重要:每个阶段都会缩小名单,让后面成本更高的阶段处理的数量变少。

阶段 0:收集与归一化

让每个号码都变成统一格式:带国家码的纯数字,不含空格和标点(即不带 + 的 E.164)。各个查询接口都能容忍前导 +,WhatsApp 的检测还接受空格、短横线和 00 前缀,但统一成一种规范格式,才能让去重可靠。无法解析的号码直接拒绝,不要猜测国家码,因为猜错会得到一个言之凿凿的「未注册」。

阶段 1:去重

在发起任何调用之前,先把所有来源(表单、导入、活动名单)中重复的号码去掉。以归一化后的形式去重,同时记录每个号码对应的来源记录,每个号码只校验一次。

阶段 2:分渠道校验

这是核心环节。对每个号码,在对你重要的每个平台上运行轻量的注册检测。各项检测彼此独立:在一个平台上命中,并不能说明另一个平台的情况。

渠道接口说明
WhatsAppcheck-exist-by-phone,或 batch-check-10isExist 为 true、false 或 null;批量调用最多 10 个号码
Telegramcheck-existspeer 为 +手机号、@用户名 或 user:<id>
Signalcheckregistered 为 true、false 或 null
Vibercheck响应带有外层结构,需在响应体内部读取 registered
Snapchatcheck-phone,或 check-phones-batch批量调用最多 50 个号码

把 null 当作「未知,稍后重试」,绝不能当作「否」。每个渠道都有各自的详细指南:WhatsApp、Telegram、Signal、Viber 和 Snapchat。如果你在前两者之间犹豫,请阅读 WhatsApp 与 Telegram 号码查询对比;处理大型名单时,可参考WhatsApp 号码批量校验中的可恢复方案。

一段可运行的校验阶段

下面的脚本完成归一化、去重,并用一个小线程池对每个号码运行其中四个渠道的检测,Snapchat 的做法与之相同。它原样保留三态答案,字段缺失时也不会抛出异常。

import re
from concurrent.futures import ThreadPoolExecutor

import requests

API_KEY = "YOUR_API_KEY"
ROOT = "https://api.opendata-api.com/api/project"


def call(project, operation, **params):
    params["key"] = API_KEY
    try:
        resp = requests.get(f"{ROOT}/{project}/{operation}", params=params, timeout=30)
        body = resp.json()
    except (requests.RequestException, ValueError):
        return {}
    # A reply can be wrapped more than once as {"code": ..., "data": {...}}
    while isinstance(body, dict) and "code" in body and isinstance(body.get("data"), (dict, list)):
        body = body["data"]
    return body if isinstance(body, dict) else {}


def normalize(raw):
    digits = re.sub(r"\D", "", raw)
    if raw.strip().startswith("00"):
        digits = digits[2:]
    return digits if 8 <= len(digits) <= 15 else None


def check_channels(number):
    return {
        "number": number,
        "whatsapp": call("whatsapp", "check-exist-by-phone", phoneNumber=number).get("isExist"),
        "telegram": call("telegram", "check-exists", peer="+" + number).get("exists"),
        "signal": call("signal", "check", number=number).get("registered"),
        "viber": call("viber", "check", number=number).get("registered"),
    }


raw_numbers = ["+1 555 123 4567", "0015551234567", "15551234567", "not a number"]
clean = sorted({n for n in map(normalize, raw_numbers) if n})
with ThreadPoolExecutor(max_workers=5) as pool:
    results = list(pool.map(check_channels, clean))

for row in results:
    print(row)

起初把并发数设得保守一些,观察响应码后再逐步放大。某一列出现 None 表示未知,应把该号码排入稍后的重试队列。

阶段 3:补全可触达的号码

对通过校验的号码,拉取公开资料来判断质量、排定优先级:WhatsApp 的头像、签名和企业资料(见资料指南)、Telegram 的简介和头像、Viber 的显示名称,或 Snapchat 的用户名。这样,一个光秃秃的电话号码就变成了带上下文的线索。校验失败的号码不要补全,这正是先校验的省钱之处。资料字段经常因为隐私选择而为空,所以评分时只看有的字段,空字段不要扣分。

阶段 4:评分与分流

把结果变成决策:

def route(row):
    channels = [c for c in ("whatsapp", "telegram", "signal", "viber") if row.get(c) is True]
    unknown = [c for c in ("whatsapp", "telegram", "signal", "viber") if row.get(c) is None]
    if channels:
        status = "reachable"
    elif unknown:
        status = "retry"
    else:
        status = "unreachable"
    return {"number": row["number"], "channels": channels, "status": status}
  • 分流:把每个联系人导向确认可用的渠道,顺序由你对该市场的偏好决定。
  • 屏蔽:把 unreachable 的号码从付费投放中剔除,并记入一张表,以免下周又为它们付费检测。
  • 重试:retry 的行隔一段时间再试,因为未知不是结论。
  • 标记:在任何渠道都没有注册、但来源记录很可靠(比如付费客户)的号码,交给人工复核,因为录入错误比用户不存在更常见。

让数据保持新鲜

应按计划重新校验,而不是每次发送前都校验:活跃名单从每月一次开始比较合理,即将收到高价值消息的联系人则应更早复查。每个号码都要保存结果、渠道和时间戳,24 小时有效的 userHash 只缓存给紧随其后的补全调用使用。

常见错误

  • 先补全后校验。 这是最大的可避免成本。
  • 把 null 当成「否」。 不确定的答案需要重试,而不是屏蔽。
  • 批量探测邮箱。 Snapchat 的邮箱探测基于账号找回,命中时可能会给机主发送一封真实的找回邮件。请在注册表单里使用它,不要对名单批量使用。
  • 忽略授权。 校验只能说明某个渠道存在,不能说明对方同意接收你的消息。

合规

只处理你有合法依据使用的号码,尊重退订请求,并遵守各平台的条款以及当地的隐私和反垃圾信息法律。以上是一般性建议,不构成法律意见。联系人通过验证并获得授权之后,自然的下一步就是通过 API 发送 WhatsApp 消息和用 Python 发送 Telegram 消息。

常见问题

是否要对每个号码校验所有渠道? 只校验对你的市场和营销活动重要的渠道。单次检测成本很低,但对大型名单跑全部渠道会累积起来,所以先从受众真正使用的一两个平台开始,数据证明有必要时再增加其他渠道。

null 结果代表什么? 它表示答案不确定,例如遇到了暂时性的状况。稍等片刻再重试,不要把它当作否定结果。

多久重新校验一次名单? 按计划刷新,例如活跃名单每月一次,是一个合理的起点。对即将发送重要内容的联系人,可以更早复查。

一个账户能同时使用不同的查询项目吗? 可以。所有查询项目共用同一个 API 密钥和同一份点数余额,所以一条管道可以同时调用 WhatsApp、Telegram、Signal、Viber 和 Snapchat。

查询成功是否意味着我可以给对方发消息? 不意味着。它只说明这个号码在该平台上有账户。你仍然需要获得对方同意或具备其他合法依据,并遵守平台规则。

整合起来

在全部 API 页面浏览完整目录,在浏览器里测试任何接口,并查看定价来估算你的名单规模所需的点数。新账户包含免费点数,可以零成本完成整套流程的原型验证:先登录,再从控制台复制密钥。