new-api 系列(九):接入国内支付——支付宝、微信与自动充值

系列目录

  1. (一)认识 new-api——新一代 AI API 管理网关
  2. (二)安装部署——从零搭建 new-api
  3. (三)渠道配置——接入各类模型提供商
  4. (四)令牌与用户管理
  5. (五)计价模型与成本控制
  6. (六)监控、日志与告警
  7. (七)生产环境部署与安全加固
  8. (八)进阶——多实例、负载均衡与 SSO
  9. (九)接入国内支付——支付宝、微信与自动充值(本文)
  10. (十)接入国际支付——Stripe、PayPal 与海外收银

# 国内支付接入 ## 支付方案对比 - 个人免签(无营业执照) - 第三方聚合支付(易支付) - 官方 API(需企业资质) - 半自动人工充值 ## 个人免签方案 - V免签:手机监听通知栏 - 码支付:扫码付 + 回调 - 原理:APP 监听 → 回调服务器 ## 易支付接入 - 注册 / 自建易支付 - 创建支付通道 - 配置回调通知 - 签名验证 ## 充值流程 - 用户发起充值 → 生成订单 - 跳转支付页面 - 支付成功 → 回调 new-api - 更新用户额度 ## 回调服务 - 接收支付通知 - 验签防篡改 - 调用 new-api 加额度 - 记录充值日志 ## 安全注意事项 - 回调验签必须做 - 订单号唯一性 - 金额校验 - 防重复回调

问题:new-api 有额度系统但没有支付

new-api 的令牌额度管理很完善——创建令牌时设额度、用完自动停、月额度自动重置。但它只提供了管理端手动加额度,没有面向终端用户的自助充值入口。

如果你在对外提供 API 服务,用户需要能自己付钱充值。本文讲解三种方案,从零搭建支付流程。

方案概览

方案 门槛 费时 手续费 适合场景
人工充值 每次手动 小团队内部、亲友圈
个人免签(V免签) 一台安卓手机 一次搭建 个人站长、小规模商用
第三方聚合(易支付) 注册账号 一次搭建 2%~5% 不想折腾手机的
官方 API 企业营业执照 开发对接 0.6% 正规商业运营
flowchart LR U["用户选择方案"] --> Q{"有营业执照?"} Q -- 有 --> OFFICIAL["官方 API\n支付宝/微信直连\n费率 0.6%"] Q -- 没有 --> SCALE{"用户规模?"} SCALE -- "<50 人" --> MANUAL["人工充值\n管理员后台操作\n零成本"] SCALE -- "50~500 人" --> PERSONAL["个人免签\nV免签 / 码支付\n需安卓手机"] SCALE -- ">500 人" --> THIRD["聚合支付\n易支付等\n费率 2%~5%"]

方案一:人工充值(最简,零成本)

如果你只是给几个朋友或小团队用,直接管理员后台手动加额度最简单。

操作流程

  1. 用户微信/支付宝转账给你
  2. 你登录 new-api 后台 →「令牌」→ 找到对应用户的令牌
  3. 编辑令牌,手动增加「剩余额度」
  4. 截图或口头告知用户已到账

优点:零门槛,不需要任何额外部署。 缺点:你人在的时候才能充值,不适合用户自主操作。

适用:团队内部使用、10 人以内的用户群。

方案二:个人免签支付(V免签 / 码支付)

这是个人站长最常用的方案——不需要营业执照,用一台闲置安卓手机监听支付宝/微信的到账通知,自动回调你的服务器完成充值。

V免签 原理

sequenceDiagram participant U as 用户 participant WEB as 充值页面 participant V as V免签 APP<br/>(安卓手机) participant NA as new-api participant PAY as 支付宝/微信 U->>WEB: 发起充值,选择金额 WEB->>WEB: 生成订单,展示收款码 U->>PAY: 扫码付款 PAY->>V: 推送付款通知 V->>V: 监听通知栏,解析金额 V->>WEB: POST 回调(金额、备注) WEB->>WEB: 验签,匹配订单 WEB->>NA: 调用 API 给用户加额度 WEB->>U: 显示充值成功

