メインコンテンツまでスキップ

Laravel Cashier(Stripe)

はじめに

Laravel Cashier Stripe は、Stripe のサブスクリプション課金サービスに対して表現豊かで流暢なインターフェースを提供します。あなたが書くのをためらっているボイラープレートのサブスクリプション課金コードのほとんどを処理します。基本的なサブスクリプション管理に加えて、Cashier はクーポン、サブスクリプションの切り替え、サブスクリプションの「数量」、キャンセル猶予期間、さらには請求書の PDF の生成さえも処理できます。

Cashier のアップグレード

新しいバージョンの Cashier にアップグレードする際には、アップグレードガイド を注意深く確認することが重要です。

警告

互換性のない変更を防ぐために、Cashier は固定された Stripe API バージョンを使用しています。Cashier 15 は Stripe API バージョン 2023-10-16 を利用しています。新しい Stripe の機能や改善を活用するために、Stripe API バージョンはマイナーリリースで更新されます。

インストール

まず、Composer パッケージマネージャを使用して Stripe のための Cashier パッケージをインストールします:

composer require laravel/cashier

パッケージをインストールした後、vendor:publish Artisan コマンドを使用して Cashier のマイグレーションを公開します:

php artisan vendor:publish --tag="cashier-migrations"

その後、データベースをマイグレーションします:

php artisan migrate

Cashier のマイグレーションは、users テーブルにいくつかの列を追加します。また、すべての顧客のサブスクリプションを保持する subscriptions テーブルと、複数の価格を持つサブスクリプション用の subscription_items テーブルを作成します。

必要であれば、vendor:publish Artisan コマンドを使用して Cashier の設定ファイルを公開することもできます:

php artisan vendor:publish --tag="cashier-config"

最後に、Stripe イベントを適切に処理するために、Cashier のウェブフック処理を設定 することを忘れないでください。

警告

Stripe は、Stripe 識別子を保存するために使用される任意の列は大文字と小文字を区別する必要があると推奨しています。そのため、MySQL を使用する場合は stripe_id 列の列照合を utf8_bin に設定する必要があります。これに関する詳細情報は、Stripe のドキュメント で確認できます。

設定

請求可能なモデル

Cashierを使用する前に、請求可能なモデルの定義にBillableトレイトを追加してください。通常、これはApp\Models\Userモデルになります。このトレイトには、サブスクリプションの作成、クーポンの適用、支払い方法情報の更新など、一般的な請求タスクを実行するためのさまざまなメソッドが提供されています:

    use Laravel\Cashier\Billable;

class User extends Authenticatable
{
use Billable;
}

Cashierは、Laravelに付属するApp\Models\Userクラスが請求可能なモデルであると想定しています。これを変更したい場合は、useCustomerModelメソッドを使用して異なるモデルを指定できます。このメソッドは通常、AppServiceProviderクラスのbootメソッドで呼び出すべきです:

    use App\Models\Cashier\User;
use Laravel\Cashier\Cashier;

/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useCustomerModel(User::class);
}
警告

Laravelの提供するApp\Models\Userモデル以外のモデルを使用している場合は、Cashier migrationsを公開して変更し、代替モデルのテーブル名に一致するようにする必要があります。

APIキー

次に、アプリケーションの.envファイルでStripeのAPIキーを設定する必要があります。StripeのコントロールパネルからStripeのAPIキーを取得できます:

STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
警告

アプリケーションの.envファイルでSTRIPE_WEBHOOK_SECRET環境変数が定義されていることを確認する必要があります。この変数は、着信ウェブフックが実際にStripeからのものであることを確認するために使用されます。

通貨の設定

デフォルトのCashier通貨は米ドル(USD)です。アプリケーションの.envファイル内でCASHIER_CURRENCY環境変数を設定することで、デフォルトの通貨を変更できます:

CASHIER_CURRENCY=eur

Cashierの通貨を設定するだけでなく、請求書上の金額を表示する際に使用されるロケールを指定することもできます。内部的には、CashierはPHPのNumberFormatterクラスを使用して通貨のロケールを設定しています:

CASHIER_CURRENCY_LOCALE=nl_BE
警告

en以外のロケールを使用するには、サーバーにext-intl PHP拡張機能がインストールおよび構成されていることを確認してください。

税金の設定

Stripe Taxのおかげで、Stripeが生成するすべての請求書の税金を自動的に計算することが可能です。App\Providers\AppServiceProviderクラスのbootメソッドでcalculateTaxesメソッドを呼び出すことで、自動税金計算を有効にすることができます:

    use Laravel\Cashier\Cashier;

/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::calculateTaxes();
}

税金の計算が有効になると、新しいサブスクリプションおよび生成される一時的な請求書に自動税金計算が適用されます。

この機能を正しく動作させるためには、顧客の請求先詳細(顧客の名前、住所、税IDなど)をStripeに同期する必要があります。これを達成するために、Cashierが提供する顧客データの同期およびTax IDメソッドを使用できます。

警告

単発請求単発請求チェックアウトには税金が計算されません。

ロギング

Cashierを使用すると、致命的なStripeエラーをロギングする際に使用するログチャネルを指定できます。.envファイル内でCASHIER_LOGGER環境変数を定義することで、ログチャネルを指定できます:

CASHIER_LOGGER=stack

StripeへのAPI呼び出しで生成された例外は、アプリケーションのデフォルトのログチャネルを介してログに記録されます。

カスタムモデルの使用

Cashierでは、内部で使用されるモデルを拡張して、独自のモデルを定義し、対応するCashierモデルを拡張することができます:

    use Laravel\Cashier\Subscription as CashierSubscription;

class Subscription extends CashierSubscription
{
// ...
}

モデルを定義した後、Laravel\Cashier\Cashierクラスを介してCashierにカスタムモデルを使用するように指示できます。通常、カスタムモデルに関する情報は、App\Providers\AppServiceProviderクラスのbootメソッドでCashierに通知する必要があります:

    use App\Models\Cashier\Subscription;
use App\Models\Cashier\SubscriptionItem;

/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useSubscriptionModel(Subscription::class);
Cashier::useSubscriptionItemModel(SubscriptionItem::class);
}

クイックスタート

製品の販売

注記

Stripe Checkoutを利用する前に、Stripeダッシュボードで固定価格の製品を定義する必要があります。さらに、Cashierのウェブフック処理を設定する必要があります。

アプリケーションを介して製品やサブスクリプションの請求を提供することは、初めは難しいかもしれません。しかし、CashierとStripe Checkoutのおかげで、現代的で堅牢な支払い統合を簡単に構築することができます。

非繰り返しの単発製品に対して顧客に料金を請求するために、Cashierを使用して顧客をStripe Checkoutに誘導し、そこで支払い情報を提供し購入を確認します。支払いがCheckout経由で行われると、顧客はアプリケーション内で選択した成功URLにリダイレクトされます:

    use Illuminate\Http\Request;

Route::get('/checkout', function (Request $request) {
$stripePriceId = 'price_deluxe_album';

$quantity = 1;

return $request->user()->checkout([$stripePriceId => $quantity], [
'success_url' => route('checkout-success'),
'cancel_url' => route('checkout-cancel'),
]);
})->name('checkout');

Route::view('/checkout/success', 'checkout.success')->name('checkout-success');
Route::view('/checkout/cancel', 'checkout.cancel')->name('checkout-cancel');

上記の例で示されているように、指定された「価格識別子」に対してCashierが提供するcheckoutメソッドを使用して、顧客をStripe Checkoutに誘導します。Stripeを使用する際、「価格」とは、特定の製品の定義された価格を指します。

必要に応じて、checkoutメソッドは自動的にStripeに顧客を作成し、そのStripe顧客レコードをアプリケーションのデータベース内の対応するユーザーに接続します。チェックアウトセッションを完了した後、顧客は専用の成功またはキャンセルページにリダイレクトされ、そこで顧客に情報メッセージを表示することができます。

Stripe Checkoutへのメタデータの提供

製品を販売する際、独自のアプリケーションで定義されたCartおよびOrderモデルを使用して、完了した注文や購入した製品を追跡することが一般的です。購入を完了するために顧客をStripe Checkoutにリダイレクトする際、完了した購入を対応する注文に関連付けるために既存の注文識別子を提供する必要があるかもしれません。

これを達成するために、checkout メソッドに metadata の配列を提供することができます。ユーザーがチェックアウトプロセスを開始すると、当社のアプリケーション内で保留中の Order が作成されると想像してみましょう。この例では、CartOrder モデルは Cashier によって提供されていないため、自分のアプリケーションのニーズに基づいてこれらの概念を実装することができます:

    use App\Models\Cart;
use App\Models\Order;
use Illuminate\Http\Request;

Route::get('/cart/{cart}/checkout', function (Request $request, Cart $cart) {
$order = Order::create([
'cart_id' => $cart->id,
'price_ids' => $cart->price_ids,
'status' => 'incomplete',
]);

return $request->user()->checkout($order->price_ids, [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
'metadata' => ['order_id' => $order->id],
]);
})->name('checkout');

上記の例でわかるように、ユーザーがチェックアウトプロセスを開始すると、checkout メソッドにカート/注文に関連付けられたすべての Stripe 価格識別子を提供します。もちろん、お客様がそれらを追加するときにこれらのアイテムを「ショッピングカート」または注文に関連付ける責任は、あなたのアプリケーションにあります。また、metadata 配列を介して注文の ID を Stripe Checkout セッションに提供します。最後に、Stripe が顧客をアプリケーションにリダイレクトする際に、Checkout 成功ルートに CHECKOUT_SESSION_ID テンプレート変数を追加しました。Stripe が顧客をアプリケーションにリダイレクトする際に、このテンプレート変数は自動的に Checkout セッション ID で埋められます。

次に、Checkout 成功ルートを構築しましょう。これは、Stripe Checkout を介して購入が完了した後にユーザーがリダイレクトされるルートです。このルート内で、Stripe Checkout セッション ID と関連する Stripe Checkout インスタンスを取得して、提供されたメタデータにアクセスし、顧客の注文を適切に更新することができます:

    use App\Models\Order;
