消息网关一期需求
一期目标是先做一个薄但可落地的消息网关:上游系统通过统一接口提交消息请求,消息网关负责选择同类型通道内的供应商,记录发送单和回执,并为后续跨类型通道路由预留框架。短信侧一期接入 1 家短信通道并承接原 CRS 短信能力迁移;语音侧一期接入 1 家 AI 外呼供应商,先服务还款提醒。不在第一版建设重型营销平台、完整催收系统或跨类型自动触达编排。
1. 背景与目标
当前 BNS、FCS、CRS 等系统都会产生客户触达诉求:
- BNS 需要发送注册 / 登录验证码、借款提交结果、绑卡引导等短信。
- FCS 需要在还款日前、到期日、逾期早期通知客户还款。
- FCS 或催收相关服务可能需要先发起语音外呼,未接通后再触发短信或 WhatsApp 提醒;该跨类型自动降级作为二期能力,一期先把消息单、通道明细、状态和配置框架预留好。
- 后续还会接入更多短信供应商、语音外呼供应商、WhatsApp Business 通道或其他 IM 通道。
如果每个业务系统都直接接供应商,会导致模板、签名、重试、回执、失败原因和通道切换逻辑分散在各系统内。消息网关一期要把这些差异先收口,让上游调用方只需要调用消息网关。
一期目标:
- 建立统一消息发送入口,BNS / FCS 等上游系统不直连触达供应商。
- 建设短信网关能力,接入 1 家短信通道,并将原 CRS 已接入的短信通道能力迁移到消息网关统一封装。
- 一期启用同类型通道路由:短信通道内可按场景选择主通道和备用通道;不同类型通道之间的自动路由和降级作为二期能力,但数据模型、配置项和状态流转框架一期先实现。
- 接入 1 家 AI 语音外呼供应商,支持还款提醒场景的名单导入、外呼结果回调和结果标准化;外呼未接通、忙线、拒接、不可达、线路异常或超时未回执时,一期只记录可降级事件,二期再启用自动短信或 WhatsApp 降级。
- 统一记录消息发送单、通道请求、通道回执、最终状态和失败原因。
- 提供最小可用的查询、重试、配置和监控能力,达到研发开发和联调标准。
2. 一期范围
2.1 包含范围
| 能力 | 一期要求 |
|---|---|
| 统一发送接口 | 上游按业务场景提交接收人、模板、变量、期望通道和幂等号 |
| 短信发送 | 接入 1 家短信通道,承接原 CRS 短信能力迁移,支持 OTP、交易通知和还款提醒短信 |
| 同类型通道路由 | 一期支持短信同类型路由框架:按场景配置主短信通道和备用短信通道;语音同类型路由保留配置模型但只接 1 家供应商 |
| 语音外呼 | 接入 1 家 AI 外呼供应商,支持还款提醒名单导入、取消外呼、实时回调、结果标准化和基础查询 |
| 跨类型通道路由 | 一期实现框架、配置字段和状态记录,不启用生产自动跨类型降级;语音失败后短信 / WhatsApp 自动触达放到二期 |
| WhatsApp 提醒 | 一期只预留通道类型、模板映射和发送明细模型;若 WhatsApp 供应商未就绪,配置关闭 |
| Push 框架 | 纳入 push 通道类型、接收人模型、token 可达性、payload 和发送记录框架;是否一期上线实际发送取决于 App 侧 FCM token 和通知权限链路完成度 |
| 状态查询 | 上游可按业务幂等号或消息单号查询发送状态 |
| 回执接收 | 支持供应商回调入库,更新消息状态 |
| 手工重试 | 支持运维 / 后台按消息单重试失败消息 |
| 基础监控 | 输出发送成功率、失败率、回执延迟、通道异常指标 |
2.2 不包含范围
- 不做完整营销活动平台。
- 不做人群圈选、客户分群和营销名单管理。
- 不做拖拽式触达旅程编排。
- 不做复杂智能路由,例如实时按价格、送达率、客户画像动态决策。
- 不在一期启用不同类型通道之间的自动路由和降级,例如 voice -> sms、voice -> WhatsApp、sms -> WhatsApp。
- 不做 A/B 实验、内容效果归因和转化分析。
- 不在一期做全量运营后台,只做必要配置、查询和重试入口。
- 不接入多家语音外呼供应商,不做语音供应商自动切换。
- 不在消息网关内建设催收案件管理、承诺还款跟进、人工坐席分案和录音质检。
- 不把 AI 外呼供应商的多轮任务排期能力做成通用编排引擎;一期只使用供应商侧已配置的
strategy_id。 - 不在一期下载和长期保存完整录音文件;只保存供应商返回的
record_url、摘要和必要状态,录音留存策略后续单独确认。
3. 角色与系统边界
| 系统 / 角色 | 职责 |
|---|---|
| BNS | 发起登录 OTP、借款流程通知、绑卡引导等消息请求 |
| FCS | 发起还款提醒、到期提醒、逾期早期提醒、语音外呼请求 |
| CRS | 原短信接入能力的迁出方;一期目标是由消息网关承接 CRS 已接入的短信通道,CRS 后续不再直接适配短信供应商 |
| 营销系统 | 未来规划建设,负责人群圈选、营销活动、营销 Push 批次、退订和静默时间策略;调用消息网关发送,不直接维护 FCM token |
| 消息网关 | 统一接收发送请求,执行模板渲染、通道路由、发送、回执、降级、查询和重试 |
| 短信供应商 | 实际发送 SMS,返回受理结果和投递回执 |
| AI 语音外呼供应商 | 按 strategy_id 执行外呼任务,返回接通、未接、忙线、拒接、不可达、线路异常、通话时长、意向标签和录音 URL 等结果 |
| WhatsApp 供应商 | 发送 WhatsApp 模板消息或会话消息 |
| 运营 / 运维 | 配置通道启停、场景路由、查看失败消息并触发重试 |
边界原则:
- BNS、FCS 不保存供应商密钥,不解析供应商私有回执。
- BNS、FCS 可以指定业务场景和期望通道,但最终供应商选择由消息网关按配置执行。
- 消息网关不判断客户是否应该被提醒还款;应提醒谁、金额多少、到期日是什么,由 FCS 决定并传入。
- 消息网关不生成登录验证码;验证码生成和校验仍由登录业务系统负责,消息网关只负责送达。
- AI 外呼的具体话术、任务排期和拨打轮次由供应商后台的
strategy_id控制;消息网关只维护场景到strategy_id的配置映射。
4. 系统框架
消息网关不是单个短信接口,也不是完整营销平台。它是业务系统和触达通道之间的统一通道层。
flowchart TD A["上游业务系统<br/>BNS / FCS / CRS / 营销系统 / 运营后台"] --> B["消息网关 API 层"] B --> C["消息编排层<br/>幂等 / 频控 / 模板校验 / 场景路由"] C --> D["消息状态层<br/>消息单 / 通道发送明细 / 回执 / 失败原因"] C --> E["通道适配层"] E --> F["短信适配器<br/>SMS Provider A / SMS Provider B"] E --> G["语音外呼适配器<br/>AI Voice Provider / Future Voice Provider"] E --> H["WhatsApp 适配器<br/>WhatsApp BSP"] E --> K["Push 适配器<br/>Firebase FCM"] F --> I["外部供应商 / 服务"] G --> I H --> I K --> I I --> J["供应商回调"] J --> B
| 层级 | 职责 |
|---|---|
| API 层 | 给上游提供稳定接口,包括发送、查询、取消、供应商回调入口 |
| 消息编排层 | 做幂等、频控、模板变量校验、场景路由、同类型通道选择;跨类型降级框架一期预留、二期启用 |
| 消息状态层 | 保存消息单、通道发送明细、标准状态、原始供应商流水和回执 |
| 通道适配层 | 按短信、语音外呼、WhatsApp、Push 等通道类型定义标准能力 |
| 供应商适配器 | 处理具体供应商鉴权、字段转换、请求发送、回执解析和错误码映射 |
系统边界:
- 消息网关负责发送、路由、模板渲染、回执、失败原因、供应商适配和基础监控。
- 消息网关不判断客户是否应该被触达,不计算还款金额、到期日、借据状态,不生成或校验 OTP。
- 供应商密钥、模板 ID、私有字段、回执枚举和主备切换规则都由消息网关内部配置和适配器处理,上游不直接感知。
- 当前 App 的服务端就是 BNS,不单独建设 App 后端或设备中心。Push 的用户 / 设备主关系归属 BNS;消息网关维护 Push token 发送镜像,用于可达性判断、FCM 发送和失效清理。未来营销系统、FCS、BNS 等上游不直接查询或选择 FCM token。
5. 标准通道能力
5.1 短信通道
标准能力:
- 模板短信发送。
- 供应商受理结果记录。
- 投递回执接收。
- 主备短信供应商切换。
- 按场景频控和幂等。
供应商差异由短信适配器处理:
| 差异 | 适配方式 |
|---|---|
| 鉴权方式不同 | 在供应商适配器内实现签名、token 或 basic auth |
| 模板 ID 不同 | 内部 templateCode 映射到供应商模板 ID |
| 变量格式不同 | 适配器转换为供应商要求的数组、键值或 extra |
| 回执状态不同 | 映射为 delivered、failed、unknown |
| 手机号格式不同 | 适配器按供应商要求转换 |
5.2 语音外呼通道
标准能力:
- 发起语音外呼。
- 支持批量名单导入类供应商。
- 支持取消外呼。
- 接收实时拨打结果回调。
- 标准化接通、未接、忙线、拒接、不可达、空号、线路异常。
- 保存通话时长、意向标签、摘要、录音 URL 等扩展信息。
语音供应商差异由语音适配器处理。供应商如果是单呼模式,实现单呼适配器;如果是批量任务模式,实现批量导入适配器。上游仍只调用 sendMessage(scene=repayment_voice_reminder)。
5.3 WhatsApp 通道
一期只预留 WhatsApp 通道类型、模板映射和发送明细模型;供应商未就绪时配置关闭。后续正式接入后,WhatsApp 适配器负责 BSP 鉴权、模板 ID 映射、变量转换、投递状态和失败原因映射。
5.4 Push 通道
Push 建议先以 Firebase Cloud Messaging 作为首个实现。客户端 SDK、FCM token 获取、Android 通知权限、前后台消息处理和点击跳转要求参考 12-迭代需求管理/AF接入/AppsFlyer_Android_SDK_接入需求文档.md。
消息网关只承接服务端侧:
- 基于
user_id、device_id或fcm_token发送 Push,不以手机号作为唯一接收人。 - 维护 Push 发送镜像,即从 BNS 同步一份发送所需的 FCM token、App 版本、国家、语言、通知权限、token 状态、登录状态、最近同步时间和最近刷新时间;用户 / 设备主关系仍以 BNS 为准。
- 标准化 title、body、image、businessType、jumpTarget、params、TTL、dedupeId / collapseKey。
- 识别无 token、token 失效、通知权限关闭、用户退订、App 卸载等不可达原因。
- FCM 服务端受理只表示 Firebase 已接收请求,不等同于用户已看到;打开、点击依赖客户端事件回传。
一期建议把 Push 纳入框架和数据模型,是否上线实际发送取决于 App 向 BNS 上传 FCM token、BNS 同步用户设备关系和 Android 13+ 通知权限链路是否已经完成。跨类型路由仍按二期处理。
6. 核心业务场景
6.1 BNS 发送短信
典型场景:
- 注册 / 登录 OTP。
- 借款申请提交成功通知。
- 借款审批通过 / 拒绝通知。
- 绑卡引导提醒。
流程:
sequenceDiagram participant BNS as BNS participant MSG as 消息网关 participant SMS as 短信通道 BNS->>MSG: sendMessage(scene, templateCode, phone, variables, bizId) MSG->>MSG: 校验幂等号和模板变量 MSG->>MSG: 按 scene 选择短信通道 MSG->>SMS: 提交短信 SMS-->>MSG: 受理结果 MSG-->>BNS: 返回 messageId + accepted / failed SMS-->>MSG: 投递回执 MSG->>MSG: 更新最终状态
要求:
- BNS 调用消息网关后,不关心具体供应商。
- OTP 场景要求低延迟,一期不做长时间排队。
- 同一
bizId + scene + receiver重复请求需幂等处理,避免重复发送验证码或业务通知。
6.2 FCS 还款语音外呼,失败后降级提醒
典型场景:
- 到期日前提醒客户还款。
- 到期日当天提醒客户还款。
- 逾期 1-3 天早期提醒。
流程:
sequenceDiagram participant FCS as FCS participant MSG as 消息网关 participant VOICE as 语音外呼通道 FCS->>MSG: sendMessage(scene=repayment_voice_reminder, phone, variables, bizId) MSG->>VOICE: 发起语音外呼 VOICE-->>MSG: 外呼结果 alt 接通 MSG->>MSG: 记录 delivered / connected else 未接通或失败 MSG->>MSG: 记录失败原因和 fallback_candidate=true MSG->>MSG: 不自动发送短信 / WhatsApp end MSG-->>FCS: 状态可查询
要求:
- FCS 传入客户手机号、还款金额、到期日、还款链接、借据号或还款计划标识等变量。
- 消息网关根据场景配置决定是否发起语音;语音失败后只记录可降级事件,自动短信 / WhatsApp 降级二期启用。
- 语音通道一期通过 AI 外呼供应商的名单导入接口提交外呼案件,按
sourceSystem + scene + bizId + receiverPhone生成供应商ref_id。 - 外呼失败类型至少区分:未接通、忙线、拒接、关机 / 不可达、空号、线路异常、供应商受理失败、超时无回执。
- 如果二期启用降级消息,降级消息必须关联原始语音消息单,便于追踪一次触达链路;一期先保留
parent_attempt_id、fallback_candidate等框架字段。 - 同一还款提醒场景需支持频控,避免同一客户短时间被重复外呼和短信轰炸。
- AI 外呼回调中的意向标签、通话总结和录音 URL 只作为触达结果补充信息,一期不驱动自动催收动作。
6.3 还款短信直接发送
当业务策略不需要语音外呼时,FCS 可直接请求短信提醒:
- 还款日前 N 天短信提醒。
- 还款日当天短信提醒。
- 扣款失败后短信提醒。
- 还款链接短信发送。
要求:
- 还款链接作为变量由 FCS 或短链服务生成后传入,消息网关不生成还款链接。
- 消息网关负责模板渲染、通道发送和回执追踪。
- 短信发送失败时,一期支持按配置切换备用短信通道重试一次;是否再降级 WhatsApp 可配置关闭。
7. 消息模型
7.1 消息发送单
| 字段 | 说明 |
|---|---|
message_id | 消息网关生成的消息单号 |
biz_id | 上游业务幂等号,例如验证码流水、还款提醒任务 ID |
source_system | 来源系统:BNS / FCS / CRS / marketing / admin |
scene | 业务场景,例如 login_otp、repayment_voice_reminder |
receiver_type | 接收人类型:customer / staff / test |
receiver_user_id | 接收用户 ID;Push 场景必传或必须可由设备 token 反查,短信 / 语音场景建议传入用于链路追踪和用户维度频控 |
receiver_phone | 规范化手机号,尼日利亚使用 +234 格式 |
preferred_channel | 上游期望通道:sms / voice / whatsapp / push / auto |
actual_channel | 实际首发通道 |
template_code | 模板编码 |
template_variables | 模板变量快照 |
priority | 优先级:high / normal / low |
status | 当前状态 |
final_status | 最终状态:success / failed / partial_success |
created_at | 创建时间 |
updated_at | 更新时间 |
7.2 通道发送明细
一次消息单可能产生多次通道发送,例如语音失败后短信降级。
| 字段 | 说明 |
|---|---|
attempt_id | 通道发送明细 ID |
message_id | 关联消息单号 |
parent_attempt_id | 降级发送时关联原始 attempt |
channel_type | sms / voice / whatsapp |
provider_code | 供应商编码 |
provider_request_id | 供应商请求流水 |
provider_message_id | 供应商消息 ID |
provider_batch_id | 批量导入类供应商的批次号,例如 AI 外呼 batch_id |
provider_strategy_id | 外呼策略 ID,例如 AI 外呼 strategy_id |
request_payload_snapshot | 请求摘要,敏感信息需脱敏 |
accept_status | 供应商受理结果 |
delivery_status | 投递 / 接通结果 |
failure_code | 内部标准失败码 |
provider_failure_code | 供应商原始失败码 |
callback_received_at | 最近一次回执时间 |
retry_count | 当前明细重试次数 |
created_at | 创建时间 |
8. 状态定义
| 状态 | 说明 |
|---|---|
created | 已创建消息单,未提交通道 |
accepted | 通道已受理 |
sending | 正在发送或等待回执 |
delivered | 短信 / WhatsApp 已投递成功 |
opened | Push 客户端上报已打开或点击通知 |
connected | 语音外呼已接通 |
not_connected | 语音外呼未接通 |
rejected_by_user | 语音外呼被客户拒接 |
unreachable | 语音外呼不可达、离线、信号差或号码不可用 |
line_failed | 语音外呼线路异常 |
failed | 当前通道发送失败 |
fallback_triggered | 已触发降级发送 |
final_success | 触达链路最终成功 |
final_failed | 所有可用通道均失败 |
cancelled | 发送前被取消 |
最终状态口径:
- 短信或 WhatsApp 投递成功,记为
final_success。 - 语音接通,记为
final_success。 - 二期启用跨类型降级后,语音未接通但降级短信或 WhatsApp 成功,记为
final_success,同时保留语音 attempt 的未接通结果。一期只记录语音结果和可降级候选。 - 所有配置通道都失败,记为
final_failed。
9. 通道路由与降级策略
9.1 场景路由配置
一期按场景配置,不做复杂规则引擎。一期生产只启用同类型通道路由;跨类型通道路由只保留配置和状态框架,默认关闭。
| 配置项 | 说明 | 示例 |
|---|---|---|
scene | 业务场景 | repayment_voice_reminder |
enabled | 场景是否启用 | true |
primary_channel | 首发通道 | voice |
primary_provider | 首发供应商 | ai_voice_provider |
provider_strategy_id | 供应商外呼策略 ID | 50 |
backup_channel | 备用通道 | sms / whatsapp |
backup_provider | 备用供应商 | sms_provider_a |
fallback_condition | 降级触发条件 | not_connected / rejected_by_user / unreachable / line_failed / timeout / provider_failed |
cross_channel_enabled | 是否启用跨类型自动降级 | 一期默认 false |
max_attempts | 最大通道尝试次数 | 2 |
cooldown_minutes | 同客户同场景冷却时间 | 60 |
9.2 短信通道路由
多家短信通道路由采用配置化方式实现,不在一期引入复杂规则引擎。核心模型是“场景路由配置 + 供应商优先级 / 权重 + 失败切换”。
一期支持:
- 每个场景配置一个主短信供应商。
- 主供应商调用失败时,按配置切换备用短信供应商重试一次,且只允许
sms -> sms同类型切换。 - 供应商被运维手工禁用时,自动跳过该供应商。
- OTP 场景默认只允许快速失败和一次备用,不做长时间异步重试。
- 若一期只有 1 家短信通道,仍需按多通道模型落库和配置,备用通道可为空。
路由配置字段:
| 字段 | 说明 |
|---|---|
scene | 业务场景,例如 login_otp、repayment_due_sms |
country | 国家,默认 Nigeria |
phone_prefix | 号段规则,可为空;后续用于按运营商或号段选择通道 |
provider_code | 短信供应商编码 |
priority | 优先级,数字越小越优先 |
weight | 权重,一期预留,二期用于同优先级分流 |
enabled | 是否启用 |
retryable_failure_codes | 允许切换备用通道的失败码 |
执行逻辑:
- 按
scene + country + phone_prefix查询可用短信供应商。 - 过滤禁用、模板未映射、供应商不可用的通道。
- 按
priority选择主供应商;一期只有 1 家时直接选择该供应商。 - 主供应商超时、明确失败或命中
retryable_failure_codes时,才允许切换备用短信供应商。 - 每次供应商调用都生成独立
attempt_id,备用发送通过parent_attempt_id关联主发送记录。 - 没有可用供应商或备用失败时返回标准失败码,不静默丢弃。
三家短信通道配置示例:
| scene | country | phone_prefix | provider_code | priority | weight | enabled | 说明 |
|---|---|---|---|---|---|---|---|
login_otp | NG | 空 | sms_provider_a | 1 | 100 | true | 主通道 |
login_otp | NG | 空 | sms_provider_b | 2 | 100 | true | 第一备用 |
login_otp | NG | 空 | sms_provider_c | 3 | 100 | true | 第二备用 |
在以上配置下,一期支持 A 失败后切 B,B 失败后是否继续切 C 由 max_attempts 和场景配置控制。OTP 建议最多尝试 1-2 次,因此通常只会使用主通道和第一备用;普通通知可按业务容忍度配置最多 2-3 次。同优先级按 weight 分流属于二期能力,一期不做 A/B/C 按比例分流。
后续再扩展:
- 按成功率自动切换。
- 按成本和号段做权重。
- 按模板类型选择营销短信或交易短信通道。
9.3 语音失败降级
语音外呼结果满足以下任一条件时,可标记为跨类型降级候选。自动触发短信或 WhatsApp 为二期能力,一期只记录状态、失败原因和可降级标识:
| 外呼结果 | 一期处理 | 二期处理 |
|---|---|---|
| 接通且通话时长达到有效阈值 | 记为成功 | 不降级 |
| 未接通 | 标记 fallback_candidate=true | 发送短信或 WhatsApp 提醒 |
| 忙线 | 标记 fallback_candidate=true | 发送短信或 WhatsApp 提醒 |
| 拒接 | 标记 fallback_candidate=true | 发送短信或 WhatsApp 提醒 |
| 关机 / 不可达 | 标记 fallback_candidate=true | 发送短信或 WhatsApp 提醒 |
| 空号 | 记为最终失败,不继续同号码触达 | 不降级 |
| 线路异常 | 标记 fallback_candidate=true | 发送短信或 WhatsApp 提醒 |
| 供应商受理失败 | 标记 fallback_candidate=true | 可直接降级 |
| 超时无回执 | 标记 fallback_candidate=true | 超过配置 TTL 后降级 |
| 客户号码无效 | 记为最终失败,不继续同号码触达 | 不降级 |
二期跨类型降级只支持一层:语音 -> 短信 或 语音 -> WhatsApp。不要做语音 -> 短信 -> WhatsApp -> 人工任务的多层编排。
9.4 AI 外呼供应商结果映射
AI 外呼供应商返回的 call_result 需在消息网关内标准化:
供应商 call_result | 网关标准状态 | 是否可触发降级 |
|---|---|---|
ANSWERED | connected | 否 |
NO_ANSWER | not_connected | 二期启用 |
USER_BUSY | not_connected | 二期启用 |
CALL_REJECTED | rejected_by_user | 二期启用 |
NO_USER_RESPONSE | unreachable | 二期启用 |
UNALLOCATED_NUMBER | unreachable | 否 |
NETWORK_FAILED | line_failed | 二期启用 |
外呼结果中的 intention、intention_description、summary、record_url、talk_duration、transfer_reasons_when_end_round 应保存到通道发送明细或扩展表中,供后续催收、客服和质检使用。一期只做记录和查询,不自动生成催收任务。
10. 模板与变量
10.1 模板管理
模板由消息网关统一登记模板编码和变量要求。供应商侧需要报备或审核的模板,由通道负责人维护供应商模板 ID。
| 字段 | 说明 |
|---|---|
template_code | 内部模板编码 |
scene | 适用业务场景 |
channel_type | sms / voice / whatsapp |
language | 语言,默认 en |
content | 内部模板内容或语音话术文本 |
required_variables | 必填变量列表 |
provider_template_id | 供应商模板 ID,WhatsApp 模板尤其需要 |
provider_strategy_id | 语音外呼供应商策略 ID,voice 场景必填 |
status | enabled / disabled |
10.2 一期模板示例
| 场景 | 通道 | 模板变量 |
|---|---|---|
login_otp | sms | otp_code、expire_minutes |
loan_submit_success | sms | customer_name、application_no |
repayment_due_sms | sms | customer_name、due_amount、due_date、repayment_link |
repayment_voice_reminder | voice | customer_name、due_amount、due_date |
repayment_voice_fallback | sms / whatsapp | customer_name、due_amount、due_date、repayment_link |
模板变量要求:
- 上游必须传齐模板必填变量;缺失时消息网关直接拒绝请求。
- 金额、日期等变量由上游按业务口径计算并传入,消息网关不重新计算还款金额。
- 模板渲染后的内容需保存快照,便于问题追溯。
11. 接口需求
11.1 发送消息
POST /message-gateway/api/v1/messages/send请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
sourceSystem | 是 | BNS / FCS / CRS / marketing / admin |
bizId | 是 | 上游业务幂等号 |
scene | 是 | 业务场景 |
receiverType | 否 | 接收人类型:phone / user / device / token;短信和语音默认 phone,Push 使用 user / device / token |
receiverUserId | 条件必填 | 用户 ID。Push 按用户发送时必填;短信 / 语音建议传入,用于链路追踪、用户维度频控和后续跨通道路由 |
receiverDeviceId | 条件必填 | 设备 ID。Push 指定设备发送时必填 |
receiverToken | 条件必填 | FCM token。Push 指定 token 发送时必填,主要用于联调或补偿 |
receiverPhone | 条件必填 | 接收手机号,建议 E.164;短信 / 语音必填,Push 可不填 |
preferredChannel | 否 | sms / voice / whatsapp / push / auto |
deviceSelectPolicy | 否 | Push 设备选择策略:all_active / latest_active / specified_device / specified_token;未传时按场景配置 |
templateCode | 是 | 模板编码 |
variables | 是 | 模板变量 |
priority | 否 | high / normal / low |
callbackUrl | 否 | 上游需要异步通知时传入 |
响应字段:
| 字段 | 说明 |
|---|---|
messageId | 消息网关单号 |
bizId | 上游业务幂等号 |
status | accepted / rejected / duplicate |
actualChannel | 实际首发通道 |
rejectReason | 拒绝原因 |
11.2 查询消息状态
GET /message-gateway/api/v1/messages/status?messageId={messageId}
GET /message-gateway/api/v1/messages/status?sourceSystem={sourceSystem}&bizId={bizId}返回:
| 字段 | 说明 |
|---|---|
messageId | 消息单号 |
bizId | 上游业务幂等号 |
scene | 业务场景 |
status | 当前状态 |
finalStatus | 最终状态 |
attempts | 通道发送明细列表 |
failureCode | 标准失败码 |
updatedAt | 最近更新时间 |
11.3 供应商回执接收
POST /message-gateway/api/v1/provider-callback/{providerCode}要求:
- 每个供应商单独验签或校验 token。
- 原始回调报文需落库或保存摘要,敏感字段脱敏。
- 同一供应商回执重复推送时必须幂等。
- 回执无法匹配消息单时,记录异常待人工排查,不直接丢弃。
AI 外呼供应商回调必须支持按 call_id 幂等处理,并通过 ref_id 反查消息网关发送明细。供应商仅在 HTTP 状态非 200 时重试回调,最多 5 次,间隔为 3s、6s、12s、24s、48s;因此网关接收成功后应返回 HTTP 200 和业务 code=0。
11.4 手工重试
POST /message-gateway/api/v1/messages/{messageId}/retry要求:
- 仅允许失败或超时消息重试。
- 重试时需记录操作人、操作时间和原因。
- OTP 类消息默认不允许后台手工重试,避免发送过期验证码。
12. 频控与幂等
12.1 幂等规则
- 唯一键:
sourceSystem + scene + bizId + receiverPhone。 - 命中同一幂等键时,不重复创建新消息单,直接返回原
messageId和当前状态。 - 如上游明确需要再次发送,必须使用新的
bizId。
12.2 频控规则
| 场景 | 一期频控建议 |
|---|---|
| 登录 OTP | 同手机号 60 秒内最多 1 次,单日最多 N 次,N 可配置 |
| 还款短信 | 同客户同借据同场景 60 分钟内最多 1 次 |
| 还款语音 | 同客户同借据同场景 24 小时内最多 1 次,具体由 FCS 任务频率和网关频控共同保障 |
| 跨类型降级候选 | 同一次语音失败只标记 1 次候选状态,不自动发送 |
| 二期语音失败降级短信 | 同一次语音失败只触发 1 次降级 |
| 二期 WhatsApp 降级 | 同一次语音失败只触发 1 次降级 |
频控命中时,消息网关返回 rejected,拒绝原因为 rate_limited,并记录日志。
13. 异常处理
| 异常 | 处理 |
|---|---|
| 模板不存在或禁用 | 拒绝发送,返回 template_invalid |
| 必填变量缺失 | 拒绝发送,返回 variable_missing |
| 手机号格式非法 | 拒绝发送,返回 receiver_invalid |
| 主通道禁用 | 选择备用通道;无备用则失败 |
| 供应商受理失败 | 记录失败原因,按配置重试或降级 |
| 供应商超时 | 标记 timeout,按场景决定是否异步查询或降级 |
| AI 外呼批次重复 | 标记 provider_duplicate_batch,按幂等结果处理,不重复创建外呼 |
| AI 外呼回调重复 | 按 call_id 幂等更新,不重复标记候选状态;二期不重复触发短信或 WhatsApp 降级 |
| 回执长期未返回 | 超过 TTL 后标记未知或失败,并进入监控 |
| 上游回调失败 | 记录回调失败,最多重试配置次数 |
14. 管理与配置
一期只需要最小后台能力,可放在后台管理或运维配置页中:
| 配置 / 页面 | 一期要求 |
|---|---|
| 通道配置 | 查看供应商编码、通道类型、启停状态、环境、优先级 |
| 场景路由配置 | 配置 scene 的主通道、备用通道、降级条件和冷却时间 |
| 模板配置 | 配置模板编码、通道类型、内容、变量、启停状态 |
| 语音策略配置 | 配置消息场景和 AI 外呼 strategy_id 的映射 |
| 消息查询 | 按手机号、bizId、messageId、scene、状态查询 |
| 发送明细 | 查看每次通道发送、供应商流水、回执、失败原因 |
| 手工重试 | 对符合条件的失败消息触发重试 |
权限要求:
- 普通客服可查询消息状态,但不能查看完整敏感报文。
- 运营可查看模板和场景配置。
- 运维 / 管理员可启停通道、修改路由和触发重试。
- 供应商密钥只允许服务端配置,不在页面明文展示。
15. 供应商标准接入规范
后续无论接短信供应商、语音外呼供应商、WhatsApp 供应商还是 Push 服务,都按同一套接入方式落地,避免每个上游系统重复适配。
15.1 定义供应商编码和通道类型
| 字段 | 说明 |
|---|---|
provider_code | 内部唯一编码,例如 uspeedo_sms、ai_voice_provider、firebase_fcm |
channel_type | sms / voice / whatsapp / push |
provider_name | 供应商展示名称 |
environment | test / production |
enabled | 是否启用 |
要求:
provider_code一旦上线,不随供应商展示名称变化。- 测试环境和生产环境分开配置。
- 上游系统不得直接使用供应商编码作为业务逻辑判断条件。
15.2 配置鉴权和环境
需要沉淀测试 / 生产域名、app key / secret / token、签名算法、超时时间、IP 白名单或回调地址要求、供应商接口文档和联系人。密钥只在服务端安全配置或配置中心保存,不进入 Markdown 明文、前端、普通后台或业务日志。
15.3 实现供应商适配器
每个供应商适配器至少实现:
| 方法 | 说明 |
|---|---|
send | 发起发送、外呼或导入任务 |
cancel | 可选,取消未完成发送或外呼 |
parseCallback | 解析供应商回调 |
mapStatus | 映射供应商状态到网关标准状态 |
mapFailureCode | 映射供应商失败码到网关标准失败码 |
healthCheck | 可选,检查供应商可用性 |
适配器只处理供应商协议差异,不写 BNS、FCS 的业务规则。
15.4 配置模板、路由和回调
- 内部统一使用
templateCode,供应商模板 ID、语音策略 ID、WhatsApp 模板 ID、FCM payload 差异都在网关侧映射。 - 场景路由配置维护
scene、primary_channel、primary_provider、backup_channel、backup_provider、fallback_conditions、cross_channel_enabled。 - 所有供应商回调统一进入
POST /message-gateway/api/v1/provider-callback/{providerCode}。 - 回调必须能反查
message_id和attempt_id,重复回调不得重复触发降级、重试或业务通知。
15.5 新供应商接入文档模板
新增供应商需求文档建议按以下结构编写:接入目标、一期范围、供应商接口概览、鉴权与签名、发送 / 导入接口、取消 / 查询接口、回调接口、字段映射、状态和失败码映射、数据落库要求、场景路由配置、异常与补偿、监控指标、联调用例、验收标准。
16. 监控指标
一期至少输出以下指标,供监控告警接入:
| 指标 | 说明 |
|---|---|
message_send_total | 按 scene、channel、provider 统计发送请求数 |
message_accept_success_rate | 供应商受理成功率 |
message_delivery_success_rate | 投递 / 接通成功率 |
message_failure_total | 失败数量,按标准失败码分组 |
message_callback_delay_seconds | 回执延迟 |
message_fallback_total | 降级触发次数 |
message_rate_limited_total | 频控拒绝次数 |
provider_timeout_total | 供应商超时次数 |
voice_call_connected_rate | 语音外呼接通率 |
voice_call_no_answer_total | 语音未接通、忙线、拒接、不可达数量 |
voice_callback_missing_total | 超过 TTL 未收到语音结果回调的数量 |
告警建议:
- OTP 短信 5 分钟受理成功率低于阈值,触发 P0。
- 还款提醒短信 30 分钟投递成功率低于阈值,触发 P1。
- AI 语音外呼供应商连续超时、导入名单失败、接通结果长期无回执或线路异常显著升高,触发 P1。
- WhatsApp 供应商鉴权失败或模板不可用,触发 P1。
17. 安全与合规
- 供应商密钥、token、签名密钥必须加密存储或通过配置中心安全注入。
- 请求和回执日志中手机号需支持脱敏展示。
- 模板内容不得包含不必要的敏感个人信息。
- WhatsApp 模板需遵守供应商模板审核和用户触达规则。
- AI 外呼话术中不得承诺未由业务系统确认的优惠、减免、展期或强制执行动作。
record_url可能包含客户对话录音,普通客服只可按权限查看,不允许在日志中明文打印。- 测试环境不得向真实客户手机号发送消息,除非明确使用白名单。
- 后台手工重试必须记录操作审计。
18. 联调要求
18.1 BNS 联调
- 登录 OTP 请求能通过消息网关发送短信。
- BNS 可拿到
messageId并按bizId查询状态。 - OTP 发送失败时,BNS 能拿到明确失败原因,用于前端提示或重试控制。
- 审核账号或测试账号可通过白名单避免真实短信发送。
18.2 FCS 联调
- FCS 可提交还款短信提醒请求,消息网关完成模板渲染和发送。
- FCS 可提交还款语音提醒请求,消息网关调用语音通道。
- 消息网关能按场景映射 AI 外呼
strategy_id,并将还款提醒变量转换为供应商details.extra。 - 语音未接通时,消息网关按配置标记可降级候选;自动短信或 WhatsApp 降级二期启用。
- FCS 可按借据 / 还款提醒任务的
bizId查询整条触达链路状态。 - 还款链接由 FCS 或短链服务生成并作为变量传入,消息网关不自行拼接。
18.3 通道供应商联调
- 短信供应商受理成功、受理失败、投递成功、投递失败均可模拟。
- 语音供应商接通、未接、忙线、超时、供应商失败均可模拟。
- AI 外呼名单导入、重复批次、取消外呼、实时结果回调和重复回调均可模拟。
- WhatsApp 发送成功、模板不存在、用户不可达均可模拟或以 mock 完成。
- 回执重复推送不产生重复状态流转。
19. 验收标准
- BNS 调用统一发送接口后,可以完成登录 OTP 短信发送,不直接调用短信供应商。
- FCS 调用统一发送接口后,可以完成还款短信提醒发送,不直接调用短信供应商。
- FCS 发起还款语音提醒后,消息网关能记录外呼结果。
- AI 外呼供应商可以通过名单导入接口接收还款提醒任务,供应商
batch_id、strategy_id、ref_id与消息网关发送明细可互相追踪。 - AI 外呼供应商回调
ANSWERED、NO_ANSWER、USER_BUSY、CALL_REJECTED、NO_USER_RESPONSE、UNALLOCATED_NUMBER、NETWORK_FAILED后,消息网关能映射为标准状态。 - 语音未接通、忙线、供应商失败或超时后,消息网关能按配置标记跨类型降级候选;生产自动短信或 WhatsApp 降级不在一期启用。
UNALLOCATED_NUMBER或手机号非法不触发同号码降级触达。- 同一次语音失败只触发一次降级消息,降级消息能关联原语音发送明细。
- 同一
sourceSystem + scene + bizId + receiverPhone重复请求不会重复发送。 - 模板变量缺失、手机号非法、通道禁用等异常能返回明确错误码。
- 供应商回执能更新消息状态,重复回执不会重复处理。
- 上游可通过
messageId或sourceSystem + bizId查询消息状态和通道发送明细。 - 后台或运维入口可查询失败消息,并对允许重试的消息触发手工重试。
- OTP 类消息不允许后台手工重试过期验证码。
- 基础监控指标能按场景、通道、供应商拆分。
- 供应商密钥不暴露给 BNS、FCS、前端或普通后台用户。
- AI 外呼回调按
call_id幂等处理,重复回调不会重复更新业务状态或重复标记降级候选。 - 一期没有引入人群圈选、复杂营销编排、A/B 实验等重型能力。
20. 后续演进
一期稳定后,再逐步考虑:
- 多短信供应商按成功率、成本、号段、时间窗口做动态路由。
- 启用不同类型通道之间的自动路由和降级,例如语音失败后短信 / WhatsApp。
- WhatsApp 富媒体、按钮、会话消息和模板生命周期管理。
- 语音外呼录音、转写和催收结果结构化。
- 客户触达偏好和退订管理。
- 批量任务、定时发送和优先级队列。
- 营销活动、A/B 实验和转化归因。
- 与催收系统、客服系统、运营后台形成完整触达闭环。