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

Stripe Issuing卡支付拦截Webhook开发求助:需手动审批支付

Stripe Issuing 支付手动审批Webhook 问题修复

代码中的核心问题

  • Flask路由函数参数错误:webhook函数无法直接接收event参数,需从请求中获取原始数据并完成Stripe签名验证
  • Stripe事件结构访问错误:事件的业务数据存储在event['data']['object']节点下,直接访问event['data']['settings']会导致KeyError
  • Customer邮箱获取逻辑错误:Payment Attempt对象中的customer字段是Stripe Customer的ID,而非完整对象,需通过API查询才能获取邮箱
  • 签名验证逻辑位置错误:stripe.Webhook.construct_event必须放在路由函数内部处理请求,而非__main__代码块
  • 缺少Stripe API密钥初始化:调用Stripe API前必须设置有效的API密钥
  • 缺少响应返回:Webhook必须返回2xx状态码,否则Stripe会持续重试事件
  • 审批逻辑不符合需求:当前代码自动允许未拦截的支付,而需求是所有支付默认拦截,通知后手动审批,需调整逻辑

修正后的完整代码

import stripe
from flask import Flask, request, jsonify

# 初始化Flask应用
app = Flask(__name__)

# 设置Stripe API密钥(替换为你的实际密钥)
stripe.api_key = "sk_test_your_api_key_here"
# 设置Webhook签名密钥(替换为你的实际密钥)
WEBHOOK_SECRET = "whsec_your_webhook_secret_here"

# 模拟邮件发送函数,需根据实际需求实现(比如用SMTP或第三方邮件服务)
def send_admin_notification(payment_attempt_id, amount, currency, customer_email):
    subject = f"待审批支付请求: {payment_attempt_id}"
    body = f"""
    收到一笔待审批的支付请求:
    支付ID: {payment_attempt_id}
    金额: {amount} {currency}
    持卡人邮箱: {customer_email}
    请通过Stripe Dashboard或调用API手动审批该支付。
    """
    # 这里替换为实际的邮件发送逻辑,比如使用smtplib或SendGrid等
    print(f"发送通知邮件: {subject}\n{body}")

@app.route('/webhook', methods=['POST'])
def webhook():
    # 获取请求原始数据和签名头
    payload = request.data
    sig_header = request.headers.get('STRIPE_SIGNATURE')
    event = None

    # 验证Webhook签名,防止伪造请求
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, WEBHOOK_SECRET
        )
    except ValueError as e:
        # 无效的请求数据
        return jsonify({"error": str(e)}), 400
    except stripe.error.SignatureVerificationError as e:
        # 签名验证失败
        return jsonify({"error": str(e)}), 400

    # 只处理支付尝试事件
    if event['type'] != 'issuing.card.payment_attempted':
        return jsonify({"status": "ignored"}), 200

    payment_attempt = event['data']['object']

    # 确认支付已被默认拦截(需提前在Stripe后台配置Card/Cardholder的默认拦截规则)
    if payment_attempt['settings']['blocked']:
        # 通过Customer ID查询获取持卡人邮箱
        customer = stripe.Customer.retrieve(payment_attempt['customer'])
        customer_email = customer['email']

        # 通知管理员处理审批
        send_admin_notification(
            payment_attempt['id'],
            payment_attempt['amount'],
            payment_attempt['currency'],
            customer_email
        )

    # 返回成功响应,告知Stripe已接收事件
    return jsonify({"status": "processed"}), 200

if __name__ == '__main__':
    # 启动Flask服务,生产环境建议使用Gunicorn等WSGI服务器
    app.run(port=4242, debug=True)

关键补充说明

  1. 默认拦截配置:需在Stripe后台为目标Issuing Card或Cardholder设置默认拦截所有支付,这样所有支付尝试都会触发issuing.card.payment_attempted事件且settings.blocked为True
  2. 手动审批方式:收到通知后,你可以通过两种方式审批:
    • 在Stripe Dashboard中找到对应的Payment Attempt,手动修改Blocked状态为False
    • 调用Stripe API完成审批:
      stripe.issuing.PaymentAttempt.update(
          "pa_xxxxxx",
          blocked=False
      )
      
  3. 邮件函数实现:send_admin_notification需要你根据实际环境实现,比如使用Python的smtplib模块连接邮件服务器,或使用SendGrid、Mailgun等第三方邮件服务

内容的提问来源于stack exchange,提问作者Gonzalo Pena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:22:42