use Illuminate\Http\Request;
use Laravel\Cashier\Cashier;

Route::get('/checkout/success', function (Request $request) {
$sessionId = $request->get('session_id');

if ($sessionId === null) {
return;
}

$session = Cashier::stripe()->checkout->sessions->retrieve($sessionId);

if ($session->payment_status !== 'paid') {
return;
}

$orderId = $session['metadata']['order_id'] ?? null;

$order = Order::findOrFail($orderId);

$order->update(['status' => 'completed']);

return view('checkout-success', ['order' => $order]);
})->name('checkout-success');

Stripe のCheckout セッションオブジェクトに含まれるデータについての詳細は、Stripe のドキュメントを参照してください。

サブスクリプションの販売

注記

Stripe Checkout を利用する前に、Stripe ダッシュボードで固定価格の製品を定義する必要があります。さらに、Cashier のウェブフック処理を設定する必要があります。

アプリケーションを介して製品やサブスクリプションの請求を提供することは、 intimidating かもしれません。しかし、Cashier と Stripe Checkout のおかげで、現代的で堅牢な支払い統合を簡単に構築することができます。

CashierとStripe Checkoutを使用してサブスクリプションを販売する方法を学ぶために、基本的な月間(price_basic_monthly)および年間(price_basic_yearly)プランを持つサブスクリプションサービスのシンプルなシナリオを考えてみましょう。これらの2つの価格は、Stripeダッシュボードの「Basic」製品(pro_basic)の下にグループ化されるかもしれません。さらに、当社のサブスクリプションサービスは、pro_expertとしてExpertプランを提供するかもしれません。

まず、顧客が当社のサービスにサブスクライブする方法を見つけましょう。もちろん、顧客が当社のアプリケーションの価格設定ページでBasicプランの「購読」ボタンをクリックすることを想像することができます。このボタンまたはリンクは、選択したプランに対してStripe Checkoutセッションを作成するLaravelルートにユーザーをリダイレクトする必要があります:

    use Illuminate\Http\Request;

Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_basic_monthly')
->trialDays(5)
->allowPromotionCodes()
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});

上記の例で示されているように、顧客をStripe Checkoutセッションにリダイレクトして、Basicプランにサブスクライブできるようにします。成功したチェックアウトまたはキャンセル後、顧客はcheckoutメソッドに提供したURLにリダイレクトされます。実際にサブスクリプションが開始されたことを知るために(一部の支払い方法は数秒かかる場合があるため)、Cashierのウェブフック処理を構成する必要もあります

顧客がサブスクリプションを開始できるようになったので、特定の部分を制限して、サブスクライブされたユーザーのみがそれらにアクセスできるようにする必要があります。もちろん、CashierのBillableトレイトが提供するsubscribedメソッドを介して、ユーザーの現在のサブスクリプションステータスを常に判断できます:

@if ($user->subscribed())
<p>You are subscribed.</p>
@endif

さらに、ユーザーが特定の製品または価格にサブスクライブしているかどうかを簡単に判断することもできます:

@if ($user->subscribedToProduct('pro_basic'))
<p>You are subscribed to our Basic product.</p>
@endif

@if ($user->subscribedToPrice('price_basic_monthly'))
<p>You are subscribed to our monthly Basic plan.</p>
@endif

サブスクライブされたミドルウェアの構築

便宜上、ミドルウェアを作成して、着信リクエストがサブスクライブされたユーザーからであるかどうかを判断することができます。このミドルウェアが定義されると、ルートに簡単に割り当てて、サブスクライブされていないユーザーがルートにアクセスできないようにすることができます。

    <?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class Subscribed
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): Response
{
if (! $request->user()?->subscribed()) {
// Redirect user to billing page and ask them to subscribe...
return redirect('/billing');
}

return $next($request);
}
}

ミドルウェアが定義されたら、それをルートに割り当てることができます:

    use App\Http\Middleware\Subscribed;

Route::get('/dashboard', function () {
// ...
})->middleware([Subscribed::class]);

顧客が請求プランを管理できるようにする

もちろん、顧客は別の製品や「階層」へのサブスクリプションプランを変更したい場合があります。これを許可する最も簡単な方法は、顧客をStripeのCustomer Billing Portalに案内することです。これは、顧客が請求書をダウンロードしたり、支払い方法を更新したり、サブスクリプションプランを変更したりするためのホストされたユーザーインターフェースを提供します。

まず、アプリケーション内に、ユーザーをLaravelルートにリダイレクトするために使用するリンクまたはボタンを定義します。これを使用して請求ポータルセッションを開始します:

<a href="{{ route('billing') }}">
Billing
</a>

次に、Stripeの顧客請求ポータルセッションを開始し、ユーザーをポータルにリダイレクトするルートを定義しましょう。redirectToBillingPortalメソッドは、ユーザーがポータルを終了して返されるべきURLを受け入れます:

    use Illuminate\Http\Request;

Route::get('/billing', function (Request $request) {
return $request->user()->redirectToBillingPortal(route('dashboard'));
})->middleware(['auth'])->name('billing');
注記

CashierのWebhook処理を構成している限り、CashierはStripeからの着信Webhookを検査して、自動的にアプリケーションのCashier関連のデータベーステーブルを同期させます。たとえば、ユーザーがStripeのCustomer Billing Portalを介してサブスクリプションをキャンセルすると、Cashierは対応するWebhookを受信し、アプリケーションのデータベースでサブスクリプションを「キャンセル済み」としてマークします。

顧客

顧客の取得

Cashier::findBillableメソッドを使用して、Stripe IDで顧客を取得できます。このメソッドは、請求可能なモデルのインスタンスを返します:

    use Laravel\Cashier\Cashier;

$user = Cashier::findBillable($stripeId);

顧客の作成

時々、サブスクリプションを開始せずにStripeの顧客を作成したい場合があります。createAsStripeCustomerメソッドを使用してこれを達成できます:

    $stripeCustomer = $user->createAsStripeCustomer();

Stripeで顧客が作成されたら、後日サブスクリプションを開始することができます。Stripe APIでサポートされている顧客作成パラメータを追加で渡すためにオプションの$options配列を提供することができます:

    $stripeCustomer = $user->createAsStripeCustomer($options);

請求可能なモデルのStripe顧客オブジェクトを返す場合は、asStripeCustomerメソッドを使用できます:

    $stripeCustomer = $user->asStripeCustomer();

与信可能なモデルに対してStripe顧客オブジェクトを取得したい場合は、createOrGetStripeCustomerメソッドを使用できます。ただし、与信可能なモデルがすでにStripeの顧客であるかどうか確認できない場合は、このメソッドは新しい顧客をStripeに作成します:

    $stripeCustomer = $user->createOrGetStripeCustomer();

顧客情報の更新

時折、追加情報を含めてStripe顧客を直接更新したい場合があります。updateStripeCustomerメソッドを使用してこれを行うことができます。このメソッドは、Stripe APIでサポートされている顧客更新オプションの配列を受け入れます:

    $stripeCustomer = $user->updateStripeCustomer($options);

残高

Stripeでは、顧客の「残高」を入金または引き落としすることができます。後でこの残高は新しい請求書で入金または引き落としされます。顧客の総残高を確認するには、与信可能なモデルで利用可能なbalanceメソッドを使用できます。balanceメソッドは、顧客の通貨で残高のフォーマットされた文字列表現を返します:

$balance = $user->balance();

顧客の残高を入金するには、creditBalanceメソッドに値を提供することができます。必要であれば、説明も提供できます:

$user->creditBalance(500, 'プレミアム顧客のトップアップ。');

debitBalanceメソッドに値を提供すると、顧客の残高が引き落とされます:

$user->debitBalance(300, '悪用ペナルティ。');

applyBalanceメソッドは、顧客の新しい残高取引を作成します。これらの取引レコードはbalanceTransactionsメソッドを使用して取得でき、顧客が確認するためのクレジットとデビットのログを提供するのに役立ちます:

    // Retrieve all transactions...
$transactions = $user->balanceTransactions();

foreach ($transactions as $transaction) {
// Transaction amount...
$amount = $transaction->amount(); // $2.31

// Retrieve the related invoice when available...
$invoice = $transaction->invoice();
}

税ID

Cashierは、顧客の税IDを管理する簡単な方法を提供します。たとえば、taxIdsメソッドを使用して、顧客に割り当てられた税IDをコレクションとして取得することができます:

$taxIds = $user->taxIds();

また、顧客の特定の税IDを識別子で取得することもできます:

$taxId = $user->findTaxId('txi_belgium');

有効なtypeと値をcreateTaxIdメソッドに提供することで、新しい税IDを作成できます:

$taxId = $user->createTaxId('eu_vat', 'BE0123456789');

createTaxIdメソッドは、すぐにVAT IDを顧客のアカウントに追加します。VAT IDの検証もStripeによって行われますが、これは非同期プロセスです。customer.tax_id.updatedウェブフックイベントに登録し、VAT IDのverificationパラメータを検査することで、検証の更新を通知できます。Webhookの処理に関する詳細情報については、Webhookハンドラの定義に関するドキュメントを参照してください。

deleteTaxIdメソッドを使用して税IDを削除できます:

$user->deleteTaxId('txi_belgium');

Stripeとの顧客データの同期

通常、アプリケーションのユーザーが名前、メールアドレス、またはStripeにも保存されている他の情報を更新するときは、更新をStripeに通知する必要があります。これにより、Stripeの情報がアプリケーションの情報と同期されます。

これを自動化するために、モデルのupdatedイベントに反応するイベントリスナーを定義し、イベントリスナー内でモデルのsyncStripeCustomerDetailsメソッドを呼び出すことができます:

    use App\Models\User;
use function Illuminate\Events\queueable;

