【Stripe】既存のSubscriptionにScheduleを追加して更新する

こんにちは、サイオステクノロジーの佐藤 陽です。

今回は Subscription Schedule のちょっとした Tips をご紹介します。
ニッチな部分ではありますが、誰かに刺さることを願って書きたいと思います。

  • Subscription Schedule 使いこなしたい!
  • Subscription Schedule の更新がうまくいかない。

という人は是非最後までご覧ください。

はじめに

Subscription Schedule は、Subscription の変更をあらかじめ設定しておき
指定したタイミングで、自動で Subscriptionの内容を切り替えたり、キャンセルするといった便利機能です。

非常に便利な機能なのですが、その分使いこなすのもやや難しい印象です。

今回は以下のようなケースの実装例を紹介したいと思います。

  1. 既に Subscription が存在する(Schedule なし)
  2. この Subscription に対して Schedule を追加し、即座にプランの変更を実施する

ポイントとしては「即座にプランの変更を実施する」です。

イメージとしてはこのような感じです。

準備

サブスクリプションを扱うにあたり

  • 商品・価格オブジェクト
  • 支払いカード割り当て済みの顧客オブジェクト

については、作成してあるものとして話を進めていきます。

今回は、商品に関して

  • STANDARD(10,000 円/月)
  • PREMIUM(20,000 円/月)

の2種類を作成しました。

要件(スケジュール)

組みたい要件(スケジュール)としては以下の通りです。

  1. STANDARDを新規契約する
    ~ 一定時間経過 ~
  2.  PREMIUM への変更と同時に、以下のSchedule追加する
    ・ 1 Iteration分だけ PREMIUM を利用後、STANDARD に戻す(今回であれば 1 ヵ月)
  3. その後 Schedule を Release する。

(あんまりよくわからない要件ですが、そこは目をつむってください。)

環境

APIバージョンは2023-08-16を利用します。

APIのコールにはcurlを利用していきます。
各言語SDKでも同じことができると思うので、パラメータを参考にして実装してみてください。

実装

以下の流れで実装していきます。

  1. 新規にサブスクリプション作成
  2. 既存のサブスクリプションを元に Schedule を作成
  3. Schedule の内容を更新

それでは進めていきましょう。

新規にサブスクリプション作成

まずはサブスクリプションを作成していきます。
STANDARDの商品を一つ契約する Subscription を作成します。

STRIPE_SECRET_KEY=""

curl https://api.stripe.com/v1/subscriptions \
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'customer=cus_OdiWVHTctWeyRI' \
-d 'items[0]price=price_1NqQlgE7qHO17eJUQnSUd7ru' #STANDARD priceId

作成が完了したら、レスポンスに含まれるSubscriptionId を控えておきましょう。(sub_1NqRATE7qHO17eJURAJwAorV)

既存の Subscription に対して Schedule を作成

作成したサブスクリプションに対して Schedule を作成していきます。

CreateSubscriptionSchedulefrom_subscriptionというパラメータが存在するため、こちらを利用します。

このパラメータの説明には以下のように書かれています。

Migrate an existing subscription to be managed by a subscription schedule. If this parameter is set, a subscription schedule will be created using the subscription’s item(s), set to auto-renew using the subscription’s interval. When using this parameter, other parameters (such as phase values) cannot be set. To create a subscription schedule with other modifications, we recommend making two separate API calls.

from_subscriptionを使った場合は、Phase などのパラメータは使えませんよって書いてあります。

つまり、既存のサブスクリプションに対して Schedule を追加し、なおかつ Schedule の内容を変更することを一回のコールでは許容してないようです。

なのでここではひとまず、Schedule を追加するだけのリクエストを送ってみます。

STRIPE_SECRET_KEY=""

curl -L 'https://api.stripe.com/v1/subscription_schedules' \
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'from_subscription=sub_1NqRATE7qHO17eJURAJwAorV' #先ほど作成したSubscriptionId

