休眠アカウントのサブスクリプション請求をStripeで自動停止する方法

最近、Netflix社のように「長期間利用がないユーザーの契約をキャンセルまたは請求停止する」サービスを耳にすることが増えてきました。

https://news.livedoor.com/article/detail/18297928/

https://togetter.com/li/1905843

この記事では、このようなサービスを提供するために、Stripeでどのような実装ができるかを紹介します。

## Stripeで、休眠アカウントに対してできるアクション

Stripeでサブスクリプションを契約中の「休眠アカウント」に対しては、２つのアクションがとれます。

- Netflixのように、サブスクリプションを自動解約する
- サブスクリプションは残し、請求だけを一時的に停止する

どちらも処理を実行したタイミングから、顧客に対する請求は停止します。

ですが後者の請求一時停止の場合、「サブスクリプションの契約データ」はそのまま残ります。
そのため、以下のようなケースでは解約ではなく一時停止を選択することができます。

- 復帰後に、前回と同じ契約（プラン・割引など）を提供したい場合
- 休会など、「期限付きの解約」を実現させたい場合
- 自動解約の前に猶予期間を設けたい場合

## サブスクリプションを解約する方法

Stripeでサブスクリプションを解約する場合、「その場で解約」または「契約期間終了後に解約」の２つが選べます。

### 契約期間終了後に解約する

バッチ処理で休眠アカウントの判定を行う場合、顧客の契約期間が終了するタイミングで解約するのが親切です。

この場合、「サブスクリプションの更新」という形で解約を設定します。

```js
await stripe.subscriptions.update(
  'sub_xxx',
  {
    cancel_at_period_end: true,
  }
);
```

契約期間が終了して、実際に解約されるまでの間であれば、`cancel_at_period_end`を`false`にすることで解約をキャンセルできます。

```js
await stripe.subscriptions.update(
  'sub_xxx',
  {
    cancel_at_period_end: false,
  }
);
```

### その場で解約する
その場で解約する場合は、`Cancel a Subscription`のAPIを呼び出します。

```js
await stripe.subscriptions.del(
  'sub_xxx',
  {
    invoice_now: true,
  }
);
```

この場合、従量課金の請求などの「未払いの請求」を処理するために、`invoice_now: true`を設定しましょう。
実際には、usageRecordの最終集計などが必要になりますので、従量課金を含む場合は`cancel_at_period_end`を使う方が手軽かもしれません。

## サブスクリプションを一時停止する方法

一時停止する場合、「停止期間の請求をどう扱うか」と「いつまで一時停止するか」の２点を設定します。

サブスクリプション更新のAPIで、`pause_collection`パラメータを渡しましょう。

```js
await stripe.subscriptions.update('sub_xxx', {
  pause_collection: {
    behavior: 'void'
  }
})
```

### 一時停止期間の請求書の扱い

Stripe Billingでは、一時停止期間中も請求書自体は作成されます。
発行された請求書のステータスを変更することで、顧客への請求を一時停止します。

請求書のステータスは「下書き`keep_as_draft`」「回収不可`mark_uncollectible`」「無効`void`」の3種類から選べます。

![スクリーンショット 2022-06-24 13.15.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/622e545d-509c-124d-0a82-ea5f37b57411.png)

今回のような、「休眠アカウントに対して、請求とサービス提供を一時停止する」ケースでは、請求書を無効にする方法を推奨しています。


```js
await stripe.subscriptions.update('sub_xxx', {
  pause_collection: {
    behavior: 'void'
  }
})
```

「無効」を設定すると、その請求書で顧客に請求を行うことができません。
そのため、一時停止期間の請求を後日回収したい場合は、「下書き」を選択しましょう。

### 期限付きの一時停止措置

一時停止措置を期限付きで行いたい場合、`pause_collection`に`resumes_at`を追加します。

```js
await stripe.subscriptions.update('sub_xxx', {
  pause_collection: {
    behavior: 'void',
    resumes_at: dayjs().add(2, 'month').unix()
  }
})
```

このサンプルでは、２ヶ月後にサブスクリプションを再開します。

### 一時停止措置の終了方法

顧客が再びサービスの利用を再開した場合、`pause_collection`を`null`に変更することで請求を再開できます。

```js
await stripe.subscriptions.update('sub_xxx', {
  pause_collection: null
})
```

## サブスクリプションが一時停止状態になったことを判別する方法

アプリケーション側で処理が必要な場合、`customer.subscription.update` Webhookを利用します。

このイベントで更新後のSubscriptionデータがAPIに送信されますので、その中の`pause_collection`属性をチェックしましょう。

ここの値が`null`**ではない場合**は、一時停止中のサブスクリプションです。

```json
{
  "id": "evt_1LE40qKlXtpaTqYx26p0Y3B6",
  "object": "event",
  "api_version": "2020-08-27",
  "created": 1656044456,
  "data": {
    "object": {
      "pause_collection": {
        "behavior": "void",
        "resumes_at": 1661314855
      },
...
    },
    "previous_attributes": {
      "pause_collection": {
        "resumes_at": null
      }
    }
  },
  "livemode": false,
  "type": "customer.subscription.updated"
}
```

`previous_attributes`を併せてみることで、`pause_collection`が変更されたかどうかの判別もできます。

同様に一時停止状態から復帰した場合についても、同じ値をチェックして処理を行いましょう。



## ドキュメント

- https://stripe.com/docs/api/subscriptions/update#update_subscription-pause_collection
- https://stripe.com/docs/billing/subscriptions/pause
- https://stripe.com/docs/billing/subscriptions/cancel


## [PR] Stripe開発者向け情報をQiitaにて配信中！

- [Stripe Updates]：開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について週に２〜３本ペースで更新中です。

-> [Stripe Organizationsをフォローして最新情報をQiitaで受け取る](https://qiita.com/organizations/stripe)