/**
* The "booted" method of the model.
*/
protected static function booted(): void
{
static::updated(queueable(function (User $customer) {
if ($customer->hasStripeId()) {
$customer->syncStripeCustomerDetails();
}
}));
}

これで、顧客モデルが更新されるたびに、その情報がStripeと同期されます。便宜上、Cashierは初めて顧客が作成されるときに自動的に顧客の情報をStripeと同期します。

あなたは、Cashier が提供するさまざまなメソッドをオーバーライドすることで、Stripe に顧客情報を同期するために使用するカラムをカスタマイズすることができます。たとえば、Cashier が顧客情報をStripe に同期する際に「名前」として考慮すべき属性をカスタマイズするために stripeName メソッドをオーバーライドすることができます:

    /**
* Get the customer name that should be synced to Stripe.
*/
public function stripeName(): string|null
{
return $this->company_name;
}

同様に、stripeEmailstripePhonestripeAddressstripePreferredLocales メソッドをオーバーライドすることもできます。これらのメソッドは、Stripe 顧客オブジェクトを更新する際に、それぞれの顧客パラメータに情報を同期します。顧客情報の同期プロセスを完全に制御したい場合は、syncStripeCustomerDetails メソッドをオーバーライドすることができます。

請求ポータル

Stripe は、請求ポータルを簡単に設定する方法を提供しており、お客様がサブスクリプションを管理したり、支払い方法を設定したり、請求履歴を表示したりできるようになります。コントローラやルートから請求ポータルにユーザをリダイレクトするには、請求可能なモデルで redirectToBillingPortal メソッドを呼び出すことができます:

    use Illuminate\Http\Request;

Route::get('/billing-portal', function (Request $request) {
return $request->user()->redirectToBillingPortal();
});

デフォルトでは、ユーザがサブスクリプションを管理を終えると、Stripe 請求ポータル内のリンクを介してアプリケーションの home ルートに戻ることができます。ユーザが戻るべきカスタム URL を提供したい場合は、redirectToBillingPortal メソッドに引数として URL を渡すことができます:

    use Illuminate\Http\Request;

Route::get('/billing-portal', function (Request $request) {
return $request->user()->redirectToBillingPortal(route('billing'));
});

HTTP リダイレクトレスポンスを生成せずに請求ポータルへの URL を生成したい場合は、billingPortalUrl メソッドを呼び出すことができます:

$url = $request->user()->billingPortalUrl(route('billing'));

支払い方法

支払い方法の保存

Stripe を使用してサブスクリプションを作成したり「一回限り」の料金を請求するためには、支払い方法を保存し、その識別子をStripe から取得する必要があります。これを達成するために使用するアプローチは、支払い方法をサブスクリプションまたは単発料金に使用するかによって異なるため、以下でそれぞれを調査します。

サブスクリプションの支払い方法

顧客のクレジットカード情報を将来のサブスクリプションで使用するために保存する場合、Stripeの「Setup Intents」APIを使用して、顧客の支払い方法の詳細を安全に収集する必要があります。 「Setup Intent」は、Stripeに顧客の支払い方法を請求する意図を示します。 Cashierの Billable トレイトには、新しい Setup Intent を簡単に作成する createSetupIntent メソッドが含まれています。このメソッドを呼び出すべきは、顧客の支払い方法の詳細を収集するフォームをレンダリングするルートまたはコントローラです。

return view('update-payment-method', [
'intent' => $user->createSetupIntent()
]);

Setup Intent を作成し、ビューに渡した後は、支払い方法を収集する要素にその秘密を添付する必要があります。たとえば、次の「支払い方法の更新」フォームを考えてみてください:

<input id="card-holder-name" type="text">

<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>

<button id="card-button" data-secret="{{ $intent->client_secret }}">
Update Payment Method
</button>

次に、Stripe.js ライブラリを使用して、フォームに Stripe Element を添付し、顧客の支払い詳細を安全に収集できます:

<script src="https://js.stripe.com/v3/"></script>

<script>
const stripe = Stripe('stripe-public-key');

const elements = stripe.elements();
const cardElement = elements.create('card');

cardElement.mount('#card-element');
</script>

次に、カードを検証し、Stripe を使用して安全な「支払い方法識別子」を取得するために Stripe の confirmCardSetup メソッド を使用できます:

const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;

cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: { name: cardHolderName.value }
}
}
);

if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});

Stripeによってカードが検証された後、結果の setupIntent.payment_method 識別子を Laravel アプリケーションに渡し、顧客に添付することができます。支払い方法は、新しい支払い方法として追加 するか、デフォルトの支払い方法を更新 するために使用できます。また、支払い方法識別子を直ちに使用して 新しいサブスクリプションを作成 することもできます。

注記

Setup Intents および顧客の支払い詳細の収集に関する詳細については、Stripe が提供するこの概要をご覧ください

単一の請求のための支払い方法

もちろん、顧客の支払い方法に対して単一の請求を行う場合、支払い方法の識別子は1回だけ使用する必要があります。Stripeの制限により、顧客の保存されたデフォルトの支払い方法を単一の請求に使用することはできません。顧客には、Stripe.jsライブラリを使用して支払い方法の詳細を入力させる必要があります。たとえば、次のフォームを考えてみてください:

<input id="card-holder-name" type="text">

<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>

<button id="card-button">
Process Payment
</button>

このようなフォームを定義した後、Stripe.jsライブラリを使用してフォームにStripe Elementを添付し、顧客の支払い詳細を安全に収集できます:

<script src="https://js.stripe.com/v3/"></script>

<script>
const stripe = Stripe('stripe-public-key');

const elements = stripe.elements();
const cardElement = elements.create('card');

cardElement.mount('#card-element');
</script>

次に、カードを検証し、Stripeを使用して安全な「支払い方法識別子」を取得するためにStripeのcreatePaymentMethodメソッドを使用できます:

const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');

cardButton.addEventListener('click', async (e) => {
const { paymentMethod, error } = await stripe.createPaymentMethod(
'card', cardElement, {
billing_details: { name: cardHolderName.value }
}
);

if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});

カードが正常に検証された場合、paymentMethod.idをLaravelアプリケーションに渡し、単一の請求を処理できます。

支払い方法の取得

請求可能なモデルインスタンスのpaymentMethodsメソッドは、Laravel\Cashier\PaymentMethodインスタンスのコレクションを返します:

$paymentMethods = $user->paymentMethods();

デフォルトでは、このメソッドはすべてのタイプの支払い方法を返します。特定のタイプの支払い方法を取得するには、メソッドにtypeを引数として渡すことができます:

$paymentMethods = $user->paymentMethods('sepa_debit');

顧客のデフォルトの支払い方法を取得するには、defaultPaymentMethodメソッドを使用できます:

$paymentMethod = $user->defaultPaymentMethod();

findPaymentMethodメソッドを使用して、請求可能なモデルにアタッチされた特定の支払い方法を取得できます:

$paymentMethod = $user->findPaymentMethod($paymentMethodId);

支払い方法の存在

請求可能なモデルにデフォルトの支払い方法がアタッチされているかどうかを判断するには、hasDefaultPaymentMethodメソッドを呼び出します。

if ($user->hasDefaultPaymentMethod()) {
// ...
}

hasPaymentMethodメソッドを使用して、請求可能なモデルに少なくとも1つの支払い方法がアカウントにアタッチされているかどうかを判断できます:

if ($user->hasPaymentMethod()) {
// ...
}

このメソッドは、請求可能なモデルがどの支払い方法を持っているかを判断します。モデルの特定のタイプの支払い方法が存在するかどうかを判断するには、メソッドにtypeを引数として渡すことができます:

if ($user->hasPaymentMethod('sepa_debit')) {
// ...
}

デフォルト支払い方法の更新

updateDefaultPaymentMethodメソッドを使用して、顧客のデフォルト支払い方法情報を更新できます。このメソッドはStripe支払い方法識別子を受け入れ、新しい支払い方法をデフォルトの請求支払い方法として割り当てます:

$user->updateDefaultPaymentMethod($paymentMethod);

顧客のデフォルト支払い方法情報をStripeのデフォルト支払い方法情報と同期させるには、updateDefaultPaymentMethodFromStripeメソッドを使用できます:

$user->updateDefaultPaymentMethodFromStripe();
警告

顧客のデフォルト支払い方法は、請求書の作成と新しいサブスクリプションの作成にのみ使用できます。Stripeによって課せられた制限のため、単発の請求には使用できません。

支払い方法の追加

新しい支払い方法を追加するには、支払い方法識別子を渡して、請求可能なモデルでaddPaymentMethodメソッドを呼び出すことができます:

$user->addPaymentMethod($paymentMethod);
注記

支払い方法識別子の取得方法については、支払い方法の保存に関するドキュメントを参照してください。

支払い方法の削除

支払い方法を削除するには、削除したいLaravel\Cashier\PaymentMethodインスタンスでdeleteメソッドを呼び出すことができます:

$paymentMethod->delete();

deletePaymentMethodメソッドは、請求可能なモデルから特定の支払い方法を削除します。```

    $user->deletePaymentMethod('pm_visa');

`deletePaymentMethods` メソッドは、請求可能なモデルの支払い方法情報をすべて削除します:

$user->deletePaymentMethods();

デフォルトでは、このメソッドはすべてのタイプの支払い方法を削除します。特定のタイプの支払い方法を削除するには、メソッドに `type` を引数として渡すことができます:

$user->deletePaymentMethods('sepa_debit');

:::warning
ユーザーがアクティブなサブスクリプションを持っている場合、アプリケーションはデフォルトの支払い方法を削除することを許可すべきではありません。
:::

<a name="subscriptions"></a>
## サブスクリプション

サブスクリプションは、お客様の定期支払いを設定する方法を提供します。Cashier によって管理される Stripe サブスクリプションは、複数のサブスクリプション価格、サブスクリプション数量、トライアルなどをサポートします。

<a name="creating-subscriptions"></a>
### サブスクリプションの作成

サブスクリプションを作成するには、まず請求可能なモデルのインスタンスを取得します。通常、これは `App\Models\User` のインスタンスになります。モデルインスタンスを取得したら、`newSubscription` メソッドを使用してモデルのサブスクリプションを作成できます:

```php
use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription(
'default', 'price_monthly'
)->create($request->paymentMethodId);

