概述
中台地址 https://userpay.aitalker.vip,提供统一用户系统 + 微信支付通道。金额单位统一为分(1元=100分)。所有接口返回 JSON。
鉴权
| 凭据 | 说明 | 用法 |
|---|---|---|
X-API-Key | 业务服务器调支付接口用(.env API_KEY) | /api/pay/create、/api/pay/query、/api/pay/refund。仅服务端,不能登录管理后台,不能暴露给前端。 |
X-App-Key | 外部应用调额度接口用 | /api/app/*。后台创建应用后生成。 |
| JWT Token | 用户身份凭证,登录成功后返回,默认 24 小时过期 | 请求头 Authorization: Bearer <token> |
| 微信登录 | 获取 JWT 的方式(扫码 / 网页授权) | 调用下方「用户 & 微信扫码登录」中的接口换取 token |
| admin_token Cookie | 管理后台登录凭证 | 浏览器访问管理后台,微信扫码后自动设置。与 X-API-Key 无关。 |
JWT 适用的接口:/api/user/*、/api/pay/create-for-app(前端 App 下单)。
管理员:在 ADMIN_USER_IDS 配置或后台「用户管理」设为管理员。部署参数见 agent skill.MD 的 P0。
用户 & 微信扫码登录
本中台仅支持微信/QR 扫码登录。用户扫码→自动注册或登录→返回 JWT Token。没有密码注册流程。
使用 snsapi_base 静默授权,不弹窗。用户首次扫码自动注册。
步骤 1:获取授权链接
参数:redirect_uri 你的回调地址,state 任意字符串(可选)
GET /api/user/wechat/auth-url?redirect_uri=https://你的域名/callback&state=abc
→ {
"code": 0,
"data": {
"auth_url": "https://open.weixin.qq.com/connect/oauth2/..."
}
}
把 auth_url 作为微信登录按钮跳转链接。用户点击→授权→微信回调你的 redirect_uri?code=xxx。
步骤 2:code 换 Token
Content-Type: application/json
{ "code": "微信回调带来的 code" }
→ {
"code": 0,
"data": {
"user_id": 3,
"token": "eyJhbG...",
"expires_in": 86400,
"is_new": true // 首次扫码为 true
}
}
https://userpay.aitalker.vip/callback,中台自动完成登录全流程,前端一行后端代码不用写。QR 扫码登录(推荐)
无需微信开放平台。用户扫码→微信内静默授权→桌面自动登录。纯前端 3 步集成。
步骤 1:发起 QR 登录
POST /api/user/qr-login/start
→ {
"code": 0,
"data": {
"key": "a1b2c3...",
"qr_url": "https://userpay.aitalker.vip/api/user/qr-login/go?key=a1b2c3...",
"expire_seconds": 300
}
}
把 qr_url 生成二维码显示给用户。
步骤 2:轮询检查
GET /api/user/qr-login/check?key=a1b2c3...
→ { "code": 0, "data": { "status": "pending" } } // 继续等
→ { "code": 0, "data": { "status": "done", "token": "eyJh...", "user_id": 1 } } // 完成
→ { "code": 0, "data": { "status": "expired" } } // 超时
每 2 秒轮询一次。done 返回 token(查后即焚,同一个 key 只能取一次)。
集成的完整前端代码
// 1. 发起 QR 登录
const resp = await fetch('https://userpay.aitalker.vip/api/user/qr-login/start', {method:'POST'});
const {key, qr_url} = (await resp.json()).data;
// 2. 生成二维码(用 qrcodejs 库)
new QRCode(el, {text: qr_url, width: 200, height: 200});
// 3. 轮询
const timer = setInterval(async () => {
const r = await fetch(`https://userpay.aitalker.vip/api/user/qr-login/check?key=${key}`);
const {status, token, user_id} = (await r.json()).data;
if (status === 'done') {
clearInterval(timer);
localStorage.setItem('token', token); // 存 token,后续 API 用
window.location.href = '/dashboard'; // 登录成功跳转
} else if (status === 'expired') {
clearInterval(timer); // 刷新页面重试
}
}, 2000);
绑定手机号
微信扫码只拿 openid。如需手机号,前端调 wx.getPhoneNumber 拿 code:
Authorization: Bearer <token>
Content-Type: application/json
{ "code": "wx.getPhoneNumber 返回的 code" }
→ { "code": 0, "message": "ok" }
账号合并逻辑
| 场景 | 结果 |
|---|---|
| 手机号空闲 | 直接绑定 |
| 被老用户占用,老用户没绑微信 | 自动合并:删新号,openid 迁到老号,返回 {"merged":true} |
| 被老用户占用,老用户已有微信 | 400 "该手机号已绑定其他微信账号" |
| 新用户已有支付订单 | 400 拒绝合并,提示联系客服 |
获取用户信息
Authorization: Bearer <token>
→ {
\"code\": 0,
\"data\": {
\"user_id\": 1,
\"phone\": \"138****8000\",
\"nickname\": \"张三\",
\"created_at\": \"2026-06-06T00:00:00\"
}
}
微信支付
中台提供两种下单方式,适用于不同的接入场景:
| 接口 | 鉴权 | user_id | 适用场景 |
|---|---|---|---|
POST /api/pay/create |
X-API-Key(服务端密钥) |
手动传 | 你的后端 Server 调用。你有自己的后端服务,在中台完成下单后自行处理后续逻辑。 |
POST /api/pay/create-for-app |
Authorization: Bearer ***(JWT 登录 Token) |
自动从 Token 取 | 纯前端 App 调用(如 1 元建站)。用户 QR 扫码登录后拿到 JWT,直接下单,无需经过你的后端。 |
这么设计的原因
之前只有 /api/pay/create 一个接口,它需要 X-API-Key 鉴权——这个 Key 是服务端密码,绝不能暴露给前端浏览器。但 1 元建站这类纯前端应用没有自己的后端,前端直接调中台就会把 Key 暴露出去。
新增 /api/pay/create-for-app 后,前端只需要 QR 扫码登录拿 JWT Token,然后用 Token 鉴权下单。用户 ID 自动从 Token 提取,前端不用管 user_id,也不用管 API Key。
创建支付订单(服务端调用)
适合有后端的 Server B 接入。需要 X-API-Key 头。金额单位 分。
X-API-Key: <api-key>
Content-Type: application/json
{
"user_id": 1,
"out_trade_no": "MYAPP20260606001",
"description": "会员月卡",
"amount": 990,
"pay_type": "jsapi",
"openid": "oUpF8u...",
"notify_url_b": "https://你的域名/callback"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| user_id | int | 是 | 中台用户 ID |
| out_trade_no | string | 是 | 你的订单号。建议 产品前缀+日期+序号 |
| description | string | 是 | 商品描述,显示在微信支付页 |
| amount | int | 是 | 金额,单位分(990=9.9元) |
| pay_type | string | 是 | jsapi 或 native |
| openid | string | jsapi必填 | 用户微信 openid |
| notify_url_b | string | 否 | 支付成功通知地址 |
JSAPI 返回 pay_params,前端直接传 wx.requestPayment(pay_params)。
Native 返回 code_url,生成二维码给用户扫码付。
创建支付订单(前端 App 调用)
适合纯前端 App(如 1 元建站)。不需要 X-API-Key,不需要传 user_id。用户通过 QR 扫码登录拿到 JWT Token 后,用 Bearer Token 鉴权直接下单。
Authorization: Bearer <JWT token>
Content-Type: application/json
{
"out_trade_no": "YIJIAN20260607001",
"description": "1元建站 - 会员",
"amount": 100,
"pay_type": "native",
"notify_url_b": "" // 可选,支付成功通知地址
}
→ {
"code": 0,
"message": "ok",
"data": {
"prepay_id": "",
"pay_params": {
"code_url": "weixin://wxpay/bizpayurl?pr=xxx"
}
}
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| out_trade_no | string | 是 | 你的订单号。建议 产品前缀+日期+序号 |
| description | string | 是 | 商品描述,显示在微信支付页 |
| amount | int | 是 | 金额,单位分(100=1元) |
| pay_type | string | 是 | jsapi 或 native |
| openid | string | jsapi必填 | 用户微信 openid |
| notify_url_b | string | 否 | 支付成功通知地址 |
1 元建站完整接入代码
// 1. QR 扫码登录(已有 token 则跳过)
const startResp = await fetch('https://userpay.aitalker.vip/api/user/qr-login/start', {method:'POST'});
const {key, qr_url} = (await startResp.json()).data;
// 生成二维码显示给用户扫码
new QRCode(document.getElementById('qrcode'), {text: qr_url, width: 200, height: 200});
// 轮询等待扫码结果
const timer = setInterval(async () => {
const r = await fetch(`https://userpay.aitalker.vip/api/user/qr-login/check?key=${key}`);
const {status, token, user_id} = (await r.json()).data;
if (status === 'done') {
clearInterval(timer);
localStorage.setItem('token', token); // 存 token
// 2. 用 token 直接下单(不需要 X-API-Key,不需要传 user_id)
const payResp = await fetch('https://userpay.aitalker.vip/api/pay/create-for-app', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
out_trade_no: 'YIJIAN' + Date.now(),
description: '1元建站 - 会员',
amount: 100, // 100 分 = 1 元
pay_type: 'native' // 扫码付
})
});
const {pay_params} = (await payResp.json()).data;
// pay_params.code_url 就是微信支付二维码链接
new QRCode(document.getElementById('pay-qrcode'), {text: pay_params.code_url, width: 200, height: 200});
} else if (status === 'expired') {
clearInterval(timer);
alert('二维码已过期,请刷新页面重试');
}
}, 2000);
查询订单
X-API-Key: <api-key>
→ {
"out_trade_no": "...",
"trade_state": "SUCCESS",
"transaction_id": "420000...",
"paid_amount": 990,
"paid_at": "2026-06-06T13:07:49",
"source": "wechat"
}
trade_state:NOTPAY / SUCCESS / REFUND / CLOSED。
source: "wechat" 表示微信实时查询,"local" 表示微信失败用了缓存。
退款
X-API-Key: <api-key>
Content-Type: application/json
{
"out_trade_no": "MYAPP20260606001",
"refund_amount": 990,
"reason": "用户申请退款"
}
可部分退款。订单必须 SUCCESS。
支付回调(你接的)
支付成功后,中台 POST 到你传的 notify_url_b:
POST https://你的域名/callback
Content-Type: application/json
{
"out_trade_no": "MYAPP20260606001",
"transaction_id": "4200001234567890",
"amount": 990,
"user_id": 1,
"trade_state": "SUCCESS"
}
应用平台 API
外部应用通过 X-App-Key 头鉴权调用。密钥从后台管理 App 获取。
app_id 隔离,同一套 API 支撑多个产品(一言建站、知识库等),每个 App 有独立额度和密钥。查询用户额度
X-App-Key: <app-key>
→ {
"code": 0,
"data": {
"credits": 100,
"credits_used": 30,
"available": 70
}
}
用户不存在时返回全 0。
扣减额度
X-App-Key: <app-key>
Content-Type: application/json
{
"external_user_id": "user_abc",
"amount": 1,
"action": "generate",
"reason": "生成文章"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| external_user_id | string | 是 | 你系统的用户标识 |
| amount | int | 是 | 扣减点数 |
| action | string | 否 | 业务场景:generate / edit,默认 deduct |
| reason | string | 否 | 原因备注 |
增加额度(管理员)
X-App-Key: <app-key>
Content-Type: application/json
{
"external_user_id": "user_abc",
"amount": 100,
"reason": "初始赠送"
}
应用用户列表
X-App-Key: <app-key>
→ {
"code": 0,
"data": {
"total": 3,
"users": [{ "external_user_id": "...", "credits": 100, ... }]
}
}
额度变更日志
X-App-Key: <app-key>
→ {
"code": 0,
"data": {
"total": 12,
"logs": [{ "action": "deduct", "change_amount": -1, ... }]
}
}
不传 external_user_id 则查全应用日志。
管理后台 API
仅供中台管理员使用,应用开发方接入支付/用户接口不需要调用本节。
鉴权方式:浏览器 Cookie(admin_token)。流程:访问 /admin/login → 微信扫码 → 中台校验该用户是否为管理员 → 设置 Cookie。不再支持 X-API-Key 调用管理接口。
管理员登录
返回二维码扫码页面。仅 ADMIN_USER_IDS 或后台「设为管理员」的用户可登录。
检查登录状态(需 Cookie)。返回 {id, nickname, avatar_url, is_super}。
用户管理
需管理员 Cookie。
→ {
"code": 0,
"data": {
"total": 3,
"users": [{
"id": 3,
"phone": "138****1234",
"nickname": "囍",
"has_openid": true,
"is_admin": true,
"admin_via_env": true,
"avatar_url": "https://...",
"province": "上海"
}]
}
}
search 可选。后台 UI 可对用户「设为管理员」/「取消管理员」。
用户详情 + 最近 50 条订单。需管理员 Cookie。
设为管理员。用户须已绑定微信(有 openid)。需管理员 Cookie。
取消管理员。不能取消自己或唯一管理员。若仍在 ADMIN_USER_IDS 中会提示改 .env。需管理员 Cookie。
应用管理
列出所有应用,含用户数。需管理员 Cookie。
Content-Type: application/json
{
"name": "一言建站",
"description": "...",
"callback_url": "https://yiyan.aitalker.vip/api/pay/callback"
}
返回 {id, name, api_key}。api_key 仅创建时返回一次,给应用服务端作 X-App-Key 用。
应用详情,含用户额度列表。需管理员 Cookie。
更新应用名称 / 说明 / 回调地址。需管理员 Cookie。
手动调整额度
Content-Type: application/json
{
"external_user_id": "user_abc",
"amount": 100,
"reason": "用户充值"
}
amount 正数=增加,负数=扣减。需管理员 Cookie。
概览统计
总用户数、订单数、收入等。需管理员 Cookie。
订单管理
订单列表,支持应用/日期/状态筛选。需管理员 Cookie。
管理员认证
Content-Type: application/json
{ "token": "用户 JWT Token", "headimgurl": "头像URL(可选)" }
QR 登录成功后,用用户 JWT 换取管理员 Cookie。仅管理员用户成功。
清除管理员 Cookie。需管理员 Cookie。
错误码
| HTTP | detail | 原因 |
|---|---|---|
| 400 | 手机号已注册 / 订单号已存在 / 用户不存在 | 参数错误 |
| 401 | 无效的 API Key / Token 无效或已过期 | 鉴权失败 |
| 429 | 请求过于频繁 | 速率限制 |
| 502 | 微信支付接口调用失败 | 微信端异常 |
| 503 | 支付服务未配置 | 中台没配微信支付 |