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
相关产品推荐
相关产品推荐

