快速开始
在 Web 管理后台为目标公司创建第三方应用,复制 App ID 和 App Secret;如需接收最终结果,再填写可选的 Callback URL。
Engine 会为可选 audience 选中的用户生成通知中心记录(默认是绑定公司的全部有效用户),并仅向符合条件的已注册设备尝试发送系统 Push。
接口与认证
API 环境:
第三方服务端发送的每个 JSON 请求都必须通过 HTTP Basic Authentication 携带 Authorization: Basic Base64(KEY:SECRET),其中 KEY 是 App ID,SECRET 是 App Secret:
接口:POST /openapi/v1/notifications。
curl --request POST 'https://<your-engine-host>/openapi/v1/notifications' \
--header 'Authorization: Basic <Base64(AppID:AppSecret)>' \
--header 'Content-Type: application/json' \
--data '{"requestId":"order-20260819-001","title":"订单已完成","body":"您的订单已经完成。","imageUrls":["https://cdn.example.com/order/001-1.webp","https://cdn.example.com/order/001-2.webp"],"displayFields":[{"label":"店铺名称","value":"小韩面(望京店)"},{"value":"ORD-10086"}],"tags":["已完成","望京店"]}'请求契约
字段总览
| 字段 | 必填 | 类型 | 含义 |
|---|---|---|---|
requestId | 是 | string | 调用方生成的请求唯一标识,也是幂等键;去除首尾空白后不能为空。 |
title | 是 | string | 通知标题;去除首尾空白后不能为空。 |
body | 是 | string | 通知正文;去除首尾空白后不能为空。 |
imageUrls | 否 | string[] | 通知详情中按顺序展示的图片 URL。 |
displayFields | 否 | object[] | 通知详情中按顺序展示的补充文本字段。 |
tags | 否 | string[] | 仅在通知详情中按顺序展示的纯文本标签。 |
audience | 否 | object | 将发送范围缩小到指定用户或公司角色;省略时发送给全公司有效用户。 |
图片 imageUrls
- 省略、
null或[]都表示没有图片;否则可按展示顺序传入 1-9 个 URL。 - 每个 URL 会去除首尾空白,必须唯一,并且是无用户名和密码的绝对
HTTPSURL。 - 单个 URL 最多 2048 个 Unicode 字符;任一 URL 不合法都会拒绝整个请求。
- Engine 只存储 URL,不会抓取、探测、代理或缓存图片。
展示字段 displayFields
| 子字段 | 必填 | 限制 | 显示方式 |
|---|---|---|---|
label | 否 | 去除首尾空白后不能为空;最多 32 Unicode 字符 | 作为字段名称显示。 |
value | 是 | 去除首尾空白后不能为空;最多 256 Unicode 字符 | 作为字段内容显示。 |
{
"displayFields": [
{ "label": "店铺名称", "value": "小韩面(望京店)" },
{ "value": "ORD-10086" }
]
}- 省略、
null或[]都表示没有额外字段;最多传 10 个对象。 - 不含
label或label为null的对象,会把value显示为独占整行。 - 内容始终按 plain text 展示,不支持 HTML、Markdown、链接、嵌套数据、字段类型或样式指令。
详情标签 tags
- 省略、传
null或[]都表示没有标签;否则最多传 8 个字符串,并按传入顺序展示。 - 每个标签会去除首尾空白,去除后必须为 1-20 Unicode 字符。空值、非字符串、超长值或去除空白后重复,都会让整个请求返回
INVALID_REQUEST。 - 标签仅在通知详情中以不可点击的 plain text 展示,并保留原顺序。
发送对象 audience
type | 选择器 | ID 含义 |
|---|---|---|
USERS | userIds | 公司成员 ID |
ROLES | roles | CompanyRole ID;命中任一角色的有效成员都会接收。 |
公司成员 ID 可从 Web 管理后台的公司成员列表复制;该成员必须属于第三方应用绑定的公司。
{
"audience": {
"type": "USERS",
"userIds": ["companyMemberId"]
}
}{
"audience": {
"type": "ROLES",
"roles": ["roleId"]
}
}- 省略
audience或传null时,发送给绑定公司的全部有效用户。 - 对应数组必须有 1-100 个原始字符串;ID 会被去除首尾空白,空白项被忽略,并按集合去重、排序。
- 不存在、禁用、已删除或跨公司的 ID 会被忽略,其余有效对象照常接收。
- 合法选择器没有命中有效对象时仍会受理,以
recipientCount=0完成,绝不会回退为全公司发送。 - 不匹配当前 type 的字段可省略或传
null;其他混用、未知 type、缺失或空数组、非字符串项、未知字段以及超过 100 项都会返回INVALID_REQUEST。
限制与幂等
- 完整请求体上限为 256 KiB;
requestId、title、body分别最多 128、100、1000 个 Unicode 字符。 - 每个 App ID 每分钟最多 10 次、每小时最多 100 次。
- 使用相同
requestId和等价的规范化内容重试会返回原结果。图片、展示字段和 tags 均保留顺序;audience 按类型和目标 ID 集合比较,顺序和重复项不影响幂等性。 - 相同
requestId携带不同内容时返回IDEMPOTENCY_CONFLICT。已完成请求的status可能是SUCCESS、PARTIAL_SUCCESS或FAILED。
接收响应
合法请求返回 HTTP 202:
{
"requestId": "order-20260819-001",
"notificationId": "00000000-0000-0000-0000-000000000001",
"status": "ACCEPTED"
}ACCEPTED 仅表示 Engine 已保存请求并等待分发,不代表 APNs/FCM 或设备已经展示系统横幅。
Callback 结果
配置 Callback URL 后,Engine 会发送一次终态结果:
{
"requestId": "order-20260819-001",
"status": "PARTIAL_SUCCESS",
"recipientCount": 8,
"pushAcceptedCount": 1,
"pushFailedCount": 1
}recipientCount 是通知中心接收用户数;pushAcceptedCount 和 pushFailedCount 是 Push Outbox 批次数,不是用户数、设备数或系统横幅送达数。
Callback 测试
管理后台每次测试 Callback 时都会发送一个独立的探测事件:
{
"requestId": "callback-test-<unique-id>",
"status": "SUCCESS",
"recipientCount": 1,
"pushAcceptedCount": 1,
"pushFailedCount": 0,
"test": true
}收到 test: true 时,只需校验结构并返回 2xx;不要将该探测事件关联到已提交的通知请求,也不要更新业务送达状态。其中的计数是固定探测值,不代表真实接收用户或 Push Outbox 批次。
终态 status 为 SUCCESS、PARTIAL_SUCCESS 或 FAILED。返回任意 2xx 即确认成功。
否则 Engine 会在 1 分钟、5 分钟、30 分钟、2 小时、6 小时和 24 小时后重试。当前 Callback 没有 HMAC 签名:必须使用 HTTPS、校验非测试结果的 requestId 是否属于己方请求、尽量限制入口暴露范围,并保证幂等处理。
错误说明
| HTTP | Code | 含义 |
|---|---|---|
| 400 | INVALID_REQUEST | Content-Type、JSON 结构、大小或字段校验失败。 |
| 401 | INVALID_APP_CREDENTIALS | App ID 或 App Secret 无效。 |
| 403 | APPLICATION_INACTIVE | 应用或绑定公司未启用。 |
| 409 | IDEMPOTENCY_CONFLICT | 相同 requestId 被用于不同内容。 |
| 429 | RATE_LIMITED | 超过应用级限流。 |
| 503 | NOTIFICATION_UNAVAILABLE | 通知服务暂时不可用。 |
安全与发送范围
- App ID 和 App Secret 是服务端到服务端凭证,禁止放入浏览器、移动 App、公开代码库、URL 或客户端存储;如有泄露请立即重置 App Secret。
- 私有目标 ID 不会写入应用 logs,私有 audience 选择器和目标 ID 也不会进入 GraphQL、Push、Callback、realtime 或 navigation 载荷。
- 不传
audience时,绑定公司的全部有效用户都会获得通知中心记录;传入后只发送给解析出的有效对象,并计入recipientCount。 - 系统 Push 仅尝试发送到有效且允许
BUSINESS分类的PushInstallation,仍不保证每台设备一定显示系统横幅。 - 完整的
imageUrls列表只会出现在已授权的通知详情中,但 Engine 可能把imageUrls中的第一个 URL 发送给 APNs/FCM,用于原生系统横幅展示图片。displayFields和tags不会进入 Push 或 Callback,且都是不可点击的 plain text;请勿放入密码、访问令牌、支付数据或其他敏感信息。 title和body必须在没有图片时仍能完整表达通知;图片下载或渲染失败不会改变 accepted、Callback 或 Push 状态。- 移动客户端每张图片最多接受 5 MiB,且单张图片完整下载操作的超时时间为 10 秒。客户端不会跟随 3xx 重定向,因此每个 URL 都必须直接返回图片。
- 移动客户端会直接从公共 CDN 下载图片,因此 URL 不得要求认证或 Cookie,且应至少保持 90 天可访问;CDN 会获得用户 IP、请求时间和 User-Agent。
- URL 对应内容可能变化,如需稳定保留历史展示,请使用不可变对象 URL。