レスポンスとしては以下の内容が返ってきました。

{
  "id": "sub_sched_1NqRNeE7qHO17eJUmno71IQy",
  "object": "subscription_schedule",
  "application": null,
  "canceled_at": null,
  "completed_at": null,
  "created": 1694743418,
  "current_phase": {
    "end_date": 1697334601,
    "start_date": 1694742601
  }
  (略)
  "end_behavior": "release",
  (略)
}

Subscription Schedule Idは、改めて使うので控えておきましょう(sub_sched_1NqRNeE7qHO17eJUmno71IQy)

またこの時、レスポンスから

  • end_behaviorが”release”である
  • start_dateとend_dateが1 Iteration分である
  • Phaseが1つしか含まれていない

ということが分るため、

from_subscriptionでScheduleを追加した場合は、 1 Iteration分だけのScheduleが組まれるようです。

Schedule の内容を更新

次に、この Schedule の Phase の内容を切り替えていきます。

※Phaseというのは、スケジュール内における塊の単位です。
各Phaseに対して、どのPriceを適用するのか、どの長さにするのか、等を設定できます。

繰り返しになりますが、要件としては

  1. STANDARD をすぐに PREMIUM に変更し
  2. 1か月経過した後にSTANDARDへ変更

です。

最初、以下の内容で Schedule を Update すればいいのでは?と考えました。

phase[0]:PREMIUM
phase[1]:STANDARD

一度この内容で、UpdateSchedule のリクエスト作成し、送ってみます。

※少し話が逸れますが、1つポイントとして、start_dateに”now”というパラメータを設定しています。

これはStripe側で自動で現在時刻を設定してくれるものであり、
テストクロックを利用した場合も、その時間軸での現在時刻を設定してくれます。
なので、アプリ上で現在時刻を値として与えるのではなく、”now”を使う事を推奨します。

STRIPE_SECRET_KEY=""

curl -L 'https://api.stripe.com/v1/subscription_schedules/sub_sched_1NqRNeE7qHO17eJUmno71IQy' \ # 先ほど作成したSchedule
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'phases[0][items][0][price]=price_1NqQlgE7qHO17eJUDIF2tl6f' \ #STANDARDのpriceId
-d 'phases[0][items][0][quantity]=1' \
-d 'phases[0][start_date]=now' \
-d 'phases[0][iterations]=1' \
-d 'phases[1][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \ #PREMIUMのpriceId
-d 'phases[1][items][0][quantity]=1' \
-d 'phases[1][iterations]=1'

以下のレスポンスが返ってきました。

{
  "error": {
    "message": "You can not modify the start date of the current phase.",
    "request_log_url": "https://dashboard.stripe.com/test/logs/req_6yPP3HqTApLXUC?t=1694746189",
    "type": "invalid_request_error"
  }
}

なるほど!
currentPhase の start_date は変更できないようです。
もう始まってしまっている部分のパラメータは変えられないようですね。

なので、以下のようにリクエスト内容を変えてやりました。

処理の内容としては、

  1. 現在の Phase (STANDARD)を即時終了させる
  2. PREMIUM の Phase を 1 Iteration 分追加する
  3. STANDARD の Phase を 1 Iteration 分追加する

という流れです。(下図(A))

STRIPE_SECRET_KEY=""

curl -L 'https://api.stripe.com/v1/subscription_schedules/sub_sched_1NqRNeE7qHO17eJUmno71IQy' \ # 先ほど作成したSchedule
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'phases[0][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \ #STANDARDのpriceId
-d 'phases[0][items][0][quantity]=1' \
-d 'phases[0][start_date]=1694742601' \ #Schedule作成時のレスポンスからstart_dateを取得
-d 'phases[0][end_date]=now' \ #CurrentPhaseを即時終了させる
-d 'phases[1][items][0][price]=price_1NqQlgE7qHO17eJUDIF2tl6f' \ #PREMIUMのpriceId
-d 'phases[1][items][0][quantity]=1' \
-d 'phases[1][iterations]=1' \
-d 'phases[2][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \ #STANDARDのpriceId
-d 'phases[2][items][0][quantity]=1' \
-d 'phases[2][iterations]=1'

