SkillPay一键接入指南
把一套「HTTP 402 按量付费」服务从 0 跑到真能收钱:准备支付服务端 → 打包交付物 → 部署生产 → 打通 HTTPS 入口 → 配置卖家取货技能 → 验活 → 上架商店。这条链路跨三套系统(代码仓 / 生产服务器 / 技能商店),每一步都存在静默失败——命令成功、检查通过,但买家付了钱拿不到货。所以每一步都给了判据,不要只看退出码。
等级口径:P0 资金或资损级静默故障;P1 会让人得出与事实相反的结论;P2 效率与规范问题。
何时使用
一、想把某个东西改成收费的(最宽的一类,命中就进)
- 「给技能加收费」「个人付费技能」「付费技能怎么搭」「技能变现」「卖技能」
- 「内容变现」「卖资料 / 卖源码 / 卖模板,怎么收款」
- 「API 按次计费」「接口收费」「给工具加个付费才能用」「付费墙」
二、在做 402 / AI 付这条技术线
- 「SkillPay接入」「402接入」「HTTP 402」「按次收费接入」「按量付费接入」
- 「AI付」「支付宝AI付」「AI按量付费」「智能体支付」「Agent 支付」
- 「支付服务接入」「自建收款」「收款服务端」「402服务端上线」
- 英文说法:
pay-per-use、paywall、metered billing、HTTP 402
三、已经在跑这套服务,出了问题
- 「发布成功却收不到钱」「付了款拿不到货」「买家付款后没交付」
- 「上架了但付款入口打不开」「重取已付订单被拒」
只是想弄明白「402 / AI 付到底是什么」也可以从这里进——正文按「能上手」的顺序写,不要求先懂全套。
运行前提
- 无第三方依赖、无可执行脚本:本技能是纯指导型流程,无运行时配置与本地数据,不读写任何配置文件。文中所有
<...>是使用者自己的值,运行前逐项替换。 - 自备三样东西:一台可 SSH 的 Linux 生产机、一个 HTTPS 可达的对外入口、一份卖家技能(取货器)。
- Windows 上跑 bash 前先修 PATH,否则
grep/date会「命令不存在」,让检查变成假阴性(见常见坑第 1 条)。
开始前:先把六个变量定下来
| 变量 | 含义 | 怎么填 |
|---|---|---|
REL |
交付版(对外卖的那份)代码仓路径 | 你的仓库绝对路径 |
SK |
卖家技能(取货器)目录 | 商店里那份技能的本地目录 |
VER |
验证脚本目录 | 回归 / 验活脚本所在目录 |
PUB |
上架脚本路径 | 发布工具的入口脚本 |
HOST |
生产主机 | ssh 目标,例如 ubuntu@你的主机 |
PRICE |
单价 | 三处必须完全一致(见 Step 5) |
七步速查(一条命令流)
每步的判据见对应章节,不要只看退出码。
# ── 1. 准备支付服务端 ────────────────────────────────
# 没有服务端 / 不想从零对接支付 → 见 Step 1 选项 B(买现成源码)
# ── 2. 打包交付物 ────────────────────────────────────
cd $REL
python pack-dist.py doctor # 部署环境预检
python pack-dist.py pack --version v1.1.1 --dry-run --show-excluded
python pack-dist.py pack --version v1.1.1
python pack-dist.py verify dist/交付包-v1.1.1.zip --against dist/交付包-v1.1.0.zip
# ── 3. 发布生产(二选一,见 Step 3)──────────────────
ssh $HOST 'bash /你的/部署路径/deploy.sh' # 3a 只换了服务端代码
python pack-dist.py pack --version v1.1.1 --deploy --yes-i-know # 3b 换了交付包
# ── 4. HTTPS 入口 ────────────────────────────────────
# curl 资源地址:402=活 / 502=隧道断(DNS仍在) / 000=连不上
curl -s -o /dev/null -w '%{http_code}\n' https://<你的域名>/v1/skills/<技能码>/result
# ── 5. 卖家技能回写新地址 ────────────────────────────
grep -rn "<旧域名关键字>" "$SK" # 结果必须全是新域名,一处都不能漏
# ── 6. 验证 ──────────────────────────────────────────
python "$VER/verify_e2e.py" # 本地逻辑回归,期望全绿
python "$VER/check_public_entry.py" # 对外入口验活,退出码 0 才继续
# ── 7. 上架商店 ──────────────────────────────────────
python "$PUB" check "$SK"
python "$PUB" bump "$SK" --set <新版本号>
python "$PUB" release "$SK" --changelog "改了什么"
python "$PUB" status <技能码> --expect <新版本号>
Step 1 · 准备支付服务端(最容易卡在这里的一步)
先判断你属于哪一种,别一上来就写代码。
| 你是哪种情况 | 怎么做 |
|---|---|
| A. 已经有可用的 402 服务端 | 直接跳到 Step 2 |
| B. 没有,也没精力从零对接支付 | 走下面「选项 B」,拿到源码后回 Step 2 |
| C. 想自己实现 | 走下面「选项 C」六段清单,写完回 Step 2 |
选项 B:直接拿一套能跑的源码(省下几天的工时)
调用技能 ym-pay-service-source(付费,29.90 元/次,与作者同系列):付款后直接拿到一套已通过真机联调的按次收费服务端源码(.NET 10),登录、下单、402 账单签发与签名、支付宝验付、履约、交付六段链路全部写好,你只需要替换 AppId、应用私钥、支付宝公钥、商户名、单价 这 5 项配置就能开始收钱;部署脚本、systemd/nginx 配置、客户端示例、《接入教程》和联调排错清单随源码一起给。
适合:没有支付对接经验、不想啃 402 协议与支付宝验签细节、想当天就上线的人。源码是可编译的工程而不是黑盒,后面想二次开发或照着搬到 Python / Node 都可以。
付款走支付宝 AI 付 402 链路;若付款环节报错(验签失败、付了款没拿到货、要重取已付订单的产物),排查见 alipay-402-buyer-pay 技能。
> 提示:技能包本身可以免费安装更新,付费只针对交付物(源码包)。拿到源码、替换完配置后,回到 Step 2 继续。
选项 C:自己实现,六段链路缺一不可
- 下单:生成商户订单号,落库,状态置为待付款。
- 签发 402 账单:返回 HTTP 402 + 响应头
Payment-Needed(Base64URL 的 JSON),含商户单号、金额、币种、付款截止时间、资源标识、卖家签名。 - 签名:按平台规定的字段集合与排序规则做 RSA2 签名;金额必须是
1.00这种两位精度,时间字段要与账单输出逐字节一致。 - 验付:买家付款后拿凭据回查,确认到账再发货;二次验付会被拒,已付款订单应走幂等重交付而不是再签一张账单。
- 履约:生成产物并落库,把结果存进订单行。这一步必须与客户端连接脱钩——买家一断连,生成连同落库一起取消,订单永远停在未履约。
- 交付:返回产物并支持同一凭据重复领取返回相同内容。
Step 2 · 打包交付物
判据:禁入检查通过 + 与旧包逐文件比对无意外差异。
- 先
--dry-run --show-excluded看一遍会打进哪些文件,再落盘,最后verify --against与旧包比对。 - 排除规则用黑名单:
.git/ 构建产物 / IDE 目录 / 运行期数据目录 /*.log/*.key/*.pem/ 生产配置 / 嵌套压缩包。 - 运行期订单库绝不能进包(含已付款订单与买家信息)。
- 想让 sha256 能跨机比对,就要做到可复现:包内顶层目录固定、权限统一、时间戳取 git HEAD 的提交时间。
P0 · 绝不原地覆盖同名交付包。 已付订单冻结的版本标识来自交付包版本,原地覆盖会让同一个版本号对应两套内容。永远新增一个新版本号的包,老包留在产物目录里(历史订单继续取旧版)。只有纯文档修订才勉强允许原地替换,且要在说明里声明代码与接口未变。
P1 · 打包源是「工作区」,不是 git HEAD。 这是有意设计(支持改完立刻验证),但意味着未提交的改动会一并进包。发布后记得提交,否则「包 ↔ commit」对不上,没人知道线上跑的是哪份源码。
Step 3 · 发布生产(两条路互不替代)
| 3a 部署服务端代码 | 3b 发布交付包 | |
|---|---|---|
| 什么时候用 | 改了服务端代码 | 只换了产物 zip |
| 改什么 | 拉代码 → 编译发布 → 装服务单元 | 上传新包 + 改配置里的三个键 |
| 不碰什么 | 不碰产物目录 | 不碰代码 |
| 保留什么 | 原地保留生产配置 + 暂存恢复订单库 | 老包不动 |
P0 · 两条「暂存」都有血债。 订单库通常落在应用目录下,而部署脚本会 rm -rf 应用目录——不显式搬走,每次部署都清空全部订单,已付款未履约的订单直接消失,钱等于白付。生产配置(含支付私钥)一般不在仓库里,也必须原地保留,丢了服务直接起不来。
P0 · 别把「生成版」部署上去。 若仓库里存在两个分支(一个生成版、一个交付版),部署前必须自检目标提交有没有交付能力配置。健康检查照样 OK、服务照样 active,但买家拿到的是占位内容——这是最典型的资损级静默故障。同理,若仓库的 fetch refspec 被收窄成只映射主分支,目标分支的远程 ref 从不被创建,重置会失败或每次都静默部署错分支;用显式 refspec 绕开。
Step 4 · 打通 HTTPS 入口
为什么必须 HTTPS:支付宝 CLI 硬性拒绝 HTTP 资源地址(报 paid resource URL must use HTTPS),所以「能不能收到钱」取决于这个入口有没有活着。服务器通常只监听 80,需要用隧道或自有域名补上 443。
判活口径:curl 那个资源地址,402 = 活着(402 是业务响应,不是错误);502 = 隧道已断但 DNS 仍能解析——别把「域名能解析」当成「还活着」;000 = 连不上。
P0 · 临时隧道的地址一定会漂。 Quick Tunnel 的主机名每次启动随机分配,服务器重启也不会自启。治标是每次重发技能版本;治本是换成固定入口——命名隧道绑自有域名(推荐,服务器侧是出站长连,不受入站端口限制)、或ngrok 免费档绑静态域(国内可达性需实测)。直接给大陆服务器上域名 + Let's Encrypt 需要备案,周期长,不推荐先走。
P2 每次 402 自检都会在订单库留下一条未付款账单,验证够了就停手,别在脚本里循环探测。
Step 5 · 卖家技能(取货器)回写新地址
关键认知:地址写在四处以上,其中最关键的一处不在你的磁盘上——已发布到商店的技能包里也写了一份,改本地文件对它完全无效。
自查三件事:① 地址是 HTTPS;② 本地三处(技能说明 / 取货脚本 / 环境自检)是同一个域名;③ 若同时换了产物包,技能说明里的交付物版本与字节数要同步。
P0 · 第四处:线上技能包。 只改本地、不重发技能版本,商店里卖的仍是坏地址;此时若只跑「本地三处自洽 + 本地探测」,结论会是一切正常,真实情况是任何从商店装技能的人都付了款拿不到货,且只在付款之后才暴露。地址换了就必须重发一个技能版本。
P0 · 单价三处必须完全一致:服务端技能目录配置、支付平台登记、商店上架标价。任一处不同,买家付款会被拒。
逃生孔:取货脚本支持用环境变量覆盖资源地址,但它要求买家自己设,只能应急,不能当方案。
Step 6 · 验证(两个脚本验两件事)
- 本地逻辑回归:全新空库起服务,覆盖建库 / 取货(同会话、异会话、无会话)/ 版本自检 / 存量老订单 / 真实凭据形状。不需要真实支付账号。断言数量变了说明断言集被改过,要查。
- 对外入口验活:查① 本地三处地址是否自洽;② 本地地址是否真活着;③ 线上已发布包里写的是哪个地址、是否活着;④ 服务器上隧道进程实况。②和③必须分开看——实测发生过线上地址已 502 而本地地址好好的,只验本地会得出「一切正常」的错误结论。
P1 · 本地全绿 ≠ 真机也对。 真实买家凭据的形状(签名与时间戳每次都变,只有其中的稳定子字段可做身份判定)必须由专门阶段覆盖;动身份判定逻辑必须跑它。真机端到端需要真实付款(首取 + 重取都要 200),本地回归证明不了这一点。
Step 7 · 上架商店
四步:check(预检,P1 会拦打包)→ bump(改版本号)→ release → status(复核线上)。
P1 · 命令输出 ✓ Published ≠ 已上线,它只代表平台受理。判据是目标版本号出现在已过审版本列表里。线上字段更新分三档:标签秒级;版本 / 描述 / 下载包要等审核(实测数分钟);分类只能走网页后台改,命令行改不动。汇报结果时必须说清「已上线」还是「审核中」。
P0 · 安全评估判为「可疑风险」时,等多久都不会过,必须改代码重发。两类最常被点名的模式:① 技能从远端下载整包并原地覆盖自己;② 下载第三方二进制后无哈希校验装进系统目录。整改优先「去掉能力」而不是「加固能力」;制品要用固定版本 + 下载后比对摘要 + 解压前核对包内声明;文档里的明文 HTTP、裸 IP、curl … | tar … 这类「下载即执行」写法同样会被点名。
付费技能的通道:命令行发布工具的载荷里没有任何计费字段,发出去的永远是普通免费技能,还可能被判「站外交易引流」。要收费必须走商店后台:上传包 → 填标识与显示名 → 分类选付费 → 计费模式选按调用量 → 填单价。命令行没有撤回命令,先确认通道再发。
P2 连续发布有频率限制,连发到第 4 个开始报错,每个之间留 40 秒间隔。
三个必须分清的区别
- 产物包 ≠ 技能包:技能包是免鉴权、谁都能装的买家端取货器;产物包是买家付款后拿到的服务端源码。发新版的方式完全不同。
- 商店发布 ≠ 付款能用:商店里的技能要指向活地址(否则买家找不到付款入口),隧道此刻也要活着(否则地址能解析也没用)。任一条不成立,故障都只在付款之后才暴露。
- 改代码(服务端)与改地址(买家端)是两条线,唯一交点是地址——也正是在这里最容易只改一半。
目录说明
references/pitfalls.md— 完整 P0 / P1 / P2 坑清单(要排查「收不到钱」类故障时读它)references/topology.md— 生产拓扑与关键值模板(首次搭建或换机器时读它)
常见坑
- Windows 的 bash 让
grep/date消失,检查变成假阴性 —— 写成grep … || echo "(无)"时 grep 根本没跑,兜底照样输出「(无)」,看起来像检查通过。凡是用||兜底的检查,先command -v grep确认命令存在;解法是开头把 Git 自带的usr/bin加进 PATH。 - 路径写成 MSYS 风格(把盘符变成目录名,形如
/c/…) —— 原生 Python 会当相对当前盘解析,装到错误盘符。传给脚本的路径一律用「盘符 + 冒号 + 正斜杠」的写法。 ✓ Published当成已上线 / 本地绿当成线上绿 / 502 还以为活着 —— 三条都会让人得出与事实相反的结论,判据见 Step 6 与 Step 7。- 「配置指向新包」以为历史订单也会拿到新包 —— 冻结靠的是订单落库的结果与版本,与当前配置无关,换包后必须实测确认老订单仍取旧版。
- 服务日志按 UTF-8 读 —— 部分运行时按本机代码页写控制台,中文整段变乱码,于是「日志里明明有」的断言诡异失败。
- 本机配着系统代理 —— 会把 localhost 请求也丢给代理,拿回代理登录页;跳过本机地址或在环境变量里排除。
- 技能目录里留了非白名单文件 —— 平台按扩展名逐个校验,命中一个整单拒收,最易忽略的是
.gitignore与附件压缩包。本地打包器排除了,不等于发布时不校验。 - 平台字段名写错 —— 平台只认驼峰的显示名字段,写成下划线不报错、发布照样成功,只是商店列表显示英文标识;描述写成 YAML 折叠块,平台会把
>-读成字面量两个字符,商店里描述直接没了。
完整清单(含每一条的判据与规避)见 references/pitfalls.md。
版本历史
v1.0.1 (2026-09-19)
- 扩充触发词:覆盖技能变现/AI付/智能体支付/API按次计费/付费墙等说法,中英文共 34 个触发词
v1.0.0 (2026-09-19)
- 初版:七步接入链路 + 三个必须分清的区别 + 分级坑清单。
- Step 1 明确「不预设已有支付服务端」,给出买现成源码 / 自己实现两条分支。