// ...
});

newSubscription メソッドに渡す最初の引数は、サブスクリプションの内部タイプである必要があります。アプリケーションが単一のサブスクリプションのみを提供する場合、これを default または primary と呼ぶかもしれません。このサブスクリプションタイプは、内部アプリケーション使用のみであり、ユーザーに表示されるものではありません。さらに、スペースを含めず、サブスクリプション作成後に変更されるべきではありません。2番目の引数は、ユーザーが購読する特定の価格です。この値は、Stripe での価格の識別子に対応する必要があります。

create メソッドは、Stripe の支払い方法識別子 または Stripe の PaymentMethod オブジェクトを受け入れ、サブスクリプションを開始し、請求可能なモデルの Stripe カスタマー ID およびその他の関連する請求情報を更新します。

警告

create サブスクリプションメソッドに直接支払い方法識別子を渡すと、ユーザーの保存された支払い方法に自動的に追加されます。


#### インボイスメールを通じた定期支払いの集金

顧客の定期支払いを自動的に集める代わりに、Stripeに指示して、顧客が定期支払いが支払期日になるたびにインボイスをメールで送信するようにすることができます。その後、顧客はインボイスを受け取ったら手動で支払うことができます。顧客は、定期支払いをインボイス経由で集める際に最初に支払い方法を提供する必要はありません:

$user->newSubscription('default', 'price_monthly')->createAndSendInvoice();

顧客がサブスクリプションをキャンセルされる前にインボイスを支払うための期間は、`days_until_due`オプションによって決定されます。デフォルトでは、これは30日ですが、必要に応じてこのオプションに特定の値を指定することができます:

$user->newSubscription('default', 'price_monthly')->createAndSendInvoice([], [
'days_until_due' => 30
]);

#### 量

サブスクリプションを作成する際に価格に特定の[数量](https://stripe.com/docs/billing/subscriptions/quantities)を設定したい場合は、サブスクリプションビルダーでサブスクリプションを作成する前に`quantity`メソッドを呼び出す必要があります:

$user->newSubscription('default', 'price_monthly')
->quantity(5)
->create($paymentMethod);

#### 追加の詳細

Stripeでサポートされている追加の[顧客](https://stripe.com/docs/api/customers/create)または[サブスクリプション](https://stripe.com/docs/api/subscriptions/create)オプションを指定したい場合は、これらを`create`メソッドの2番目と3番目の引数として渡すことで行うことができます:

$user->newSubscription('default', 'price_monthly')->create($paymentMethod, [
'email' => $email,
], [
'metadata' => ['note' => '追加情報です。'],
]);

#### クーポン

サブスクリプションを作成する際にクーポンを適用したい場合は、`withCoupon`メソッドを使用できます:

$user->newSubscription('default', 'price_monthly')
->withCoupon('code')
->create($paymentMethod);

または、[Stripeプロモーションコード](https://stripe.com/docs/billing/subscriptions/discounts/codes)を適用したい場合は、`withPromotionCode`メソッドを使用することができます:

$user->newSubscription('default', 'price_monthly')
->withPromotionCode('promo_code_id')
->create($paymentMethod);

与えられたプロモーションコードIDは、顧客向けのプロモーションコードではなく、Stripe API IDである必要があります。指定された顧客向けプロモーションコードに基づいてプロモーションコードIDを見つける必要がある場合は、`findPromotionCode`メソッドを使用できます:

// 顧客向けコードによるプロモーションコードIDの検索...
$promotionCode = $user->findPromotionCode('SUMMERSALE');

// 顧客向けコードによるアクティブなプロモーションコードIDの検索...
$promotionCode = $user->findActivePromotionCode('SUMMERSALE');

上記の例では、返される`$promotionCode`オブジェクトは`Laravel\Cashier\PromotionCode`のインスタンスです。このクラスは基礎となる`Stripe\PromotionCode`オブジェクトをデコレートします。プロモーションコードに関連するクーポンを取得するには、`coupon`メソッドを呼び出します:

$coupon = $user->findPromotionCode('SUMMERSALE')->coupon();

クーポンインスタンスを使用して、割引額やクーポンが固定割引かパーセンテージベースの割引かを判断できます:

```php
if ($coupon->isPercentage()) {
return $coupon->percentOff().'%'; // 21.5%
} else {
return $coupon->amountOff(); // $5.99
}

また、顧客やサブスクリプションに現在適用されている割引を取得することもできます:

$discount = $billable->discount();

$discount = $subscription->discount();

返されるLaravel\Cashier\Discountインスタンスは、基礎となるStripe\Discountオブジェクトインスタンスをデコレートします。この割引に関連するクーポンを取得するには、couponメソッドを呼び出します:

$coupon = $subscription->discount()->coupon();

顧客やサブスクリプションに新しいクーポンやプロモーションコードを適用したい場合は、applyCouponメソッドまたはapplyPromotionCodeメソッドを使用できます:

$billable->applyCoupon('coupon_id'); $billable->applyPromotionCode('promotion_code_id');

$subscription->applyCoupon('coupon_id'); $subscription->applyPromotionCode('promotion_code_id');

Stripe API ID が割り当てられたプロモーションコードを使用し、顧客向けのプロモーションコードを使用しないでください。顧客またはサブスクリプションには、一度に1つのクーポンまたはプロモーションコードのみ適用できます。

この件に関する詳細情報については、クーポン および プロモーションコード に関する Stripe ドキュメントを参照してください。

サブスクリプションの追加

既にデフォルトの支払い方法を持つ顧客にサブスクリプションを追加したい場合は、サブスクリプションビルダーで add メソッドを呼び出すことができます:

use App\Models\User;

$user = User::find(1);

$user->newSubscription('default', 'price_monthly')->add();

Stripe ダッシュボードからのサブスクリプションの作成

Stripe ダッシュボードからもサブスクリプションを作成することができます。この場合、Cashier は新しく追加されたサブスクリプションを同期し、default のタイプを割り当てます。ダッシュボードで作成されたサブスクリプションに割り当てられるサブスクリプションタイプをカスタマイズするには、webhook イベントハンドラを定義してください。

さらに、Stripe ダッシュボードを介して1つのタイプのサブスクリプションのみを作成できます。アプリケーションが異なるタイプを使用する複数のサブスクリプションを提供する場合、Stripe ダッシュボードを介して追加できるのは1つのサブスクリプションのみです。

最後に、アプリケーションが提供するサブスクリプションのタイプごとにアクティブなサブスクリプションを1つだけ追加するように常に注意してください。顧客が2つの default サブスクリプションを持っている場合、Cashier は両方がアプリケーションのデータベースと同期されているにもかかわらず、最も最近追加されたサブスクリプションのみが使用されます。

サブスクリプションの状態を確認する

顧客がアプリケーションに登録されている場合、さまざまな便利なメソッドを使用して簡単にサブスクリプションの状態を確認できます。まず、subscribed メソッドは、顧客がアクティブなサブスクリプションを持っている場合に true を返します。サブスクリプションが現在トライアル期間内であっても、subscribed メソッドはそのサブスクリプションのタイプを最初の引数として受け入れます:

    if ($user->subscribed('default')) {
// ...
}

subscribed メソッドは、ユーザーの購読状態に基づいてルートやコントローラへのアクセスをフィルタリングするための ルートミドルウェア としても適しています:

    <?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserIsSubscribed
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->user() && ! $request->user()->subscribed('default')) {
// This user is not a paying customer...
return redirect('billing');
}

return $next($request);
}
}

ユーザーがトライアル期間内かどうかを判断したい場合は、onTrial メソッドを使用できます。このメソッドは、ユーザーに対してまだトライアル期間中であることを警告する必要があるかどうかを判断するのに役立ちます:

if ($user->subscription('default')->onTrial())

subscribedToProduct メソッドは、与えられた Stripe 製品の識別子に基づいてユーザーが指定された製品に購読しているかどうかを判断するために使用できます。Stripe では、製品は価格のコレクションです。この例では、ユーザーの default サブスクリプションがアプリケーションの "premium" 製品にアクティブに購読されているかどうかを判断します。与えられた Stripe 製品識別子は、Stripe ダッシュボード内の製品識別子の1つに対応する必要があります:

if ($user->subscribedToProduct('prod_premium', 'default'))

subscribedToProduct メソッドに配列を渡すことで、ユーザーの default サブスクリプションがアプリケーションの "basic" または "premium" 製品にアクティブに購読されているかどうかを判断できます:

if ($user->subscribedToProduct(['prod_basic', 'prod_premium'], 'default'))

subscribedToPrice メソッドは、顧客のサブスクリプションが特定の価格 ID に対応しているかどうかを判断するために使用できます:

if ($user->subscribedToPrice('price_basic_monthly', 'default'))

recurring メソッドは、ユーザーが現在購読しており、トライアル期間内でないかどうかを判断するために使用できます:

if ($user->subscription('default')->recurring())

警告

ユーザーが同じタイプの2つのサブスクリプションを持っている場合、subscription メソッドによって常に最新のサブスクリプションが返されます。たとえば、ユーザーが default タイプの2つのサブスクリプションレコードを持っているかもしれませんが、そのうち1つは古い期限切れのサブスクリプションであり、もう1つは現在の有効なサブスクリプションです。最新のサブスクリプションが常に返され、古いサブスクリプションはデータベースに保持されて履歴的に確認されます。

キャンセルされたサブスクリプションのステータス

ユーザーが以前にアクティブなサブスクライバーであったが、サブスクリプションをキャンセルしたかどうかを判断するには、canceled メソッドを使用できます:

if ($user->subscription('default')->canceled())

ユーザーがサブスクリプションをキャンセルしたが、サブスクリプションが完全に期限切れになるまで "猶予期間" にあるかどうかも判断できます。たとえば、ユーザーが3月5日にサブスクリプションをキャンセルし、元々3月10日に期限切れになる予定だった場合、ユーザーは3月10日まで "猶予期間" にあります。この期間中に subscribed メソッドは引き続き true を返します:

if ($user->subscription('default')->onGracePeriod())

ユーザーがサブスクリプションをキャンセルし、かつ "猶予期間" の中にいないかどうかを判断するには、ended メソッドを使用できます:

if ($user->subscription('default')->ended())

不完全および期限切れのステータス

サブスクリプションが作成後に二次的な支払いアクションが必要な場合、サブスクリプションは incomplete とマークされます。サブスクリプションのステータスは Cashier の subscriptions データベーステーブルの stripe_status 列に保存されます。

同様に、価格の交換時に二次的な支払いアクションが必要な場合、サブスクリプションは past_due とマークされます。これらの状態のいずれかにある場合、顧客が支払いを確認するまでサブスクリプションはアクティブになりません。サブスクリプションに不完全な支払いがあるかどうかを判断するには、請求可能なモデルまたはサブスクリプションインスタンスの hasIncompletePayment メソッドを使用できます:

if ($user->hasIncompletePayment('default'))

if ($user->subscription('default')->hasIncompletePayment())

サブスクリプションに不完全な支払いがある場合、ユーザーを Cashier の支払い確認ページに案内し、latestPayment 識別子を渡す必要があります。この識別子を取得するには、サブスクリプションインスタンスで利用可能な latestPayment メソッドを使用できます:

<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
Please confirm your payment.
</a>

past_dueまたはincompleteの状態にあるままでサブスクリプションを有効なままにしたい場合は、Cashierが提供するkeepPastDueSubscriptionsActiveおよびkeepIncompleteSubscriptionsActiveメソッドを使用できます。通常、これらのメソッドは、App\Providers\AppServiceProviderregisterメソッド内で呼び出す必要があります。

    use Laravel\Cashier\Cashier;

/**
* Register any application services.
*/
public function register(): void
{
Cashier::keepPastDueSubscriptionsActive();
Cashier::keepIncompleteSubscriptionsActive();
}
警告

サブスクリプションがincompleteの状態にある場合、支払いが確認されるまで変更できません。したがって、サブスクリプションがincompleteの状態にある場合、swapおよびupdateQuantityメソッドは例外をスローします。

サブスクリプションスコープ

ほとんどのサブスクリプションの状態は、クエリスコープとしても利用可能です。これにより、特定の状態にあるサブスクリプションを簡単にデータベースからクエリできます。

// すべての有効なサブスクリプションを取得... $subscriptions = Subscription::query()->active()->get();

// ユーザーのキャンセルされたサブスクリプションをすべて取得... $subscriptions = $user->subscriptions()->canceled()->get();

利用可能なスコープの完全なリストは以下にあります。

Subscription::query()->active(); Subscription::query()->canceled(); Subscription::query()->ended(); Subscription::query()->incomplete(); Subscription::query()->notCanceled(); Subscription::query()->notOnGracePeriod(); Subscription::query()->notOnTrial(); Subscription::query()->onGracePeriod(); Subscription::query()->onTrial(); Subscription::query()->pastDue(); Subscription::query()->recurring();

価格の変更

顧客がアプリケーションに登録した後、時折新しいサブスクリプション価格に変更したい場合があります。顧客を新しい価格に変更するには、Stripeの価格識別子をswapメソッドに渡します。価格を交換する際は、ユーザーが以前にキャンセルした場合にサブスクリプションを再度有効にしたいと想定されます。指定された価格識別子は、Stripeダッシュボードで利用可能なStripe価格識別子に対応している必要があります。```

    use App\Models\User;

$user = App\Models\User::find(1);

$user->subscription('default')->swap('price_yearly');

顧客がトライアル中の場合、トライアル期間は維持されます。さらに、サブスクリプションに「数量」がある場合、その数量も維持されます。

価格を交換し、顧客が現在トライアル中の場合はトライアル期間をキャンセルしたい場合は、`skipTrial`メソッドを呼び出すことができます:

$user->subscription('default')
->skipTrial()
->swap('price_yearly');

価格を交換し、顧客が次の請求サイクルを待つのではなく、すぐに請求書を発行したい場合は、`swapAndInvoice`メソッドを使用できます:

$user = User::find(1);

$user->subscription('default')->swapAndInvoice('price_yearly');

<a name="prorations"></a>
#### プロレーション

デフォルトでは、Stripeは価格の交換時に料金をプロレートします。料金をプロレートせずにサブスクリプションの価格を更新するには、`noProrate`メソッドを使用できます:

$user->subscription('default')->noProrate()->swap('price_yearly');

サブスクリプションのプロレーションに関する詳細は、[Stripeのドキュメント](https://stripe.com/docs/billing/subscriptions/prorations)を参照してください。

:::warning
`swapAndInvoice`メソッドの前に`noProrate`メソッドを実行すると、プロレーションには影響しません。請求書は常に発行されます。
:::

<a name="subscription-quantity"></a>
### サブスクリプション数量

時々、サブスクリプションは「数量」に影響を受けます。例えば、プロジェクト管理アプリケーションはプロジェクトごとに月額$10を請求するかもしれません。サブスクリプション数量を簡単に増減させるには、`incrementQuantity`および`decrementQuantity`メソッドを使用できます:

use App\Models\User;

$user = User::find(1);

$user->subscription('default')->incrementQuantity();

// サブスクリプションの現在の数量に5を追加...
$user->subscription('default')->incrementQuantity(5);

$user->subscription('default')->decrementQuantity();

// サブスクリプションの現在の数量から5を減算...
$user->subscription('default')->decrementQuantity(5);

代わりに、updateQuantity メソッドを使用して特定の数量を設定することもできます:

$user->subscription('default')->updateQuantity(10);

noProrate メソッドを使用して、料金を分割せずにサブスクリプションの数量を更新することができます:

$user->subscription('default')->noProrate()->updateQuantity(10);

サブスクリプションの数量に関する詳細は、Stripe のドキュメントを参照してください。

複数の製品を持つサブスクリプションの数量

サブスクリプションが複数の製品を持つサブスクリプションである場合、増減させたい数量の価格の ID を incrementQuantity / decrementQuantity メソッドの第二引数として渡す必要があります:

$user->subscription('default')->incrementQuantity(1, 'price_chat');

複数の製品を持つサブスクリプション

複数の製品を持つサブスクリプションでは、複数の課金製品を単一のサブスクリプションに割り当てることができます。例えば、月額 $10 の基本サブスクリプション価格を持ち、追加で月額 $15 のライブチャットアドオン製品を提供するカスタマーサービスの「ヘルプデスク」アプリケーションを構築しているとします。複数の製品を持つサブスクリプションの情報は、Cashier の subscription_items データベーステーブルに保存されます。

newSubscription メソッドの第二引数として価格の配列を渡すことで、特定のサブスクリプションに複数の製品を指定できます:

    use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default', [
'price_monthly',
'price_chat',
])->create($request->paymentMethodId);

// ...
});

