我的付费能力 Pay Skill
> 本 Skill 是一个 Pay Skill 通用骨架模板:支付链路(微信下单 → X402 预下单 → 402 触发支付 → 支付后重试交付)已完整实现,
> 业务侧只需替换 src/business/handler.js 中的 runBusiness() 即可接入任意付费服务。
能力说明
- 输入:一段查询内容(
query,字符串或 JSON 对象,最长 2000 字) - 输出:结构化付费结果(
result),附带订单号、金额等元信息(meta) - 计费:按次计费,单次价格由服务端
PRICE_CENTS决定 - 幂等:同一订单号重复请求返回首次结果,不会重复扣费
付费前置检查
调用本 Skill 前,检查当前 Agent 是否已安装 weixinpay 插件:
- 已安装:可继续提供付费服务
- 未安装:提示「当前 Agent 暂不支持微信支付付费能力」,终止流程
工作流程
第一步:请求资源
POST https://your-domain.com/demo/skill/invoke
Content-Type: application/json
{"query": "用户的查询内容"}
> 把 your-domain.com 替换为实际部署域名;本地自测为 http://localhost:3000。
第二步:处理 402 响应
首次请求会返回 402 Payment Required。提取并保存以下两个响应头,两者都必须保存:
| Header | 含义 |
|---|---|
WeixinPay-Required |
支付码(paymentCode),用于发起支付 |
X-Out-Trade-No |
本次调用的商户订单号,支付成功后重试时要带回 |
响应体中也会附带一份 WeixinPay 提示块,内容与上述 Header 一致,便于只读 body 的 Agent 解析。
第三步:发起支付
将第二步拿到的 WeixinPay-Required 值作为 paymentCode,调用 weixinpay_pay,向用户申请支付授权。
第四步:支付成功后获取资源(⚠️ 必须执行)
> ⚠️ 这一步最容易遗漏:不携带 X-Out-Trade-No 重新请求,就永远拿不到付费内容。
> body 必须与第一步完全一致,只通过 Header 传递支付凭证和订单号。
POST https://your-domain.com/demo/skill/invoke
Content-Type: application/json
WeixinPay-Required: <第二步保存的支付码>
X-Out-Trade-No: <第二步保存的订单号>
{"query": "用户的查询内容"}
成功后返回 200:
{
"result": { "...": "付费内容" },
"meta": { "outTradeNo": "skillpay_20260903_xxxx", "amountCents": 30, "paidAt": 1750924300 }
}
边界与异常
| 情况 | 表现 | 处理方式 |
|---|---|---|
| 未支付就重试 | 再次返回 402,携带同一订单号 | 继续等待用户授权,不会重复扣费 |
| 订单过期(默认 15 分钟) | 返回 402,携带新的订单号 | 用新订单号重新执行第三、四步 |
| 业务执行失败 | 返回 500 BUSINESS_FAILED |
用相同 Header 重试,不重复扣费 |
| 结果生成中并发重试 | 返回 409 ORDER_ALREADY_CONSUMED |
稍后携带相同 Header 重试 |
query 为空或超长 |
返回 400 INVALID_QUERY |
修正参数后重试,不触发计费 |
若服务端启用的是支付宝按量付费通道
当服务端 PAY_CHANNEL=alipay 时,凭证头与微信通道不同。按下面四步走:
第一步:请求资源
同上,POST 相同的 body 到同一接口。
第二步:处理 402 响应
提取 Payment-Needed 响应头 —— 它是 Base64URL 编码的支付账单。
| Header | 含义 |
|---|---|
Payment-Needed |
支付账单,交给支付宝完成支付 |
响应体的 Alipay 块里也有一份同样的账单,便于只读 body 的 Agent 解析。
第三步:发起支付
将 Payment-Needed 的值交给支付宝完成支付。支付成功后会得到 Payment-Proof。
第四步:携带 Payment-Proof 重试(⚠️ 必须执行)
> ⚠️ 同样是最容易遗漏的一步:不携带 Payment-Proof 重新请求,就永远拿不到付费内容。
> body 必须与第一步完全一致,只通过 Header 传递支付凭证。
POST https://your-domain.com/demo/skill/invoke
Content-Type: application/json
Payment-Proof: <第三步拿到的支付凭证>
{"query": "用户的查询内容"}
成功后返回 200,并带回 Payment-Validation 响应头(含订单号与资源标识):
{
"result": { "...": "付费内容" },
"meta": { "outTradeNo": "skillpay_20260904_xxxx", "tradeNo": "2026...", "alreadyFulfilled": false }
}
与微信通道的差异:支付宝只需要一个 Header。商户订单号包含在凭证里,不需要单独传。
若响应 meta.alreadyFulfilled 为 true,说明这笔订单此前已交付过,返回的是同一份结果,不会重复扣费。
使用建议
- 先用较短的
query试跑一次,确认计费与返回结构符合预期,再处理大批量任务。 - 每次调用产生独立订单;如需批量,请逐次调用,不要复用订单号。
- 支付授权有 15 分钟时效,超时需重新发起。