💵

【Shopify.dev和訳】Apps/App billing/Subscriptions

2021/11/26に公開

この記事について

この記事は、Apps/App billing/Subscriptionsの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://apps.shopify.com/shopify-application-314?locale=ja&from=daniel

Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。

https://apps.shopify.com/font-picker-1?locale=ja&from=daniel

Billing API で定期的な購読を管理する

Shopify は、定期購入の管理に役立つ課金機能を提供しています。以下のセクションでは、GraphQL Admin API を使用して定期購入を管理する方法を説明します。

AppSubscription リソースの実装

AppPurchaseOneTime リソースは、2 つの課金モデルをサポートしています。

定期的な課金

appSubscriptionCreateミューテーションを使用して、定期的な課金を作成できます。ラインアイテムのプランの appRecurringPricingDetails フィールドを使用して、プランの詳細を指定できます。namepricereturnUrlintervalを指定します。intervalフィールドには 2 つの値を指定できます。EVERY_30_DAYSまたはANNUALです。間隔フィールドが提供されない場合、間隔はデフォルトでEVERY_30_DAYSとなります。

currencyCodeは、USD のみ入力可能です。returnUrlは、マーチャントがチャージを承認した後にリダイレクトされる場所で、チャージ ID も含まれます。

mutation {
  appSubscriptionCreate(
    name: "Super Duper Recurring Plan"
    returnUrl: "http://super-duper.shopifyapps.com"
    lineItems: [
      {
        plan: {
          appRecurringPricingDetails: {
            price: { amount: 10.00, currencyCode: USD }
            interval: EVERY_30_DAYS
          }
        }
      }
    ]
  ) {
    userErrors {
      field
      message
    }
    confirmationUrl
    appSubscription {
      id
    }
  }
}

JSON レスポンス

mutation はアプリのサブスクリプション ID を返します。

{
  "data": {
    "appSubscriptionCreate": {
      "userErrors": [],
      "confirmationUrl": "https://domain.myshopify.com/admin/charges/4019552312/confirm_recurring_application_charge?signature=BAh7BzoHaWRsKwc4gJXvOhJhdXRvX2FjdGl2YXRlVA%3D%3D--74e39487ff00313ca4409dea7ab00081001c45d5",
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4019552312"
      }
    }
  },
  ...
}

使用量ベースの課金

使用量ベースの課金を設定するには、2 つのステップが必要です。

  • appSubscriptionCreatemutation で利用料金プランを作成します。
  • 使用量の記録を作成します。

利用料金プランの作成

appSubscriptionCreateミューテーションを使用して、利用料金プランを作成することができます。このパラメータは、マーチャントが Shopify の 30 日の請求サイクル内で請求される使用量の最大値を示します。また、マーチャントが価格プランを承認する際に確認するtermsフィールドも含める必要があります。ペイロードに含まれるアプリのサブスクリプション ID とラインアイテム ID は、後で使用記録を作成するために使用されます。

コピー

mutation {
  appSubscriptionCreate(
    name: "Super Duper Capped Pricing Plan"
    returnUrl: "http://super-duper.shopifyapps.com"
    lineItems: [
      {
        plan: {
          appUsagePricingDetails: {
            terms: "$1 for 100 emails"
            cappedAmount: { amount: 20.00, currencyCode: USD }
          }
        }
      }
    ]
  ) {
    userErrors {
      field
      message
    }
    confirmationUrl
    appSubscription {
      id
      lineItems {
        id
        plan {
          pricingDetails {
            __typename
          }
        }
      }
    }
  }
}

JSON のレスポンス

mutation は、利用記録の作成に使用できるアプリのサブスクリプション ID とラインアイテム ID を返します。

{
  "data": {
    "appSubscriptionCreate": {
      "userErrors": [],
      "confirmationUrl": "https://domain.myshopify.com/admin/charges/4019585080/confirm_recurring_application_charge?signature=BAh7BzoHaWRsKwc4AJbvOhJhdXRvX2FjdGl2YXRlVA%3D%3D--924efed32be5c4af3c94c427ecbf380aef88f123",
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4019585080",
        "lineItems": [
          {
            "id": "gid://shopify/AppSubscriptionLineItem/4019585080?v=1&index=0",
            "plan": {
              "pricingDetails": {
                "__typename": "AppUsagePricing"
              }
            }
          }
        ]
      }
    }
  },
  ...
}

