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

Stripe自动扣费异常:默认支付字段存储不一致及支付方式选择疑问

问题解答

1. Stripe Payment Intent 支付方式选择方案

对于自动扣费场景(如你的短信费用收取),推荐两种可靠实现方式:

  • 自动使用客户默认支付方式:创建Payment Intent时,仅传入customer参数,不指定payment_method。Stripe会自动优先读取invoice_settings.default_payment_method,若该字段为空则 fallback 到default_source,完全兼容两种字段存储情况,这是最省心的方案。
  • 指定具体支付方式:若需精准控制扣费使用的支付方式,可先兼容获取客户的默认支付方式ID(优先新版字段,旧版作为兜底),再传入payment_method参数。注意旧版default_source是Source ID,需转换为PaymentMethod ID才能适配新版API(可通过stripe.paymentMethods.attach(sourceId, {customer: stripeCusID})完成转换)。

2. 默认支付方式字段不一致的原因及解决办法

原因

Stripe API迭代中,用新版invoice_settings.default_payment_method(基于PaymentMethod体系)取代了旧版default_source(基于Source体系):

  • 新客户:若创建时使用2019-02-19及以后的Stripe API版本,默认使用invoice_settings.default_payment_method存储默认支付方式。
  • 老客户:若创建时使用旧版API,系统仍沿用default_source字段,客户门户添加新卡时也会继续使用该旧字段更新默认支付方式。

解决办法

临时兼容方案(修改现有代码)

在获取支付方式ID时同时兼容两个字段,优先取新版字段,旧版字段作为 fallback:

async function chargeSMS(stripeCusID, chargeValue, chemistName, chemistID, countSMS) {
    const customerObject = await stripe.customers.retrieve(stripeCusID);
    
    // 优先使用新版默认支付方式字段,为空则 fallback 到旧版并转换
    let payMethodID = customerObject.invoice_settings.default_payment_method;
    if (!payMethodID && customerObject.default_source) {
        const paymentMethod = await stripe.paymentMethods.attach(customerObject.default_source, {
            customer: stripeCusID
        });
        payMethodID = paymentMethod.id;
    }

    if (!payMethodID) {
        console.log("No default payment method found for customer:", stripeCusID);
        return;
    }

    try {
        const response = await stripe.paymentIntents.create({
            amount: chargeValue,
            currency: 'aud',
            customer: stripeCusID,
            description: `SMS Charges: ${countSMS} sent`,
            payment_method: payMethodID,
            confirm: true
        });
        console.log("Successful SMS Charge:", response.id, chemistName);
        chemCharged(chemistID);
    } catch (err) {
        console.log("Charge failed:", err.message, stripeCusID, chargeValue, chemistName);
    }
}

简化版:直接去掉payment_method参数,让Stripe自动处理默认支付方式选择,无需手动兼容两个字段,代码更简洁。

长期迁移方案

将所有老客户的default_source统一迁移到invoice_settings.default_payment_method,彻底统一使用新版PaymentMethod体系:

async function migrateOldCustomers() {
    let customers = await stripe.customers.list({limit: 100});
    while (customers.data.length > 0) {
        for (const customer of customers.data) {
            if (customer.default_source && !customer.invoice_settings.default_payment_method) {
                try {
                    const paymentMethod = await stripe.paymentMethods.attach(customer.default_source, {
                        customer: customer.id
                    });
                    await stripe.customers.update(customer.id, {
                        invoice_settings: {
                            default_payment_method: paymentMethod.id
                        }
                    });
                    console.log("Migrated customer:", customer.id);
                } catch (err) {
                    console.log("Migration failed for customer:", customer.id, err.message);
                }
            }
        }
        // 分页处理所有客户
        if (customers.has_more) {
            customers = await stripe.customers.list({limit: 100, starting_after: customers.data[customers.data.length-1].id});
        } else {
            break;
        }
    }
}

额外注意事项

  • 确保你的Stripe Node.js SDK是最新版本,避免因API版本不兼容导致的字段差异问题。
  • 检查客户门户设置中是否开启“允许客户设置默认支付方式”选项,该选项会影响门户添加卡片时的默认字段存储行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:20:59