You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django集成QuickBooks Payments实现循环支付:如何永久存储客户卡片以支持重复自动扣费?

Django集成QuickBooks Payments实现循环支付:如何永久存储客户卡片以支持重复自动扣费?

看起来你已经搞定了单次支付的核心环节,但卡在了循环扣费的关键节点上——没错,QuickBooks的Vault Token本身就是一次性凭证,只能用来发起首次交易或者绑定卡片,后续重复用肯定会失败。下面我结合QuickBooks Payments的官方规则,给你梳理正确的永久存卡+循环扣费方案:

核心思路:用「QuickBooks Customer ID + 永久Card ID」替代一次性Vault Token

QuickBooks里的卡档案(Card-on-File)是和具体的QuickBooks Customer绑定的,你需要先把临时的Vault Token转化为该客户名下的永久卡片记录,之后就可以用Customer ID + Card ID来发起无限次的扣费请求。

具体步骤调整

1. 先把Vault Token转化为客户名下的永久卡片

当你首次获取到Vault Token(客户输入卡片后),需要调用QuickBooks的「给客户绑定卡片」API,将临时Token转为永久卡记录:

def bind_card_to_customer(access_token, realm_id, qb_customer_id, vault_token):
    url = f"https://sandbox.api.intuit.com/quickbooks/v4/payments/customers/{qb_customer_id}/cards"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Accept": "application/json",
        "Content-Type": "application/json"
    }
    payload = {
        "token": vault_token,  # 用首次拿到的一次性Vault Token
        "cardOnFile": True  # 标记为可重复使用的卡档案
    }
    resp = requests.post(url, json=payload, headers=headers)
    card_data = resp.json()
    # 从响应里取出永久的cardId,和qb_customer_id一起存在你的数据库里
    return card_data.get("cardId"), card_data.get("last4"), card_data.get("expiry")

调用这个函数后,把返回的cardId和你已有的qb_customer_id、last4、 expiry一起存在用户记录里,Vault Token就可以丢弃了,不用再存。

2. 修改循环扣费函数,用Customer ID + Card ID发起扣费

原来的函数里用Vault Token的地方,换成qb_customer_id和cardId,调整payload结构:

def charge_recurring_payment(access_token, realm_id, user, amount):
    url = "https://sandbox.api.intuit.com/quickbooks/v4/payments/charges"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Accept": "application/json",
        "Content-Type": "application/json"
    }
    payload = {
        "amount": str(amount),
        "currency": "USD",
        "customerId": user.qb_customer_id,  # 加上客户ID
        "cardOnFile": {
            "value": user.qb_card_id,  # 这里用永久的cardId,不是Vault Token
            "type": "CARD"  # 类型从TOKEN改成CARD
        }
    }
    resp = requests.post(url, json=payload, headers=headers)
    return resp.json()

这样调整后,这个扣费请求就可以重复发起,只要卡片状态有效、客户账户正常。

关键注意事项

  • Access Token续期:QuickBooks的Access Token有效期只有1小时,Celery任务执行时要确保用的是最新的有效Token(需要用Refresh Token定期刷新并存储)。
  • 沙箱环境测试:沙箱里的测试卡片可以重复使用,但要注意QuickBooks沙箱的API调用频率限制。
  • 数据存储合规:只存必要的字段(qb_customer_id、cardId、last4、expiry),不要存任何敏感卡片信息,符合PCI合规要求。
  • 官方模式确认:这就是QuickBooks Payments推荐的循环扣费标准流程——先将卡片绑定到客户名下生成永久Card ID,后续通过客户+卡ID发起自动扣费,你用Celery调度任务的方式完全可行(如果需要QB自动管理扣费计划,也可以用官方的订阅API,但手动调度更灵活)。

对你疑问的直接解答

  • 👉 应该存储Customer ID + Card ID而不是Vault Token:完全正确,这是永久复用卡片的唯一方式。
  • 👉 有没有官方Django/Python模式:官方没有专门的Django库,但标准流程就是上面的「绑定卡片→存储Card ID→循环扣费」,你当前的技术栈(Django+Celery)适配这个流程毫无问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 09:23:01