上記の例では、顧客は default サブスクリプションに 2 つの価格が紐付けられます。両方の価格はそれぞれの課金間隔で請求されます。必要に応じて、各価格に特定の数量を示すために quantity メソッドを使用できます:

$user = User::find(1);

$user->newSubscription('default', ['price_monthly', 'price_chat']) ->quantity(5, 'price_chat') ->create($paymentMethod);

既存のサブスクリプションに別の価格を追加したい場合は、サブスクリプションの addPrice メソッドを呼び出すことができます:

$user = User::find(1);

$user->subscription('default')->addPrice('price_chat');

上記の例では、新しい価格が追加され、次回の請求サイクルで顧客に請求されます。顧客にすぐに請求したい場合は、addPriceAndInvoice メソッドを使用できます:

$user->subscription('default')->addPriceAndInvoice('price_chat');

特定の数量で価格を追加したい場合は、addPrice または addPriceAndInvoice メソッドの第二引数として数量を渡すことができます:

$user = User::find(1);

$user->subscription('default')->addPrice('price_chat', 5);

removePrice メソッドを使用して、サブスクリプションから価格を削除することができます:

$user->subscription('default')->removePrice('price_chat');

警告

サブスクリプションから最後の価格を削除することはできません。代わりに、単純にサブスクリプションをキャンセルする必要があります。

価格の交換

複数の製品が含まれるサブスクリプションに関連付けられた価格を変更することもできます。たとえば、顧客が price_basic サブスクリプションと price_chat アドオン製品を持っているとし、顧客を price_basic から price_pro にアップグレードしたい場合:

use App\Models\User;

$user = User::find(1);

$user->subscription('default')->swap(['price_pro', 'price_chat']);

上記の例を実行すると、price_basic を持つ基礎となるサブスクリプションアイテムが削除され、price_chat を持つものが保持されます。さらに、price_pro の新しいサブスクリプションアイテムが作成されます。

swap メソッドにキー/値のペアの配列を渡すことで、サブスクリプションアイテムのオプションを指定することもできます。たとえば、サブスクリプション価格の数量を指定する必要がある場合があります:

$user = User::find(1);

$user->subscription('default')->swap([ 'price_pro' => ['quantity' => 5], 'price_chat' ]);

サブスクリプションで単一の価格を交換したい場合は、サブスクリプションアイテム自体の swap メソッドを使用して行うことができます。このアプローチは、他の価格のメタデータをすべて保持したい場合に特に便利です:

<a name="proration"></a>
#### プロレーション

デフォルトでは、Stripe は複数の製品を持つサブスクリプションに価格を追加または削除する際に料金をプロレートします。プロレーションなしで価格調整を行いたい場合は、価格操作に `noProrate` メソッドをチェーンしてください:

$user->subscription('default')->noProrate()->removePrice('price_chat');

<a name="swapping-quantities"></a>
####