これを実行すると、即座に PREMIUMプランに更新され
なおかつ 1 Iteration 分だけ PREMIUMプランを利用した後、STANDARD に戻る Schedule が作成されました!

また、こういった書き方もできるかな?と思いました。

STRIPE_SECRET_KEY=""

curl -L 'https://api.stripe.com/v1/subscription_schedules/sub_sched_1NqRNeE7qHO17eJUmno71IQy' \ # 先ほど作成したSchedule
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'phases[0][items][0][price]=price_1NqQlgE7qHO17eJUDIF2tl6f' \ #PREMIUMのpriceId
-d 'phases[0][items][0][quantity]=1' \
-d 'phases[0][start_date]=1694746172' \ #Schedule作成時のレスポンスからstart_dateを取得
-d 'phases[0][iterations]=1' \
-d 'phases[1][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \ #STANDARDのpriceId
-d 'phases[1][items][0][quantity]=1' \
-d 'phases[1][iterations]=1'

これはCurrent Phase上書きパターンですね。(下図(B))

ただ、こうしたときに注意が必要なのは、プレミアムプランが1 Iteration分続かない事です。
あくまでPhaseのIterationが1なので、Schedule作成時から1 Iteration分の期間が経過すると、自動的にStandardプランに戻ってしまいます。

なのでPREMIUMプランが1か月続かないことから、今回の要件には適しませんね。

このあたり、end_dateとのパラメータの設定でも調整できると思いますので
ビジネス要件に合わせて柔軟に設定してみてください。

支払請求日について

また、ここでひとつ注意したいのが、支払い請求日とPhaseの変更日は別物である事です。

もしScheduleのPhase変更タイミングに支払い請求日も変更したい場合は
Phaseのbilling_cycle_anchorをphase_startに設定する必要があります。

(A)のパターンでPREMIUMへの変更時に支払い請求日を変更したい場合は

phases[1][billing_cycle_anchor]=phase_start

を利用し、以下のように変更します。

STRIPE_SECRET_KEY=""

curl -L 'https://api.stripe.com/v1/subscription_schedules/sub_sched_1NqRNeE7qHO17eJUmno71IQy' \ # 先ほど作成したSchedule
-H "Authorization: Bearer ${STRIPE_SECRET_KEY}" \
-d 'phases[0][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \
-d 'phases[0][items][0][quantity]=1' \
-d 'phases[0][start_date]=1694742601' \ #Schedule作成時のレスポンスからstart_dateを取得
-d 'phases[0][end_date]=now' \ #CurrentPhaseを即時終了させる
-d 'phases[1][items][0][price]=price_1NqQlgE7qHO17eJUDIF2tl6f' \
-d 'phases[1][items][0][quantity]=1' \
-d 'phases[1][start_date]=now' \
-d 'phases[1][iterations]=1' \
-d 'phases[1][billing_cycle_anchor]=phase_start' \ #支払い請求日をPhaseの開始日に合わせる
-d 'phases[2][items][0][price]=price_1NqQlgE7qHO17eJUQnSUd7ru' \
-d 'phases[2][items][0][quantity]=1' \
-d 'phases[2][iterations]=1'

まとめ

今回は既存のSubscriptionにScheduleを追加し、なおかつその内容を更新する流れについて触れてみました。
Subscription Scheduleの扱いに関しては、パラメータも多く難しい部分もありますが、使いこなしていきたいところです。

自分も書いている間に混乱しがちだったので、
もっとシンプルに実装できるよ!ここ間違えてるよ!!
なんて事があればぜひぜひコメントお願いします。

ではまた!

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

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

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

コメントを残す

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