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

Laravel Cashier迁移Stripe Checkout后事件监听问题咨询

问题:Laravel Cashier迁移至Stripe Checkout后,事件监听该如何调整?

我正在将Laravel Cashier配置迁移至Stripe Checkout功能,平台同时支持订阅和一次性收费,其中一项一次性收费为用户账户充值短信额度。

原本使用invoicePrice方法并传递元数据:

$addonItemPrice = Cashier::stripe()->prices->retrieve($addonItem->stripe_id);
Auth::user()->invoicePrice(
    $addonItem->stripe_id, 1, [
        'metadata' => [
            'is_addon' => true,
            'is_sms_addon' => true,
            'created_at' => Carbon::now(),
            'user_id' => Auth::id(),
            'addon_id' => $addonItem->id,
            'addon_quantity' => $addonItem->quantity,
            'apply_credit_balance' => true,
        ],
    ]
);

之后通过监听invoice.payment_succeeded Webhook事件为用户添加短信额度:

/**
 * Handle received Stripe webhooks.
 */
public function handle(WebhookReceived $event)
{
    match ($event->payload['type']) {
        'customer.subscription.created' => $this->handleSubscriptionCreated($event->payload),
        'invoice.payment_succeeded' => $this->handleInvoicePaymentSucceeded($event->payload),
        default => null
    };
}

迁移至Stripe Checkout后,代码改为:

$charge = $user->checkout([$addonItemPrice->id => 1], [
    'success_url' => "$frontendURL"."account/billing/checkout/success/",
    'cancel_url' => "$frontendURL"."account/billing/add-ons/",
    'metadata' => [
        'is_addon' => true,
        'is_sms_addon' => true,
        'created_at' => Carbon::now(),
        'user_id' => Auth::id(),
        'addon_id' => $addonItem->id,
        'addon_quantity' => $addonItem->quantity,
        'apply_credit_balance' => true,
    ],
]);

但现在完全收不到invoice.payment_succeeded事件,元数据关联到了checkout.session.completed事件。我想咨询是否应该迁移至该事件,是否存在不可靠的情况?我仅希望在发票支付成功时触发相关逻辑。


回答

为什么收不到invoice.payment_succeeded?

Stripe Checkout处理一次性收费时,默认不会自动生成发票,因此不会触发invoice.payment_succeeded事件。此时支付完成后只会触发checkout.session.completed,你设置的元数据也会绑定在这个会话事件上。

两种可行方案

方案1:迁移至checkout.session.completed事件

完全可以迁移到这个事件,但必须注意:checkout.session.completed仅表示用户完成了Checkout流程,不代表支付一定成功(比如用户用了无效卡片后关闭页面,会话也会标记为完成,但支付状态是失败的)。

你需要在事件处理逻辑中先校验支付状态,再执行业务代码:

public function handle(WebhookReceived $event)
{
    match ($event->payload['type']) {
        'customer.subscription.created' => $this->handleSubscriptionCreated($event->payload),
        'invoice.payment_succeeded' => $this->handleInvoicePaymentSucceeded($event->payload),
        'checkout.session.completed' => $this->handleCheckoutSessionCompleted($event->payload),
        default => null
    };
}

private function handleCheckoutSessionCompleted(array $payload)
{
    $session = $payload['data']['object'];
    
    // 核心校验:只有支付成功才执行逻辑
    if ($session['payment_status'] !== 'paid') {
        return;
    }
    
    $metadata = $session['metadata'];
    // 判断是否是短信充值的一次性收费
    if (isset($metadata['is_sms_addon']) && $metadata['is_sms_addon'] === 'true') {
        // 执行添加短信额度的业务逻辑
        $userId = $metadata['user_id'];
        $addonQuantity = $metadata['addon_quantity'];
        // ...你的具体业务代码
    }
}

这个方案的优势是贴合Stripe Checkout的原生流程,无需额外配置,适合仅需处理支付成功触发逻辑的场景。

方案2:启用发票生成,继续监听invoice.payment_succeeded

如果你必须依赖发票实体(比如需要记录发票号、后续对账),可以在Checkout配置中强制生成发票,这样支付成功后就会触发invoice.payment_succeeded事件。

修改Checkout代码,添加invoice_creation参数,并将元数据同步到发票中:

$charge = $user->checkout([$addonItemPrice->id => 1], [
    'success_url' => "$frontendURL"."account/billing/checkout/success/",
    'cancel_url' => "$frontendURL"."account/billing/add-ons/",
    'metadata' => [
        'is_addon' => true,
        'is_sms_addon' => true,
        'created_at' => Carbon::now(),
        'user_id' => Auth::id(),
        'addon_id' => $addonItem->id,
        'addon_quantity' => $addonItem->quantity,
        'apply_credit_balance' => true,
    ],
    // 启用发票生成
    'invoice_creation' => [
        'enabled' => true,
        'invoice_data' => [
            'metadata' => [
                // 将核心元数据同步到发票,确保事件中能获取到
                'is_addon' => true,
                'is_sms_addon' => true,
                'addon_id' => $addonItem->id,
                'addon_quantity' => $addonItem->quantity,
            ]
        ]
    ]
]);

这样配置后,Stripe会为这次一次性收费生成发票,支付成功后就会触发invoice.payment_succeeded,你可以复用之前写好的handleInvoicePaymentSucceeded逻辑,无需大幅修改。

总结

  • 若无需依赖发票实体,方案1更简洁高效,只要做好支付状态校验就不存在可靠性问题;
  • 若业务必须关联发票,选择方案2,配置发票生成即可继续使用原有事件逻辑。

内容的提问来源于stack exchange,提问作者Ryan H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:47:07