Notifo v1.3.0 API 使用详解
Notifo 1.3.0 API 实战详解:X-ApiKey 与 OAuth client_credentials 双认证、全端点总览、创建应用到 Mailhog 收信的全链路 curl 实测回显,以及 204 假成功等实测坑。
Notifo v1.3.0 API 使用详解
目标:给对接者一份「照着敲就能通」的 Notifo 1.3.0 API 实战手册——三种认证方式、全端点总览、从创建 App 到收到邮件的全链路 curl 实测(含真实回显),以及只在实测中才会暴露的坑(204 假成功、405 错端点、Bearer 401 等)。本文所有回显均来自本地 1.3.0 实例(2026-10-30 实测)。
一、环境信息
| 项目 | 内容 |
|---|---|
| 服务版本 | Notifo 1.3.0(squidex/notifo:1.3.0) |
| API 基地址 | http://192.168.1.200:8151(下文简写为 $B,替换为你的部署地址) |
| API 规范 | 运行实例自带 OpenAPI:GET /api/openapi.json 或 /swagger/v1/swagger.json(实测均返回 200) |
| 认证实测 | 应用 API Key、用户 API Key、OAuth client_credentials 三种均实测通过 |
| 部署环境 | 三容器 Compose(notifo + mongo:5 + mailhog),Mailhog UI http://192.168.1.200:8150 |
二、前置条件
- 已按《Notifo v1.3.0 Docker Compose 部署指南》完成部署并登录 Dashboard;
- 已创建 App 并拿到一把 Admin 角色的 API Key(App 页可见,32 位随机串形如
gdxvtksxxo9...); - 若要验证 Email 渠道,App 内已启用 SMTP 集成(测试环境指向 Mailhog:主机
notifo-mailhog、端口1025,实测保存后状态即 Verified)。
三、认证方式(三种,均实测)
Notifo 的 API Key 认证用的是自定义请求头 X-ApiKey,而不是常规的 Bearer——这是对接第一坑。
3.1 应用 API Key(服务端对接主通道)
curl -s -H "X-ApiKey: $APPKEY" "$B/api/apps/$APP/users?take=1"
# 实测 200:{"items":[{"id":"user-1","apiKey":"homvt2...","fullName":"Demo User One",...}],"total":1}
3.2 用户 API Key(用户自操作通道)
用户对象自带 apiKey 字段(创建用户时返回),用它访问 /api/me/* 域接口,即「用户视角」的能力(查自己的通知/订阅、自行订阅、给自己发推送):
curl -s -H "X-ApiKey: $USERKEY" "$B/api/me"
# 实测 200:{"fullName":"Demo User One","emailAddress":"user1@example.com",
# "preferredLanguage":"en","preferredTimezone":"UTC","supportedLanguages":["en"],...}
3.3 OAuth client_credentials(自动化脚本)
在环境变量 IDENTITY__ADMINCLIENTID/ADMINCLIENTSECRET 配置了客户端后(部署篇默认 notifo-admin / q1w2e3r4):
curl -s -X POST "$B/connect/token" \
-d "grant_type=client_credentials&client_id=notifo-admin&client_secret=q1w2e3r4&scope=NotifoAPI"
# 实测 200:{"access_token":"eyJhbGciOiJSU0EtT0FFUCIs...(JWE)","token_type":"Bearer","expires_in":2592000}
得到的 token 用标准 Bearer 头调用(有效期 30 天):
curl -s -H "Authorization: Bearer $TOKEN" "$B/api/apps"
# 实测 200:[{"id":"8360bb27-...","name":"demo","role":"Owner","apiKeys":{...}}]
⚠️ 实测坑:把 API Key 直接放进
Authorization: Bearer <apiKey>会稳定返回 401(应用 Key 与用户 Key 均如此,实测复现)。Bearer 头只服务 OAuth token;API Key 一律走X-ApiKey。
四、API 总览
以下端点清单提取自运行实例 OpenAPI(/api/openapi.json),按域分组($APP 为 AppId):
| 域 | 端点 | 方法 |
|---|---|---|
| 应用 | /api/apps、/api/apps/$APP | GET / POST |
| 成员 | /api/apps/$APP/contributors | POST |
| 用户 | /api/apps/$APP/users、/api/apps/$APP/users/{id} | GET / POST(批量 upsert)、DELETE |
| 订阅 | /api/apps/$APP/users/{id}/subscriptions、DELETE .../subscriptions/{prefix} | GET / POST / DELETE |
| 主题 | /api/apps/$APP/topics、DELETE .../topics/{path} | GET / POST / DELETE |
| 发布 | /api/apps/$APP/events | POST(PublishManyDto) |
| 通知 | /api/apps/$APP/notifications | GET(列表+渠道状态) |
| 用户通知 | /api/apps/$APP/users/{id}/notifications | GET |
| 集成 | /api/apps/$APP/integration、/integrations、`PUT | DELETE /integrations/{id}` |
| Email 模板 | /api/apps/$APP/email-templates(含 /render、/{code}、/{id}/preview) | GET / POST / PUT / DELETE |
| Messaging/SMS 模板 | /api/apps/$APP/messaging-templates、/sms-templates | 同上 |
| 媒体 | /api/apps/$APP/media | GET / POST / DELETE |
| 日志 | /api/apps/$APP/logs | GET |
| 用户自操作 | /api/me、/api/me/events(给自己发布)、/api/me/subscriptions、/api/me/notifications、/api/me/topics | GET / POST |
| 系统用户 | /api/system-users(管理员账号管理) | GET / POST / PUT / DELETE |
| 元数据 | /api/languages、/api/timezones | GET |
| 健康探测 | /healthz、/ping | GET |
五、全链路实战(创建 App → 收到邮件)
以下一条龙全部实测通过,把 $APPKEY、$B 换成你的值即可复跑。
1)创建 App(也可在 Dashboard 点出来)
curl -s -X POST -H "Content-Type: application/json" \
-d '{"name":"demo"}' "$B/api/apps"
实测回显(节选,注意 apiKeys 就是现成的调用凭据):
{"id":"8360bb27-7714-4e45-8aca-1437184f1bd4","name":"demo","role":"Owner",
"languages":["en"],
"apiKeys":{"gdxvtksxxo9co9sj1k1fxatu8pcpzaptpt7tekpkt8ex":"Admin", ...}}
2)创建用户(批量 upsert,body 为数组)
curl -s -X POST -H "X-ApiKey: $APPKEY" -H "Content-Type: application/json" \
-d '[{"id":"user-1","fullName":"Demo User One","emailAddress":"user1@example.com",
"preferredLanguage":"en","preferredTimezone":"UTC"}]' \
"$B/api/apps/$APP/users"
实测回显(用户 API Key 由此返回,3.2 节要用):
[{"id":"user-1","apiKey":"homvt2cyyyieitq5x7xfbzqpgm8ftyjsjpv6uctmovcx",
"fullName":"Demo User One","emailAddress":"user1@example.com",...}]
3)为用户订阅主题
curl -s -X POST -H "X-ApiKey: $APPKEY" -H "Content-Type: application/json" \
-d '{"subscribe":[{"topicPrefix":"releases/v130"}]}' \
"$B/api/apps/$APP/users/user-1/subscriptions"
# 实测:204 No Content(空体即成功)
随后 GET 同路径可看到 {"items":[{"topicPrefix":"releases/v130","topicSettings":{}}],"total":1}。
4)发布通知(核心端点:POST /api/apps/$APP/events)
无模板快速发布用 preformatted,正文按语言键组织:
curl -s -X POST -H "X-ApiKey: $APPKEY" -H "Content-Type: application/json" \
-d '{"requests":[{"topic":"releases/v130",
"preformatted":{"subject":{"en":"v1.3.0 released"},
"body":{"en":"Notifo 1.3.0 is out, published via POST /api/apps/{appId}/events."}},
"properties":{"version":"1.3.0"}}]}' \
"$B/api/apps/$APP/events"
# 实测:204 No Content,分发为异步,通常 1~4 秒完成
PublishDto 常用字段(来自实例 OpenAPI,仅 topic 必填):
| 字段 | 类型 | 说明 |
|---|---|---|
topic | string | 目标主题路径(发给所有前缀匹配的订阅者) |
templateCode | string | 走模板发布时的模板 code |
preformatted | object | 免模板直发:subject/body 均为 {语言: 文本} |
properties | object | 自定义属性,模板中引用,也会出现在通知详情 |
data | string | 业务侧附加数据(原样透传) |
correlationId | string | 业务关联 ID,可用于检索 |
scheduling | object | 延迟/定时发送 |
silent | boolean | 静默通知 |
test | boolean | 走测试集成(避免打扰真实用户) |
timeToLiveInSeconds | integer | 过期时长,过期不再投递 |
5)确认通知与渠道状态
curl -s -H "X-ApiKey: $APPKEY" "$B/api/apps/$APP/notifications?take=1"
实测回显(节选):email 与 web 双渠道均 Handled,并给出跟踪 URL:
{"channels":{"email":{"status":{"f2fc0c41-...":{"status":"Handled",
"configuration":{"EmailAddress":"user1@example.com"}}}},
"web":{"status":{"651071e3-...":{"status":"Handled"}}}},
"subject":"v1.3.0 released","created":"2026-10-30T00:33:21.345Z",
"trackSeenUrl":"http://192.168.1.200:8151/api/tracking/notifications/.../seen?culture=en",
"trackDeliveredUrl":"http://192.168.1.200:8151/api/tracking/notifications/.../delivered?culture=en"}
6)验证邮件落袋(Mailhog)
curl -s "http://192.168.1.200:8150/api/v2/messages?limit=1"
实测 Mailhog 收到主题 Your notifications from demo 的摘要邮件,text/plain 部分节选:
We have some notifications from demo for you.
v1.3.0 released
Notifo 1.3.0 is out, published via POST /api/apps/{appId}/events.
Use the following link to change your email preferences:
http://192.168.1.200:8151/api/email-preferences?access_token=...
💡 这封就是 Notifo 的 Email Digest:同一用户短时间内的多条通知合并成一封按语言渲染的摘要邮件,收件人可从邮件直达偏好设置页关停渠道。
六、各 API 域详解
App 域:GET /api/apps 列出当前凭据可见的应用;POST /api/apps 创建(body {"name":...},可带 languages);对单个 App 的 POST /api/apps/$APP 可更新语言等属性。
用户域:POST /api/apps/$APP/users 批量 upsert(按 id 幂等,改邮箱/属性再 POST 同 id 即更新);GET .../users?take=&skip= 分页;DELETE .../users/{id} 删除。实测用户对象含 settings(每渠道偏好)、requiresWhitelistedTopics、allowedTopics 等字段。
订阅域:POST .../users/{id}/subscriptions body 为 {"subscribe":[{"topicPrefix":"...","topicSettings":{...}}],"unsubscribe":["books/old"]},同请求可同时增删;topicSettings 可按渠道覆写发送行为(delay、专用模板等)。实测删除用 DELETE .../subscriptions/{prefix}(前缀需 URL 编码斜杠)。
主题域:GET /api/apps/$APP/topics 列出已出现过的主题与订阅计数;POST 可手工登记主题(配合用户 requiresWhitelistedTopics 做白名单发放)。
发布域:见第五节。用户自通道 POST /api/me/events body 为单个 PublishDto(用户 API Key 鉴权),适合「用户自产内容触发站内通知」的场景。
通知域:GET /api/apps/$APP/notifications 是管理视角的全量通知列表,GET .../users/{id}/notifications 是单用户视角;列表项含每渠道 status(Handled/Skipped/Failed 等)与 firstDelivered/firstSeen 时间。跟踪 URL 需暴露给客户端回调以完善已读统计。
集成域:POST /api/apps/$APP/integration 启用集成(实测 SMTP 配置体:
{"type":"SMTP","properties":{"host":"notifo-mailhog","port":"1025",
"fromEmail":"notifo@example.com","fromName":"Notifo Demo"},"enabled":true}
保存后返回 "status":"Verified")。GET /integrations 列出已启用项,PUT/DELETE /integrations/{id} 维护。
模板域:Email 模板按 code + 语言组织,PUT .../email-templates/{code}/{language} 设置某语言版本;POST .../email-templates/render 可以用假数据渲染预览。Messaging/SMS 模板结构类似。实测一个坑:Email 模板 language 字段必填,缺失时返回 400 {"details":["The Language field is required."],"errorCode":"VALIDATION_ERROR"}。
日志域:GET /api/apps/$APP/logs 返回 App 级系统日志(聚合去重),实测两条关键日志:Event has no subscriber.(发布时无订阅者)与 EMAIL: Cannot find template 'Unnamed'.(Email 投递缺模板)——排障先看这里。
系统用户域:/api/system-users 管理 Dashboard 登录账号(含 lock/unlock),区别于收通知的业务用户。
七、通用约定
- 204 即成功:订阅、发布等写操作统一返回
204 No Content空体,没有返回体可解析,成败靠后续查询或日志确认; - 错误结构:4xx/5xx 统一为
{"message":...,"errorCode":...,"details":[...],"traceId":...,"statusCode":...}(实测 VALIDATION_ERROR 400 与 401 均符合); - 分页:列表接口用
take+skip(实测?take=1生效),响应含items/total; - 多语言文本:所有可翻译字段均为
{语言键: 文本}字典,如"subject":{"en":"Hello","zh-CN":"你好"}; - 主题层级:
/分层(如books/novels),订阅是前缀匹配——订阅books可收到books/novels的通知;实测单级主题(solo)同样合法; - 异步投递:
POST /events入队即返回,渠道投递在后台完成(实测 1~4 秒),客户端轮询通知列表或看日志确认结果。
八、常见问题(FAQ)
Q1:POST /api/apps/{appId}/notifications 发布为什么返回 405?
该路径只有 GET(列表)。1.3.0 的发布端点是 POST /api/apps/{appId}/events(实测 405 复现后经实例 OpenAPI 确认)。
Q2:订阅返回 204 但订阅列表没变化?
请求体写成了 {"requests":[...]}(错误)。正确体是 {"subscribe":[{"topicPrefix":...}]}——实测错误的 body 同样返回 204 且静默忽略,必须回查列表确认。
Q3:发布返回 204 但没人收到?
查 GET /api/apps/$APP/logs:若见 Event has no subscriber.,说明主题无匹配订阅者(实测复现:先发布后订阅就会这样)。发布前先完成订阅。
Q4:Email 渠道 Skipped?
日志见 EMAIL: Cannot find template 'Unnamed'.:发布时既无模板又缺 preformatted 文本,或 Email 集成未启用(实测两种情形均复现为 Skipped)。
Q5:Bearer 放 API Key 为什么 401?
见第三节:API Key 必须走 X-ApiKey 头;Authorization: Bearer 仅用于 /connect/token 换取的 OAuth token。
Q6:哪里找完整字段定义?
实例自带 OpenAPI:curl $B/api/openapi.json(实测 200),PublishDto、UpsertUserDto、SubscribeDto 等全部 schema 均在其中,是 1.3.0 最权威的接口文档。
九、参考链接
- 官方 API 文档:https://docs.notifo.io/api(SDK 与集成指引)
- 运行实例 OpenAPI:
http://<你的部署地址>/api/openapi.json - 官方仓库:https://github.com/notifo-io/notifo
- 本系列文档:《Notifo 介绍与选型指南》、《Notifo v1.3.0 Docker Compose 部署指南》、《Notifo v1.3.0 配置参数详解》