また、1 つのミューテーションを使って、定期的な料金プランと利用料金プランを作成することもできます。

mutation {
  appSubscriptionCreate(
    name: "Super Duper Capped Pricing Plan"
    returnUrl: "http://super-duper.shopifyapps.com"
    lineItems: [
      {
        plan: {
          appUsagePricingDetails: {
            terms: "$1 for 100 emails"
            cappedAmount: { amount: 20.00, currencyCode: USD }
          }
        }
      }
      { plan: { appRecurringPricingDetails: { price: { amount: 10.00, currencyCode: USD } } } }
    ]
  ) {
    userErrors {
      field
      message
    }
    confirmationUrl
    appSubscription {
      id
      lineItems {
        id
        plan {
          pricingDetails {
            __typename
          }
        }
      }
    }
  }
}

JSON レスポンス

{
  "data": {
    "appSubscriptionCreate": {
      "userErrors": [],
      "confirmationUrl": "https://domain.myshopify.com/admin/charges/4028497976/confirm_recurring_application_charge?signature=BAh7BzoHaWRsKwc4AB7wOhJhdXRvX2FjdGl2YXRlVA%3D%3D--987b3537018fdd69c50f13d6cbd3fba468e0e9a6",
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4028497976",
        "lineItems": [
          {
            "id": "gid://shopify/AppSubscriptionLineItem/4028497976?v=1&index=0",
            "plan": {
              "pricingDetails": {
                "__typename": "AppRecurringPricing"
              }
            }
          },
          {
            "id": "gid://shopify/AppSubscriptionLineItem/4028497976?v=1&index=1",
            "plan": {
              "pricingDetails": {
                "__typename": "AppUsagePricing"
              }
            }
          }
        ]
      }
    }
  },
  ...
}

利用記録の作成

利用料金プランを作成し、マーチャントがプランを承認したら、利用記録を作成できます。利用記録には、appSubscriptionCreatemutation で返されたアプリサブスクリプションのラインアイテム ID を含める必要があります。

mutation {
  appUsageRecordCreate(
    subscriptionLineItemId: "gid://shopify/AppSubscriptionLineItem/4019585080?v=1&index=0"
    description: "Super Mega Plan 1000 emails"
    price: { amount: 1.00, currencyCode: USD }
  ) {
    userErrors {
      field
      message
    }
    appUsageRecord {
      id
    }
  }
}

JSON のレスポンス

このミューテーションでは、作成された利用記録のアプリ利用記録 ID を返します。

{
  "data": {
    "appUsageRecordCreate": {
      "userErrors": [],
      "appUsageRecord": {
        "id": "gid://shopify/AppUsageRecord/14518231"
      }
    }
  },
  ...
}

上限額の更新

利用料金プランの利用記録を、新しい利用記録よりも少ない金額で作成しようとすると、リクエストは失敗します。利用記録を増やすには、上限額を増やしてマーチャントの承認を得る必要があります。

作成された AppSubscription の ID をクエリすると、cappedAmountbalanceUsed フィールドを確認できます。

query {
  node(id: "gid://shopify/AppSubscription/4019585080") {
    ... on AppSubscription {
      lineItems {
        plan {
          pricingDetails {
            ... on AppUsagePricing {
              terms
              cappedAmount {
                amount
                currencyCode
              }
              balanceUsed {
                amount
                currencyCode
              }
            }
          }
        }
      }
    }
  }
}

JSON レスポンス

{
  "data": {
    "node": {
      "lineItems": [
        {
          "plan": {
            "pricingDetails": {
              "terms": "$1 for 100 emails",
              "cappedAmount": {
                "amount": "20.0",
                "currencyCode": "USD"
              },
              "balanceUsed": {
                "amount": "0.0",
                "currencyCode": "USD"
              }
            }
          }
        }
      ]
    }
  },
  ...
}

上限額を増やすには、appSubscriptionLineItemUpdateミューテーションを使用できます。

