Skip to content

Commit

Permalink
Document Premium App Subscriptions (#6451)
Browse files Browse the repository at this point in the history
* WIP premium apps

* Rework Overview (#4)

* overview page

* start app subscriptions edits

* move to monetization

* jk

* Implementing App Subscriptions

* Added query params to entitlements

* Update to Monetization Overview

* Update entitlements in interactions

* Round of small edits (#5)

* round of edits

* table/link

* Use Nelly sample app. Remove en-us from help center

* Added entitlements to Interaction object

* Update to Test Entitlement

* Testing your implementation

* Added emoji/icon docs

* Added Premium Apps to change log

* fix tables

* Update docs/monetization/App_Subscriptions.md

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

---------

Co-authored-by: shay <swdewael@gmail.com>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
  • Loading branch information
3 people committed Sep 26, 2023
1 parent 515931a commit b97fad3
Show file tree
Hide file tree
Showing 14 changed files with 543 additions and 43 deletions.
19 changes: 19 additions & 0 deletions docs/Change_Log.md
@@ -1,5 +1,24 @@
# Change Log

## Premium App Subscriptions Available in the US
#### Sep 26, 2023

Starting today, eligible US-based developers can monetize their verified apps with App Subscriptions. [App Subscriptions](#DOCS_MONETIZATION_OVERVIEW) let you to charge your users for premium functionality with a recurring, monthly subscription.

- Manage subscription SKUs in the Developer Portal
- View monetization analytics in the Developer Portal
- Team owners can setup and manage payouts in Developer Portal
- New endpoints for working with [SKUs](#DOCS_MONETIZATION_SKUS) and [Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS):
- [List SKUs](#DOCS_MONETIZATION_SKUS/list-skus) `GET /applications/<application.id>/skus`
- [List Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS/list-entitlements) `GET /applications/<application.id>/entitlements`
- [Create Test Entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/create-test-entitlement) `POST /applications/<application.id>/entitlements`
- [Delete Test Entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/delete-test-entitlement) `DELETE /applications/<application.id>/entitlements/<entitlement.id>`
- [Gateway Events](#DOCS_MONETIZATION_ENTITLEMENTS/gateway-events) for working with entitlements: `ENTITLEMENT_CREATE`, `ENTITLEMENT_UPDATE`, `ENTITLEMENT_DELETE`
- New [`PREMIUM_REQUIRED (10)` interaction response type](#DOCS_MONETIZATION_ENTITLEMENTS/premiumrequired-interaction-response) is available to prompt users to upgrade
- New `entitlements` field, which is an array of [entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/) objects, available in interaction data payloads when [receiving and responding to interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-structure)

To learn more about eligibility details and how to enable monetization for your app, check out the [Monetization Overview](#DOCS_MONETIZATION_OVERVIEW).

## Default Value in Auto-populated Select Menus

#### Sep 22, 2023
Expand Down
86 changes: 43 additions & 43 deletions docs/interactions/Receiving_and_Responding.md

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions docs/monetization/App_Subscriptions.md
@@ -0,0 +1,86 @@
# App Subscriptions

App Subscriptions enable you to charge your users for premium app functionality with a recurring subscription. Before you can add an app subscription to your app, you must complete the [Monetization Eligibility Checklist](#DOCS_MONETIZATION_OVERVIEW/eligibility-checklist).

Once you've confirmed eligibility for your app and team, you will be able to set up a [SKU](#DOCS_MONETIZATION_SKUS) (stock-keeping unit) to represent your app's premium offering.

## Types of Subscriptions

When creating subscriptions, you will need to choose between user or guild subscriptions:

- **User Subscriptions**: Offers premium features to an individual user across any server where your app installed.
- **Guild Subscriptions**: Provides premium benefits to all members within a specific server.

Currently, you can only have one published subscription SKU for your app, so you cannot offer both types of subscriptions.

## Configuring App Subscriptions

Once you have an idea what type of subscription you want to offer your app, you can create and [customize your SKU](#DOCS_MONETIZATION_SKUS/customizing-your-skus) to reflect the premium features that you are adding to your app. This is a good place to outline the benefits your users will receive from having an app subscription.

Once an app has a published SKU, there are 4 ways users will be able to subscribe:

- Server admins can use the **Integrations** tab within a server's settings menu
- Bot user profiles include an Upgrade button
- App Directory profiles offer a Premium tab containing subscription details and an Upgrade option
- Attempting to run a premium command will display the Upgrade button in the response

If you don't have any premium commands, your users will still be able to upgrade to your premium app via the Integrations settings menu, bot user profiles and App Directory profiles.

## Implementing App Subscriptions

When a user subscribes to your app, there are a few things you will need to implement in your code to check for subscription status and access.

- Gating your App with Premium Interactions
- Working with Entitlements
- Handling Gateway Events for Entitlements

### Gating Premium Interactions

Interactions like [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) commonly respond to users with a message or modal response. If you'd like to make a command only available to users with a subscription, you can reply with a `PREMIUM_REQUIRED` interaction response `type: 10`. Users without a subscription will be prompted to upgrade when they attempt to use these commands.

```javascript
return new JsonResponse({
type: 10, // PREMIUM_REQUIRED interaction response type
data: {},
});
```

![Interaction Response](monetization-interaction-response.png)

If someone is already subscribed, this command will show the upgrade prompt with a disabled upgrade button. In order to avoid this, your interaction handler should check to see if the user or guild has an active entitlement for your SKU.

Each interaction payload includes an `entitlements` field containing an array of full entitlement objects that the guild or user currently has entitlement to.

You can use this field to determine if the user or guild is subscribed to your app.

### Keeping Track of Entitlements

When a user purchases a subscription, an entitlement is created. [Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS) represent the user's access to your premium offering. You can keep track of entitlements using Gateway Events and the HTTP API.

#### Entitlement Gateway Events

When users subscribe or renew a subscription with your app, Discord will emit [entitlement gateway events](#DOCS_MONETIZATION_ENTITLEMENTS/gateway-events).

Upon a user's purchase of a SKU, you'll receive an [`ENTITLEMENT_CREATE`](#DOCS_MONETIZATION_ENTITLEMENTS/new-entitlement) event. A successful renewal triggers an [`ENTITLEMENT_UPDATE`](#DOCS_MONETIZATION_ENTITLEMENTS/updated-entitlement) event.

> info
> An [`ENTITLEMENT_DELETE`](#DOCS_MONETIZATION_ENTITLEMENTS/deleted-entitlement) event only occurs when Discord refunds a subscription or removes an entitlement, not when an entitlement expires or is canceled.
#### Entitlement HTTP Endpoints

For apps requiring background processing or not solely reliant on interactions, keeping track of entitlements is essential. You can utilize the [List Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS/list-entitlements) endpoint to list active and expired entitlements. Your app can filter entitlements by a specific user or guild by using the `?user_id=XYZ` or `?guild_Id=XYZ` query params.

This comment has been minimized.

Copy link
@DEVTomatoCake

DEVTomatoCake Sep 26, 2023

?user_id=XYZ or ?guild_Id=XYZ

id & Id, why?


For example, you might keep track of our entitlements in a database and check a user's subscription status before performing a cron job or other task.

## Testing Your Implementation

You can test your implementation by [creating](#DOCS_MONETIZATION_ENTITLEMENTS/create-test-entitlement) and [deleting](#DOCS_MONETIZATION_ENTITLEMENTS/delete-test-entitlement) test entitlements. These entitlements will allow you to test your premium offering in both a subscribed and unsubscribed state as a user or guild.

> info
> Test Entitlements do not have a `starts_at` or `ends_at` field as they are valid until they are deleted.
## Receiving Payouts

Once an app has made its first $100 it will become eligible for payout. A review will be conducted and if everything looks good, your team will begin to receive payouts.

For more information, read the [Premium Apps Payouts](https://support-dev.discord.com/hc/articles/17299902720919) Help Center article.
184 changes: 184 additions & 0 deletions docs/monetization/Entitlements.md
@@ -0,0 +1,184 @@
## Entitlement Resource

Entitlements in Discord represent that a user or guild has access to a premium offering in your application.

### Entitlement Object

###### Entitlement Structure

| Field | Type | Description |
|----------------|-------------------|---------------------------------------------------------------------------------------------|
| id | snowflake | ID of the entitlement |
| sku_id | snowflake | ID of the SKU |
| user_id? | snowflake | ID of the user that is granted access to the entitlement's sku |
| guild_id? | snowflake | ID of the guild that is granted access to the entitlement's sku |
| application_id | snowflake | ID of the parent application |
| type | integer | [Type of entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object-entitlement-types) |
| consumed | boolean | Not applicable for App Subscriptions. Subscriptions are not consumed and will be `false` |
| starts_at? | ISO8601 timestamp | Start date at which the entitlement is valid. Not present when using test entitlements. |
| ends_at? | ISO8601 timestamp | Date at which the entitlement is no longer valid. Not present when using test entitlements. |

###### Entitlement Example

```json
{
"id": "1019653849998299136",
"sku_id": "1019475255913222144",
"application_id": "1019370614521200640",
"user_id": "771129655544643584",
"promotion_id": null,
"type": 8,
"deleted": false,
"gift_code_flags": 0,
"consumed": false,
"starts_at": "2022-09-14T17:00:18.704163+00:00",
"ends_at": "2022-10-14T17:00:18.704163+00:00",
"guild_id": "1015034326372454400",
"subscription_id": "1019653835926409216"
}
```

###### Entitlement Types

| Type | ID | Description |
|--------------------------|----|--------------------------------------------------|
| APPLICATION_SUBSCRIPTION | 8 | Entitlement was purchased as an app subscription |

## List Entitlements % GET /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements

Returns all entitlements for a given app, active and expired.

###### Query Params

| param | type | description |
|----------------|-----------------------------------|------------------------------------------------------|
| user_id? | snowflake | User ID to look up entitlements for |
| sku_ids? | comma-delimited set of snowflakes | Optional list of SKU IDs to check entitlements for |
| before? | snowflake | Retrieve entitlements before this time |
| after? | snowflake | Retrieve entitlements after this time |
| limit? | integer | Number of entitlements to return, 1-100, default 100 |
| guild_id? | snowflake | Guild ID to look up entitlements for |
| exclude_ended? | boolean | Whether entitlements should be omitted |

```json
[
{
"id": "1019653849998299136",
"sku_id": "1019475255913222144",
"application_id": "1019370614521200640",
"user_id": "771129655544643584",
"promotion_id": null,
"type": 8,
"deleted": false,
"gift_code_flags": 0,
"consumed": false,
"starts_at": "2022-09-14T17:00:18.704163+00:00",
"ends_at": "2022-10-14T17:00:18.704163+00:00",
"guild_id": "1015034326372454400",
"subscription_id": "1019653835926409216"
}
]
```

## Create Test Entitlement % POST /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements

Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering.

This endpoint returns a partial entitlement object. It will **not** contain `subscription_id`, `starts_at`, or `ends_at`, as it's valid in perpetuity.

After creating a test entitlement, you'll need to reload your Discord client. After doing so, you'll see that your server or user now has premium access.

###### JSON Params

| param | type | description |
|------------|---------|-----------------------------------------------------------|
| sku_id | string | ID of the SKU to grant the entitlement to |
| owner_id | string | ID of the guild or user to grant the entitlement to |
| owner_type | integer | `1` for a guild subscription, `2` for a user subscription |

```json
{
"sku_id": "999184799365857331",
"owner_id": "847184799365857999",
"owner_type": 1
}
```

## Delete Test Entitlement % DELETE /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements/{entitlement.id#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object}

Deletes a currently-active test entitlement. Discord will act as though that user or guild _no longer has_ entitlement to your premium offering.

Returns `204 No Content` on success.

---

## Gateway Events

### New Entitlement

`ENTITLEMENT_CREATE`

Fires when a user subscribes to a SKU. Contains an entitlement object.

```json
{
"id": "1083167266843000832",
"sku_id": "1083142056391606272",
"application_id": "1083108937882013696",
"user_id": "1072239583707664384",
"promotion_id": null,
"type": 8,
"deleted": false,
"gift_code_flags": 0,
"consumed": false,
"starts_at": "2023-03-08T23:19:58.010876+00:00",
"ends_at": "2023-04-08T23:19:58.010876+00:00",
"subscription_id": "1083167255652597760"
}
```

### Updated Entitlement

`ENTITLEMENT_UPDATE`

Fires when a user's subscription renews for the next billing period. The `ends_at` field will have an updated value with the new expiration date.

If a user's subscription is cancelled, you will _not_ receive an `ENTITLEMENT_DELETE` event. Instead, you will simply not receive an `UPDATE` event with a new `ends_at` date at the end of the billing period.

### Deleted Entitlement

`ENTITLEMENT_DELETE`

Fires when a user's entitlement is deleted. Entitlement deletions are infrequent, and occur when:

- Discord issues a refund for a subscription
- Discord removes an entitlement from a user via internal tooling

Entitlements are _not_ deleted when they expire.

---

## Using Entitlements in Interactions

### PREMIUM_REQUIRED Interaction Response

If your app has monetization enabled, it will have access to a new [`PREMIUM_REQUIRED` interaction response (`type: 10`)](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). This can be sent in response to any kind of interaction. It does not allow a `content` field.

This response will create an ephemeral message shown to the user that ran the interaction, instructing them that whatever they tried to do requires the premium benefits of your app. It also contains an "Upgrade" button to subscribe. The response message is static, but will be automatically updated with the name of your premium SKU.

![Interaction Response](monetization-interaction-response.png)

```js
return res.send({
type: InteractionResponseType.PREMIUM_REQUIRED, // This has a value of 10
data: {},
});
```

---

### Checking Entitlements in Interactions

To check what the current guild or user has entitlements to, your app can inspect the `entitlements` field. `entitlements` is an array of [entitlement objects](#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object) for the current guild and user.

You can reference `entitlements` during interactions to handle subscription status, rather than fetching entitlements from the API or your database.
64 changes: 64 additions & 0 deletions docs/monetization/Overview.md
@@ -0,0 +1,64 @@
# Monetizing Your Discord App

Premium Apps is a set of monetization features for apps on Discord that allows developers to:

- Sell monthly recurring [subscriptions](#DOCS_MONETIZATION_APP_SUBSCRIPTIONS) for your app's premium functionality within Discord
- Highlight your app's premium benefits on the App Directory
- Offer native product tie-ins and upsells on the App Directory, app profiles, and in chat

![Premium App screenshot](premium-example.png)

## Eligibility Checklist

Before you can start creating SKUs and offering subscriptions for your app, your app and team must be eligible for monetization.

Only team owners can enable monetization for an app. When a team owner enables monetization, they'll be taken through a series of steps and checks to ensure the following criteria are met:

- App must be verified
- App belongs to a developer team
- Team owner must be at least 18 years old
- Team must have verified emails and 2FA set up
- App uses slash commands, or has been approved for the Message Content privileged intent
- App has a link to your Terms of Service
- This document is an agreement between you and users governing the use of your app.
- App has a link to your Privacy Policy
- This document should clearly and accurately describe to users of your app the user data you collect and how you use and share such data with us and third parties, consistent with our Developer Terms of Service and Developer Policy.
- App must not contain any harmful or bad language in the name, description, commands, or role connection metadata.
- Payouts must be setup with a valid payment method
- Agreement to the [Monetization Terms](https://support.discord.com/hc/articles/5330075836311) and [Discord App Subscriptions Policy](https://support-dev.discord.com/hc/articles/17442400631959).

## Setting Up Monetization

Adding monetization to your app is a three-step process:

1. Set up your app and developer team to offer subscriptions
2. Create and customize a SKU for your app subscription
3. Adding support for SKUs and Entitlements to your app

### Configuring Your App

Before monetization can be enabled, you will need:

- A [team](#DOCS_TOPICS_TEAMS) in the developer portal. If you don't have one, you can [create one on the Teams page](https://discord.com/developers/teams)
- A [verified app](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Allowlisting#h_46b3869c-6d50-43fc-b07c-9ed7569a1160) that is _owned by that team_
- A test app _owned by that team_
### Setting Up Team Payouts

In the meantime, you can begin setting up your payout information so you can get paid! Discord does all payout processing through Stripe, so part of setting up payouts will be going through Stripe's onboarding flow.

Only the owner of the team can enable payout settings for the team.

#### If You are Based in the United States

- Click on [your team](https://discord.com/developers/teams) on the Teams page.
- Select "Payout Settings"
- If you do not see "Payout Settings", you are not the owner of the team. Only the owner of the team can enable payout settings for the team.
- Complete the onboarding flow through Stripe

#### If You are Based Outside of the United States

Premium Apps is not currently available outside of the United States. These features will be made available to more regions soon.

### Implementing Your Premium Features

Once your team and app are all set up for monetization, you are ready to [customize your subscription](#DOCS_MONETIZATION_SKUS/customizing-your-skus) and [implement your premium features](#DOCS_MONETIZATION_APP_SUBSCRIPTIONS) in your app!

0 comments on commit b97fad3

Please sign in to comment.