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

Stripe单次扣费含多产品:一次性与recurring产品共存及PHP实现疑问

核心问题解答与实现方案

1. 一次性产品加入订阅后是否会重复扣费?

会——如果你错误地将一次性产品作为订阅的常规循环项目添加。但只要把一次性产品设置为订阅的一次性计费项,就只会在订阅创建时收取一次,后续订阅续订时不会重复扣费。

具体来说,你需要给一次性产品创建one_time类型的价格,循环产品使用recurring类型的价格。在创建订阅时,把这两类价格作为订单项加入,Stripe会自动区分:一次性价格仅在首次订阅时扣费,循环价格会按周期续订扣费。

2. PHP自定义表单实现(无需跳转Stripe页面)

要实现无跳转的自定义支付流程,需要结合Stripe Elements(前端收集卡片信息)和Stripe PHP SDK(后端创建订阅),步骤如下:

前端部分(HTML+JS)

引入Stripe.js,创建卡片输入元素,收集用户卡片信息并获取支付方法ID:

<form id="payment-form">
  <div id="card-element"></div>
  <button id="submit-button">确认支付</button>
</div>

<script src="https://js.stripe.com/v3/"></script>
<script>
  // 初始化Stripe,替换为你的公钥
  const stripe = Stripe('pk_test_your_public_key');
  const elements = stripe.elements();

  // 创建卡片元素
  const cardElement = elements.create('card');
  cardElement.mount('#card-element');

  // 提交表单处理
  const form = document.getElementById('payment-form');
  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    // 创建支付方法
    const { paymentMethod, error } = await stripe.createPaymentMethod({
      type: 'card',
      card: cardElement,
    });

    if (error) {
      console.error(error.message);
      return;
    }

    // 把paymentMethod.id发送到后端
    fetch('/create-subscription', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        payment_method_id: paymentMethod.id,
        // 传递用户选择的产品价格ID
        recurring_price_id: 'price_your_recurring_price',
        one_time_price_id: 'price_your_one_time_price'
      })
    })
    .then(response => response.json())
    .then(data => {
      if (data.success) {
        alert('支付成功!');
      } else {
        alert('支付失败:' + data.error);
      }
    });
  });
</script>

后端部分(PHP)

使用Stripe PHP SDK创建订阅,关联支付方法,确保一次性产品仅扣费一次:

<?php
require_once('vendor/autoload.php');

// 初始化Stripe,替换为你的密钥
\Stripe\Stripe::setApiKey('sk_test_your_secret_key');

header('Content-Type: application/json');

// 获取前端传递的参数
$input = json_decode(file_get_contents('php://input'), true);
$paymentMethodId = $input['payment_method_id'];
$recurringPriceId = $input['recurring_price_id'];
$oneTimePriceId = $input['one_time_price_id'];

try {
  // 创建客户(若用户已存在,直接使用已有客户ID即可)
  $customer = \Stripe\Customer::create([
    'payment_method' => $paymentMethodId,
    'invoice_settings' => [
      'default_payment_method' => $paymentMethodId,
    ],
  ]);

  // 创建订阅,包含循环产品和一次性产品
  $subscription = \Stripe\Subscription::create([
    'customer' => $customer->id,
    'items' => [
      // 循环产品项
      ['price' => $recurringPriceId],
      // 一次性产品项(需使用one_time类型的价格)
      ['price' => $oneTimePriceId]
    ],
    'payment_behavior' => 'default_incomplete',
    'expand' => ['latest_invoice.payment_intent'],
  ]);

  // 检查支付状态
  $paymentIntent = $subscription->latest_invoice->payment_intent;
  if ($paymentIntent->status === 'succeeded') {
    echo json_encode(['success' => true, 'subscription_id' => $subscription->id]);
  } else {
    echo json_encode(['success' => false, 'error' => $paymentIntent->last_payment_error->message ?? '支付未完成']);
  }
} catch (\Stripe\Exception\ApiErrorException $e) {
  echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
?>

关键注意事项

  • 确保一次性产品的价格类型是one_time,循环产品价格类型是recurring(在Stripe后台创建价格时设置)。
  • payment_behavior: 'default_incomplete'会让Stripe自动处理支付流程,无需跳转至Stripe页面。
  • 若用户已存在,无需重复创建客户,直接传入现有客户ID即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:15:52