個々のサブスクリプション価格の数量を更新したい場合は、[既存の数量メソッド](#subscription-quantity) を使用して、メソッドに価格の ID を追加引数として渡すことで行うことができます:

$user = User::find(1);

$user->subscription('default')->incrementQuantity(5, 'price_chat');

$user->subscription('default')->decrementQuantity(3, 'price_chat');

$user->subscription('default')->updateQuantity(10, 'price_chat');

:::warning
サブスクリプションに複数の価格がある場合、`Subscription` モデルの `stripe_price` および `quantity` 属性は `null` になります。個々の価格属性にアクセスするには、`Subscription` モデルで利用可能な `items` リレーションシップを使用する必要があります。
:::

<a name="subscription-items"></a>
#### サブスクリプションアイテム

サブスクリプションに複数の価格がある場合、データベースの `subscription_items` テーブルに複数のサブスクリプション "アイテム" が保存されます。これらには、サブスクリプションの `items` リレーションシップを介してアクセスできます:

use App\Models\User;

$user = User::find(1);

$subscriptionItem = $user->subscription('default')->items->first();

// 特定のアイテムの Stripe 価格と数量を取得する...
$stripePrice = $subscriptionItem->stripe_price;
$quantity = $subscriptionItem->quantity;

`findItemOrFail` メソッドを使用して特定の価格を取得することもできます:

$user = User::find(1);

$subscriptionItem = $user->subscription('default')->findItemOrFail('price_chat');

<a name="multiple-subscriptions"></a>
### 複数のサブスクリプション

Stripeはお客様が複数のサブスクリプションを同時に持つことを可能にします。たとえば、水泳のサブスクリプションとウエイトリフティングのサブスクリプションを提供するジムを運営している場合、それぞれのサブスクリプションには異なる価格が設定されているかもしれません。もちろん、お客様はどちらかまたは両方のプランに加入できるはずです。

アプリケーションがサブスクリプションを作成する際には、newSubscription メソッドにサブスクリプションの種類を指定できます。種類は、ユーザーが開始するサブスクリプションの種類を表す任意の文字列である可能性があります:

    use Illuminate\Http\Request;

Route::post('/swimming/subscribe', function (Request $request) {
$request->user()->newSubscription('swimming')
->price('price_swimming_monthly')
->create($request->paymentMethodId);

// ...
});

この例では、お客様のために月間の水泳サブスクリプションを開始しました。ただし、後で年間サブスクリプションに切り替えたい場合があります。お客様のサブスクリプションを調整する際には、単純にswimming サブスクリプションの価格を切り替えることができます:

$user->subscription('swimming')->swap('price_swimming_yearly');

もちろん、サブスクリプションを完全にキャンセルすることもできます:

$user->subscription('swimming')->cancel();

メーター課金

メーター課金 では、請求サイクル中の製品利用に基づいて顧客に料金を請求できます。たとえば、顧客に対して月ごとに送信するテキストメッセージやメールの数に基づいて料金を請求することができます。

メーター課金を開始するには、まずStripeダッシュボードでメーター価格を持つ新しい製品を作成する必要があります。その後、meteredPrice を使用して、顧客のサブスクリプションにメーター価格IDを追加します:

    use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default')
->meteredPrice('price_metered')
->create($request->paymentMethodId);

// ...
});
``

You may also start a metered subscription via [Stripe Checkout](#checkout):

```php
$checkout = Auth::user()
->newSubscription('default', [])
->meteredPrice('price_metered')
->checkout();

return view('your-checkout-view', [
'checkout' => $checkout,
]);

<a name="reporting-usage"></a>
#### Reporting Usage

As your customer uses your application, you will report their usage to Stripe so that they can be billed accurately. To increment the usage of a metered subscription, you may use the `reportUsage` method:

```php
$user = User::find(1);

$user->subscription('default')->reportUsage();

By default, a "usage quantity" of 1 is added to the billing period. Alternatively, you may pass a specific amount of "usage" to add to the customer's usage for the billing period:

```php
$user = User::find(1);

$user->subscription('default')->reportUsage(15);

If your application offers multiple prices on a single subscription, you will need to use the `reportUsageFor` method to specify the metered price you want to report usage for:

```php
$user = User::find(1);

$user->subscription('default')->reportUsageFor('price_metered', 15);

Sometimes, you may need to update usage which you have previously reported. To accomplish this, you may pass a timestamp or a `DateTimeInterface` instance as the second parameter to `reportUsage`. When doing so, Stripe will update the usage that was reported at that given time. You can continue to update previous usage records as the given date and time is still within the current billing period:

```php
$user = User::find(1);

$user->subscription('default')->reportUsage(5, $timestamp);

<a name="retrieving-usage-records"></a>
#### Retrieving Usage Records

To retrieve a customer's past usage, you may use a subscription instance's `usageRecords` method:

```php
$user = User::find(1);

$usageRecords = $user->subscription('default')->usageRecords();

If your application offers multiple prices on a single subscription, you may use the `usageRecordsFor` method to specify the metered price that you wish to retrieve usage records for:

```php
$user = User::find(1);

$usageRecords = $user->subscription('default')->usageRecordsFor('price_metered');

The `usageRecords` and `usageRecordsFor` methods return a Collection instance containing an associative array of usage records. You may iterate over this array to display a customer's total usage:

```php
@foreach ($usageRecords as $usageRecord)
- Period Starting: {{ $usageRecord['period']['start'] }}
- Period Ending: {{ $usageRecord['period']['end'] }}
- Total Usage: {{ $usageRecord['total_usage'] }}
@endforeach

For a full reference of all usage data returned and how to use Stripe's cursor based pagination, please consult [the official Stripe API documentation](https://stripe.com/docs/api/usage_records/subscription_item_summary_list).

<a name="subscription-taxes"></a>
### Subscription Taxes

:::warning
Instead of calculating Tax Rates manually, you can [automatically calculate taxes using Stripe Tax](#tax-configuration)
:::

To specify the tax rates a user pays on a subscription, you should implement the `taxRates` method on your billable model and return an array containing the Stripe tax rate IDs. You can define these tax rates in [your Stripe dashboard](https://dashboard.stripe.com/test/tax-rates):

```php
/**
* The tax rates that should apply to the customer's subscriptions.
*
* @return array<int, string>
*/
public function taxRates(): array
{
return ['txr_id'];
}

The `taxRates` method enables you to apply a tax rate on a customer-by-customer basis, which may be helpful for a user base that spans multiple countries and tax rates.

If you're offering subscriptions with multiple products, you may define different tax rates for each price by implementing a `priceTaxRates` method on your billable model:

```php
/**
* The tax rates that should apply to the customer's subscriptions.
*
* @return array<string, array<int, string>>
*/
public function priceTaxRates(): array
{
return [
'price_monthly' => ['txr_id'],
];
}

:::warning
The `taxRates` method only applies to subscription charges. If you use Cashier to make "one-off" charges, you will need to manually specify the tax rate at that time.
:::

<a name="syncing-tax-rates"></a>
#### Syncing Tax Rates

When changing the hard-coded tax rate IDs returned by the `taxRates` method, the tax settings on any existing subscriptions for the user will remain the same. If you wish to update the tax value for existing subscriptions with the new `taxRates` values, you should call the `syncTaxRates` method on the user's subscription instance:

```php
$user->subscription('default')->syncTaxRates();

This will also sync any item tax rates for a subscription with multiple products. If your application is offering subscriptions with multiple products, you should ensure that your billable model implements the `priceTaxRates` method [discussed above](#subscription-taxes).

<a name="tax-exemption"></a>
#### Tax Exemption

Cashier also offers the `isNotTaxExempt`, `isTaxExempt`, and `reverseChargeApplies` methods to determine if the customer is tax exempt. These methods will call the Stripe API to determine a customer's tax exemption status:

```php
use App\Models\User;

$user = User::find(1);

$user->isTaxExempt();
$user->isNotTaxExempt();
$user->reverseChargeApplies();

:::warning
These methods are also available on any `Laravel\Cashier\Invoice` object. However, when invoked on an `Invoice` object, the methods will determine the exemption status at the time the invoice was created.
:::

<a name="subscription-anchor-date"></a>
### Subscription Anchor Date

By default, the billing cycle anchor is the date the subscription was created or, if a trial period is used, the date that the trial ends. If you would like to modify the billing anchor date, you may use the `anchorBillingCycleOn` method:

```php
use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
$anchor = Carbon::parse('first day of next month');

$request->user()->newSubscription('default', 'price_monthly')
->anchorBillingCycleOn($anchor->startOfDay())
->create($request->paymentMethodId);

// ...
});

For more information on managing subscription billing cycles, consult the [Stripe billing cycle documentation](https://stripe.com/docs/billing/subscriptions/billing-cycle)

<a name="cancelling-subscriptions"></a>
### Cancelling Subscriptions

To cancel a subscription, call the `cancel` method on the user's subscription:

```php
$user->subscription('default')->cancel();

When a subscription is canceled, Cashier will automatically set the `ends_at` column in your `subscriptions` database table. This column is used to know when the `subscribed` method should begin returning `false`.

For example, if a customer cancels a subscription on March 1st, but the subscription was not scheduled to end until March 5th, the `subscribed` method will continue to return `true` until March 5th. This is done because a user is typically allowed to continue using an application until the end of their billing cycle.

You may determine if a user has canceled their subscription but are still on their "grace period" using the `onGracePeriod` method:

```php
if ($user->subscription('default')->onGracePeriod()) {
// ...
}

If you wish to cancel a subscription immediately, call the `cancelNow` method on the user's subscription:

```php
$user->subscription('default')->cancelNow();

If you wish to cancel a subscription immediately and invoice any remaining un-invoiced metered usage or new / pending proration invoice items, call the `cancelNowAndInvoice` method on the user's subscription:

```php
$user->subscription('default')->cancelNowAndInvoice();

You may also choose to cancel the subscription at a specific moment in time:

```php
$user->subscription('default')->cancelAt(
now()->addDays(10)
);

Finally, you should always cancel user subscriptions before deleting the associated user model:

```php
$user->subscription('default')->cancelNow();

$user->delete();

<a name="resuming-subscriptions"></a>
### Resuming Subscriptions

If a customer has canceled their subscription and you wish to resume it, you may invoke the `resume` method on the subscription. The customer must still be within their "grace period" in order to resume a subscription:

```php
$user->subscription('default')->resume();

If the customer cancels a subscription and then resumes that subscription before the subscription has fully expired the customer will not be billed immediately. Instead, their subscription will be re-activated and they will be billed on the original billing cycle.

<a name="subscription-trials"></a>
## Subscription Trials

<a name="with-payment-method-up-front"></a>
### With Payment Method Up Front

If you would like to offer trial periods to your customers while still collecting payment method information up front, you should use the `trialDays` method when creating your subscriptions:

```php
use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default', 'price_monthly')
->trialDays(10)
->create($request->paymentMethodId);

// ...
});

This method will set the trial period ending date on the subscription record within the database and instruct Stripe to not begin billing the customer until after this date. When using the `trialDays` method, Cashier will overwrite any default trial period configured for the price in Stripe.

:::warning
If the customer's subscription is not canceled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date.
:::

The `trialUntil` method allows you to provide a `DateTime` instance that specifies when the trial period should end:

```php
use Carbon\Carbon;

$user->newSubscription('default', 'price_monthly')
->trialUntil(Carbon::now()->addDays(10))
->create($paymentMethod);

You may determine if a user is within their trial period using either the `onTrial` method of the user instance or the `onTrial` method of the subscription instance. The two examples below are equivalent:

```php
if ($user->onTrial('default')) {
// ...
}

if ($user->subscription('default')->onTrial()) {
// ...
}

You may use the `endTrial` method to immediately end a subscription trial:

```php
$user->subscription('default')->endTrial();

To determine if an existing trial has expired, you may use the `hasExpiredTrial` methods:

```php
if ($user->hasExpiredTrial('default')) {
// ...
}

if ($user->subscription('default')->hasExpiredTrial()) {
// ...
}

<a name="defining-trial-days-in-stripe-cashier"></a>
#### Defining Trial Days in Stripe / Cashier

You may choose to define how many trial days your price's receive in the Stripe dashboard or always pass them explicitly using Cashier. If you choose to define your price's trial days in Stripe you should be aware that new subscriptions, including new subscriptions for a customer that had a subscription in the past, will always receive a trial period unless you explicitly call the `skipTrial()` method.

<a name="without-payment-method-up-front"></a>
### Without Payment Method Up Front

If you would like to offer trial periods without collecting the user's payment method information up front, you may set the `trial_ends_at` column on the user record to your desired trial ending date. This is typically done during user registration:

```php
use App\Models\User;

$user = User::create([
// ...
'trial_ends_at' => now()->addDays(10),
]);

:::warning
Be sure to add a [date cast](/docs/eloquent-mutators#date-casting) for the `trial_ends_at` attribute within your billable model's class definition.
:::

Cashier refers to this type of trial as a "generic trial", since it is not attached to any existing subscription. The `onTrial` method on the billable model instance will return `true` if the current date is not past the value of `trial_ends_at`:

```php
if ($user->onTrial()) {
// User is within their trial period...
}

Once you are ready to create an actual subscription for the user, you may use the `newSubscription` method as usual:

```php
$user = User::find(1);

$user->newSubscription('default', 'price_monthly')->create($paymentMethod);

To retrieve the user's trial ending date, you may use the `trialEndsAt` method. This method will return a Carbon date instance if a user is on a trial or `null` if they aren't. You may also pass an optional subscription type parameter if you would like to get the trial ending date for a specific subscription other than the default one:

```php
if ($user->onTrial()) {
$trialEndsAt = $user->trialEndsAt('main');
}

```php
if ($user->onGenericTrial()) {
// ユーザーは「一般的な」トライアル期間内です...
}
    use App\Models\User;

$subscription = User::find(1)->subscription('default');

// 今から7日後にトライアルを終了させる...
$subscription->extendTrial(
now()->addDays(7)
);

// トライアルにさらに5日追加する...
$subscription->extendTrial(
$subscription->trial_ends_at->addDays(5)
);
php artisan cashier:webhook
php artisan cashier:webhook --url "https://example.com/stripe/webhook"
php artisan cashier:webhook --api-version="2019-12-03"
php artisan cashier:webhook --disabled
    ->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
]);
})
    <?php

