Customer Portalの日付表示のズレを防止【Stripe】

こんにちは、サイオステクノロジーの佐藤 陽です。
今日も今日とて Stripe の Customer Portal のお話です。

Customer Portal に表示される日付と、Stripe Dashboard 上の日付が 1 日ずれてる経験ありませんか?
そんな経験がある方は是非最後まで読んでいってください

はじめに

Stripe の Customer Portal については、こちらをご覧ください。

Customer Portal には、現在契約しているサブスクリプションのプラン内容や、支払い金額、次回の更新日時などが表示されます。

ただ、このサブスクリプションの更新日が Stripe Dashboard 上の設定と一日ずれるケースが時々見られました。
その原因および解消方法を解説していきます。

原因

先に原因を書いてしまうと

Customer Portal の表示はUTCの時刻を基準とした表示になっており、
Stripe Dashboard の表示は現地時間を基準とした表示になっているため

です。

例えば、日本時間の 8 月 4 日の午前 8 時にサブスクリプションを新規作成した場合
次の更新日は、月単位の場合だと 9 月 4 日の午前 8 時になります。

この 9 月 4 日の午前 8 時というのが、UTC で表すと 9 月 3 日の午後 11 時になります。
そのため Customer Portal で表示した場合には、次の更新日が 9 月 3 日と表示されてしまう訳です。

再現

では本当にそうなっているのか再現してみます。
まずは、サブスクリプションを作成ていきましょう。

ただ、試すときに深夜 0 時から朝 9 時までの間に作成すると何も考えず再現できるのですが、
(JSTとUCTで日時ずれが発生するのがこの時間帯のため)

今はその時間を過ぎてしまっているため

まず Step1 として、サブスクリプション作成時に、現在時刻が BillingCycleAnchor として設定されることを確認します。

Step2 として、朝 8 時に申し込んだと仮定し、BillingCycleAnchor を明示的に指定してサブスクリプションを作成します。

そしてこの時の CustomerPortal と StripeDashboard の日付を確認してみたいと思います。

Step1

それでは何も考えず Subscription の作成から行っていきます。

前提条件として

  • Customer が作成済みである
  • Customer に PaymentMethod (クレジットカード)が割り当て済みである
  • Price が作成済みである

という状態で行います。

それでは Subscription を作成していきましょう。

curl https://api.stripe.com/v1/subscriptions \
-u "your api key" \
-d customer=cus_ONxvemk1xTB4as \
-d "items[0][price]"=price_1NR7TZIZmiK0iNLQf9VNZ3mt

レスポンスを見ると

"billing_cycle_anchor": 1691112526,
...(略)
"current_period_end": 1693790926,
...(略)

となっており、billing_cycle_anchor は現在時刻である

2023/08/04 10:28:46(JST)

を指します。

また、current_period_end

2023/09/04 10:28:46(JST)

を指しており、これは次の請求開始日を表す値でもあります。

つまり何も指定せず、サブスクリプションを作成した場合は、現在時刻が BillingCycleAnchor として設定され
そのちょうど 1 ヵ月後に次の請求が行われるということになります。

 Step2

では Step1 の内容を踏まえて、
2023/08/05 08:00:00(JST)(=1691190000)に申し込んだと仮定し、BillingCycleAnchor を明示的に指定してサブスクリプションを作成します。

curl https://api.stripe.com/v1/subscriptions \
-u "your api key" \
-d customer=cus_ONxvemk1xTB4at \
-d "items[0][price]"=price_1NR7TZIZmiK0iNLQf9VNZ3mt \
-d billing_cycle_anchor=1691190000

StripeDashboard を見ると、正しく 8 月 5 日に請求が開始されることが分かります。

では、次にこの Customer に対して CustomerPortal を作成します。

curl https://api.stripe.com/v1/billing_portal/sessions \
-u "your api key" \
-d customer=cus_ONxvemk1xTB4at

作成された Portal の URL にアクセスすると

 

プランは 2023 年 8 月 4 日に更新されます。

と表示されてます。

ここで、今回ブログの本題である、CustomerPortal の日付表示の不整合が確認できました。

理由は先ほど説明しましたが、CustomerPortal の表示は UTC の時刻を基準としているためです。

  • 2023/08/05 08:00:00(JST)
  • 2023/08/04 23:00:00(UTC)

ではこれの解決策を見ていきます。

解決策

ずばり、billing_cycle_anchor の値を UTC の 0 時に設定してしまうことです。
つまり JST でいうと、朝 9 時です。

早速やっていきます、今回は8/8に更新するとして

  • 2023/08/08 09:00:00(JST)
  • 2023/08/08 00:00:00(UTC)

のタイムスタンプ(1691452800)で登録します。

curl https://api.stripe.com/v1/subscriptions \
-u "your api key" \
-d customer=cus_ONxvemk1xTB4at \
-d "items[0][price]"=price_1NR7TZIZmiK0iNLQf9VNZ3mt \
-d billing_cycle_anchor=1691452800

StripeDashboard 上をみると 8 月 8 日となっていることが分かります。

次に CustomerPortal を再度確認すると、こちらも 8 月 8 日となっていることが分かります。

これで Dashboard と Customer Portal の表示が一致しました。

問題点

この方法で一つ問題点があるとすれば、支払い開始日時を固定することで
日割り計算をしない場合に、無料期間に差が出てしまう事です。

例えば以下のような条件があり、

  • サブスクリプション申し込み翌日の 0 時(UCT)に請求を開始する
  • 申込から請求開始日時までの間は無料期間とする(proration_behavior
    :none)

A さん、B さん二人の Customer が存在し、以下の時間に申し込んだとします。

  • A さん:8 月 4 日 00:00:01
  • B さん:8 月 4 日 23:59:59

二人とも、仕様に基づき8 月 5 日 00:00:00 に請求が開始されることになりますが

日割りしないため、それぞれ無料で使える期間が

  • A さんは: 23 時間 59 分 59 秒
  • B さんは: 0 時間 0 分 1 秒

となり、ほぼ 1 日分の差が出てしまいます。

この差分が OK なのか NG なのかは、要件次第かと思いますが、一応注意が必要ですね。

そもそも Stripe では 1 秒単位で日割り計算をしてくれるので、日割りを行うようにしておくのがいいのかもしれません。

おまけ

実はStripeにおけるこの日時の問題ですが結構厄介なケースがあり
請求日が月末になったり月始になったりコロコロ変わるケースがあります。

そちらに関しては以下のブログに詳細にまとめられているので、興味がある方は是非ご覧ください!

まとめ

今回は、Customer Portal と Stripe Dashboard 上での日付のズレ問題を解消しました。
Customer Portal も現地時間で表示してくれるようになると嬉しいですね。

ちなみに今回はBilling Cycle Anchorの日時についてお話ししましたが、
Subscription Scheduleを使っている場合は、Scheduleのstart_date/end_dateの値にも同じことが言えます。
(厳密にいうと、Billing Cycle Anchorがphase_startになってる場合のstart_date/end_dateの話になりますね)

サブスクリプションの切り替えのタイミングの日時については気を付けていきたいところです。

ではまた!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です