mutation {
  appSubscriptionLineItemUpdate(
    id: "${AppSubscriptionLineItemUsagePricing_gid}"
    cappedAmount: { amount: 100.00, currencyCode: USD }
  ) {
    userErrors {
      field
      message
    }
    confirmationUrl
    appSubscription {
      id
    }
  }

JSON レスポンス

このレスポンスには、新しい confirmationUrl と appSubscription ID が含まれます。

{
  "data": {
    "appSubscriptionLineItemUpdate": {
      "userErrors": [],
      "confirmationUrl": "https://domain.myshopify.com/admin/charges/4019585080/confirm_update_capped_amount?signature=BAh7BzoHaWRsKwc4AJbvOhJhdXRvX2FjdGl2YXRlRg%3D%3D--a93b35054feb213f04f1ee35ef5b569617ce6823",
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4019585080"
      }
    }
  },
  ...
}

アップグレードとダウングレード

マーチャントは一度に 1 つのアプリのサブスクリプションしか持つことができません。つまり、マーチャントがアプリをアップグレードまたはダウングレードした場合、古いサブスクリプションはキャンセルされ、新しいサブスクリプションに置き換えられます。マーチャントがアプリをアップグレードまたはダウングレードした場合、新しいサブスクリプションは、前回の購入と同じ 30 日間のアプリ課金サイクルをとります。これは、マーチャントがアプリをアンインストールして再インストールした場合にも適用されます。

Image from Gyazo

新しいサブスクリプションに試用期間が含まれている場合、マーチャントは次の 30 日間のアプリ請求サイクルの開始時に請求されますが、請求書には試用期間を考慮した按分されたクレジットが含まれています。

Image from Gyazo

マーチャントがより高額なサブスクリプションにアップグレードした場合、Shop は同じ請求サイクルで請求額を按分します。例えば、5 ドルのプランで 30 日間の請求サイクルを開始し、請求サイクルの 15 日目に 15 ドルのプランにアップグレードした場合、5ドル+(15ドル-5ドル)*(15/30)=10ドルの請求となります。

マーチャントがダウングレードした場合、Shopify は同じ請求サイクルを維持しながら、マーチャントのために按分されたアプリクレジットを生成します。例えば、マーチャントが 20 ドルのプランで 30 日間の請求サイクルを開始し、請求サイクルの 15 日目に 10 ドルのプランにダウングレードした場合、マーチャントには(20.00ドル - 10.00ドル) * (15/30) = 5.00ドルのアプリクレジットが提供されます。パートナーへの支払いは、発行されたクレジットとパートナーのレベニューシェアに基づいて自動的に調整されます。

サブスクリプションのキャンセル

マーチャントがアプリをアンインストールすると、そのアプリのサブスクリプションは自動的にキャンセルされます。

マーチャントに代わってサブスクリプションをキャンセルしたい場合は、appSubscriptionCancelmutation を使用できます。

mutation {
  appSubscriptionCancel(id: "gid://shopify/AppSubscription/4019585080") {
    userErrors {
      field
      message
    }
    appSubscription {
      id
      status
    }
  }
}

JSON レスポンス

レスポンスでは、解約したサブスクリプションの ID を返します。

{
  "data": {
    "appSubscriptionCancel": {
      "userErrors": [],
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4019585080",
        "status": "CANCELLED"
      }
    }
  },
  ...
}

次のステップ

GraphQL Admin API を使用した年間契約の作成

このチュートリアルでは、GraphQL Admin API を使用して、アプリケーションの継続的な課金である年間サブスクリプションを作成する方法を説明します。サブスクリプションを使用するには、アプリのインストール、サービスプランのアップグレード、または個別の購入などのマーチャントトリガーを実装する必要があります。

現在、REST Admin API を課金に使用している場合は、同じ認証トークンを使用して GraphQL Admin API で年間契約を作成することができます。

制限事項

課金には以下のような制限があります。

  • 年間契約は使用量課金をサポートしていません。
  • 年間契約は、REST 管理 API ではサポートされていません。

GraphQL Admin API での年間課金の仕組み

