【Stripe】サブスクリプションの支払いタイミングが特定日時においてズレる問題について(月初版)

f:id:kuracux:20200625113934p:plain

スタメンでエンジニアをしている田中です。 今回は決済プラットフォームであるStripeのサブスクリプションを扱う際に遭遇した問題について、発生した事象とその原因、および対策方法についてご紹介します。

なお、本記事ではStripeのサブスクリプションについての詳細は説明いたしません。また、対策方法についてはRubyのコードで記載します。RubyでStripeのサブスクリプションを扱う場合については、以下の記事にて紹介しているのでよろしければご参照ください。

【Ruby on Rails】Stripeのサブスクリプションで試したことをまとめてみた

また、以前にも同様のタイトルで記事を投稿しましたが、今回は内容が若干異なります。ただ、前回の記事の知識があると理解が早くなると思うので、この機会に読んでいただければと思います。(タイトルの括弧の中身が異なります)

【Stripe】サブスクリプションの支払いタイミングが特定日時においてズレる問題について(月末版)

前提

  • 本記事で扱うサブスクリプションは請求期間が月次のものです
  • サブスクリプションの支払い日について、通常、翌月に同じ日が存在しない場合は自動的にその前の日を指定してくれます
    • 5/31 → 6/30
    • 8/31 → 9/30

参考 https://stripe.com/docs/billing/subscriptions/billing-cycle

発生した事象

以下の画像のように、同じ日(1日)にサブスクリプションを開始しましたが、2回目の支払いのタイミングがズレてしまうということがありました。

  • 2回目の支払いが初回支払いと同じ日(1日)に行われているケース
    f:id:kuracux:20210127152115p:plain

  • 2回目の支払いが初回支払いと異なる日に行われているケース
    f:id:kuracux:20210127152135p:plain

そのため、例えば支払い成功時のWebhookにて何かしらの処理をする場合に、このズレによって影響が発生する可能性が大いに考えられます。

発生原因

先日ご紹介した記事と同様、billing_cycle_anchorとタイムゾーンの関係によるものだと思われます。 以下は、過去記事の引用です。

ここで、billing_cycle_anchorについて説明します。billing_cycle_anchorとは支払い開始の起点となる日時のことです。たとえば、毎月1日に決済したい場合、サブスクリプション作成時にbilling_cycle_anchorに翌月の1日を指定することで、毎月1日払いを実現することが出来ます。特に指定をしなければ、サブスクリプション作成時刻 = billing_cycle_anchorとなります。

参考 https://stripe.com/docs/billing/subscriptions/billing-cycle

発生原因についての詳細は下記の通りです。

  • Stripeのシステムは、UTC基準で動作する
  • 日本時間(JST)でサブスクリプションを作成する場合に、UTCの時刻から9時間の差がある
  • そのため、UTC基準では月末だが、日本時間だと翌月と判定されてしまうため今回の問題が発生する

これだけだとよく分からないため、具体例を挙げて説明します。

具体例

(1)12/1 午前0時にサブスクリプションを作成した場合 ・日本時間「2020-12-01 00:00:00」にbilling_cycle_anchorを指定

支払回数 ダッシュボード上の挙動(JST) 実際の挙動(UTC)
1回目 2020-12-01 00:00:00 2020-11-30 16:00:00
2回目 2020-12-31 00:00:00 2020-12-30 16:00:00
3回目 2020-01-31 00:00:00 2021-01-30 16:00:00
4回目 2020-03-01 00:00:00 2021-02-28 16:00:00

(2)11/1 午前0時にサブスクリプションを作成した場合 ・日本時間「2020-11-01 00:00:00」にbilling_cycle_anchorを指定

支払回数 ダッシュボード上の挙動(JST) 実際の挙動(UTC)
1回目 2020-11-01 00:00:00 2020-10-31 16:00:00
2回目 2020-12-01 00:00:00 2020-11-30 16:00:00
3回目 2021-01-01 00:00:00 2020-12-31 16:00:00
4回目 2021-02-01 00:00:00 2020-01-31 16:00:00

(1)に関してはUTC基準の場合にbilling_cycle_anchorが2020-11-30 16:00:00で設定されてしまうため、次回以降の支払いサイクルが以下の通りになってしまいます。

  • 31日がある月は31日に支払い
  • 31日がない月は1日に支払い

(2)に関してはUTC基準の場合にbilling_cycle_anchorが2020-10-31 16:00:00で設定されるので、次回以降の支払いサイクルは毎月1日支払いとなります。

上記のことから、日本時間において以下の日時にサブスクリプションが作成されると今回の問題が発生すると考えられます。

  • 前月が31日までない月の1日(3月1日, 5月1日, 7月1日, 10月1日, 12月1日)
  • 午前0時から午前9時の間

対策方法

特定日時でサブスクリプションを作成した場合、trial_endを用いて次回以降の支払い日時をずらすことで対応します。 詳細については前回の記事をご確認ください。

おわりに

今回はStripeのサブスクリプションを扱う際に遭遇した問題についてご紹介しました。 時差および月によって日数が異なることを考慮しないと想定外の挙動が発生する可能性があるので、取り扱う際にはその点を頭に入れて実装していきましょう。

最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひエンジニア採用サイトをご覧ください。