Skip to content

Commit

Permalink
premium apps: Support for multiple subscription tiers (#7304)
Browse files Browse the repository at this point in the history
* support multiple subscription tiers

* Update docs/resources/Subscription.md

Co-authored-by: Mihail Gribkov <[email protected]>

* update entitlement_ids and sku_ids

* our beloved tables

---------

Co-authored-by: Mihail Gribkov <[email protected]>
  • Loading branch information
colinloretz and Misha-133 authored Dec 12, 2024
1 parent e70f3ce commit 5af3428
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: "Premium Apps: Multiple Subscription Tiers"
date: "2024-12-12"
topics:
- "Premium Apps"
---

Developers with monetization enabled can now create and publish multiple subscription SKUs of the same type for their app. This allows developers to offer different subscription tiers with varying benefits and pricing. Users can upgrade and downgrade between published subscription SKUs.

### What's Changed

#### Developer Portal
- Under the `Monetization` tab, you can now publish multiple subscription SKUs of the same type for your app.

#### App's Store Page
- When multiple subscription SKUs are published: Users can now upgrade or downgrade between different published subscription SKUs.

#### User App Subscription Settings
- When multiple subscription SKUs are published: Users can now upgrade or downgrade between different published subscription SKUs.
- These settings are available under `User Settings → Subscriptions → App Subscriptions`.

#### Subscription Object
- New field `renewal_sku_ids` added to the [subscription object](#DOCS_RESOURCES_SUBSCRIPTION/subscription-object) response for `SUBSCRIPTION_UPDATE` events and API endpoints.
- `renewal_sku_ids` is a list of snowflakes that indicate the SKU(s) that the user will be subscribed to at renewal.

#### Updated Guide: Managing SKUs
- The [Managing SKUs](#DOCS_MONETIZATION_MANAGING_SKUS/creating-a-sku) guide has been updated to include information about creating and managing multiple subscription SKUs.

#### Updated Guide: Implementing App Subscriptions
- The [Implementing App Subscriptions](#DOCS_MONETIZATION_IMPLEMENTING_APP_SUBSCRIPTIONS/supporting-upgrades-and-downgrades) guide has been updated to include information about supporting upgrades and downgrades between multiple subscription SKUs.
93 changes: 91 additions & 2 deletions docs/monetization/Implementing_App_Subscriptions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Because entitlements are granted indefinitely and don't update on renewal or can
| `SUBSCRIPTION_CREATE` | Subscription is created | `status` is either `0 (active)` if an entitlement has been granted or `1 (ending)` if an entitlement has not yet been granted |
| `SUBSCRIPTION_UPDATE` | Subscription is granted an entitlement | `status` is `0 (active)` |
| `SUBSCRIPTION_UPDATE` | Subscription is renewed | `current_period_start`, `current_period_end` timestamps updated |
| `SUBSCRIPTION_UPDATE` | Subscription is upgraded or downgraded | `sku_ids`, `entitlement_ids`, `renewal_sku_ids` may be updated |
| `SUBSCRIPTION_UPDATE` | Subscription is canceled | `canceled_at` timestamp updated, `status` is `1 (ending)` |
| `SUBSCRIPTION_UPDATE` | Subscription ends | `status` is `2 (inactive)`, this event is processed asynchronously and will not be immediate |
| `SUBSCRIPTION_UPDATE` | Subscription is resumed/uncanceled by user | `status` is `0 (active)` |
Expand All @@ -60,7 +61,7 @@ For subscription SKUs, you will receive the following entitlement events:
| Event | Description |
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `ENTITLEMENT_CREATE` | When a user is granted an entitlement to your app's subscription SKU |
| `ENTITLEMENT_UPDATE` | When a subscription ends |
| `ENTITLEMENT_UPDATE` | When an entitlement to a subscription SKU ends |
| `ENTITLEMENT_DELETE` | When Discord refunds a subscription, removes an entitlement, or when a developer [deletes a Test Entitlement](#DOCS_RESOURCES_ENTITLEMENT/delete-test-entitlement) |

### Accessing Entitlements with the HTTP API
Expand Down Expand Up @@ -91,14 +92,102 @@ You can do this by sending a message with a [button](#DOCS_INTERACTIONS_MESSAGE_

If you are using the [Embedded App SDK](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK) to build an [Activity](#DOCS_ACTIVITIES_OVERVIEW), you can also launch the purchase flow for a specific SKU using the SDK. Check out the [Implementing In-App Purchases for Activities](#DOCS_MONETIZATION_IMPLEMENTING_IAP_FOR_ACTIVITIES) guide to learn more about monetization with the Embedded App SDK.

### Purchasing from the Store Page

Users can start, upgrade, or downgrade their subscription from your app's [Store](#DOCS_MONETIZATION_MANAGING_SKUS/viewing-your-store-page) page. You can link directly to your Store page using our [Application Directory Store URL scheme](#DOCS_MONETIZATION_MANAGING_SKUS/linking-to-your-store).

---

## Supporting Subscriptions

To support subscriptions in your app, you need to [create a subscription SKU](#DOCS_MONETIZATION_MANAGING_SKUS/creating-a-sku) and handle the following scenarios:

### Starting a new subscription

When a user subscribes to a new subscription, you will receive the following events:

| Event | Event Trigger |
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `SUBSCRIPTION_CREATE` | when the subscription is initially created. `status` is `0 (active)` if the entitlement has been granted or `1 (ending)` if the entitlement has not yet been granted. |
| `ENTITLEMENT_CREATE` | when the user is granted an entitlement for the new subscription |
| `SUBSCRIPTION_UPDATE` | when the subscription is updated with the `entitlement_ids`, `renewal_sku_ids`, and `status` (`0 (active)`) |

### Cancelling an existing subscription

Users can cancel their subscription at any time from their Subscription settings.

When a user cancels their subscription, you will receive the following events:

| Event | Event Trigger |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| `SUBSCRIPTION_UPDATE` | when the subscription is updated to end with a `status` of `1 (ending)` and `canceled_at` is set to the timestamp the user canceled |

The user's subscription and entitlement are still valid until the subscription `current_period_end` is reached.

If the subscription is not resumed before the subscription `current_period_end`, it will end and you will receive the following events:

| Event | Event Trigger |
|-----------------------|----------------------------------------------------------------------------|
| `ENTITLEMENT_UPDATE` | when the current entitlement ends. `ends_at` gets updated with a timestamp |
| `SUBSCRIPTION_UPDATE` | when the subscription is updated with the `status` of `2 (inactive)` |

### Resuming a cancelled subscription

Users can resume their subscription at any time before the `current_period_end` is reached in their Subscription settings.

When a user resumes their subscription, you will receive the following events:

| Event | Event Trigger |
|-----------------------|-----------------------------------------------------------------------------------------------------------|
| `SUBSCRIPTION_UPDATE` | when the subscription is set to continue with a `status` of `0 (active)` and `canceled_at` is set to null |

---

## Supporting Upgrades and Downgrades

If you offer multiple subscription tiers in your app, users can upgrade or downgrade their subscription at any time from your [Store page](#DOCS_MONETIZATION_MANAGING_SKUS/viewing-your-store-page) or their App Subscription settings.

To create multiple subscription tiers, you will need to [create multiple subscription SKUs](#DOCS_MONETIZATION_MANAGING_SKUS/creating-a-sku) and support the following scenarios in your app:

### Upgrading an existing subscription

If an user is on a lower tier subscription and upgrades to subscription tier that is the same price or higher, the user is charged the difference in price between the two subscriptions and the subscription period resets at the time of upgrading.

When the subscription is upgraded, the current entitlement for the lower tier will end immediately and you will receive the following events:

| Event | Event Trigger |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------|
| `ENTITLEMENT_UPDATE` | when the current entitlement ends. `ends_at` gets updated with a timestamp |
| `ENTITLEMENT_CREATE` | when a new entitlement is created for the upgrade subscription SKU |
| `SUBSCRIPTION_UPDATE` | when the subscription is updated with the new `entitlement_ids`, `sku_ids`, `current_period_start`, `current_period_end` |


### Downgrading an existing subscription

If an user is on a higher tier subscription and downgrades to a lower tier subscription, the user is not charged immediately because the price is lower than what was already paid.

The user has already paid for their current plan until `subscription.current_period_end` so their current plan will be valid until then and you will receive the following event:

| Event | Event Trigger |
|-----------------------|--------------------------------------------------------------------------------------------------|
| `SUBSCRIPTION_UPDATE` | when the subscription is updated to reflect the renewal SKU ID in `subscription.renewal_sku_ids` |

Once the user's current subscription expires on `subscription.current_period_end`, you will receive the following events:

| Event | Event Trigger |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------|
| `ENTITLEMENT_UPDATE` | when the current entitlement ends. `ends_at` gets updated with a timestamp |
| `ENTITLEMENT_CREATE` | when a new entitlement is created for the downgraded subscription SKU |
| `SUBSCRIPTION_UPDATE` | when the subscription is updated with the new `entitlement_ids`, `sku_ids`, `current_period_start`, `current_period_end` |

---

## Using the Subscription API

> info
> When implementing monetization, [Entitlements](#DOCS_RESOURCES_ENTITLEMENT) should be considered the source of truth for a user's access to a specific SKU. The Subscription API is intended for reporting and lifecycle management purposes that happen outside the flow of a user's interaction with your app.
You can use the [Subscription API](#DOCS_RESOURCES_SUBSCRIPTION) to check on the status of your app subscriptions. This API allows you to list all subscriptions for your app for reporting purposes and to check on the status of subscriptions without having to access entitlements directly.
You can use the [Subscription API](#DOCS_RESOURCES_SUBSCRIPTION) to check on the status of your app subscriptions. This API allows you to list subscriptions by user for reporting purposes and to check on the status of subscriptions without having to access entitlements directly.

- [List SKU Subscriptions](#DOCS_RESOURCES_SUBSCRIPTION/list-sku-subscriptions): List all subscriptions for a specific SKU in your app.
- [Get SKU Subscription](#DOCS_RESOURCES_SUBSCRIPTION/get-sku-subscription): Get a specific subscription in your app.
Expand Down
12 changes: 10 additions & 2 deletions docs/monetization/Managing_SKUs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@ When you click on `Create SKU`, you have the option to select from the following

Once you select the SKU type, enter a name for your SKU to continue.

### Creating Subscription Tiers

You can create multiple subscription tiers to offer different benefits at different price points. Each tier can have its own set of benefits and price and is represented by unique SKUs.

To support upgrading and downgrading between subscription tiers, see our guide on [Implementing App Subscriptions](#DOCS_MONETIZATION_IMPLEMENTING_APP_SUBSCRIPTIONS/supporting-upgrades-and-downgrades).

![Supporting multiple subscription tiers](multisub.png)

### SKU Limitations

There are some limitations to the number of SKUs you can create:
- You can create up to 50 total SKUs per app.
- Currently, you can only have **one** published subscription SKU per app (user or guild).
- You can offer either user subscription SKUs or guild subscription SKUs, but not both simultaneously.
- SKU prices must be selected from the list of available prices.

> info
Expand Down Expand Up @@ -162,7 +170,7 @@ Users can access an app's Store page from the Bot User's profile in a server. Th
![Accessing the store as a user](botuser-profile.png)

#### Subscriptions in Your Store page
![Subscriptions in your Store View](premium-subscriptions.png)
![Subscriptions in your Store View](multisub.png)

#### Items in Your Store page
![Items in your Store View](premium-items.png)
Expand Down
24 changes: 13 additions & 11 deletions docs/resources/Subscription.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ Subscriptions in Discord represent a user making recurring payments for at least

## Subscription Object

| Field | Type | Description |
|----------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| id | snowflake | ID of the subscription |
| user_id | snowflake | ID of the user who is subscribed |
| sku_ids | array of snowflakes | List of SKUs subscribed to |
| entitlement_ids | array of snowflakes | List of entitlements granted for this subscription |
| current_period_start | ISO8601 timestamp | Start of the current subscription period |
| current_period_end | ISO8601 timestamp | End of the current subscription period |
| status | SubscriptionStatus | Current status of the subscription |
| canceled_at | ISO8601 timestamp? | When the subscription was canceled |
| country? | string | ISO3166-1 alpha-2 country code of the payment source used to purchase the subscription. Missing unless queried with a private OAuth scope. |
| Field | Type | Description |
|----------------------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| id | snowflake | ID of the subscription |
| user_id | snowflake | ID of the user who is subscribed |
| sku_ids | array of snowflakes | List of SKUs subscribed to |
| entitlement_ids | array of snowflakes | List of entitlements granted for this subscription |
| renewal_sku_ids | ?array of snowflakes | List of SKUs that this user will be subscribed to at renewal |
| current_period_start | ISO8601 timestamp | Start of the current subscription period |
| current_period_end | ISO8601 timestamp | End of the current subscription period |
| status | SubscriptionStatus | Current status of the subscription |
| canceled_at | ?ISO8601 timestamp | When the subscription was canceled |
| country? | string | ISO3166-1 alpha-2 country code of the payment source used to purchase the subscription. Missing unless queried with a private OAuth scope. |

The start of a subscription is determined by its ID. When the subscription renews, its current period is updated.

Expand All @@ -32,6 +33,7 @@ If the user cancels the subscription, the subscription will enter the `ENDING` s
"user_id": "1088605110638227537",
"sku_ids": ["1158857122189168803"],
"entitlement_ids": [],
"renewal_sku_ids": null,
"current_period_start": "2024-08-27T19:48:44.406602+00:00",
"current_period_end": "2024-09-27T19:48:44.406602+00:00",
"status": 0,
Expand Down
Binary file added images/multisub.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5af3428

Please sign in to comment.