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

含trial_period_days的Stripe订阅集成报错:缺失client_secret

解决Stripe订阅添加试用期后confirmCardPayment缺少client_secret的问题

问题原因

当你给订阅设置trial_period_days:7时,因为试用期是免费的,Stripe不会为订阅的初始发票生成Payment Intent(无待收取金额),此时subscription.latest_invoice.payment_intent的值为null。你的后端代码直接尝试取它的client_secret会得到undefined,返回给前端后,用这个无效值调用stripe.confirmCardPayment就触发了报错。

而移除试用期参数后,订阅需要立即扣费,Stripe会生成Payment Intent,因此能正常拿到client_secret,功能也就正常了。

修复方案

1. 修改后端Node.js函数

在返回响应前,先判断payment_intent是否存在,仅在存在时返回clientSecret:

cors(request, response, async () => {
    try {
        if (request.method != "POST") return response.status(400);
        const { name, email, paymentMethod, priceId } = request.body;
        // 创建客户
        const customer = await stripe.customers.create({
            email,
            name,
            payment_method: paymentMethod,
            invoice_settings: { default_payment_method: paymentMethod },
        });

        // 创建订阅
        const subscription = await stripe.subscriptions.create({
            customer: customer.id,
            items: [{ price: priceId }], // 建议使用传入的priceId,而非硬编码
            payment_settings: {
                payment_method_options: {
                    card: {
                        request_three_d_secure: "any",
                    },
                },
                payment_method_types: ["card"],
                save_default_payment_method: "on_subscription",
            },
            payment_behavior: "default_incomplete",
            trial_period_days: 7,
            expand: ["latest_invoice.payment_intent"],
        });
        
        // 仅当payment_intent存在时返回clientSecret
        const responseData = {
            message: "Subscription successfully initiated",
            subID: subscription.id
        };
        if (subscription.latest_invoice.payment_intent) {
            responseData.clientSecret = subscription.latest_invoice.payment_intent.client_secret;
        }

        response.json(responseData);
    } catch (err) {
        console.error(err);
        response.status(500).json({ message: "Internal server error" });
    }
});

2. 修改前端函数

根据后端返回的clientSecret是否存在,决定是否调用confirmCardPayment:

const createSubscription = async () => {
    setProcessing(true);
    setWait('PLEASE WAIT');
    try {
        // 创建支付方式
        const paymentMethod = await stripe?.createPaymentMethod({
            type: "card",
            card: elements?.getElement(CardElement),
            billing_details: {
                name,
                email,
            },
        });

        // 调用后端创建订阅
        const response = await fetch("https://XXX.cloudfunctions.net/tplannersubscription", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                paymentMethod: paymentMethod?.paymentMethod?.id,
                name,
                lname,
                email,
                priceId
            }),
        }).then((res) => res.json());
        
        // 仅当存在clientSecret时调用确认支付
        if (response.clientSecret) {
            const confirmPayment = await stripe?.confirmCardPayment(response.clientSecret);
            // 这里可添加支付确认后的逻辑,比如处理成功/失败状态
        } else {
            // 试用期场景无需确认支付,直接处理订阅成功逻辑
            setProcessing(false);
            setWait('');
            // 示例:跳转到订阅成功页面或提示用户
        }
    } catch (err) {
        // 统一处理错误
        setProcessing(false);
        setWait('');
        console.error(err);
    }
};

额外说明

  • 试用期场景下,Stripe会在试用期结束前自动生成发票并尝试扣费,只要客户支付方式有效,无需前端额外操作。
  • 确保你的Stripe产品价格设置正确,试用期内无待收取金额(或为0金额),否则仍会生成Payment Intent。

内容的提问来源于stack exchange,提问作者Paul VI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:42:42