Stripe データのコンセプト
Tags: stripe
Published: 2020-12-08 23:20:58

---
title: Stripe データのコンセプト
published: true
description: Stripe のデータオブジェクトのコンセプト、考え方
tags: stripe
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/k3roihce5zfc9p8zakdo.jpg
---

Stripe という決済 SaaS の存在を、最近知りました。いろんな API を組み合わせて、いろんな決済処理を実装できます。個々の API エンドポイントのパラメータや挙動はドキュメントがあり、テストモードで簡単に試せます。

一方、外側からみて、Stripe におけるデータオブジェクトのコンセプトが分かると、個々の API をやみくもに調べるよりは、設計の役に立つような気がします。決済というのが、そもそも比較的抽象度の高い概念です。サービス上のユーザー体験が API と 1対1 で対応しないことがあります。そんなときは、少しレイヤーを上げた視点 **も** あるといいんじゃないかなー、と思います。

そこで [JP_Stripes Advent Calendar 2020](https://adventar.org/calendars/5626) にぶらさがって、自分なりの解釈をまとめました。

以下、クレジットカードでの支払いを想定します。

Payment Intent
===

Payment Intent は 1回の「支払い」の設定、状態、処理を管理するオブジェクトです。設定というのは「1000円」みたいな情報です。

状態というは、カード番号が必要だとか、認証が必要だとか、処理中だとか、キャンセルされたとかです。

状態遷移をするときに、裏側では必要に応じて、クレジットカードのシステムと通信が走ります。

とりあえず、どんなのか試したいときは、[Integration Builder](https://stripe.com/docs/payments/integration-builder)
が、手っ取り早いです。[もう少し細かい説明](https://stripe.com/docs/payments/payment-intents
) もあります。

大雑把な状態遷移はこんな感じ。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/a53etbox9urbi5fkzj8w.png)

- requires_payment_method: Payment Method （クレジットカード番号など）が必要。
- requires_confirmation: アプリケーションによる確認（これでOKっす、って指定する API コール）が必要。
- requires_action: 何かアクションが必要。[3Dセキュア](https://ja.wikipedia.org/wiki/3D%E3%82%BB%E3%82%AD%E3%83%A5%E3%82%A2) のパスワード入力とか。
- processing: 処理中。大抵、数秒で、次の状態に遷移する。
- succeeded: 支払い完了。クレジットカードの引き落とし日を楽しみにしてください
- canceled: アプリケーションがキャンセルした。

決済に失敗したら、requires_payment_method に遷移します。

破線枠の状態は、スキップする場合がある状態を表します。正確に分岐を明示すると、ごちゃごちゃするので省略しました。

Payment Intent は支払いの行動を追跡・処理するオブジェクトです。カード番号なんかを直接管理しません。

Payment Method
===

Payment Method は支払い方法・手段を表すオブジェクトです。クレジットカードによる支払いの場合、クレジットカード番号、有効期限、CVC などを保持します。

Payment Intent を作ってから、フロントエンドで Payment Method を作成して Payment Intent と関連づけることができます。

反対に、先に Payment Method を作成して（＝クレジットカード番号を入力させて）から、Payment Intent を作成して関連づけてもよいです。クレジットカードのブランドによって、挙動を変えたいような場合に有効な順序です。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1k90hl6nkjxnn9p1ip5i.png)

Customer
===

会員的な概念があって、繰り返し利用するクレジットカード番号を保存したい、というケースがあると思います。その場合は、Payment Method を Customer オブジェクトに attach します。

Customer オブジェクトは、顧客、より正確には支払いをする主体を表します。B2C だったらおそらくは会員とかユーザーという概念に対応します。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/im3k1oqpp41uqrup6hnb.png)

ひとつの Customer は、0個以上の Payment Method と関連づけられます。ひとつの Payment Method は、0〜1個の Customer と関連づけられます。

Payment Method を一度 Customer と関連づけると、他の Customer と関連づけることはできません。


サブスクリプション・ビジネス
===

Customer と Payment Method の関連づけができれば、毎月バッチを走らせると月額課金ができます。「毎月3,000円支払ってくれたら、うちで飼っている猫が、毎朝、朝食をとっている動画を見せてあげる」みたいなサービスを作れるわけです。やったね。

さて Billing と呼ばれるサービス・API群を使うと、このへんの処理を自動化できます。月に一度決済をするだけならいいんですが、バッチを回すだけより、もうちょい複雑なコンセプトが絡みます。

世の中には3つの嘘があります。嘘、ひどい嘘、定期的に決済するだけ、です。

まずは、定期的に決済するだけに必要なデータオブジェクトを、順番に見ていきましょう。

Product と Price
===

まず商品と料金体系を定義します。

Product は商品やサービスを表す抽象的な概念です。たとえば「猫の朝食動画ストリーミング」というサービスを表します。

Price は、Product と関連づいた価格体系を表します。ひとつの Product に対して、複数の Price を関連づけられます。

複数の Price の用途は大きくふたつあります。複数通貨の場合です。月額3,000円と、月額30ドルを用意するとかですね。

もうひとつは期間が違う場合です。月額3,000円と、年額30,000円を用意するような場合です。