年間契約の作成とユーザーへの発行は、複数のステップで行われます。

  1. マーチャントは、アプリのインストールやサービスプランのアップグレードなど、サブスクリプションを含むマーチャントトリガーを開始します。
  2. アプリがアプリの年間購読を作成する。
  3. Shopify はサブスクリプションを確認して confirmUrl を返し、マーチャントはサブスクリプションを承認または拒否するためにリダイレクトされます。
  4. マーチャントがサブスクリプションを受け入れると、アプリがサブスクリプションを発行したときにアプリが指定した returnUrl にリダイレクトされます。
  5. サブスクリプションが拒否された場合、Shopify はマーチャントを Shopify の管理画面にリダイレクトし、アプリのサブスクリプションが拒否されたことを示す通知メッセージを提供します。

Image from Gyazo

年間契約の作成

appSubscriptionCreatemutation を使用して、年間サブスクリプションを作成できます。プランの詳細を指定するには、ラインアイテムのプランの appRecurringPricingDetails フィールドを使用します。namepriceinterval、および returnUrlを提供します。returnUrl」は、定期購入を受け入れた後にマーチャントがリダイレクトされる場所です。この URL には、チャージ ID を含める必要があります。

intervalフィールドには、2 つの可能な値を入力できます。

  • EVERY_30_DAYS (デフォルト)
  • ANNUAL

intervalフィールドが提供されない場合、間隔のデフォルトはEVERY_30_DAYSとなります。

mutation {
  appSubscriptionCreate(
    name: "Product Photos PRO"
    returnUrl: "https://www.shopify.com"
    lineItems: [
      {
        plan: {
          appRecurringPricingDetails: {
            price: { amount: 10.00, currencyCode: USD }
            interval: ANNUAL
          }
        }
      }
    ]
  ) {
    appSubscription {
      id
    }
    confirmationUrl
    userErrors {
      field
      message
    }
  }
}

JSON レスポンス

{
  "data": {
    "appSubscriptionCreate": {
      "userErrors": [],
      "confirmationUrl": "https://domain.myshopify.com/admin/charges/4019552312/confirm_recurring_application_charge?signature=BAh7BzoHaWRsKwc4gJXvOhJhdXRvX2FjdGl2YXRlVA%3D%3D--74e39487ff00313ca4409dea7ab00081001c45d5",
      "appSubscription": {
        "id": "gid://shopify/AppSubscription/4019552312"
      }
    }
  }
}

既存の年間契約の移行

ワンタイムチャージまたは使用料のワークアラウンドを使用して年間契約を提供している場合、以下のいずれかの方法でマーチャントを年間契約 API に移行することができます。

  • マーチャントの年間更新の期限が来たら、年間契約 API を使用して構築された新しい年間契約プランにマーチャントを誘導する。
  • マーチャントに年間支払額の未使用分のアプリクレジットを発行し、新しい年間契約に加入してもらいます。例えば、年間購読料が 120 ドルで、マーチャントの購読期間が 6 ヶ月残っている場合、60 ドルのアプリクレジットをマーチャントに発行します。

プランの変更

アプリは、マーチャントごとに 1 つの定期的なアプリ料金しか設定できません。現在のプランが有効な間にマーチャントがサブスクリプションを変更した場合、マーチャントは新しい定期的なアプリ課金を受け入れる必要があります。マーチャントが承認すると、既存のアプリ定期課金はキャンセルされ、新しい課金に置き換えられます。

マーチャントがより高い価格の年間プランに変更した場合、新規購読料はプラン価格の差額と請求サイクルの残り時間に基づいて按分されます

マーチャントが、より高い価格の年間プランからより低い価格の年間プランに変更した場合、または年間プランから 30 日プランに変更した場合、新しいプランの料金は、現在のプランのサブスクリプションサイクルが完了するまで延期されます。例えば、マーチャントが 1 月に年間プランを開始し、9 月に 30 日プランに変更した場合、新しい 30 日プランは、1 月に年間プランの期限が切れたときに開始されます。

キャンセルと返金

マーチャントが更新日前に年間契約をキャンセルした場合、契約の残りの請求期間中はアプリを使用することができます。キャンセルは年間更新日に有効になります。

マーチャントが年間契約の返金を要求した場合、Shopify はあなたに日割り計算による返金の許可を求めます。

あなたはこれらの要求を承認するかどうかを決めることができます。承認したリクエストについては、マーチャントに返金する金額を指定する必要があります。解約はお客様の責任で行ってください。リクエストが承認された後、返金された金額は次回のパートナーペイアウトから差し引かれます。

