发送提醒
每个频道都有一个或多个发送链接。要发送提醒,向发送链接 POST 一段 JSON 即可。完整链接可以在应用中复制,格式如下:
https://<api-host>/v1/send/<token>链接中的 token 是唯一凭证。任何拿到链接的人都能向这个频道发送提醒,所以不要把它放进公开仓库或日志。发送链接只能发送,不能读取提醒,也不能修改频道。
curl -X POST "$SEND_URL" \ -H 'Content-Type: application/json' \ -d '{"alert": {"title": "构建失败", "body": "main 分支有 3 个测试失败"}}'请求成功时返回 201 Created。提醒会在响应之前保存好,随后在后台投递到设备。
| 字段 | 类型 | 说明 |
|---|---|---|
alert.title |
string | 必填。 提醒标题。 |
alert.body |
string | 可选,显示在标题下方的详细内容。 |
level |
string | urgent、high、normal 或 silent,默认 normal。见提醒级别与重复提醒。 |
require_ack |
boolean | 在有人确认之前,提醒一直保持待处理。见确认与回执。 |
receipt |
boolean | 即使不要求确认,也返回一个可以查询的回执。 |
callback |
boolean | 提醒被确认时调用频道的确认回调。 |
emergency |
object | 紧急提醒的重复提醒时间:retry_seconds 和 expire_seconds。 |
url |
string | 从提醒中打开的链接。 |
event.type |
string | 发生了什么,例如 build.failed。 |
event.subject |
string | 发生在什么对象上,例如 repo:payments:main。 |
event.fingerprint |
string | 事件的稳定标识,用来识别重复事件。默认由 subject 和 type 组成。 |
dedupe |
object | 重复事件的处理方式,见重复事件。 |
thread_key |
string | 把相关提醒归为一组,显示在提醒详情中。 |
payload |
object | 想随提醒一起保存的任意 JSON。会保存并由接口返回,但不会显示。 |
expires_at |
string | RFC 3339 时间,过了这个时间提醒可以被删除。默认为发送后 21 天。 |
idempotency_key |
string | 用同一个 key 重试请求,会返回原来的提醒而不会再创建一条。也可以放在 Idempotency-Key 请求头中。 |
要求端到端加密的频道不接受 alert,而是接受加密信封,见加密提醒。
{ "message": { "id": "msg_4f1c…", "receipt_id": "rcp_9a02…", "level": "urgent", "require_ack": true, "status": "open", "dedupe_count": 1 }, "decision": { "reason": "new_message" }}响应中的 message 是保存下来的提醒,这里只列出了部分字段。提醒需要确认或请求了 receipt 时会有 receipt_id。decision.reason 说明这次请求的结果:
| 值 | 含义 |
|---|---|
new_message |
创建了一条新提醒。 |
duplicate_updated |
重复事件更新了一条未处理的提醒,见下文。 |
duplicate_recorded |
记录了一次重复,但没有修改提醒。 |
duplicate_dropped |
忽略了这次重复。 |
idempotent_replay |
这个 idempotency_key 已经用过,返回原来的提醒。 |
decision.effective_policy 给出这次实际采用的重复事件处理方式,字段名与请求中的 dedupe 对象相同。
每分钟失败一次的任务不应该塞满你的收件箱。请求带有 event,并且有一条指纹相同、仍未处理、在时间窗口内出现过的提醒时,这次请求会更新那条提醒,而不是新建一条:标题、正文、链接和级别被替换,出现次数加一,应用里会显示为“出现 3 次”这样的字样。除非提醒需要确认,重复事件不会再次通知。
没有任何 event 字段的请求永远不会被当作重复事件。
| 字段 | 默认值 | 说明 |
|---|---|---|
dedupe.mode |
coalesce |
none 表示总是新建提醒。 |
dedupe.window_seconds |
600 |
距上一次重复多长时间内,新的请求仍会合并到这条未处理的提醒。 |
dedupe.accept_policy |
update_visible |
update_visible 更新提醒;update_and_notify 更新并再次通知;record_only 只计数不修改;drop 直接忽略。 |
dedupe.renotify_after_seconds |
0 |
允许再次通知时,距上次通知至少要间隔的时间。 |
提醒被确认或解决之后,同一指纹的下一次请求会开始一条新提醒。
长度按字符计算,一个汉字、一个英文字母、一个表情符号都算一个字符。首尾空白会被忽略。
| 字段 | 限制 |
|---|---|
| 请求体 | 64 KB |
alert.title |
100 个字符,只能一行 |
alert.body |
1000 个字符,可以包含换行和制表符 |
alert.title + alert.body |
合计 1000 个字符 |
url |
512 字节;必须是 http 或 https 绝对地址,非 ASCII 字符需百分号编码 |
thread_key、idempotency_key |
128 个字符 |
event.type |
64 个字符 |
event.subject、event.fingerprint |
200 个字符 |
payload |
JSON 不超过 8 KB,嵌套不超过 8 层 |
超过限制的请求会以 alert_too_long 拒绝,不会被悄悄截断。推送通知中过长的正文会被截短,但收件箱里始终是完整内容。所有限制汇总在限制。
- 每个发送链接默认每分钟接受 60 次请求。超过后请求返回
429 limit_exceeded和Retry-After响应头,且不算作已发送。 - 如果一个发送链接远远超出限制还在持续发送——一分钟内至少 100 次被拒绝,或者限制的十倍(取较大者)——它会被暂停,之后返回
401 invalid_send_url。否则服务器无法阻止一个失控的脚本,而泄露的链接也绝不会被悄悄恢复。修好发送端之后,在应用中重新生成链接。 - 每个网络地址在所有接口上每分钟最多 600 次请求,超过后返回
429 rate_limited。
格式校验错误会先检查,不会占用发送链接的次数。
错误响应是带有稳定 code 的 JSON:
{ "error": { "code": "alert_too_long", "message": "…", "field": "alert.title", "limit": 100, "actual": 128 } }| 状态码 | 错误码 | 含义 |
|---|---|---|
| 400 | invalid_json |
请求体不是合法的 JSON 或 UTF-8。 |
| 401 | invalid_send_url |
发送链接错误、已撤销、已暂停,或所属频道已删除。 |
| 413 | request_too_large |
请求体超过 64 KB。 |
| 422 | invalid_target |
缺少 alert.title、字段值无效或含有不允许的字符,或请求在其他方面无效;field 指明字段。 |
| 422 | alert_too_long |
字段超过限制。错误中包含 field、limit 和 actual。 |
| 422 | invalid_alert_level |
level 不是四种级别之一。 |
| 422 | invalid_emergency |
emergency 的时间超出范围。 |
| 422 | invalid_callback |
对无法确认的提醒请求了 callback。 |
| 422 | callback_not_configured |
请求了 callback,但频道没有启用回调。 |
| 422 | encryption_required |
频道只接受端到端加密的提醒。 |
| 422 | invalid_encrypted_message |
加密信封不完整或格式错误。 |
| 429 | limit_exceeded |
达到了发送链接的频率限制。等待 Retry-After 指定的秒数后重试。 |
| 429 | rate_limited |
来自你的地址的请求过多。等待 Retry-After 指定的秒数后重试。 |
整个接口的所有错误码见错误。