namespace App\Listeners;

use Laravel\Cashier\Events\WebhookReceived;

class StripeEventListener
{
/**
* 受信したStripeウェブフックを処理します。
*/
public function handle(WebhookReceived $event): void
{
if ($event->payload['type'] === 'invoice.payment_succeeded') {
// 受信したイベントを処理する...
}
}
}
    use Illuminate\Http\Request;

Route::post('/purchase', function (Request $request) {
$stripeCharge = $request->user()->charge(
100, $request->paymentMethodId
);

// ...
});
    $user->charge(100, $paymentMethod, [
'custom_option' => $value,
]);
    use App\Models\User;

$stripeCharge = (new User)->charge(100, $paymentMethod);
    try {
$payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
// ...
}
    $user->invoicePrice('price_tshirt', 5);

    $user->invoicePrice('price_tshirt', 5, [
'discounts' => [
['coupon' => 'SUMMER21SALE']
],
], [
'default_tax_rates' => ['txr_id'],
]);

    $user->tabPrice('price_tshirt', 5);
$user->tabPrice('price_mug', 2);
$user->invoice();

    $user->invoiceFor('One Time Fee', 500);

    use Illuminate\Http\Request;

Route::post('/pay', function (Request $request) {
$payment = $request->user()->pay(
$request->get('amount')
);

return $payment->client_secret;
});

    use Illuminate\Http\Request;

Route::post('/pay', function (Request $request) {
$payment = $request->user()->payWith(
$request->get('amount'), ['card', 'bancontact']
);

return $payment->client_secret;
});

    $payment = $user->charge(100, $paymentMethodId);

$user->refund($payment->id);

    $invoices = $user->invoices();

    $invoices = $user->invoicesIncludingPending();

    $invoice = $user->findInvoice($invoiceId);

    <table>
@foreach ($invoices as $invoice)
<tr>
<td>{{ $invoice->date()->toFormattedDateString() }}</td>
<td>{{ $invoice->total() }}</td>
<td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
</tr>
@endforeach
</table>

composer require dompdf/dompdf

    use Illuminate\Http\Request;

Route::get('/user/invoice/{invoice}', function (Request $request, string $invoiceId) {
return $request->user()->downloadInvoice($invoiceId);
});

    return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
'street' => 'Main Str. 1',
'location' => '2000 Antwerp, Belgium',
'phone' => '+32 499 00 00 00',
'email' => 'info@example.com',
'url' => 'https://example.com',
'vendorVat' => 'BE123456789',
]);
    return $request->user()->downloadInvoice($invoiceId, [], 'my-invoice');
    use Illuminate\Support\Facades\Http;
use Laravel\Cashier\Contracts\InvoiceRenderer;
use Laravel\Cashier\Invoice;

class ApiInvoiceRenderer implements InvoiceRenderer
{
/**
* Render the given invoice and return the raw PDF bytes.
*/
public function render(Invoice $invoice, array $data = [], array $options = []): string
{
$html = $invoice->view($data)->render();

return Http::get('https://example.com/html-to-pdf', ['html' => $html])->get()->body();
}
}
    use Illuminate\Http\Request;

Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout('price_tshirt');
});
    use Illuminate\Http\Request;

Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 15]);
});
    use Illuminate\Http\Request;

Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
    use Illuminate\Http\Request;
use Stripe\Checkout\Session;
use Stripe\Customer;

Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
]);
});

Route::get('/checkout-success', function (Request $request) {
$checkoutSession = $request->user()->stripe()->checkout->sessions->retrieve($request->get('session_id'));
    return view('checkout.success', ['checkoutSession' => $checkoutSession]);
})->name('checkout-success');

Promotion Codes

By default, Stripe Checkout does not allow user redeemable promotion codes. Luckily, there's an easy way to enable these for your Checkout page. To do so, you may invoke the allowPromotionCodes method:

use Illuminate\Http\Request;

Route::get('/product-checkout', function (Request $request) {
return $request->user()
->allowPromotionCodes()
->checkout('price_tshirt');
});

<a name="single-charge-checkouts"></a>
### Single Charge Checkouts

You can also perform a simple charge for an ad-hoc product that has not been created in your Stripe dashboard. To do so you may use the `checkoutCharge` method on a billable model and pass it a chargeable amount, a product name, and an optional quantity. When a customer visits this route they will be redirected to Stripe's Checkout page:

```php
use Illuminate\Http\Request;

Route::get('/charge-checkout', function (Request $request) {
return $request->user()->checkoutCharge(1200, 'T-Shirt', 5);
});

:::warning
When using the `checkoutCharge` method, Stripe will always create a new product and price in your Stripe dashboard. Therefore, we recommend that you create the products up front in your Stripe dashboard and use the `checkout` method instead.
:::

<a name="subscription-checkouts"></a>
### Subscription Checkouts

:::warning
Using Stripe Checkout for subscriptions requires you to enable the `customer.subscription.created` webhook in your Stripe dashboard. This webhook will create the subscription record in your database and store all of the relevant subscription items.
:::

You may also use Stripe Checkout to initiate subscriptions. After defining your subscription with Cashier's subscription builder methods, you may call the `checkout `method. When a customer visits this route they will be redirected to Stripe's Checkout page:

```php
use Illuminate\Http\Request;

Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout();
});

Just as with product checkouts, you may customize the success and cancellation URLs:

```php
use Illuminate\Http\Request;

Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});

Of course, you can also enable promotion codes for subscription checkouts:

```php
use Illuminate\Http\Request;

Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->allowPromotionCodes()
->checkout();
});

