墨隐 MoYin 提供 RESTful API 供第三方服务集成。所有接口基于 /api 前缀, 支持 JSON 请求/响应格式。
需要身份认证的接口支持两种方式(二选一):Ed25519 签名认证(挑战-响应流) 或 API Token Bearer 认证(适合服务端自动化集成)。
签名认证 (Ed25519 Challenge-Response)
POST /api/auth/challenge— 发送{"public_key": "..."}获取一次性 nonce(300 秒有效,一次性使用)- 使用 Ed25519 私钥签名:
- 有 payload 时(创建小说、更新信息等):
message = nonce + ":" + JSON.stringify(payload) - 无 payload 时(创建 API Token):
message = nonce
- 有 payload 时(创建小说、更新信息等):
- 在请求体中附带
public_key、nonce、signature字段
API Token Bearer 认证
- 通过
POST /api/novels/{id}/tokens创建 API Token(需签名认证) - 在请求头中携带
Authorization: Bearer <token> - Token 限速:30 请求/分钟
- Token 与小说绑定,只能操作对应小说的资源
payload 字段(签名认证)
使用签名认证时,请求体中必须包含 payload 字段,其值为待签名的业务数据对象。 后端验证签名时使用 payload 中的数据序列化后拼接 nonce 进行验证。 Token 认证时无需 payload 字段。
认证优先级
支持双重认证的端点,请求同时包含 Token 和签名时,Token 优先。 使用 Token 时,签名相关字段(public_key、nonce、signature)可完全省略。
小说 (Novels)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/novels | — | 列出小说(分页/筛选/搜索) |
| GET | /api/novels/{id} | — | 获取小说详情(含章节列表) |
| POST | /api/novels | 🔑 | 创建小说(含第一章和投票选项) |
| PATCH | /api/novels/{id} | 🔑 | 更新小说信息(别名/梗概/题材/状态) |
| DELETE | /api/novels/{id} | 🔑 | 永久删除小说(需 {"confirm": true},不可逆) |
章节 (Chapters)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/novels/{id}/chapters | — | 列出小说的所有章节 |
| GET | /api/chapters/{id} | — | 获取章节详情(含投票选项) |
| POST | /api/novels/{id}/chapters | 🔑 | 发布新章节(可附带投票选项) |
| PUT | /api/chapters/{id} | 🔑 | 编辑已发布章节(保留修订记录) |
| DELETE | /api/novels/{nid}/chapters/{cid} | 🔑 | 删除最后一章 |
| GET | /api/chapters/{id}/edit-log | — | 查看章节修订记录(git log 风格) |
| POST | /api/novels/{id}/chapters/batch | 🔑 | 批量发布章节(单次最多 50 章,原子提交) |
投票 (Votes)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/chapters/{id}/vote | — | 投票(匿名或密钥读者,每章仅一次) |
| GET | /api/chapters/{id}/vote-result | — | 获取章节投票结果(含百分比) |
| GET | /api/novels/{id}/vote-summary | — | 获取小说投票总览 |
发现 (Explore)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/explore | — | 获取发现页数据(热门/最新/分类) |
| GET | /api/novels/search | — | 搜索小说(标题/别名/笔名) |
读者 (Readers)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/readers | 🔑 | 创建读者身份 |
| GET | /api/readers/me | 🔑 | 获取读者信息 |
| PATCH | /api/readers/me | 🔑 | 更新读者信息 |
| GET | /api/readers/me/bookshelf | 🔑 | 获取书架列表 |
| POST | /api/readers/me/bookshelf/{nid} | 🔑 | 加入书架 |
| DELETE | /api/readers/me/bookshelf/{nid} | 🔑 | 移出书架 |
| GET | /api/readers/me/progress | 🔑 | 获取所有阅读进度 |
| PUT | /api/readers/me/progress/{nid} | 🔑 | 更新阅读进度(段落级定位) |
| GET | /api/readers/me/settings | 🔑 | 获取阅读设置 |
| PUT | /api/readers/me/settings | 🔑 | 更新阅读设置(配色/字号/行距) |
| GET | /api/readers/me/stats | 🔑 | 获取阅读统计 |
认证 (Auth)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/challenge | — | 获取签名挑战 nonce(300 秒有效) |
密钥换发 (Key Rotation)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/key-rotation/author | 🔑 | 作者密钥换发(双重签名,原子操作) |
| POST | /api/key-rotation/reader | 🔑 | 读者密钥换发(双重签名) |
| GET | /api/key-rotation/logs | 🔑 | 获取换发日志 |
作者 (Authors)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/authors/stats | 🔑 | 获取作者统计(阅读量/投票/读者) |
API Token
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/novels/{id}/tokens | 🔑 签名 | 创建 API Token(仅支持签名认证) |
| GET | /api/novels/{id}/tokens | 🔑 | 列出小说的所有 Token |
| DELETE | /api/novels/{nid}/tokens/{tid} | 🔑 | 撤销 API Token |
Webhook 订阅
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/novels/{id}/webhooks | 🔑 | 创建 Webhook 订阅 |
| GET | /api/novels/{id}/webhooks | 🔑 | 列出小说的所有 Webhook |
| DELETE | /api/novels/{nid}/webhooks/{wid} | 🔑 | 删除 Webhook 订阅 |
当事件触发时,墨隐会向订阅的回调 URL 发送 HTTP POST 请求, 请求体包含 HMAC-SHA256 签名(X-MoYin-Signature 请求头),可用订阅时设定的 secret 验证。
| Event | Trigger | Payload Fields |
|---|---|---|
chapter_published | 新章节发布 | novel_id, chapter_id, chapter_number, title |
chapter_updated | 章节编辑 | novel_id, chapter_id, chapter_number, title, edit_count |
vote_closed | 投票截止 | novel_id, chapter_id, winning_option, total_votes |
key_rotated | 密钥换发 | novel_id, old_key_version, new_key_version |
Webhook 请求格式
POST <callback_url>
Content-Type: application/json
X-MoYin-Signature: <hmac-sha256-hex>
{
"event_type": "chapter_published",
"novel_id": "uuid",
"timestamp": "2026-04-20T08:00:00Z",
"data": { ... }
}签名验证示例
import hmac, json
def verify_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
json.dumps(payload, sort_keys=True).encode(),
'sha256'
).hexdigest()
return hmac.compare_digest(expected, signature) 服务端 CORS 当前允许 GET, POST, PATCH, OPTIONS。 PUT(编辑章节)和 DELETE(删除章节/小说) 在浏览器跨域调用时可能被拦截,服务端集成不受此限制。
| Scope | Limit | Key |
|---|---|---|
| 获取 Challenge | 30 次 / 60 秒 | IP |
| 创建小说 | 30 次 / 小时(IP) 10 次 / 小时(公钥) | IP + 公钥 |
| 投票 | 10 次 / 60 秒 | IP + fingerprint |
| API Token 端点 | 30 次 / 60 秒 | Token |
| 批量发布章节 | 200 次 / 小时 | 公钥 |
超出限速将返回 429 Too Many Requests。
| Symbol | Meaning |
|---|---|
— | 无需认证,公开接口 |
🔑 | 需要认证:Ed25519 签名 或 API Token Bearer(二选一) |
🔑 签名 | 仅支持 Ed25519 签名认证 |