维护说明:本文档已并入本站直接维护(单仓重构后原 backend/docs/*.md、前端 docs/*.md 不再随仓库发布)。 实现细节以 pay-unify 源码 为准,页面与源码的对应关系见相关资源

SkillHub X402 支付集成指南

✅ 认证:/api/v2/* 一律使用 OAuth2 —— POST /oauth/token 换取 Authorization: Bearer <token> 后调用,见认证体系

统一支付后端(Pay-Unify backend/)提供完整的 SkillHub X402 支付能力,任何 Skill 只需简单配置即可接入付费流程。


目录


1. 整体架构

┌─ 用户 / AI Agent ───────────────────────────────┐ │ │ │ 1. 触发 Skill(如 "epub转txt") │ │ 2. 收到 402 + WeixinPay-Required │ │ 3. 用户手机确认支付(AI 专属卡) │ │ 4. 携带 X-Out-Trade-No 重试获取内容 │ └──────────────────────┬───────────────────────────┘ │ ┌──────────────────────▼───────────────────────────────────┐ │ SkillHub 平台 │ │ - 来源认证、内容完整性校验、可信调用入口 │ │ - 管理 X402 协议支付流程 │ │ - 将请求路由到商户后端 │ └──────────────────────┬───────────────────────────────────┘ │ ┌──────────────────────▼───────────────────────────────────┐ │ 商户后端 (Pay-Unify backend) │ │ │ │ POST /api/v2/skillpay/resource ← 核心入口 │ │ │ │ ├─ 首次请求 (无 X-Out-Trade-No) │ │ │ 1. 微信支付 Native 下单(获取 prepay_id + code_url) │ │ │ 2. X402 L1 签名(SHA256withRSA) │ │ │ 3. 返回 402 + WeixinPay-Required Header │ │ │ │ │ └─ 付费后重试 (有 X-Out-Trade-No) │ │ 1. 查询微信支付确认已付 │ │ 2. 执行 Skill 业务脚本(如 epub_to_txt.py) │ │ 3. 返回 200 + 付费内容 │ │ │ │ GET /api/v2/skillpay/query/:no ← 查询订单状态 │ └──────────────────────────────────────────────────────────┘

核心角色

角色 说明
AI Agent / SkillHub 用户触发 Skill 的入口,处理 X402 支付协议的客户端交互
Pay-Unify 后端 商户后端,处理微信支付下单、X402 签名、验证支付、执行业务
微信支付 实际资金通道,Native 二维码支付
Skill 业务脚本 付费后执行的业务逻辑(如 epub_to_txt.py),由后端调用

2. 后端做了什么

2.1 支付层

internal/pkg/service/payment/ 目录下的基础设施:

组件 文件 职责
WechatPayService wepay_service.go 微信支付 V3 API 封装:下单、查单、关闭、退款、回调验签
SkillHubService skillhub_service.go X402 协议签名:构造 L2 JSON → Base64 → SHA256withRSA → L1 5行签名串
AlipayService alipay_service.go 支付宝支付封装(Pay Skill 可扩展使用)

2.2 X402 协议签名(skillhub_service.go)

L2 载荷(JSON): { "out_trade_no": "WX402_20260724123456", "amount": 50, // 单位:分 "description": "EPUB转文本: book.epub", "skill_id": "epub-to-txt", "wechat_params": { "native_order": { "prepay_id": "wx...", "trade_type": "NATIVE" } } } ↓ Base64 编码 SHA256withRSA 签名(使用 SkillHub 开发者私钥) ↓ Base64 编码 L1 5 行签名串: sh-xxxxxxxx PUB_KEY_xxxxxxxx <L2_base64> <signature_base64> (空行)

这个 5 行 payment_code 是 X402 协议的核心凭据,通过 HTTP Header 返回给 Agent。

2.3 业务编排层(skillpay_handler.go)

POST /api/v2/skillpay/resource 是整个集成入口,使用 OAuth2 Bearer 认证(scope: skillpay:call)。

请求格式:

1{
2  "query": "/path/to/book.epub"
3}

请求头(OAuth2 Bearer 认证):

Authorization: Bearer <access_token> Content-Type: application/json X-Out-Trade-No: <X402订单号> ← 付费后重试时携带

处理流程(HandleResource):

收到请求 │ ├─ 检查 X-Out-Trade-No Header │ │ │ ├─ 无 → createPaymentOrder(): │ │ 1. Snowflake 生成 orderNo │ │ 2. WeChat Pay Native 下单 → prepay_id + code_url │ │ 3. X402 签名 → 5行 payment_code │ │ 4. 保存订单到 MySQL(Extra 中存 query) │ │ 5. 返回 402 + WeixinPay-Required Header │ │ │ └─ 有 → verifyAndFulfill(): │ 1. 查 DB 获取订单(含 Extra.query) │ 2. QueryOrder 查微信支付确认已付 │ 3. 更新订单状态为已支付 │ 4. executeBusiness(query) 执行业务脚本 │ 5. 返回 200 + 付费内容

2.4 业务执行层(executeBusiness

后端通过配置的 ExecScriptPath 调用外部脚本执行实际的付费业务:

1cmd := exec.Command("python3", scriptPath, query)
2output, err := cmd.CombinedOutput()
3// 返回 output 作为付费内容

如果未配置脚本路径,返回模拟数据用于测试。

2.5 订单存储

所有 X402 支付订单存在 tb_payment_order 表,关键字段:

字段 示例值 说明
order_no 202607241234567890 内部订单号(Snowflake 生成)
subject EPUB转文本: book.epub 支付描述(微信支付显示)
amount 0.50 支付金额(元)
status 1=未支付, 201=已支付 订单状态
pay_way wechat 支付方式
trade_no wx... 微信支付 prepay_id
extra {"query":"...", "skill_id":"..."} 扩展信息(存业务参数)
app_id skillhub 来源标识

3. Skill 如何结合后端

3.1 整体协作流程

SkillHub 层(用户触发 Skill) │ ▼ AI Agent 调用商户后端 │ POST /api/v2/skillpay/resource {"query": "..."} │ ▼ 商户后端处理支付 │ ├─ 未付 → 402(含 payment_code) │ → Agent 展示给用户 │ → 用户手机确认支付 │ → Agent 带 X-Out-Trade-No 重试 │ └─ 已付 → 调用 Skill 业务脚本 → 返回执行结果给 Agent → Agent 呈现给用户

3.2 Skill 需要做的

Skill 开发者只需要做两件事:

① 编写业务脚本(如 epub_to_txt.py

提供一个可以通过命令行调用的脚本,接收业务参数(如文件路径),输出结果到 stdout:

1python3 my_skill_script.py /path/to/input.data

脚本的输出(stdout)会作为付费内容返回给 Agent。

② 配置 skill.yaml

1name: my-pay-skill
2pay:
3  enabled: true
4  price:
5    amount: 0.50              # 定价
6    currency: CNY
7  billing:
8    mode: per_call            # 按次计费
9  x402:
10    auth_mode: per_payment    # 笔笔确认

3.3 后端需要做的

config.toml 中配置:

1[SkillHubConfig]
2  Enabled = true
3  DeveloperId = "sh-xxxxxxxx"          # SkillHub 商户号
4  PubKeyId = "PUB_KEY_xxxxxxxx"        # 开发者公钥 ID
5  PrivateKey = "/etc/certs/skillhub/private_key.pem"  # RSA 私钥
6  SkillId = "my-pay-skill"             # Skill slug(与 skill.yaml 一致)
7  PriceAmount = 0.50                   # 定价(与 skill.yaml 一致)
8  Description = "我的付费技能"
9  ExecScriptPath = "/app/my-skill/scripts/my_skill_script.py"  # 脚本路径
10  ExecHandler = "cli"                  # 执行模式:cli 直接命令行调用

3.4 数据流详情

每次请求: query = 业务参数(如 EPUB 文件路径) ↓ 首次: query 存入 order.extra.query 重试: 从 order.extra.query 取出 → 传给 executeBusiness() ↓ executeBusiness(): exec.Command("python3", ExecScriptPath, query) → 脚本 stdout 作为响应内容返回

4. 快速接入一个新 Skill

步骤 1:编写业务脚本

创建一个可独立运行的脚本,接收一个参数,输出结果到 stdout:

1#!/usr/bin/env python3
2import sys
3
4def do_something(input_path):
5    # 你的业务逻辑
6    return f"处理结果: {input_path}"
7
8if __name__ == '__main__':
9    if len(sys.argv) < 2:
10        print('{"success":false,"error":"缺少参数"}')
11        sys.exit(1)
12    result = do_something(sys.argv[1])
13    print(result)

步骤 2:部署脚本到服务器

1# 将脚本部署到服务器
2scp my_skill_script.py user@host:/app/my-skill/scripts/

步骤 3:配置后端

编辑 config.toml(或部署的 config-prod.toml):

1[SkillHubConfig]
2  Enabled = true
3  SkillId = "my-pay-skill"
4  PriceAmount = 0.50
5  Description = "我的付费技能"
6  ExecScriptPath = "/app/my-skill/scripts/my_skill_script.py"
7  ExecHandler = "cli"

步骤 4:创建 skill.yaml

1name: my-pay-skill
2display_name: "我的付费技能"
3version: "1.0.0"
4actions:
5  - type: script
6    path: ./scripts/my_skill_script.py
7    handler: main
8pay:
9  enabled: true
10  price:
11    amount: 0.50
12    currency: CNY
13  billing:
14    mode: per_call
15  x402:
16    auth_mode: per_payment

步骤 5:测试

1# 首次调用(未付费,应返回 402)
2curl -s -X POST https://your-domain.com/api/v2/skillpay/resource \
3  -H "Content-Type: application/json" \
4  -H "Authorization: Bearer $TOKEN" \
5  -d '{"query": "/app/my-skill/input.data"}'
6# → 402 + WeixinPay-Required Header

认证方式见认证体系;完整 X402 调用顺序见第 7 节


5. 配置参考

5.1 后端配置([SkillHubConfig]

配置项 必填 说明 示例值
Enabled 启用 SkillHub 支付集成 true
DeveloperId SkillHub 商户号 sh-xxxxxxxx
PubKeyId 开发者公钥 ID PUB_KEY_xxxxxxxx
PrivateKey RSA 2048 私钥文件路径 /etc/certs/skillhub/private_key.pem
SkillId Skill slug(与 skill.yaml 一致) epub-to-txt
SkillVersion Skill 版本 1.0.0
PriceAmount 定价(元,默认 0.50) 0.50
Description 支付描述前缀 EPUB转文本
ExecScriptPath 付费后调用的脚本路径 /app/epub-to-txt/scripts/epub_to_txt.py
ExecHandler 执行模式(仅 cli cli

5.2 Skill 配置(skill.yaml

配置项 说明 示例值
pay.price.amount 定价 0.50
pay.billing.mode 计费模式 per_call
pay.billing.min_balance 最低预存(减少弹窗) 5.00
pay.trial.calls 免费试用次数 3
pay.x402.auth_mode X402 授权模式 per_payment

6. 接口文档

6.1 核心入口

POST /api/v2/skillpay/resource

认证: OAuth2 Bearer(与 /api/v2/payment/* 一致)

请求(首次 — 未付费):

1// Headers: Authorization: Bearer <token>
2// Body:
3{
4  "query": "/path/to/input.data"
5}

响应(402 Payment Required):

1// Headers:
2//   WeixinPay-Required: <5行payment_code>
3//   X-Out-Trade-No: WX402_<orderNo>
4{
5  "code": "PAYMENT_REQUIRED",
6  "message": "需要支付 ¥0.50 才能继续",
7  "WeixinPay": {
8    "WeixinPay-Required": "<5行payment_code>"
9  },
10  "out_trade_no": "WX402_20260724123456",
11  "skill_id": "epub-to-txt",
12  "amount": 50,
13  "orderNo": "20260724123456"
14}

请求(重试 — 已付费):

1// Headers: Authorization: Bearer <token>, X-Out-Trade-No: WX402_<orderNo>
2// Body:
3{
4  "query": "/path/to/input.data"
5}

响应(200 OK):

1{
2  "code": "SUCCESS",
3  "content": "业务脚本的输出内容(stdout)",
4  "orderNo": "20260724123456"
5}

6.2 订单查询

GET /api/v2/skillpay/query/:outTradeNo

响应(200 OK):

1{
2  "code": 200,
3  "message": "Success",
4  "data": {
5    "orderNo": "20260724123456",
6    "amount": 0.50,
7    "status": 201,
8    "payWay": "wechat",
9    "payTime": 1721812345
10  }
11}

订单状态:1=未支付, 2=已扫码, 201=已支付, 300=已关闭, 400=已退款


7. 端到端测试

7.1 测试前提

  1. 后端已部署运行
  2. [SkillHubConfig] Enabled = true
  3. [WechatPayConfig] Enabled = true 且微信商户配置正确
  4. 在「API 应用管理」创建了带 skillpay:call/refund scope 的应用

7.2 手动测试(curl)

1# === Step 1: 首次请求(未付费)===
2# 换取 OAuth2 Bearer token(scope 需含 skillpay:call)
3CLIENT_ID="your-client-id"
4CLIENT_SECRET="your-client-secret"
5TOKEN=$(curl -s -X POST http://localhost:8097/oauth/token \
6  -H "Content-Type: application/json" \
7  -d "{\"grant_type\":\"client_credentials\",\"client_id\":\"${CLIENT_ID}\",\"client_secret\":\"${CLIENT_SECRET}\"}" \
8  | jq -r .access_token)
9
10# 发送请求
11curl -s -w "\nHTTP %{http_code}\n" -X POST http://localhost:8097/api/v2/skillpay/resource \
12  -H "Content-Type: application/json" \
13  -H "Authorization: Bearer $TOKEN" \
14  -d '{"query": "/app/test/sample.epub"}'
15
16# 期望输出:HTTP 402 + WeixinPay-Required Header
17
18# === Step 2: 模拟付费后重试 ===
19# (将 <OUT_TRADE_NO> 替换为上一步返回的 out_trade_no)
20curl -s -w "\nHTTP %{http_code}\n" -X POST http://localhost:8097/api/v2/skillpay/resource \
21  -H "Content-Type: application/json" \
22  -H "Authorization: Bearer $TOKEN" \
23  -H "X-Out-Trade-No: <OUT_TRADE_NO>" \
24  -d '{"query": "/app/test/sample.epub"}'
25
26# 如果微信支付已付 → HTTP 200 + 付费内容
27# 如果未付 → HTTP 402 + "订单尚未支付完成"

7.3 验证 402 响应格式

1curl -s -D - -X POST http://localhost:8097/api/v2/skillpay/resource \
2  -H "Content-Type: application/json" \
3  -H "Authorization: Bearer $TOKEN" \
4  -d '{"query": "test.epub"}' | head -20
5
6# 必须包含:
7# ✅ HTTP/1.1 402 Payment Required
8# ✅ WeixinPay-Required: <payment_code>
9# ✅ Content-Type: application/json
10# ✅ Body 含 WeixinPay 节点

8. 现有集成示例:epub-to-txt

8.1 文件结构

pay-unify/backend/ ├── config.toml # 后端配置(含 SkillHubConfig) ├── internal/ │ ├── handler/skillpay_handler.go # X402 处理器(核心) │ └── pkg/service/payment/ │ ├── skillhub_service.go # X402 签名服务 │ └── wepay_service.go # 微信支付(含 CreateNativePrepayOrder) └── ... .claude/skills/epub-to-txt/ ├── SKILL.md # Skill 文档 ├── skill.yaml # SkillHub 发布配置 └── scripts/ └── epub_to_txt.py # 业务脚本(付费后执行)

8.2 已配置的内容

后端 config.toml:

1[SkillHubConfig]
2  Enabled = true
3  DeveloperId = "sh-xxxxxxxx"
4  PubKeyId = "PUB_KEY_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
5  PrivateKey = "/etc/certs/skillhub/private_key.pem"
6  SkillId = "epub-to-txt"
7  PriceAmount = 0.50
8  Description = "EPUB转文本"
9  ExecScriptPath = "/app/epub-to-txt/scripts/epub_to_txt.py"
10  ExecHandler = "cli"

Skill skill.yaml(已发布):

1name: epub-to-txt
2pay:
3  enabled: true
4  price:
5    amount: 0.50
6  billing:
7    mode: per_call
8    min_balance: 5.00
9  trial:
10    calls: 3

8.3 付费流程示例

用户: "帮我把这本书转换成文本" Agent → POST /api/v2/skillpay/resource {"query": "/app/books/book.epub"} │ ├─ 后端创建微信支付订单 + X402 签名 ├─ 返回 402 + WeixinPay-Required │ ├─ Agent 展示支付二维码给用户 ├─ 用户微信扫码 → AI 专属卡 → 确认支付 ¥0.50 │ └─ Agent 携带 X-Out-Trade-No 重试 ├─ 后端确认已付 ├─ 执行: python3 epub_to_txt.py /app/books/book.epub └─ 返回: {"success":true, "output_path":"...", "file_size":102400} Agent: "转换完成!文件已保存到 /app/books/book.txt(100.0 KB)"

8.4 定价与定价策略参考

定价金额 适用场景 说明
¥0.10 – ¥0.50 单次查询/简单转换 低频低价值,薄利多销
¥0.50 – ¥5.00 内容生成/分析 按产出计费,价值感强
¥1.00 – ¥10.00 专业工具/数据 专业价值,用户愿付费
¥9.90 – ¥99.00/月 持续服务 订阅制,稳定现金流

建议新 Skill 从低价起步(¥0.10-¥0.50),设 3 次免费试用,根据数据逐步调价。