PAYATHON 2026

Laravel 5.5 Cashier 如何设置分钟或秒级试用期

支付老李

结论

Laravel Cashier 5.5 支持通过 trialUntil() 指定试用结束的准确时间,所以在代码中可以设置分钟或秒级的试用期:

use Carbon\Carbon;

$user->newSubscription('main', 'monthly')
    ->trialUntil(Carbon::now()->addMinutes(10))
    ->create($creditCardToken);

但 Cashier 最终还是要把试用结束时间提交给支付平台。以 Laravel 5.5 常用的 Stripe 为例,当时的 API 对试用期设有最短时长限制,分钟或秒级的时间可能被 Stripe 拒绝。因此,Cashier 支持这种写法,不等于支付平台一定允许这么短的试用期。

设置分钟或秒级时间

trialDays() 只接收天数。如果需要更精确地控制时间,可以改用 trialUntil(),并传入日期时间对象。

设置 10 分钟:

use Carbon\Carbon;

$user->newSubscription('main', 'monthly')
    ->trialUntil(Carbon::now()->addMinutes(10))
    ->create($creditCardToken);

设置 30 秒:

use Carbon\Carbon;

$user->newSubscription('main', 'monthly')
    ->trialUntil(Carbon::now()->addSeconds(30))
    ->create($creditCardToken);

也可以先构造具体的结束时间:

use Carbon\Carbon;

$trialEndsAt = Carbon::now()->addHour();

$user->newSubscription('main', 'monthly')
    ->trialUntil($trialEndsAt)
    ->create($creditCardToken);

Cashier 会将这个时间转换为支付平台需要的 trial_end 时间戳。

为什么可能无法成功

trialUntil() 解决的是 Cashier 如何表示试用结束时间,订阅本身仍由 Stripe 创建。如果当前 Stripe API 版本要求试用期至少持续若干天,下面这样的请求就会收到 Stripe 返回的参数错误:

->trialUntil(Carbon::now()->addMinutes(5))

限制来自 Stripe,而不是 Carbon 或 Laravel,也不应该通过修改 Cashier 源码来绕过。如果支付平台不接受这个时间,只修改本地数据库中的 trial_ends_at,也无法让 Stripe 提前扣款。

如何测试 recurring payments 和 webhooks

如果 Stripe 不接受分钟或秒级试用期,可以拆开测试:

  • 在 Stripe 测试模式下创建订阅。
  • 使用支付平台提供的测试功能触发相应的 webhook。
  • 将 webhook 请求发送到本地或测试环境,验证签名、路由及业务处理逻辑。
  • 为订阅状态变化编写自动化测试,直接构造对应的 webhook payload。
  • 如果需要测试完整的试用结束流程,就使用支付平台允许的最短试用时间。

应用内部与试用期有关的判断可以单独测试,不必等待 Stripe 跑完一次完整的计费周期:

$trialEndsAt = Carbon::now()->addMinutes(5);

$this->assertTrue($trialEndsAt->isFuture());

注意事项

不要只更新本地 subscriptions 表中的 trial_ends_at。Cashier 的本地记录必须与 Stripe 的订阅状态保持一致,否则应用可能认为试用已经结束,而 Stripe 仍将订阅视为处于试用期。

分钟或秒级试用期可以通过 trialUntil() 表示,但能否创建成功,取决于当前账户使用的 Stripe API 版本及其试用期限制。

备注:内容仅供参考。