:::warning
Unfortunately Stripe Checkout does not support all subscription billing options when starting subscriptions. Using the `anchorBillingCycleOn` method on the subscription builder, setting proration behavior, or setting payment behavior will not have any effect during Stripe Checkout sessions. Please consult [the Stripe Checkout Session API documentation](https://stripe.com/docs/api/checkout/sessions/create) to review which parameters are available.
:::

<a name="stripe-checkout-trial-periods"></a>
#### Stripe Checkout and Trial Periods

Of course, you can define a trial period when building a subscription that will be completed using Stripe Checkout:

$checkout = Auth::user()->newSubscription('default', 'price_monthly')
->trialDays(3)
->checkout();

However, the trial period must be at least 48 hours, which is the minimum amount of trial time supported by Stripe Checkout.

<a name="stripe-checkout-subscriptions-and-webhooks"></a>
#### Subscriptions and Webhooks

Remember, Stripe and Cashier update subscription statuses via webhooks, so there's a possibility a subscription might not yet be active when the customer returns to the application after entering their payment information. To handle this scenario, you may wish to display a message informing the user that their payment or subscription is pending.

<a name="collecting-tax-ids"></a>
### Collecting Tax IDs

Checkout also supports collecting a customer's Tax ID. To enable this on a checkout session, invoke the `collectTaxIds` method when creating the session:

$checkout = $user->collectTaxIds()->checkout('price_tshirt');

When this method is invoked, a new checkbox will be available to the customer that allows them to indicate if they're purchasing as a company. If so, they will have the opportunity to provide their Tax ID number.

:::warning
If you have already configured [automatic tax collection](#tax-configuration) in your application's service provider then this feature will be enabled automatically and there is no need to invoke the `collectTaxIds` method.
:::

<a name="guest-checkouts"></a>
### Guest Checkouts

Using the `Checkout::guest` method, you may initiate checkout sessions for guests of your application that do not have an "account":

```php
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;

Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});

Similarly to when creating checkout sessions for existing users, you may utilize additional methods available on the `Laravel\Cashier\CheckoutBuilder` instance to customize the guest checkout session:

```php
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;

Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()
->withPromotionCode('promo-code')
->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});

After a guest checkout has been completed, Stripe can dispatch a `checkout.session.completed` webhook event, so make sure to [configure your Stripe webhook](https://dashboard.stripe.com/webhooks) to actually send this event to your application. Once the webhook has been enabled within the Stripe dashboard, you may [handle the webhook with Cashier](#handling-stripe-webhooks). The object contained in the webhook payload will be a [`checkout` object](https://stripe.com/docs/api/checkout/sessions/object) that you may inspect in order to fulfill your customer's order.

<a name="handling-failed-payments"></a>
## Handling Failed Payments

Sometimes, payments for subscriptions or single charges can fail. When this happens, Cashier will throw an `Laravel\Cashier\Exceptions\IncompletePayment` exception that informs you that this happened. After catching this exception, you have two options on how to proceed.

First, you could redirect your customer to the dedicated payment confirmation page which is included with Cashier. This page already has an associated named route that is registered via Cashier's service provider. So, you may catch the `IncompletePayment` exception and redirect the user to the payment confirmation page:

```php
use Laravel\Cashier\Exceptions\IncompletePayment;
    try {
$subscription = $user->newSubscription('default', 'price_monthly')
->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('home')]
);
}

On the payment confirmation page, the customer will be prompted to enter their credit card information again and perform any additional actions required by Stripe, such as "3D Secure" confirmation. After confirming their payment, the user will be redirected to the URL provided by the redirect parameter specified above. Upon redirection, message (string) and success (integer) query string variables will be added to the URL. The payment page currently supports the following payment method types:

  • Credit Cards
  • Alipay
  • Bancontact
  • BECS Direct Debit
  • EPS
  • Giropay
  • iDEAL
  • SEPA Direct Debit

Alternatively, you could allow Stripe to handle the payment confirmation for you. In this case, instead of redirecting to the payment confirmation page, you may setup Stripe's automatic billing emails in your Stripe dashboard. However, if an IncompletePayment exception is caught, you should still inform the user they will receive an email with further payment confirmation instructions.

Payment exceptions may be thrown for the following methods: charge, invoiceFor, and invoice on models using the Billable trait. When interacting with subscriptions, the create method on the SubscriptionBuilder, and the incrementAndInvoice and swapAndInvoice methods on the Subscription and SubscriptionItem models may throw incomplete payment exceptions.

Determining if an existing subscription has an incomplete payment may be accomplished using the hasIncompletePayment method on the billable model or a subscription instance:

if ($user->hasIncompletePayment('default'))

if ($user->subscription('default')->hasIncompletePayment())

You can derive the specific status of an incomplete payment by inspecting the payment property on the exception instance:

    use Laravel\Cashier\Exceptions\IncompletePayment;

try {
$user->charge(1000, 'pm_card_threeDSecure2Required');
} catch (IncompletePayment $exception) {
// Get the payment intent status...
$exception->payment->status;

// Check specific conditions...
if ($exception->payment->requiresPaymentMethod()) {
// ...
} elseif ($exception->payment->requiresConfirmation()) {
// ...
}
}

Confirming Payments

Some payment methods require additional data in order to confirm payments. For example, SEPA payment methods require additional "mandate" data during the payment process. You may provide this data to Cashier using the withPaymentConfirmationOptions method:

$subscription->withPaymentConfirmationOptions([ 'mandate_data' => '...', ])->swap('price_xxx');

You may consult the Stripe API documentation to review all of the options accepted when confirming payments.

Strong Customer Authentication

If your business or one of your customers is based in Europe you will need to abide by the EU's Strong Customer Authentication (SCA) regulations. These regulations were imposed in September 2019 by the European Union to prevent payment fraud. Luckily, Stripe and Cashier are prepared for building SCA compliant applications.

警告

Before getting started, review Stripe's guide on PSD2 and SCA as well as their documentation on the new SCA APIs.

Payments Requiring Additional Confirmation

SCA regulations often require extra verification in order to confirm and process a payment. When this happens, Cashier will throw a Laravel\Cashier\Exceptions\IncompletePayment exception that informs you that extra verification is needed. More information on how to handle these exceptions be found can be found in the documentation on handling failed payments.

Payment confirmation screens presented by Stripe or Cashier may be tailored to a specific bank or card issuer's payment flow and can include additional card confirmation, a temporary small charge, separate device authentication, or other forms of verification.

Incomplete and Past Due State

When a payment needs additional confirmation, the subscription will remain in an incomplete or past_due state as indicated by its stripe_status database column. Cashier will automatically activate the customer's subscription as soon as payment confirmation is complete and your application is notified by Stripe via webhook of its completion.

For more information on incomplete and past_due states, please refer to our additional documentation on these states.

Off-Session Payment Notifications

Since SCA regulations require customers to occasionally verify their payment details even while their subscription is active, Cashier can send a notification to the customer when off-session payment confirmation is required. For example, this may occur when a subscription is renewing. Cashier's payment notification can be enabled by setting the CASHIER_PAYMENT_NOTIFICATION environment variable to a notification class. By default, this notification is disabled. Of course, Cashier includes a notification class you may use for this purpose, but you are free to provide your own notification class if desired:

CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment

オフセッションの支払い確認通知が配信されるようにするには、アプリケーションにStripeウェブフックが構成されていることを確認し、Stripeダッシュボードでinvoice.payment_action_requiredウェブフックが有効になっていることを確認してください。さらに、BillableモデルはLaravelのIlluminate\Notifications\Notifiableトレイトを使用する必要があります。

警告

顧客が追加の確認が必要な支払いを手動で行っている場合でも、通知が送信されます。残念ながら、Stripeは支払いが手動で行われたか「オフセッション」であるかを知る方法はありません。ただし、顧客は支払いをすでに確認した後に支払いページを訪れると、「支払い成功」というメッセージが表示されます。顧客は同じ支払いを誤って2回確認してしまい、誤って2回請求されることはありません。

Stripe SDK

Cashierの多くのオブジェクトはStripe SDKオブジェクトのラッパーです。Stripeオブジェクトと直接やり取りしたい場合は、asStripeメソッドを使用して便利に取得できます。

$stripeSubscription = $subscription->asStripeSubscription();

$stripeSubscription->application_fee_percent = 5;

$stripeSubscription->save();

また、Stripeサブスクリプションを直接更新するには、updateStripeSubscriptionメソッドを使用できます。

$subscription->updateStripeSubscription(['application_fee_percent' => 5]);

Cashierクラスのstripeメソッドを呼び出すと、Stripe\StripeClientクライアントを直接使用できます。たとえば、このメソッドを使用してStripeClientインスタンスにアクセスし、Stripeアカウントから価格のリストを取得できます。

use Laravel\Cashier\Cashier;

$prices = Cashier::stripe()->prices->all();

テスト

Cashierを使用するアプリケーションをテストする場合、Stripe APIへの実際のHTTPリクエストをモックすることができます。ただし、これにはCashierの動作の一部を再実装する必要があります。そのため、テストが実際のStripe APIにアクセスすることをお勧めします。これは遅いですが、アプリケーションが期待どおりに機能していることをより確信するためのものであり、遅いテストは独自のPest / PHPUnitテストグループ内に配置することができます。

テスト時には、Cashier自体にはすでに優れたテストスイートがあるため、独自のアプリケーションのサブスクリプションと支払いフローのテストに焦点を当てるべきです。

始めるには、phpunit.xmlファイルにStripeシークレットのtestingバージョンを追加してください。

これで、テスト中にCashierとやり取りする際に、実際のAPIリクエストがStripeのテスト環境に送信されます。便宜上、テスト中に使用するサブスクリプション/価格をStripeのテストアカウントに事前に準備しておくと便利です。

注記

クレジットカードの拒否や失敗など、さまざまな請求シナリオをテストするためには、Stripeが提供するテスト用カード番号とトークンの幅広い範囲を使用できます。