业务范围用户 ID
业务范围用户 ID(BSUID)是 Meta 为 WhatsApp 用户分配的标识符,作用域为一个业务组合。无论联系人是否使用 WhatsApp 用户名,入站消息都会携带该标识符,它可以在你没有联系人电话号码的情况下定位该联系人。
Bird 将其作为消息的 from 和 to 上的 bsuid 呈现,接受它作为发送的 to,并按它筛选消息列表。Meta 的业务范围用户 ID参考文档是上线本身以及其他 Meta 界面如何使用该标识符的权威来源。
为什么联系人到达时没有电话号码
WhatsApp 正在推出用户名功能。采用用户名的用户在应用中显示用户名而非电话号码,Meta 随后会从企业收到的载荷中隐去该号码。BSUID 是始终存在的身份标识,因此入站消息可以只携带 BSUID 而完全没有 phone_number。
当你与联系人已有关系时,Meta 仍会包含电话号码:当该特定商业电话号码在过去 30 天内向其发送过消息或拨打过电话、或收到过其消息或来电时,或者当对方在你的 Meta 通讯录中时。30 天条件按商业电话号码逐一评估,因此,曾向你的某个号码发送消息的联系人,在另一个号码上仍可能没有电话号码。
来自 WhatsApp 用户的消息还会携带其公开的个人资料,位于 from 上的 username 和 display_name 中。当联系人未采用用户名或消息不携带个人资料时,两者都不存在,且都不能用于寻址消息。
BSUID 的格式
代码示例
{
"from": {
"bsuid": "US.13491208655302741918",
"username": "alexr",
"display_name": "Alex Rivera"
}
}一个 ISO 3166 alpha-2 国家代码,一个句点,然后最多 128 个字母数字字符。父级 BSUID 允许托管企业注册后在一组业务组合中使用同一标识符,它在国家代码之后插入 ENT:US.ENT.11815799212886844830。Bird 接受这两种形式作为收件人。
三个特性决定了你如何存储和使用 BSUID:
- 原样传递完整值,不要修改。 Meta 会拒绝被修改的 BSUID,因此其中没有任何部分是可选的:国家代码、句点和标识符的每个字符必须一起传递。Bird 在接受发送之前会验证格式,国家代码必须是大写的、真实的 ISO 3166 alpha-2 代码;小写或未知前缀会被拒绝而非自动纠正。128 字符上限适用于国家代码之后的标识符部分,以及父级 BSUID 上 ENT. 段之后的部分。
- 作用域为业务组合。 同一业务组合中的任何商业电话号码都可以向该 BSUID 发送消息;不同业务组合中的号码则不行,发送会失败。
- 非永久性。 Meta 记录了联系人更换电话号码时其 BSUID 会被重新生成,因此它标识的是会话对象,而非可作为你自己持久客户键使用的标识。
一次对话的典型流程
一个你此前未交流过的联系人通过 BSUID 联系到你,获取其号码的交互分三步完成:
- 联系人向你发消息。 入站消息携带 from.bsuid,from.phone_number 可能缺失。该消息会打开客服窗口,你可以在接下来的 24 小时内自由回复。
- 您请求号码。 发送联系信息请求,这是一个让联系人分享电话号码的按钮。同样的请求也可以通过模板的 request_contact_info 按钮发送,适用于对话窗口已关闭的联系人。
- 联系人点击按钮。 披露的号码以入站联系人名片的形式到达,其中 origin 设为 contact_request,号码位于 phone_numbers 中。披露的联系人名片可以描述另一个人或另一个号码。将该披露内容与发送者的 WhatsApp 身份分开存储;在后续消息中使用实际提供的身份,而不是仅凭名片覆盖客户记录。
联系人可以拒绝。关闭分享面板不会产生任何消息或 webhook,因此需要号码的流程必须自行设置超时,而不是等待拒绝事件到达,并且必须在联系人始终不分享号码的情况下仍能正常运行。
向 BSUID 发送消息
to 在所有接受电话号码的位置同样接受 BSUID:
代码示例
{
"to": "US.13491208655302741918",
"from": "+13124495648",
"text": { "body": "Your order shipped." }
}与按电话号码寻址的发送相比,有四点不同:
- from 必须位于 BSUID 所属的业务组合中。 这与 Meta 施加的业务组合要求相同,不匹配时在 WhatsApp 阶段而非接受阶段失败。
- 一次性验证码模板需要电话号码。 Bird 管理的、属于 authentication 类别的模板,或携带一次性验证码按钮的模板,会在接受阶段被拒绝,返回 422 E15014 WhatsAppRecipientNotSupportedForTemplate。你的工作区自行创建的模板不会在接受阶段被检查:Meta 要求一键、免点击和复制验证码的身份验证模板必须使用电话号码,因此此类发送会被接受但随后失败。
- 既非电话号码也非格式正确的 BSUID 的值会在接受阶段被拒绝,返回 422 E15001 WhatsAppInvalidRecipient。
- 价格取决于 BSUID 的国家前缀。 电话号码提供消息计价所依据的国家,对于 BSUID 发送则由两字母前缀提供。
发送的其他一切保持不变:客服窗口仍然控制自由格式内容的发送,202 仍然表示已接受而非已送达。
使用联系人联系你时所用的身份来寻址。 Bird 会为入站消息携带的每个身份记录一个打开的窗口,发送时根据寻址身份查找对应窗口。仅通过 BSUID 联系你的联系人不会留下基于电话号码的窗口,因此向你从其他渠道获得的电话号码发送自由格式消息,可能会被拒绝并返回 422 E15044 WhatsAppServiceWindowClosed,即使 Meta 仍认为该对话处于打开状态。回复其消息的 from 可以避免这种不匹配。
按 BSUID 读取和筛选
每次读取都会携带消息所包含的所有身份标识:
- 在消息上,from 和 to 各自携带 phone_number、bsuid,或两者兼有。入站消息在 from 上标注联系人;出站消息在 to 上标注联系人。
- 在 webhook 上,相同的地址信息位于事件载荷中。参阅WhatsApp 事件了解信封结构。
- 在消息列表上,to 和 from 各自接受 BSUID 和电话号码,每个匹配消息的一端。bsuid 筛选器在两个方向上匹配联系人。旧的 phone_number 筛选器已弃用:to 和 from 取代了它,并匹配两种身份标识。
将两种身份标识都存储在你自己的联系人记录中,并以你自己的标识符而非 Meta 的任一标识符作为记录的键。联系人可能初始只有 BSUID,在分享号码后获得电话号码,又在更换号码时获得新的 BSUID。
后续步骤
- 接收联系人名片:分享的号码到达的路径
- WhatsApp 联系信息请求:请求号码的按钮
- 发送 WhatsApp 消息:请求信封、202 模型和安全重试
- Meta 业务范围用户 ID 参考文档:上线计划、父级 BSUID 以及 Meta 的其他相关界面