微信小程序调用手册
发送用户已订阅的模板服务消息
以开发版目标发送一次符合用户订阅与模板字段的服务提醒,处理拒收、模板错误和投递边界。
← 返回平台功能接入准备
- 已在官方后台选择与真实业务匹配的订阅模板,记录模板 ID、字段名称与类型。
- 用户在小程序点击操作中调用 wx.requestSubscribeMessage({tmplIds:[实际模板ID]});success 回调仍需检查该 ID 的值为 accept。
- 后台已有同一用户 OpenID 和当前小程序 token;本例会真实消耗订阅次数,本站没有执行。
准备环境变量
示例值需要替换为自己的凭证或资源 ID。代码在本机或服务端运行;密钥不应放进公开网页。
WX_MINI_ACCESS_TOKEN- 同一小程序的后台 token,来自本平台的 stable-token 手册。
WX_MINI_OPENID- 同一小程序中已主动订阅该模板的测试用户。
WX_MINI_TEMPLATE_ID- 官方后台已有且用户已订阅的模板 ID。
WX_MINI_TEMPLATE_DATA_PATH- 本地 JSON 文件,内容为真实模板对应的 data 对象。
export WX_MINI_ACCESS_TOKEN='replace_with_current_backend_token'
export WX_MINI_OPENID='replace_with_subscribed_user_openid'
export WX_MINI_TEMPLATE_ID='replace_with_actual_template_id'
export WX_MINI_TEMPLATE_DATA_PATH='./template-data.json'以上 export 适用于 macOS / Linux 的终端。按调用步骤保存代码文件,再在同一终端执行。
调用步骤
- 01
在测试小程序中完成一次真实用户主动订阅,确认该模板未拒收或封禁。
- 02
按自己模板的字段创建 template-data.json,例如 {"thing1":{"value":"示例事项"}},这里 thing1 只是示意,必须替换成真实模板字段。
- 03
设置环境变量后运行下方 Node 代码。示例 miniprogram_state=developer;测试用户需有对应开发版访问权限。
- 04
核对 errcode,并按需要接收官方下发结果事件;请求成功不等于用户已读。
调用 01
请求发送模板服务消息
从本地文件读取真实模板字段,避免把别人的字段名作为通用固定参数。
POST
https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${WX_MINI_ACCESS_TOKEN}请求头
Content-Typeapplication/json
参数说明
参数表可左右滑动,查看完整说明。
| 字段 / 位置 | 类型 / 必填 | 说明 |
|---|---|---|
access_tokenQuery | string必填 | 同一小程序后台 token。 |
template_id请求体 | string必填 | 实际已有模板 ID。 |
touser请求体 | string必填 | 已订阅该模板的用户 OpenID。 |
data请求体 | object必填 | 与真实模板字段、类型与长度要求一致。 |
miniprogram_state请求体 | string必填 | developer/trial/formal,本例 developer。 |
lang请求体 | string必填 | 本例 zh_CN。 |
调用代码
替换示例 ID 与请求体内容后运行。
// Node.js 22+,保存为 request.mjs,环境变量在同一终端设置。
const required = name => {
const value = process.env[name];
if (!value) throw new Error('缺少环境变量 ' + name);
return value;
};
async function request(url, body) {
const response = await fetch(url, {
method: body === undefined ? 'GET' : 'POST',
headers: { 'Content-Type': 'application/json' },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
redirect: 'error', signal: AbortSignal.timeout(20000),
});
const raw = await response.text();
if (!response.ok) throw new Error('HTTP ' + response.status);
let result;
try { result = JSON.parse(raw); } catch { throw new Error('平台未返回有效 JSON'); }
if (!result || typeof result !== 'object' || Array.isArray(result)) throw new Error('响应结构不正确');
if (Object.hasOwn(result, 'errcode') && result.errcode !== 0) {
throw new Error('微信业务错误 ' + result.errcode + ': ' + (result.errmsg || ''));
}
return result;
}
// 从本地 JSON 文件读取当前真实模板对应的 data 字段,避免写死别人的模板结构。
const { readFileSync } = await import('node:fs');
const data = JSON.parse(readFileSync(required('WX_MINI_TEMPLATE_DATA_PATH'), 'utf8'));
if (!data || typeof data !== 'object' || Array.isArray(data) || Object.keys(data).length === 0) {
throw new Error('模板 data 需要非空对象,请按自己模板的字段配置');
}
for (const item of Object.values(data)) {
if (!item || typeof item.value !== 'string') throw new Error('每个模板字段须含字符串 value');
}
const url = new URL('https://api.weixin.qq.com/cgi-bin/message/subscribe/send');
url.search = new URLSearchParams({ access_token: required('WX_MINI_ACCESS_TOKEN') }).toString();
const result = await request(url, {
template_id: required('WX_MINI_TEMPLATE_ID'), touser: required('WX_MINI_OPENID'),
miniprogram_state: 'developer', lang: 'zh_CN', data,
});
if (result.errcode !== 0) throw new Error('消息响应缺少成功状态');
console.log(JSON.stringify({ accepted: true, errmsg: result.errmsg }, null, 2));
// 请求受理成功不代表已读;需要时按官方下发结果事件核对最终投递。
返回示例
结构示意,非实测。errcode=0 为请求成功,最终投递与已读不是同一状态。 以下为结构示意,非本站实测结果。
{
"errcode": 0,
"errmsg": "ok"
}常见错误与排查
43101用户未订阅或一次性订阅次数已用完。- 核对具体模板订阅结果,不反复重试或绕过用户选择。
40037 / 47003模板 ID 或 data 字段不正确。- 按自己模板实际字段核对类型、长度和名称。
43107账号或模板的消息能力被封禁。- 在官方后台处理封禁原因,不更换凭证规避。
40001 / 40014后台 token 无效。- 检查该小程序凭证和有效期,再重新校验。
调用注意
- 本例不配置 page,避免引用不存在的页面;如添加只能使用本小程序实际路径。
注意事项
- 本页仅覆盖用户弹窗订阅模式,不把新版其他一次性订阅或设备消息机制混成同一种接口。
- 客户端 success 表示接口调用完成,仍要按模板 ID 的 accept/reject/ban/filter 判断用户选择。
核验来源
本站按官方资料整理本场景的必要调用步骤与代码,覆盖范围以本页列出的接口为准。官方资料用于追溯规范及查看变更。
- 01用户弹窗订阅流程与投递事件核验日期 2026-10-15
- 02客户端主动订阅核验日期 2026-10-15
- 03发送订阅消息请求与字段核验日期 2026-10-15
