API · INTEGRATION
公众号发布 + 小程序通道 · 接入文档
面向第三方调用方(exomind CLI、其它系统)。覆盖公众号发布(§1-8)与小程序通道(§9-11:订阅消息发送、内容安全校验)。小游戏后端暂不开放接入。
1. 概述
本服务是微信公众号发布共享服务,调用方经一个 HTTP 接口把文章发到公众号草稿箱:
- 在 auth 服务申请 API Key(绑定 service_name,如
exomind) - 带
x-api-keyheader 调POST /api/mp/publish - 同步拿到
draft_id(草稿 media_id),完成。封面按cover策略处理。
2. 认证(API Key)
API Key 经 x-api-key header 传递,由 auth 服务签发:
curl -H "x-api-key: YOUR_API_KEY" https://yyps.net/api/mp/publish
⚠️ 不是 Authorization: Bearer ...(那是 admin 后台 JWT,与调用方无关)。不带或无效 Key → 401。
3. 发布接口
POST https://yyps.net/api/mp/publish Content-Type: application/json
| 参数 | 必填 | 说明 |
|---|---|---|
account | 是 | 账号 key(如 ailang) |
title | 是 | 文章标题 |
content | 是 | 正文(HTML 或 Markdown) |
content_format | 否 | html/markdown,默认 html |
cover | 否 | 封面策略 ai/auto/provided/none,默认 ai(详见第 4 节) |
cover_image_prompt | 否 | cover=ai 时直传 AI 画面 prompt;不传则服务端 LLM 读全文提炼 |
thumb_media_id | 否 | cover=provided 时必填,封面 media_id |
author | 否 | 作者名(显示在文章顶部) |
digest | 否 | 摘要(不填微信自动抓正文前 54 字) |
theme | 否 | Markdown 渲染配色主题:10 个预设(4 基础 default/blue/green/dark + 6 精选 indigo/soft-blue/haze-blue/slate-blue/violet/ink-green)+ custom 主题(theme_key,见第 7 节);仅 markdown 生效 |
show_cover_pic | 否 | 正文顶部是否显示封面图(0/1),默认 1 |
need_open_comment | 否 | 是否开启留言(0/1),默认 1 |
only_fans_can_comment | 否 | 是否仅粉丝可留言(0/1),默认 0 |
idempotency_key | 建议 | 调用方稳定业务键,建议 article-id:revision。同账号重复提交返回原草稿;同 key 不可用于不同原文 |
force_publish | 否 | true 时显式跳过去重并创建新草稿,默认 false |
timestamp / nonce | 建议 | 防重放(timestamp 5 分钟内,nonce 一次性) |
4. 封面策略 cover(核心)
cover 是封面策略枚举,互斥,默认 ai:
| cover | 行为 |
|---|---|
ai(默认) | 发文用兜底封面秒回,后台 AI 生成(LLM 提炼画面 + 21:9)再 draft/update 换上,~1-2 分钟生效 |
auto | 服务端兜底(默认封面 / 素材库最近一张),不 AI |
provided | 用调用方传的 thumb_media_id(须永久素材 id) |
none | 强制无封面(罕见,微信 draft/add 通常要求 thumb) |
兜底链服务端兜(provided → default_covers → 素材库最近),调用方不用管封面来源,服务端保证"发得出"。
cover=ai 时传 cover_image_prompt 则按它出图(适合自带强 LLM 的调用方),不传则服务端 LLM 读全文提炼。AI 生成在后台异步,发文秒回不阻塞。
5. 响应
{
"success": true,
"message": "发布成功",
"draft_id": "T1NF4457kCm1K5GW1HRWT...",
"duplicate": false
}
draft_id 即草稿 media_id。未传 idempotency_key 时,服务端仍按原始 account/title/content 指纹自动判重。重复成功返回 success:true、duplicate:true、原 draft_id 和 duplicate_of;处理中重复会带 duplicate_status:"processing"。渲染主题、封面和正文配图产生的微信 URL 不参与指纹。
6. 示例 curl
① cover=ai(零配置,推荐)
curl -X POST https://yyps.net/api/mp/publish \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"account":"ailang","title":"测试文章","content":"<p>正文</p>","content_format":"html","cover":"ai","idempotency_key":"article-123:1"}'
② cover=auto(服务端兜底,不 AI)
curl -X POST https://yyps.net/api/mp/publish \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"account":"ailang","title":"测试","content":"<p>正文</p>","content_format":"html","cover":"auto"}'
③ cover=ai + 直传 AI 画面 prompt
curl -X POST https://yyps.net/api/mp/publish \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"account":"ailang","title":"测试","content":"<p>正文</p>","content_format":"html","cover":"ai","cover_image_prompt":"横幅封面:橘猫坐窗台看雨,水彩风格,灰蓝调,右侧留白"}'
7. 主题列表接口(theme 可选值动态查)
GET https://yyps.net/api/publish/themes/public 公开,无需认证
返回所有 is_public 主题(10 个预设 + admin 自建 custom),取 theme_key 作为发文 theme 参数。
curl https://yyps.net/api/publish/themes/public
# {"data":[{"theme_key":"blue","theme_name":"科技蓝",...},{"theme_key":"ink-green","theme_name":"墨绿",...},{"theme_key":"<custom>",...}]}
7.1 账号默认主题查询(本地渲染取色)
GET https://yyps.net/api/mp/account-theme?account=<账号key> API Key 认证(x-api-key)
返回该账号当前生效主题(admin「账号管理」配置的默认主题;未配置时 theme_key/theme_config 为 null)。
content_format=html 的调用方(本地渲染,如 wechat-md)应先取本接口 → 用 theme_config 本地渲染着色 → 再发布,实现「账号配置主题 → 生成文章生效」。注意:服务端不对 html 做主题着色(主题仅对 markdown 生效);发布时另有微信兼容改写(列表/外链/加粗兜底,与主题无关)。
curl -H "x-api-key: ***" "https://yyps.net/api/mp/account-theme?account=ailang"
# {"success":true,"account":"ailang","theme_key":"blue","theme_name":"科技蓝","theme_config":{"h1_color":"#177dd4",...}}
8. 失败与降级
- 发文始终同步返回(不会因 AI 封面生成超时阻塞——AI 在后台)。
cover=ai的 AI 生成失败不阻断发文,草稿保留兜底封面(可在 admin 发布历史点"重新生成封面"重试)。- 账号未配任何封面 → 友好报错"账号未配封面,请配默认封面或传 thumb",不会裸抛微信 40007。
success:false时message含原因,可直接展示给调用方。
9. 小程序通道 · 概述与鉴权
小程序通道把小程序的服务端能力(订阅消息发送、内容安全校验)以纯通道形式开放:小程序 AppSecret 由本服务加密托管,调用方不持小程序 secret,只经 HTTP 调用(密钥单点真相)。
- 鉴权与公众号发布同体系:
x-api-keyheader(auth 服务签发的 service key)。无效/缺失 → 401。 - 权限码:与发布接口不同(发布仅需有效 key),小程序通道两端点要求 key 持有对应权限码(auth 侧签发时勾选),缺失 → 403。持
admin:manage的 key 天然豁免。 - appid 前提:请求携带的
appid须为本服务已注册且启用的 active 小程序账号,未注册/停用 → 403。 - 量护栏:每 key 1 小时滑动窗口计数,成功+失败都计,超限 → 429(调用方按通道异常处理,fail-open)。护栏防 key 泄露后被刷量:订阅发送 3000 次/h(正常量≈订阅用户数/天);内容安全校验 1000 次/h(每次调用消耗微信 msgSecCheck 配额)。
| 端点 | 权限码 |
|---|---|
POST /api/miniprogram/subscribe/send | subscribe:send |
POST /api/miniprogram/sec-check | sec_check:check |
10. 订阅消息发送接口
POST https://yyps.net/api/miniprogram/subscribe/send Content-Type: application/json
向单个用户发送一条小程序订阅消息(如每日简报提醒)。接收者须已订阅该模板,否则微信拒绝(HTTP 200 + reason:"no_credit")。
| 参数 | 必填 | 说明 |
|---|---|---|
appid | 是 | 小程序 AppID(须已注册 active) |
template_id | 是 | 订阅消息模板 ID(须挂在该小程序账号下,否则 400) |
touser | 是 | 接收者 openid |
data | 是 | 模板数据,按微信字段名:{"thing2":{"value":"…"},"thing4":{"value":"…"}} |
page | 否 | 点击卡片落点,如 pages/index/index?from=submsg |
dedupe_key | 建议 | 幂等键(≤200 字符)。同键重复请求不重复发送,直接回上次结果(duplicate:true) |
miniprogram_state | 否 | 跳转小程序版本 formal(默认)/trial/developer |
timestamp / nonce | 建议 | 防重放(timestamp 5 分钟内,nonce 一次性) |
响应:{success, message, duplicate, errcode?, reason?, code?}
{"success":true,"message":"发送成功","duplicate":false,"errcode":0,"reason":"ok"}
状态码约定:微信业务拒绝走 HTTP 200 + success:false + 语义化 reason(这是正常业务结果,不是通道故障);参数/权限错误 4xx(code 与 HTTP 状态码一致);上游故障 5xx。
| reason | 含义 |
|---|---|
no_credit | 用户未订阅或订阅额度已用尽(微信 43101),未送达 |
invalid_openid | openid 无效(微信 40003) |
data_invalid / invalid_page | 模板数据 / 落点页不合法 |
rate_limited | 触发微信频率限制(45009),稍后重试 |
unauthorized | 该账号无权调用(48001) |
curl -X POST https://yyps.net/api/miniprogram/subscribe/send \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"appid":"wx0123456789abcdef","template_id":"AbCdEfGh...","touser":"oXYZ123...","data":{"thing1":{"value":"今日简报已生成"}},"dedupe_key":"daily-brief:2026-09-17:oXYZ123"}'
11. 内容安全校验接口
POST https://yyps.net/api/miniprogram/sec-check Content-Type: application/json
校验一段文本是否合规(微信 msgSecCheck 2.0)。纯通道:业务策略(何时校验、校验哪些文本)由调用方决定。
| 参数 | 必填 | 说明 |
|---|---|---|
appid | 是 | 小程序 AppID(须已注册 active) |
content | 是 | 待校验文本;超 2000 字符服务端截断(中文按字符计),长文本请自行拆分或只传关键字段 |
openid | 建议 | 用户 openid。微信 2.0 接口必填(用户须近两小时访问过小程序);缺失时微信报错 → 502,调用方按 fail-open 放行 |
响应:{pass, label?, keyword?, reason?, errcode?}
{"pass":false,"label":"20006","keyword":"赌博","reason":"blocked"}
| 场景 | HTTP | 响应 |
|---|---|---|
| 校验通过 | 200 | {"pass":true,"reason":"ok","errcode":0} |
| 命中违规 | 200 | pass:false + label/keyword(内容结论,应拦截) |
| 空文本 | 200 | pass:true(无内容可校验) |
| 缺权限 / appid 未注册 | 403 | reason:"permission_denied" / "appid_not_allowed" |
| appid 为空 | 400 | reason:"invalid_appid" |
| 微信侧异常 | 502 | reason:"wechat:<errcode>" 或 "service_error" |
| 量护栏超限 | 429 | reason:"rate_limited"(通道状态,fail-open 放行) |
核心约定:只有 HTTP 200 + pass:false 是内容结论;其余(403/429/502 等)都是通道状态,调用方应 fail-open 放行——内容安全闸门不因服务抖动误伤正常业务。
curl -X POST https://yyps.net/api/miniprogram/sec-check \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"appid":"wx0123456789abcdef","content":"分享卡片标题文本","openid":"oXYZ123..."}'
12. 渲染接口(公开,无需认证)
POST https://yyps.net/api/render Markdown / IR → 微信兼容 HTML
content(Markdown) 与ir(render-ir/v1 结构化 IR) 二选一theme传主题库 key:内置default/blue/green/dark+ 系统精选indigo/soft-blue/haze-blue/slate-blue/violet/ink-green,亦支持公开自建 custom;缺省default,未知名回落defaultcustom_config内联主题配置(优先于theme)
curl -X POST https://yyps.net/api/render -H "Content-Type: application/json" \
-d '{"content":"## 标题\n\n正文**加粗**","theme":"blue"}'
# {"success":true,"html":"<section>…</section>","message":"渲染成功"}
该接口只做渲染,不过发布链路的微信兼容改写;完整说明见仓库 docs/render-api.md。