Stripe Billingで複数のサブスクリプション契約を管理したい場合の実装方法

StripeのBillingでは、さまざまな料金体系・契約期間のサブスクリプション契約を顧客に提供できます。

## １つにまとめるか、個別にデータを作成するか

レンタルサーバーや定期購入サービスなどでは、顧客が複数のサブスクリプション契約を結ぶユースケースを考慮する必要があります。

Stripeを利用する場合、2つの方法で複数のサブスクリプションを管理することができます。

- 1: 1つのSubscriptionデータに、「数量」として追加・削除する
- 2: 契約の度にSubscriptionデータを作成する

## 管理方法1: 1つのSubscriptionデータに、「数量」として追加・削除する

Stripe APIの組み込みがシンプルなのは、契約を「数量」として扱う方法です。

この場合、顧客に対してSubscriptionは1つだけ作成します。

```js
  await stripe.subscriptions.create({
    customer: 'cus_xxx',
    items: [{
      price: 'price_xxx',
      quantity: 1
    }]
  })
```

そして「レンタルサーバーサービスでの、新しいサーバーの追加注文」のように、契約を追加するケースでは、作成済みのSubscriptionを変更して対応します。

```js
  await stripe.subscriptions.update('sub_xxx', {
    items: [{
      price: 'price_xxx',
      quantity: 2
    }]
  })
```

「メールオプション」など、サーバープランに付随するプランを追加したい場合は、別の料金を追加します。

```js
  await stripe.subscriptions.update('sub_xxx', {
    items: [{
      price: 'price_yyyy',
      quantity: 1
    }]
  })
```

### プランのキャンセル処理

プランをキャンセルする場合は、「数を減らす」または「アイテムを削除する」で対応します。

もしキャンセル後に残る契約数が０以上の場合は、`update`で数量を変更します。

```js
  await stripe.subscriptions.update('sub_xxx', {
    items: [{
      price: 'price_xxx',
      quantity: 1
    }]
  })
```

0になる場合は、数量の代わりに`deleted: true`を設定しましょう。


```js
  await stripe.subscriptions.update('sub_xxx', {
    items: [{
      price: 'price_xxx',
      deleted: true
    }]
  })
```

もし`quantity: 0`をセットすると、以下のようなAPIエラーが発生します。

```json
{
  "error": {
    "message": "Cannot add multiple subscription items with the same plan: price_xxxxxxx,
    "param": "plan",
    "request_log_url": "https://dashboard.stripe.com/test/logs/req_xxxxxxx?t=1668423793",
    "type": "invalid_request_error"
  }
}
```

### 1Subscriptionにまとめるメリットとデメリット

１つのSubscriptionにまとめることで、「その顧客がどんなサブスクリプション・プランを契約しているか」や「過去の請求履歴」などを１Subscriptionデータから確認できます。

また、月末・月初のように請求サイクルをシステムで統一している場合、請求日に複数の請求書が顧客へ送信されることを防ぐこともできます。

一方で、「１契約ごと」に追加の情報やrelationを持たせたい場合や、決済方法・配送先住所などを変更したい場合には注意が必要です。

「１契約ごとに別のクレジットカードを設定したいケース」では、Subscriptionの分割作業が必要になります。

また、自社のDB内の情報と契約を紐付けしたい場合、「Subscriptionのどのpriceと対応するか」の関係性をシステム側で持たせる必要があることにもご注意ください。

## 管理方法2: 契約の度にSubscriptionデータを作成する

もう1つの方法は、契約の度にSubscriptionデータを作成する方法です。

この場合は、メインの契約ごとにSubscriptionを作成します。

```js
  await stripe.subscriptions.create({
    customer: 'cus_xxx',
    items: [{
      price: 'price_xxx',
      quantity: 1
    }]
  })

  await stripe.subscriptions.create({
    customer: 'cus_xxx',
    items: [{
      price: 'price_xxx',
      quantity: 1
    }, {
      price: 'price_yyy',
      quantity: 1
    }]
  })
```

1つのCustomerデータに対して、複数のSubscriptionが作成されます。

自社DBのリソースとの紐付けも、SubscriptionのIDをリソースに保存すれば、あとはStripe APIを呼び出すだけでデータの取得が可能です。


### 都度Subscriptionを作成するメリットとデメリット

Subscriptionデータが複数作成されるため、StripeダッシュボードやCustomer Portalで「どれがどのSubscriptionか？」を判別できる仕組みが必要です。

そのため、Subscriptionを作成する際に`description`を設定することをお勧めします。


```diff_javascript
  await stripe.subscriptions.create({
    customer: 'cus_xxx',
    items: [{
      price: 'price_xxx',
      quantity: 1
    }],
+    description: '定期Aコース',
  })
```

https://qiita.com/hideokamoto/items/c741cd0ef3e9e107e2f7

また、`metadata`に情報を登録することで、Search APIを利用した検索を実装することも可能です。

https://stripe.com/docs/search?locale=ja-JP#%E3%82%B5%E3%83%96%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89

## 関連ドキュメント

https://stripe.com/docs/billing/subscriptions/multiple-products