V免签 APP 运行在一台安卓手机上,保持支付宝/微信在后台运行。当有付款到账时,APP 读取通知栏的到账信息,回调你的服务器。

部署步骤

第一步:准备安卓手机

  • 一台闲置安卓手机(Android 7.0+)
  • 安装支付宝和微信,登录你的收款账号
  • 开启通知栏权限

第二步:安装 V免签 APP

V免签 GitHub 下载 APK,安装到手机上。打开后配置:

配置项 说明
回调地址 你的服务器 URL,如 https://api.example.com/pay/notify
通信密钥 随机字符串,用于签名验证
监听模式 通知栏监听(推荐)

第三步:写充值页面和回调服务

下面是一个最小化的回调处理示例(Python Flask),部署在你的服务器上:

# callback_server.py
from flask import Flask, request, jsonify
import hashlib
import hmac
import requests
import sqlite3
from datetime import datetime

app = Flask(__name__)

# = 配置 =
VMQ_SECRET = "your-communication-key"  # 与 V免签 APP 里一致
NEW_API_URL = "http://127.0.0.1:3000"
ADMIN_TOKEN = "sk-your-admin-token"    # new-api 管理员令牌
DB_PATH = "orders.db"                  # 订单数据库

# = 订单数据库初始化 =
def init_db():
    conn = sqlite3.connect(DB_PATH)
    conn.execute('''CREATE TABLE IF NOT EXISTS orders (
        order_id TEXT PRIMARY KEY,
        token_name TEXT,
        amount REAL,
        status TEXT DEFAULT 'pending',
        created_at TEXT
    )''')
    conn.commit()
    conn.close()

init_db()

# = V免签 回调接收 =
@app.route('/pay/notify', methods=['POST'])
def vmq_callback():
    data = request.form
    # V免签回调字段: price, mark, sign, type
    price = data.get('price')
    mark = data.get('mark')      # 订单号
    sign = data.get('sign')

    # 验签:price + mark + type 的 MD5 + secret
    raw = f"{price}{mark}{data.get('type', '')}"
    expected = hashlib.md5((raw + VMQ_SECRET).encode()).hexdigest()

    if sign != expected:
        return 'sign error', 403

    # 查找订单
    conn = sqlite3.connect(DB_PATH)
    order = conn.execute('SELECT * FROM orders WHERE order_id=? AND status="pending"',
                         (mark,)).fetchone()
    if not order:
        conn.close()
        return 'order not found', 404

    # 校验金额(允许 0.01 误差)
    if abs(float(price) - order[2]) > 0.01:
        conn.close()
        return 'amount mismatch', 400

    # 标记订单已支付
    conn.execute('UPDATE orders SET status="paid" WHERE order_id=?', (mark,))
    conn.commit()
    conn.close()

    # 调用 new-api 给用户加额度
    add_quota_to_token(order[1], order[2])

    return 'success'

# = 给 new-api 用户加额度 =
def add_quota_to_token(token_name, amount_usd):
    """
    通过 new-api 的管理 API 给令牌增加额度。
    new-api 目前没有直接的"加额度"API,这里用两种变通方式:
    1) 如果有管理 API,直接调用
    2) 或者直接操作 SQLite 数据库(仅限 SQLite 部署)
    """
    # 方式一:如果有暴露管理 API(取决于 new-api 版本)
    # resp = requests.post(f"{NEW_API_URL}/api/token/quota",
    #     headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
    #     json={"token_name": token_name, "quota": amount_usd})
    # return resp.ok

    # 方式二:直接操作数据库(SQLite,简单粗暴)
    # 注意:操作前停服或确保 new-api 不会同时写入
    conn = sqlite3.connect('/home/user/new-api/new-api.db')
    token = conn.execute(
        'SELECT id, remain_quota FROM tokens WHERE name=?', (token_name,)
    ).fetchone()
    if token:
        new_quota = token[1] + int(amount_usd * 100)  # new-api 内部以"分"存储
        conn.execute('UPDATE tokens SET remain_quota=? WHERE id=?',
                     (new_quota, token[0]))
        conn.commit()
    conn.close()