用語解説

Subscription(サブスクリプション): パートナーが定義した条件に基づいて、マーチャントがアプリを使用することを約束すること。条件には、マーチャントによる定期的な課金の事前承認、間隔で発生する課金、またはアプリの使用による課金、サブスクリプションを通じてマーチャントが利用できるアプリの機能の概要が含まれます。各サブスクリプションは、パートナーとマーチャントの間の請求契約に記録され、サブスクリプションに関連する料金はマーチャントの Shopify 請求書に 1 行項目として追加されます。

Interval(インターバル): アプリのサブスクリプションに対してマーチャントに発行される定期的な請求を作成する頻度です。間隔は毎月または毎年に設定できます。

Proration: サブスクリプションのインターバルのうち、未使用だが既に支払われた部分を評価すること。按分された値は、その後のマーチャントの請求書に反映されます。按分は、マーチャントがアプリのサブスクリプションの変更を承認し、それが直ちに有効になった場合に発生します。

Deferral(延期):マーチャントのサブスクリプションに対する承認済みの変更を、現在のインターバルが完了するまで延期することです。延期は、マーチャントがアプリサブスクリプションへの変更を承認しても、現在のインターバルが完了するまでは有効にならない場合に発生します。

FAQ

既に回避策を講じて年間契約を導入している場合、なぜこの新しい API 機能を採用する必要があるのでしょうか?
マーチャントとデベロッパーの利便性を考慮して、この新しい機能を構築しました。年間契約は自動的に更新されるので、手動で更新作業をする必要がありません。マーチャントは、年間契約の料金や条件を明確に理解することができるので、より良い体験をすることができます。

また、アップグレードやダウングレードなどのサブスクリプションの更新に対応するために、proration と deferral のロジックを構築しました。年間契約を作成するための専用の方法を持つことで、データの整合性が保たれ、さまざまな間隔で指標を追跡することができます。

年間契約は無料トライアルに対応していますか?
はい、年間契約は、30 日契約と同様に無料トライアルをサポートしています。

なぜ年間契約では使用料をサポートしないことにしたのですか?
使用料には上限があり、サブスクリプションの請求サイクルと密接に関連しているため、年単位で使用料や上限を有効にすることは現実的ではありません。仮に 1 年間で使用料が発生した場合、使用料の額は大きく、予測できないものになります。これでは、加盟店の財務管理が難しくなり、年内に上限を超えてしまうと問題が発生する可能性があります。また、アプリ開発者としては、利用料の支払いを受けるまで 1 年間待たなければならず、財務上のリスクが大きくなります。

アプリの価格に使用料が含まれていますが、使用料を年間契約に適用することはできますか?
現在のところ、年間契約での使用料はサポートしていませんが、将来的にはこの機能を導入する可能性があります。

REST API で年間契約をサポートしないことにした理由は何ですか?
GraphQL はより効率的にデータを取得することができ、Shopify の API 構築のための技術として選ばれているためです。今まで GraphQL の採用を躊躇していたのであれば、部分的に統合して、同じ認証トークンを使って GraphQL Admin API で年間契約を作成するという選択肢もありますので、この機会に少しずつ始めてみてはいかがでしょうか。

私のアプリが REST API を使用していて、新しい間隔が GraphQL でしか利用できない場合、この新しい年間契約をどのように利用できますか?
現在、REST Admin API を課金に使用している場合は、同じ認証トークンを使用して GraphQL Admin API で年間契約を作成できます。GraphQL についての詳細は、Shopify and GraphQLを参照してください。

アプリ開発者はいつ年間購読の支払いを受け取りますか?
年間購読からの支払いは、30 日購読と同じように動作します。マーチャントがサブスクリプションを承認すると、料金は次の Shopify 請求書に追加されます。請求書が支払われると、未収金額がペイアウトに追加され、月に 2 回支払われます。詳細については、アプリの課金をご覧ください。

次のステップ

Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://apps.shopify.com/shopify-application-314?locale=ja&from=daniel

Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。

https://apps.shopify.com/font-picker-1?locale=ja&from=daniel

Discussion

ログインするとコメントできます