DEV Community

Cover image for Stripe データのコンセプト
Toru Furukawa
Toru Furukawa

Posted on • Edited on

Stripe データのコンセプト

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

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

そこで JP_Stripes Advent Calendar 2020 にぶらさがって、自分なりの解釈をまとめました。

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

Payment Intent

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

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

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

とりあえず、どんなのか試したいときは、Integration Builder
が、手っ取り早いです。もう少し細かい説明 もあります。

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

Alt Text

  • requires_payment_method: Payment Method (クレジットカード番号など)が必要。
  • requires_confirmation: アプリケーションによる確認(これでOKっす、って指定する API コール)が必要。
  • requires_action: 何かアクションが必要。3Dセキュア のパスワード入力とか。
  • 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

Customer

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

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

Alt Text

ひとつの 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

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

3ヶ月ごと、半年ごとの価格体系を追加するときは、Price を操作するのがよいでしょう。

ただ Price 側でいろいろ定義したり、後述する Coupon を使ったりして、いろんなバリエーションを作れます。このあたりこそが、設計者の腕の見せ所だと思います。

Subscription

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

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

Alt Text

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

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

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

Invoice

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

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

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

Alt Text

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

Top comments (1)

Collapse
 
techt01ia profile image
Techtolia

If you are looking the latest solution of Stripe subscription integration in ASP.NET, check out the demo ==> techtolia.com/StripeSubscriptions/