Stripe Checkoutを利用した場合の、Customer作成タイミングについて

Stripeでカードをはじめとした顧客情報を取り扱う場合、Customerを作成する必要があります。
このCustomerデータを、どのタイミングで作成するかについて、簡単にまとめました。

# Customer作成タイミング

Checkoutを利用する場合のCustomer作成タイミングは、大きく分けて4種類あります。

- 1: 事前に作成する
- 2: Checkoutセッション作成時に作成する
- 3: Checkout後にリダイレクトされるページで登録する
- 4: Webhookで作成する


## 1: 事前に作成する
Checkoutのセッションを作成するステップとは別のタイミング・APIでCustomerを作成します。
例えば、Auth0やFirebase / Cognito User Poolsなどでユーザーデータを作成するタイミングで、`stripe.customer.create` APIを実行します。

### 事前作成のメリット
この方法のメリットは、１ユーザー１Customerを固定化できることです。
ユーザー作成時に必ずCustomerを作成しますので、後述の方法のように複数のCustomerが作成されてしまうケースを回避できます。

また、支払い方法の登録がなくとも、金額が「０」に設定された料金をサブスクリプションさせることは可能です。
そのため、無料プランのあるSaaSなどでは、以下のステップをまとめて実行してしまうことも検討できます。

- ユーザーデータを作成（各種idpなどを利用）
- StripeでCustomerを作成
- 作成したCustomerで、無料のサブスクリプションを開始する

### 事前作成のデメリット
一方で、支払い情報などのない顧客データが大量に登録されてしまうこともデメリットとして考えられます。
無料ユーザーが多いサービスなどでは、無料のサブスクリプションだけをもつCustomerデータの比率が高くなり、バッチ処理やデータ連携などで取得する必要のあるデータ量が大きくなるケースが存在します。

