自定义应用 Bridge API
基于持续 HTTP NDJSON 流的自定义应用消息中转接口与字段说明。
自定义应用由外部 runner 主动连接 Mopheus。外发消息通过持续返回的 HTTP NDJSON 事件流投递;入站消息、附件和投递结果通过独立 HTTP 请求提交。Mopheus 不向 runner 发起回调,也不要求回调地址。所有示例路径均相对于 Mopheus API 根地址。
约定与认证
| 项目 | 约定 |
|---|---|
| Bridge 基础路径 | /api/v1/channel/bridge |
| 协议版本 | 事件与消息体的 version: 1;事件流请求头 X-Bridge-Protocol-Version: 1 |
| Bridge 认证 | Authorization: Bearer mcb_<installation-uuid>_<secret>;令牌在创建或轮换时仅返回一次 |
| JSON 响应 | 成功为 {"success":true,"data":{...}};失败为 {"success":false,"code":"...","error":"...","requestId":"..."}。未出现的可选字段不要假设为 null |
| 时间与 ID | 时间为 RFC 3339;内部 ID 为 UUID;平台 ID 是最长 255 字节的字符串,保持大小写和原值 |
| HTTPS | 生产环境使用 HTTPS;二进制上传仍使用同一 Bridge Bearer 令牌 |
Bridge 令牌只授权所属安装,不能代替成员登录。创建、轮换和撤销使用成员认证及工作区权限;其余 /channel/bridge 路由统一由 Bridge 令牌中间件认证。HTTP 400 表示输入错误,401 表示令牌无效,403 表示渠道功能关闭或成员无权操作,404 表示资源不存在或不可访问,409 表示事件流已占用、租约失效或结果冲突,5xx 表示服务端或依赖故障。客户端应按 code 和 HTTP 状态处理错误,不解析 error 文案。
安装管理(成员 API)
以下接口位于 /api/v1/channel,需要成员登录和工作区请求头(与其他工作区 API 相同)。安装需要渠道管理权限。
| 方法与路径 | 请求 | 成功 data |
|---|---|---|
POST /bridge/installations | {"name":"示例应用","platformKey":"example","assigneeType":1,"assigneeId":"<agent-uuid>","externalBotId":"bot-1"} | {"installation":{...}} |
POST /bridge/installations/{installationId}/credentials | 空请求体 | {"bridgeToken":"mcb_..."};首次调用生成令牌,再次调用轮换并使旧令牌失效 |
DELETE /bridge/installations/{installationId}/credentials/{credentialId} | 无请求体;V1 的 credentialId 等于安装 ID | null;撤销当前令牌并断开事件流 |
platformKey 匹配 ^[a-z0-9][a-z0-9_-]{1,49}$;name 最长 100 字节,externalBotId 最长 255 字节。assigneeType 为 1(Agent)或 3(Team),assigneeId 必须属于当前工作区。创建安装不会生成令牌;在安装详情页点击“生成令牌”后,立即写入 runner 的秘密配置。令牌仅显示一次。
持续接收外发事件
GET /api/v1/channel/bridge/stream HTTP/1.1
Authorization: Bearer mcb_...
Accept: application/x-ndjson
X-Bridge-Protocol-Version: 1
X-Bridge-Runner-Id: example-runner
X-Bridge-Version: example/1.0.0
X-Bridge-Platform-Key: example
X-Bridge-Inbound-Capabilities: text,image,file,audio,video,reply,thread,mention
X-Bridge-Outbound-Capabilities: text,image,file,audio,video,reply,thread,mention成功返回 HTTP 200、Content-Type: application/x-ndjson; charset=utf-8。响应体每行是一个完整 JSON 对象,服务端逐行刷新;连接不会在第一行后结束。必须逐行解析,忽略空行。一个安装同时只允许一条有效连接;冲突时返回 409。代理应关闭响应缓冲并允许长连接。断开后用指数退避重连,不能把流重连理解为投递成功。
{
"version": 1,
"type": "hello",
"id": "<event-uuid>",
"sentAt": "2026-10-14T10:00:00Z",
"payload": {
"connectionId": "<uuid>",
"heartbeatSeconds": 20,
"deliveryLeaseSeconds": 60,
"acceptedCapabilities": {
"inbound": [
"text",
"file"
],
"outbound": [
"text",
"file"
]
}
}
}
{
"version": 1,
"type": "heartbeat",
"id": "<event-uuid>",
"sentAt": "2026-10-14T10:00:20Z",
"payload": {
"connectionId": "<uuid>"
}
}
{
"version": 1,
"type": "delivery",
"id": "<event-uuid>",
"sentAt": "2026-10-14T10:00:22Z",
"envelope": {
"deliveryId": "<uuid>",
"attemptId": "<uuid>",
"attempt": 1,
"leaseExpiresAt": "2026-10-14T10:01:22Z",
"completedParts": [],
"target": {
"type": "chat",
"conversationId": "group-1",
"conversationType": "group",
"threadId": "topic-1"
},
"replyTo": {
"messageId": "platform-parent-1"
},
"content": {
"text": "报告见附件",
"format": "plain",
"parts": [
{
"partId": "text:0",
"type": "text",
"text": "报告见附件"
},
{
"partId": "file:0",
"type": "attachment",
"attachmentId": "<attachment-uuid>",
"kind": "file",
"filename": "report.pdf",
"mimeType": "application/pdf",
"sizeBytes": 20480,
"downloadPath": "/api/v1/channel/bridge/deliveries/<delivery-uuid>/assets/<attachment-uuid>"
}
]
}
}
}上面三行代表三条独立事件,不是一个 JSON 数组。deliveryId 跨重试稳定,attemptId 每次派发变化。completedParts 是服务端可识别的已完成 part 列表;V1 服务端不持久化逐 part 结果,runner 必须自行保存 deliveryId + partId -> platformMessageId。target.type 是现有渠道外发目标枚举,常见值为 chat;conversationId、userId、threadId 只在适用目标中出现。平台发送成功后应先持久化真实平台消息 ID,再提交结果。没有收到结果响应时,用同一投递的已保存 part 记录重试。
提交入站消息
POST /api/v1/channel/bridge/messages,Content-Type: application/json,请求体最大 256 KiB:
{
"version": 1,
"type": "message.inbound",
"id": "<request-uuid>",
"sentAt": "2026-10-14T10:02:00Z",
"payload": {
"eventId": "platform-event-1",
"messageId": "platform-message-1",
"occurredAt": "2026-10-14T10:01:59Z",
"conversation": {"id":"group-1","type":"group","title":"研发","threadId":"topic-1"},
"sender": {"id":"user-1","kind":"user","stableId":"account-1","displayName":"李四"},
"recipient": {"botId":"bot-1","addressedToBot":true},
"replyTo": {"messageId":"platform-parent-1","rootMessageId":"platform-root-1"},
"content": {"kind":"mixed","text":"请看报告","parts":[
{"type":"text","text":"请看报告"},
{"type":"mention","id":"user-2","label":"@王五"},
{"type":"attachment","assetId":"<uploaded-asset-uuid>","kind":"file"}
]},
"extensions": {"platformSpecific":"optional"}
}
}conversation.type: direct | group;sender.kind: user | bot | system;content.kind: text | image | file | audio | video | mixed | unknown。unknown 必须有可读 text。parts 保留顺序,类型为 text | mention | attachment | link | code | emoji | quote;attachment 必须提供已上传且属于同一安装、同一 messageId 的 assetId。content.text 与每段文字最多 64 KiB,最多 100 段、其中最多 20 个附件。eventId 与 messageId 都必填;同一平台消息的重试必须保留 messageId 和正文,不得用原 ID 表示编辑。
成功响应示例:
{"success":true,"data":{"messageId":"platform-message-1","status":"ingested","chatSessionId":"<uuid>","mediaState":"pending"}}data.status | 处理方式 |
|---|---|
ingested | 消息已入库;不代表 Agent 已完成。带附件时 mediaState 可为 pending |
duplicate | 安装内同一 messageId 已处理;终态 |
dropped | 按渠道规则丢弃,例如机器人消息或未绑定用户;可查看 reason |
rejected | 时间过期、目标机器人不匹配等;终态 |
retry | 临时处理失败;保留本地事件,按 retryAfterMs 重发 |
发生网络错误或 5xx 时保留原消息并重试。超过 7 天或未来超过 5 分钟的 occurredAt 会返回 rejected。机器人和系统发送者会返回 dropped,防止消息回环。入站队列由 runner 持久化;收到终态前不能删除源事件。V1 去重只按安装和 messageId,不能识别同 ID 的正文变化,也不支持编辑或撤回事件。
图片和附件
入站先申请,再上传原始字节,最后提交引用该资源的消息。平台私有下载、鉴权和解密由 runner 完成;Mopheus 不抓取平台 URL。
POST /api/v1/channel/bridge/assets
Content-Type: application/json
{
"messageId": "platform-message-1",
"sourceKey": "file:0",
"kind": "file",
"filename": "report.pdf",
"mimeType": "application/pdf",
"sizeBytes": 20480,
"sha256": "<64位十六进制SHA-256>"
}成功 data 为 {"assetId":"<uuid>","state":"upload","uploadPath":"/api/v1/channel/bridge/assets/<uuid>"};已上传资源的 state 为 ready,此时无需重复 PUT。sourceKey 是同一消息内稳定的附件标识。单个文件最多 25 MiB;文件名不得带路径。sizeBytes 和 sha256 在申请阶段校验格式与上限;V1 不把申请摘要持久化,上传时另按实际字节校验 X-Content-SHA256。
PUT /api/v1/channel/bridge/assets/<assetId>
Content-Type: application/pdf
X-Bridge-Filename: report.pdf
X-Content-SHA256: <本次上传原始字节的SHA-256>
<二进制字节>成功 data 为 {"state":"ready"}。上传中冲突返回 409;重复上传已就绪资源也返回 ready。V1 不支持分片、Range 和断点续传。提交入站消息前应等到所有附件就绪。
外发附件使用事件中的 downloadPath:
GET /api/v1/channel/bridge/deliveries/<deliveryId>/assets/<attachmentId>
X-Bridge-Attempt-Id: <attemptId>此接口返回 application/octet-stream 原始字节,不包裹 JSON。只有当前有效投递尝试能下载本安装、当前消息的附件;无权或失效时返回 JSON 错误。
确认、失败与续租
外发所有 part 成功后提交真实平台消息 ID:
POST /api/v1/channel/bridge/deliveries/<deliveryId>/result
Content-Type: application/json
{
"attemptId": "<uuid>",
"status": "sent",
"parts": [
{
"partId": "text:0",
"platformMessageId": "platform-1"
},
{
"partId": "file:0",
"platformMessageId": "platform-2"
}
]
}sent 必须包含当前投递的全部 part,partId 不能重复或未知,platformMessageId 不可为空。成功 data 为 {"deliveryId":"<uuid>","attemptId":"<uuid>","status":"sent","completedParts":null};若字段未出现,客户端应按空列表处理。相同成功尝试重复提交会返回 sent。失败请求为 {"attemptId":"<uuid>","status":"failed","category":"rate_limited","platformCode":"429","message":"try later","retryAfterMs":30000,"parts":[]}。可重试分类为 rate_limited | transient | unknown;其他分类或达到最大尝试次数进入 failed。尚可重试时返回 status: "pending"。服务端只保存整条投递状态,不能作为逐 part 成功日志。
长时间上传/平台发送前可续租:POST /api/v1/channel/bridge/deliveries/<deliveryId>/renew,请求体 {"attemptId":"<uuid>"};成功 data 为 {"leaseExpiresAt":"<RFC3339时间>"}。每次延长至当前时间后 60 秒,且不超过任务过期时间。尝试失效、租约已过期或被替换时返回 409;runner 不应再提交旧 attemptId 的结果。平台发送成功但本地日志写入前崩溃可能重复发送,协议只保证至少一次投递。优先使用平台支持的幂等键 deliveryId:partId。
用户绑定与示例
外部用户收到一次性绑定令牌后,由已登录的 Mopheus 成员调用 POST /api/v1/channel/bind,请求体 {"token":"<one-time-binding-token>"};成功 data 为绑定记录。此接口使用成员认证,不使用 Bridge 令牌。
可运行的 runner 和协议检查脚本见代码仓库的 examples/channel-bridge/ 与 scripts/test-channel-bridge.sh。生产 runner 需要持久化入站消息和外发 part 结果,并实现真实平台发送适配器;打印消息并回报成功会造成消息丢失。
示例 runner 的平台 HTTP 接口
这一节是 examples/channel-bridge/runner.py、runner.go、runner.mjs 对平台提供的示例接口,不是 Mopheus 服务端路由。runner 默认监听 127.0.0.1:8765;外网监听需设置 MOPHEUS_BRIDGE_WEBHOOK_TOKEN,平台请求携带 X-Platform-Token。平台事件先持久化,runner 才返回 HTTP 202。
POST http://127.0.0.1:8765/platform/messages
Content-Type: application/json
X-Platform-Token: <仅在配置时必需>
{"messageId":"platform-msg-1","eventId":"event-1","occurredAt":"2026-10-14T10:01:59Z","conversation":{"id":"group-1","type":"group","title":"研发","threadId":"topic-1"},"sender":{"id":"user-1","kind":"user","displayName":"李四"},"recipient":{"botId":"bot-1","addressedToBot":true},"content":{"kind":"mixed","text":"报告","parts":[{"type":"text","text":"报告"},{"type":"attachment","kind":"file","filename":"report.txt","mimeType":"text/plain","dataBase64":"aGVsbG8="}]}}| 平台字段 | 必需 | 转成 Mopheus 字段 |
|---|---|---|
messageId | 是 | payload.messageId;同一平台消息重试必须不变 |
eventId、occurredAt | 否 | payload.eventId、payload.occurredAt;缺省分别为 messageId 和接收时间 |
conversation | 是 | 原样映射至 payload.conversation,至少需要 id 和 type |
sender | 是 | 原样映射至 payload.sender,至少需要 id 和 kind |
recipient | 否 | 映射至 payload.recipient;缺省 addressedToBot: true |
content.text、content.parts | 否 | 保留文本与有序 parts;无 parts 时缺省 kind: text |
附件 dataBase64 | 附件时必需 | runner 解码后先调用 POST /assets、PUT /assets/{assetId},再用 assetId 替换原始字节 |
成功返回 HTTP 202 {"accepted":true,"messageId":"platform-msg-1"},表示 runner 已持久化,不表示 Mopheus 已完成;同 ID 不同请求返回 409,缺字段或非法 JSON 返回 400,令牌错误返回 401。示例请求体最多 36 MiB,单附件最多 25 MiB。收到 202 后由 runner 承担重试。
外发时 runner 将 Mopheus delivery.envelope 的每个 part POST 到 MOPHEUS_BRIDGE_PLATFORM_SEND_URL。示例平台发送 API 请求与响应:
POST http://127.0.0.1:8766/send
Content-Type: application/json
{
"deliveryId": "<uuid>",
"partId": "file:0",
"idempotencyKey": "<uuid>:file:0",
"target": {
"type": "chat",
"conversationId": "group-1",
"conversationType": "group"
},
"replyTo": null,
"part": {
"partId": "file:0",
"type": "attachment",
"filename": "report.txt",
"mimeType": "text/plain"
},
"assetPath": ".bridge-downloads/<uuid>-file:0",
"attachment": {
"filename": "report.txt",
"mimeType": "text/plain",
"dataBase64": "aGVsbG8="
}
}
HTTP/1.1 200 OK
Content-Type: application/json
{"platformMessageId":"sim-123"}文本 part 没有 attachment。平台应按 idempotencyKey 去重;平台返回非 2xx 或缺少非空 platformMessageId 时,runner 不会向 Mopheus 报告 sent。platform_simulator.py serve 提供上述 /send 和只读 /messages 发件箱,供三种 runner 联调。真实平台可替换该 URL,或用 MOPHEUS_BRIDGE_SEND_COMMAND 包装 SDK。
字段字典
以下“必需”指请求方必须提供;服务端事件字段由 Mopheus 填写。JSON 名称区分大小写,均为 camelCase。<uuid> 表示 UUID 字符串,<time> 表示 RFC 3339 时间字符串。
安装请求与响应
| 字段 | 类型/必需 | 含义 |
|---|---|---|
name | string / 是 | 页面显示的应用名称,最长 100 字节;不参与平台路由 |
platformKey | string / 是 | 开发者定义的平台标识;必须与事件流头 X-Bridge-Platform-Key 相同 |
assigneeType | integer / 是 | 负责处理消息的对象类型:1 为 Agent,3 为 Team |
assigneeId | UUID / 是 | 对应 Agent 或 Team 的工作区内 ID |
externalBotId | string / 否 | 外部平台的机器人 ID;入站 recipient.botId 非空时必须匹配 |
installation.id | UUID / 创建响应 | 自定义应用安装 ID,同时也是 V1 凭据路径中的 credentialId |
bridgeToken | string / 凭据响应 | 在详情页生成或轮换时只返回一次;轮换后旧值立即无效 |
入站信封 POST /messages
| 字段 | 类型/必需 | 含义 |
|---|---|---|
version | integer / 是 | 协议版本,目前只能为 1 |
type | string / 是 | 事件类型,目前只能为 message.inbound |
id | UUID / 是 | 这次 HTTP 事件的传输 ID;重试可重新生成,不作为消息去重键 |
sentAt | time / 是 | runner 提交本次 HTTP 请求的时间 |
payload.eventId | string / 是 | 平台事件 ID,最长 255 字节;用于追踪该平台事件 |
payload.messageId | string / 是 | 平台消息 ID,最长 255 字节;同一安装的入站去重键 |
payload.occurredAt | time / 是 | 平台消息真实发生时间;超过 7 天或未来超过 5 分钟会拒绝 |
payload.conversation.id | string / 是 | 平台会话 ID;区分私聊/群聊的会话身份 |
payload.conversation.type | string / 是 | direct 私聊或 group 群聊 |
payload.conversation.title | string / 否 | 群聊显示名称,不参与去重 |
payload.conversation.threadId | string / 否 | 平台话题/线程 ID;用于回复到同一话题 |
payload.sender.id | string / 是 | 平台发送者 ID;用于账号绑定与消息归属 |
payload.sender.kind | string / 是 | user、bot、system;后两者丢弃以避免回环 |
payload.sender.stableId | string / 否 | 平台跨会话稳定的账号 ID,可供身份匹配 |
payload.sender.displayName | string / 否 | 发送者的显示名称 |
payload.recipient.botId | string / 否 | 目标机器人 ID;非空时与安装的 externalBotId 核对 |
payload.recipient.addressedToBot | boolean / 是 | 此消息是否明确发给机器人;影响群聊消息路由 |
payload.replyTo.messageId | string / 有引用时 | 被引用的外部平台消息 ID |
payload.replyTo.rootMessageId | string / 否 | 引用链的根消息 ID |
payload.extensions | object / 否 | 平台专有的扩展数据;不要把秘密放在这里 |
正文与有序 parts
| 字段 | 类型/必需 | 含义 |
|---|---|---|
content.kind | string / 是 | 总体内容类型:text、image、file、audio、video、mixed、unknown;unknown 必须有可读文本 |
content.text | string / 是 | 可读正文或降级文本;最多 64 KiB;有 parts 时按 parts 顺序生成展示文本 |
content.parts | array / 否 | 按平台显示顺序排列的片段,最多 100 个,附件最多 20 个 |
parts[].type | string / 是 | text、mention、attachment、link、code、emoji、quote |
parts[].text | string / 文本类时 | 文本、代码或引用的内容;每段最多 64 KiB |
parts[].id | string / mention 时 | 被提及的平台用户 ID,最长 255 字节 |
parts[].label | string / mention/link/emoji 时 | 展示标签,例如 @李四 或链接标题 |
parts[].assetId | UUID / attachment 时 | 通过 Bridge 附件申请和上传后取得的 ID;不是平台文件 ID |
parts[].kind | string / 否 | 附件类型,例如 image 或 file |
parts[].url | string / link 时 | 链接地址;平台私有附件 URL 不应放在这里代替上传 |
parts[].language | string / 否 | 代码块语言提示 |
parts[].unicode、platformCode | string / 否 | 表情的 Unicode 或平台自定义编码 |
parts[].authorLabel | string / 否 | 引用作者的展示名称 |
parts 中各类型使用适用字段;未使用的字段可省略。mention 必须有 id 与 label,link 必须有 url 与 label,emoji 必须有 label。Mopheus 展示正文从有序 parts 计算,而 slash 命令只从 text part 读取,避免引用、提及等意外触发命令。
入站结果与附件
| 字段 | 类型/必需 | 含义 |
|---|---|---|
data.messageId | string / 响应 | 对应平台消息 ID |
data.status | string / 响应 | ingested、duplicate、dropped、rejected、retry;含义见上文状态表 |
data.reason | string / 否 | 丢弃/拒绝原因,例如 needs_binding、expired_event、bot_mismatch |
data.chatSessionId | UUID / 响应 | 已建立的 Mopheus 会话 ID;无会话时可能为全零 UUID |
data.mediaState | string / 响应 | none 或 pending;pending 表示附件绑定仍由异步流程完成 |
data.retryAfterMs | integer / retry 时 | runner 下次重试前建议等待的毫秒数 |
assets.messageId | string / 是 | 附件所属平台消息 ID,必须与后续 /messages 一致 |
assets.sourceKey | string / 是 | 消息内稳定的附件位置标识,例如 file:0;重试时保持不变 |
assets.kind | string / 是 | 图片、文件、音频或视频等类型提示 |
assets.filename | string / 是 | 原文件名,不含目录路径,最长 255 字节 |
assets.mimeType | string / 是 | MIME 类型,最长 100 字节 |
assets.sizeBytes | integer / 是 | 原始二进制大小,必须大于零且不超过 25 MiB |
assets.sha256 | string / 是 | 原始二进制 SHA-256 的 64 位十六进制值;申请时只校验格式 |
data.assetId | UUID / 响应 | Mopheus 附件 ID,供入站 part 的 assetId 引用 |
data.state | string / 响应 | upload 需继续 PUT,ready 可直接发送消息 |
data.uploadPath | string / 响应 | PUT 原始字节的相对路径 |
X-Content-SHA256 | header / PUT 必需 | 本次 PUT 实际字节的 SHA-256;服务端逐字节校验 |
X-Bridge-Filename | header / PUT 必需 | 本次上传的文件名 |
外发事件、结果与续租
| 字段 | 类型/必需 | 含义 |
|---|---|---|
version、type、id、sentAt | 事件顶层 / 服务端 | 协议版本、hello/heartbeat/delivery 类型、事件 UUID 和发送时间 |
hello.connectionId | UUID / 服务端 | 当前事件流连接 ID,不是投递 ID |
hello.heartbeatSeconds | integer / 服务端 | 预计心跳间隔,单位秒 |
hello.deliveryLeaseSeconds | integer / 服务端 | 初始投递租约时长,单位秒 |
hello.acceptedCapabilities.inbound/outbound | string[] / 服务端 | 服务端接受的收发能力列表 |
heartbeat.connectionId | UUID / 服务端 | 对应的流连接 ID |
envelope.deliveryId | UUID / 服务端 | 外发任务 ID,跨重试不变 |
envelope.attemptId | UUID / 服务端 | 当前派发尝试 ID;续租、附件下载和结果提交必须使用它 |
envelope.attempt | integer / 服务端 | 当前任务第几次派发,从 1 开始 |
envelope.leaseExpiresAt | time / 服务端 | 当前尝试的租约截止时间 |
envelope.expiresAt | time / 否 | 整条外发任务的最终过期时间 |
envelope.completedParts | string[] / 服务端 | 服务端已知完成的 part ID;V1 通常为空,不能替代 runner 本地日志 |
envelope.target.type | string / 服务端 | chat 发往会话,user 发往用户 |
envelope.target.conversationId | string / chat 时 | 平台会话 ID |
envelope.target.conversationType | string / chat 时 | direct 或 group |
envelope.target.userId | string / user 时 | 平台目标用户 ID |
envelope.target.threadId | string / 否 | 平台话题/线程 ID |
envelope.replyTo.messageId | string / 否 | 应引用的外部平台消息 ID |
envelope.content.text | string / 服务端 | 整条消息的可读文本快照 |
envelope.content.format | string / 服务端 | V1 为 plain |
envelope.content.parts[].partId | string / 服务端 | 片段稳定 ID;与 deliveryId 组成平台幂等键 |
parts[].type、text | string / 服务端 | 片段类型与文本内容 |
parts[].attachmentId | UUID / 附件时 | Mopheus 附件 ID |
parts[].kind、filename、mimeType、sizeBytes | 附件元数据 / 附件时 | 平台发送附件所需的类型、文件名、MIME 和字节大小 |
parts[].downloadPath | string / 附件时 | 当前尝试可 GET 的附件相对路径;需带 X-Bridge-Attempt-Id |
result.attemptId | UUID / 是 | 本次结果对应的有效尝试 |
result.status | string / 是 | sent 全部成功,或 failed 本次发送失败 |
result.parts[].partId | string / sent 时 | 已发送片段 ID;成功结果需覆盖全部片段 |
result.parts[].platformMessageId | string / sent 时 | 平台实际返回的消息 ID,不能为空 |
result.platformRequestId | string / 否 | 平台请求追踪 ID,便于排障 |
result.category、platformCode、message | string / failed 时可选 | 错误分类、平台错误码、可读错误信息 |
result.retryAfterMs | integer / 否 | 可重试失败后的建议等待毫秒数 |
renew.attemptId | UUID / 是 | 要延长的有效尝试 ID |
renew.data.leaseExpiresAt | time / 响应 | 续租后的新截止时间 |
结果响应中的 data.deliveryId、data.attemptId、data.status 分别回显任务、尝试和当前状态。status 可能为 sent、pending 或 failed。data.completedParts 在 V1 可能为 null 或空列表,客户端应按空列表处理。失败后的新尝试会产生新的 attemptId,旧尝试不应继续写入。