# = 创建充值订单 =
@app.route('/pay/create', methods=['POST'])
def create_order():
    data = request.json
    token_name = data.get('token_name')
    amount = data.get('amount')  # 美元金额

    import uuid
    order_id = f"TOPUP{datetime.now().strftime('%Y%m%d%H%M%S')}{uuid.uuid4().hex[:6]}"

    conn = sqlite3.connect(DB_PATH)
    conn.execute(
        'INSERT INTO orders (order_id, token_name, amount, created_at) VALUES (?,?,?,?)',
        (order_id, token_name, amount, datetime.now().isoformat())
    )
    conn.commit()
    conn.close()

    # 返回收款信息(V免签通常不需要额外参数,用户直接扫你固定的收款码)
    # 付款备注填订单号,V免签通过 mark 字段回传
    return jsonify({
        'order_id': order_id,
        'amount': amount,
        'qr_note': f'请转账 {amount} 元,备注:{order_id}'
    })

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000)

第四步:用 Nginx/Caddy 反代回调服务

# 在已有的 Nginx 配置中追加
location /pay/ {
    proxy_pass http://127.0.0.1:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

提示:V免签的回调地址需要公网可达,不能用 127.0.0.1。确保你的服务器有域名 + HTTPS。

码支付(替代方案)

码支付 是另一个类似的方案,通过软件监听 PC 端支付宝/微信收款。不需要手机,但需要 PC 一直开机。接入流程类似。

方案二的小结

  • 需要一台安卓手机 24 小时开机跑 V免签 APP
  • 回调服务需要公网可达
  • 零手续费,适合个人站长
  • 注意手机端的通知权限不要被系统杀掉

方案三:第三方聚合支付(易支付)

如果你不想维护一台安卓手机,可以用第三方支付平台。易支付是国内站长圈最常用的个人可用的聚合支付,支持支付宝、微信扫码。

自建 vs 使用第三方

方式 说明
使用别人搭建的易支付 注册账号即可,但费率较高(3%~5%),且有跑路风险
自建易支付 在自己的服务器上搭建,需要对接官方 API(支付宝/微信)或上游易支付

自建易支付同样需要解决收款渠道的问题——如果你有企业资质,可以直接对接支付宝/微信官方 API;如果没有,自建易支付也需要找一个上游渠道。

对接流程(以使用第三方易支付为例)

sequenceDiagram participant U as 用户 participant WEB as 充值页面 participant EP as 易支付平台 participant CB as 回调服务 participant NA as new-api U->>WEB: 发起充值 WEB->>EP: 创建订单(金额、订单号、回调URL) EP-->>WEB: 返回支付链接 WEB->>U: 跳转到支付页面 U->>EP: 扫码付款 EP->>CB: POST 回调(订单号、金额、签名) CB->>CB: 验签 CB->>NA: 给用户加额度 CB->>U: 显示充值成功

第一步:注册易支付账号

找一个靠谱的易支付平台注册(注意甄别,行业内跑路的不少)。注册后获取:

  • 商户 ID(pid
  • 商户密钥(key
  • 平台 API 地址

第二步:写充值页面

# 易支付集成示例
import requests
import hashlib

def create_epay_order(amount, order_id, notify_url, return_url):
    """创建易支付订单,返回支付链接"""
    EP_API = "https://pay.example.com/submit.php"
    pid = "your-merchant-id"
    key = "your-merchant-key"

    params = {
        'pid': pid,
        'type': 'alipay',        # alipay / wxpay
        'out_trade_no': order_id,
        'notify_url': notify_url,
        'return_url': return_url,
        'name': f'API额度充值 ${amount}',
        'money': str(amount),
    }

    # 生成签名(易支付的签名方式各平台可能不同,以文档为准)
    sign_str = '&'.join(f'{k}={v}' for k, v in sorted(params.items())) + key
    params['sign'] = hashlib.md5(sign_str.encode()).hexdigest()
    params['sign_type'] = 'MD5'

    # 构建支付 URL
    pay_url = EP_API + '?' + '&'.join(f'{k}={v}' for k, v in params.items())
    return pay_url

第三步:写回调服务

@app.route('/pay/epay/notify', methods=['GET', 'POST'])
def epay_notify():
    """易支付回调"""
    data = request.args if request.method == 'GET' else request.form
    pid = data.get('pid')
    trade_no = data.get('trade_no')
    out_trade_no = data.get('out_trade_no')  # 你的订单号
    money = data.get('money')
    trade_status = data.get('trade_status')
    sign = data.get('sign')

    # 验签:排除 sign 和 sign_type 后排序拼接 + key
    sign_params = {k: v for k, v in data.items()
                   if k not in ('sign', 'sign_type')}
    sign_str = '&'.join(f'{k}={v}' for k, v in sorted(sign_params.items())) + KEY
    expected = hashlib.md5(sign_str.encode()).hexdigest()

    if sign != expected:
        return 'sign error'

    if trade_status != 'TRADE_SUCCESS':
        return 'fail'

    # 查找订单,加额度(与 V免签 示例相同逻辑)
    process_topup(out_trade_no, float(money))

    return 'success'

易支付的注意事项

  • 验签必须做:回调不验签等于裸奔,任何人都可以伪造请求给自己加额度
  • 订单唯一性out_trade_no 必须在你的系统里唯一,防止重复充值
  • 回调幂等:易支付可能多次回调同一个订单,需要先查订单状态,已处理的直接返回 success
  • HTTPS:回调地址必须 HTTPS,且能被公网访问

方案四:官方 API(企业资质)

如果你有企业营业执照,可以直接对接支付宝和微信支付的官方 API。这是最正规的方案,费率最低(0.6%),但开发和审核门槛最高。

步骤 说明
1. 注册支付宝商户 需要营业执照、对公账户
2. 开通「当面付」或「电脑网站支付」 获取 APPID、商户私钥、支付宝公钥
3. 接入支付宝 SDK pip install alipay-sdk-python
4. 微信支付同理 需要服务号或商户号

开发对接逻辑和上述易支付类似——创建订单 → 返回支付链接 → 接收异步通知。只是 SDK 和签名方式不同。

官方对接超出本文范围,参考 支付宝开放平台微信支付文档

完整的充值系统架构

综合以上方案,一个完整的自助充值系统的推荐架构:

flowchart LR U["用户"] --> WEB["充值页面<br/>选择金额 / 支付方式"] WEB --> ORDER["创建订单<br/>订单号 + 金额 + 用户ID"] ORDER --> PAY["支付网关<br/>V免签 / 易支付 / 官方API"] PAY --> CB["回调服务<br/>验签 + 匹配订单"] CB --> DB["订单数据库<br/>标记已支付"] CB --> NA["new-api<br/>更新用户额度"] CB --> NOTIFY["通知用户<br/>(可选:邮件/微信)"]

充值页面前端示例

<!-- topup.html - 最简充值页面 -->
<!DOCTYPE html>
<html>
<head><title>API 额度充值</title></head>
<body>
  <h2>充值中心</h2>
  <div>
    <label>令牌名称:</label>
    <input type="text" id="tokenName" placeholder="你的令牌名">
  </div>
  <div>
    <label>充值金额(USD):</label>
    <select id="amount">
      <option value="5">$5 - 约 35 元</option>
      <option value="10">$10 - 约 70 元</option>
      <option value="20">$20 - 约 140 元</option>
      <option value="50">$50 - 约 350 元</option>
    </select>
  </div>
  <button onclick="createOrder()">去支付</button>

  <script>
  async function createOrder() {
    const tokenName = document.getElementById('tokenName').value;
    const amount = document.getElementById('amount').value;
    if (!tokenName) return alert('请输入令牌名称');

    const resp = await fetch('/pay/create', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({token_name: tokenName, amount: parseFloat(amount)})
    });
    const data = await resp.json();

    // 跳转到支付页面(易支付模式)
    // window.location.href = data.pay_url;

    // 或者展示收款码(V免签模式)
    alert(`订单号: ${data.order_id}\n请转账 ${amount} 元并备注订单号`);
  }
  </script>
</body>
</html>

安全注意事项

回调验签(最重要)

无论用哪种方案,回调接口必须验签。不验签的后果:攻击者直接 POST 你的回调地址 {"amount": 99999, "order_id": "fake"} 就能无限充值。

# 验签示例(通用模式)
def verify_sign(data, secret, received_sign):
    # 1. 排除 sign 字段,按 key 排序
    sign_params = {k: v for k, v in data.items() if k != 'sign'}
    # 2. 拼接 key=value&key=value + secret
    raw = '&'.join(f'{k}={v}' for k, v in sorted(sign_params.items()))
    raw += secret
    # 3. MD5 或 HMAC
    expected = hashlib.md5(raw.encode()).hexdigest()
    return hmac.compare_digest(expected, received_sign)

防止重复回调

支付平台可能多次回调同一个订单。处理前先检查订单状态:

order = db.get_order(order_id)
if order['status'] == 'paid':
    return 'success'  # 已处理,直接返回成功

金额校验

回调金额必须与创建订单时的金额一致:

if abs(callback_amount - order_amount) > 0.01:
    return 'amount mismatch', 400

订单号规则

订单号必须全局唯一,建议格式:TOPUP-{日期}-{随机串}

IP 白名单

如果支付平台提供回调 IP 白名单,加上它:

EPAY_IPS = ['1.2.3.4', '5.6.7.8']
if request.remote_addr not in EPAY_IPS:
    return 'unauthorized ip', 403

与 new-api 用户系统的衔接

new-api 的额度是绑定在令牌上的。充值回调里需要做的是:

  1. 根据订单里的 token_name 找到令牌
  2. 更新 remain_quota 字段
  3. 记一条充值日志(可选)

如果你的 new-api 使用 SQLite,最简单的做法是直接操作数据库:

def topup_token(token_name, amount_usd):
    conn = sqlite3.connect(NEW_API_DB)
    token = conn.execute(
        'SELECT id, remain_quota FROM tokens WHERE name=?', (token_name,)
    ).fetchone()
    if not token:
        raise ValueError(f'Token {token_name} not found')

    new_quota = token[1] + int(amount_usd * 100)  # 分转整数
    conn.execute('UPDATE tokens SET remain_quota=? WHERE id=?',
                 (new_quota, token[0]))
    conn.commit()
    conn.close()

如果是 MySQL,替换为对应的 SQL 即可。

注意:直接操作数据库时要确保 new-api 不会同时写入同一条记录。SQLite 的写锁是进程级的,建议在 new-api 低峰期操作,或者通过管理 API 间接更新(如果 new-api 版本支持)。

不同场景的推荐方案

场景 推荐方案 理由
自用 / 家人 人工充值 零成本,没几次操作
小团队(<20人) 人工充值 每月收一次钱,手动加额度
对外服务(<100用户) V免签 零手续费,一台旧手机搞定
对外服务(>100用户) 易支付 / 官方 API 稳定性更重要,值得付费
正规商业运营 支付宝/微信官方 API 最低费率,最可靠

系列导航

系列导航

实操清单

  • 确定支付方案(人工 / V免签 / 易支付 / 官方API)
  • 如用 V免签:准备安卓手机,安装 APP,配置回调地址
  • 如用易支付:注册账号,获取商户 ID 和密钥
  • 部署回调服务(Python Flask 或其他)
  • 配置 Nginx/Caddy 反代回调地址,确保公网可达 + HTTPS
  • 创建订单数据库(SQLite 记录订单状态)
  • 编写充值页面(HTML + JS,调用 /pay/create)
  • 实现 new-api 加额度逻辑(数据库操作或 API 调用)
  • 全额测试:扫码支付 → 确认回调 → 确认额度到账
  • 测试防重复回调(模拟多次 POST 同一订单)
  • 测试验签失败场景(确认返回错误而非加额度)
  • 配置回调 IP 白名单(如有)