この方法を採用する場合、[Search API(2022/1時点ではベータ機能)](https://stripe.com/docs/search-api)や[Stripe Sigma](https://stripe.com/sigma)などを利用して、データ取得を行う方法を検討しましょう。

## 2: Checkoutセッション作成時に作成する
２つめの方法は、Checkoutセッションを作成する際に作成します。
Checkoutセッションを開始して、ユーザーが決済を始めようとするタイミングでCustomerデータを作成することができます。

### Checkoutセッション作成時にするメリット
この方法の場合、Stripeに作成されるCustomerは「何かしらの料金を支払う」意思を表明していると判断できます。

また、`checkout.sessions.create`APIを呼び出す前にCustomerを作成することで、いわゆる「カゴ落ち」が発生した際のフォローアップメール送信なども可能になります。

https://stripe.com/docs/payments/checkout/abandoned-carts

このケース以外でCustomerデータを作成していない場合、「Customerは存在するが、支払い情報や決済履歴のないユーザー」を「カゴ落ちしたユーザー」と考えることも可能です。

### Checkoutセッション作成時にするデメリット

Checkoutでセッションを開始する際、「すでにCustomerが作成されているか否か」を判別する必要があります。

以下は架空のユーザー管理サービスのデータを利用して、メタデータに登録されたStripeのCustomerデータを取得するコードです。データが存在しなかった場合、新しくCustomerを作成し、ユーザー管理サービスにそのIDを登録しています。

```js
import { AnyAuthService } from 'any-awesome-auth-service'

const getOrCreateStripeCustomer = async () => {
  const user = await AnyAuthService.getUser()
  try {
    const customer = await stripe.customers.retrieve(user.metadata.stripeCustomerId)
    return customer
  } catch (e) {
    if (e.code !== 'resource_missing') throw e
  }
  const newCustomer = await stripe.customers.create({
    email: user.email,
    metadata: {
      username: user.name
    }
  })
  await AnyAuthService.update(user.name, {
    metadata: {
      stripeCustomerId: newCustomer.id
    }
  })
  return newCustomer
}
```

１の手法では、「すべてのユーザーが、かならず１つのStripe Customerデータを持っている」前提で実装できました。しかしこの方法の場合、「初めての購入客ではCustomerを作成する」と「購入歴がある場合、登録済みのCustomerを利用する」の２つを実装する必要があります。

## 3: Checkoutの成功ページで登録する

Checkoutでの決済が完了した後にリダイレクトされるページで、Customer作成のためのステップを進める方法も存在します。

### 2022/10追記: Stripe API: `2022-08-01`以降を利用する場合の注意点

Stripe APIのバージョン`2022-08-01`以降を利用中の場合、Checkoutのデフォルト値が「ゲスト顧客モード」に変わります。

そのため、この方法を利用するには、`customer_creation: 'always'`を明示的に設定しましょう。

```diff_javascript
    const result = await stripe.checkout.sessions.create({
    customer_creation: 'always',
...
```

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

### リダイレクト先でCustomerを作成する 

まず、リダイレクトURLに以下のようなセッションIDのクエリ文字列を追加します。

```diff_javascript
const session = await stripe.checkout.sessions.create({
-  success_url: "http://yoursite.com/order/success",
+  success_url: "http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}",
  // other options...,
});
```

リダイレクト後に表示されるページの、サーバー側の処理でセッションIDから顧客データなどを取得できます。

```js
app.get('/order/success', async (req, res) => {
  const session = await stripe.checkout.sessions.retrieve(req.query.session_id);
  const customer = await stripe.customers.retrieve(session.customer);

  res.send(`<html><body><h1>Thanks for your order, ${customer.name}!</h1></body></html>`);
});
```

あとはこのデータを利用して、Customerデータをサービスのユーザー情報に紐づけます。

### 成功ページを利用するメリット

この方法は、「サービス側でまだユーザーアカウントが存在しない」ケースに向いています。

決済完了後にユーザー登録画面を表示し、登録処理のなかで取得したセッションIDから作成済みのCustomerデータの取得と関連づけを行うことができます。

### 成功ページを利用するデメリット

セッションIDからCustomerデータを取得する必要があるなど、前の２つと比較してすこしステップの多い手法です。

そのため、「すでにサービス側のユーザーアカウントがある場合は１または２の手法、そうでない場合は３の手法を取り入れる」運用を検討するなど、組み合わせて活用することをお勧めします。


## 4: Webhookで自動生成されたCustomerを処理する

最後の方法は、Checkoutセッションが完了した際のWebHookイベントでCustomerを作成する方法です。

Checkoutでの操作が完了した場合、入力されたメールアドレスを利用してCustomerデータが作成されます。
また、併せて`checkout.session.completed`のイベントがWebhookに送られます。

このデータを利用し、Webhook API上でCustomerデータをサービスのユーザー情報に紐づけます。


### 2022/10追記: Stripe API: `2022-08-01`以降を利用する場合の注意点

Stripe APIのバージョン`2022-08-01`以降を利用中の場合、Checkoutのデフォルト値が「ゲスト顧客モード」に変わります。

そのため、この方法を利用するには、`customer_creation: 'always'`を明示的に設定しましょう。

```diff_javascript
    const result = await stripe.checkout.sessions.create({
    customer_creation: 'always',
...
```

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



### Webhook作成のメリット

３の手法をフロントエンドを通さずに実行することができます。
そのため、「購入後のユーザー登録をサポートしたいが、サーバー側だけで完結したい」ユースケースに向いています。

### Webhook作成のデメリット

サーバー側で処理を完結させるため、サービス側のユーザーアカウントが自動で作成される仕組みになります。

そのため、「注文したら、勝手にアカウントまで作られた」とユーザーが感じないような動線や説明などを用意する必要があります。

# それぞれのユースケースについて

ユーザー登録が完了したタイミングでCustomerを作成する手法を採用することで、サービスのユーザーアカウントとStripeのCustomerデータの関連付けなどを効率化することができます。

しかし「もともと無料サービスとして提供していたものに、有料機能を追加したい」など、後から決済系機能を追加するユースケースでは、Checkoutのセッション作成時にCustomerを作成することをお勧めします。

また、ユーザー登録が必須でないサービスでは、「購入後に登録を促す仕組み」を成功ページやWebhookを利用して提供することも可能です。


---

# [PR] Stripe開発者向け情報をQiitaにて配信中！
2021年12月よりQiitaにて、Stripe開発者のためのブログ記事更新を開始しました。

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

など、Stripeを利用してオンラインビジネスを始める方法について随時更新してまいります。

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