これで商品と価格体系の定義ができました。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/m4rt2ybp154vehdhgpxm.png)

「猫の**夕**食動画ストリーミング」というサービスを追加する場合や、「朝夕バンドル」を追加する場合には、Product 側を変更するとすっきりするでしょう。

3ヶ月ごと、半年ごとの価格体系を追加するときは、Price を操作するのがよいでしょう。

ただ Price 側でいろいろ定義したり、後述する Coupon を使ったりして、いろんなバリエーションを作れます。このあたりこそが、設計者の腕の見せ所だと思います。

Subscription
===

Subscription オブジェクトは、定期課金の契約の定義と状態の保持、それから関連する自動化処理のトリガーの役割があります。

「ある Customer が、ある Price にサブスクライブする」という契約を定義するのがSubscription です。Price で定義したとおり、Customer に関連づいた Payment Method から資金を回収したいよ、という契約です。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jxkkj9kq6tmpus532oz4.png)

注意すべきは Customer は支払いの主体だ、ということです。たとえば「3ユーザーまで視聴可」みたいな契約のとき、Customer はおそらく「ユーザー」には関連づかず、支払いをする代表ユーザーのみを表すことになるでしょう。

先払いの契約を想定しているため、契約開始時に最初の請求が発生します。

しかし Subscription は契約を保持するだけで、直接決済をしません。じゃあ、どうするかっていうと、支払いが必要になったとき、自動的に Invoice オブジェクトをつくります。


Invoice
===

Invoice オブジェクトは1回の請求行為を表します。猫ストリームの例では「今月ぶんの3,000円を請求するのだ」という活動です。

未払いだとか、支払い済みだとか、期限切れだとか、もういらねぇよ（void）などの状態を持ちます。

請求の状態を持ちますが、支払いを直接管理しません。じゃあどうするのかというと、ここで最初に出てきた Payment Intent が登場します。Invoice が資金の回収ができる条件がそろうと、自動的に Payment Intent を作り、実行しようとします。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/etkcl4htfntug703f1vf.png)

Payment Intent は、Customer -> Subscription -> Invoice と伝搬・継承してきた Payment Method から、支払いを回収しようとします。その結果は、今度は逆向きに Invoice -> Subscription のほうに伝搬していきます。

Invoice が回収に失敗したとき、スマートリトライなる自動化処理があり、なんとなくいいタイミングでリトライします。それでも失敗し続けると、諦めます。その場合に、未回収だけど subscription を生かしておく、subscription をキャンセルするなどの挙動定義は、ダッシュボードで設定できます。


trial
===

さて、めでたくサブスクリプション・ビジネスのサービスが開発できました。やったね！　すると、マーケティング担当とか、グロース担当とかが、こういうことを言い出すわけです。

「今月サブスクしたら、一ヶ月無料キャンペーンをしよう！」

だるいですね。

初月無料キャンペーンのだるいところは、契約開始日と資金回収開始日がずれてしまうことです。そんなデータ構造持ってねぇよ、って言いたくなりますよね。

そこで trial です。Subscription オブジェクトを作るときに、使用期間を指定できます。これは subscription が始まってからしばらく無料が続き、そのあとで最初の支払いを発生させるためのパラメータです。

Subscription を作った時点では、0円の invoice が作られます。支払いは発生しないので Payment Intent は作られず、Invoice はすぐに paid 状態になります。そのため subscription は生きたままです。

trial 期間が終わると、そこから支払いサイクルが始まり、Invoice -> Payment Intent の連鎖が始まります。


Coupon
===

やりました。開発者のみなさんは、trial をも乗り越えました。すると、グロース担当（）が言うわけです。

「競合が似たサービスを作ってきた！　継続してもらうために、既存顧客を2ヶ月間 50% オフにしよう！」

はー。だるいですね。

「難しかったら、1ヶ月でもいいよ」

そういう問題じゃねーよ、お前のギャラを120%オフにすんぞ。

それはそれとして、Coupon オブジェクトが使えるかもしれません。Subscription に Coupon を関連づけると、その Subscription の今後の請求に割引が適用されます。定義できる割引の挙動には、以下のようなパラメータがあります。

- 何%オフにするか、◯◯円引きにするか
- 1度だけか、指定した回数か、ずーっとか
- クーポン適用できる期限
- クーポンを適用できる最大数
- など

物理的に配るクーポン、デジタルクーポンを管理するものではありません。「Subscription に適用する割引」を表す、抽象的な概念です。

Coupon が適用された結果、支払いサイクルで請求額が0円になる場合もあます。そのときは、0円 の Invoice が作られます。

おわりに
===

バッチでできなくもないんですが、ワークフロー的な挙動をある程度 SaaS に任せられると、だるさから開放されることも多いと思います。ここでは、基本的なコンセプトを、自分なりにまとめてみました。

よいお年を。

**Disclaimer**: この記事は、公開されている情報を、個人が解釈して書き記したものです。所属する組織と関係ありそうに見えるかもしれませんが、関係ありません。

**Disclaimer 2**: 所属する組織の人々へ。この文書は、勤務時間外に、個人の機材を使って、個人の解釈をまとめたものです。仕事ではないので、仕事として何か言ってこないでください。もちろん問題があったら修正・削除します。よろ。