diff --git a/README.md b/README.md
index 285b5f81..80e448da 100644
--- a/README.md
+++ b/README.md
@@ -98,19 +98,19 @@ The default sidebar is rendered at the bottom of `sidebars.js`.
- Install dependencies
- ```sh
- $ yarn install
- ```
+ ```sh
+ $ yarn install
+ ```
- Optionally install [typos-cli](https://github.com/crate-ci/typos)
- ```sh
- brew install typos-cli
- ```
+ ```sh
+ brew install typos-cli
+ ```
- See the link for other options.
-
- This is optional, but will enable running it via the pre-commit hook. You can also use the recommended [vscode extension](https://marketplace.visualstudio.com/items?itemName=tekumara.typos-vscode) or let it run via GitHub Actions when you create a PR.
+ See the link for other options.
+
+ This is optional, but will enable running it via the pre-commit hook. You can also use the recommended [vscode extension](https://marketplace.visualstudio.com/items?itemName=tekumara.typos-vscode) or let it run via GitHub Actions when you create a PR.
### Local Development
diff --git a/docs/getting-started/entitlements/roku-products.md b/docs/getting-started/entitlements/roku-products.md
index 407ba545..964d08f5 100644
--- a/docs/getting-started/entitlements/roku-products.md
+++ b/docs/getting-started/entitlements/roku-products.md
@@ -4,15 +4,17 @@ slug: roku-products
excerpt: Setting up your in-app purchases in Roku
hidden: false
---
+
:::warning Beta Feature
RevenueCat's Roku support is currently in beta.
:::
-To set up in-channel products for Roku, start by logging into the [Roku dashboard](https://developer.roku.com/dev/landing).
+To set up in-channel products for Roku, start by logging into the [Roku dashboard](https://developer.roku.com/dev/landing).
**This guide assumes basic knowledge of Roku and the Roku dashboard, as well as having a Roku channel set up and ready for products.** For more information, visit Roku's [documentation](https://developer.roku.com/docs/developer-program/getting-started/roku-dev-prog.md).
## Create a new Product
+
This process is going to configure a subscription product, but the steps are similar for creating other products. To configure other types of products, select the appropriate 'Purchase Type'. However, please read our [limitations](/getting-started/installation/roku#beta-limitations) on what we currently support in this beta program.
To create a new in-channel product, click on products in the sidebar of the Roku Developer Dashboard, then click **Add a new product**.
@@ -22,64 +24,69 @@ To create a new in-channel product, click on products in the sidebar of the Roku
![](/images/roku/roku-add-product.png)
### Product basics
+
![](/images/roku/roku-product-basics.png)
- **Channels**: From the channels list, select one or more channels where this product will be available for sale. The channels listed in this selection show the channels belonging to the root account.
- **Product category**: Select a product category for the product you are creating.
- - _Video_: Primarily video content, includes music videos.
- - _Audio_: Primarily audio content without accompanying video, such as streaming music services or audio-only podcasts.
- - _Game_: Primarily functions as a game.
- - _App/Utility_: Application or utility. Examples include screensavers, weather apps, etc.
+ - _Video_: Primarily video content, includes music videos.
+ - _Audio_: Primarily audio content without accompanying video, such as streaming music services or audio-only podcasts.
+ - _Game_: Primarily functions as a game.
+ - _App/Utility_: Application or utility. Examples include screensavers, weather apps, etc.
- **Product name**: Enter a 30-character maximum product name in English. The product name will be disaplued to your customers in their purchasing workflow, as well as emails sent by Roku. Roku recommends the following syntax: "channelName - planName".
:::warning
-The product name must clearly identify the service being offered. Product names may not include the name "Roku", text related to a trial or discount offer, or any misleading language.
+The product name must clearly identify the service being offered. Product names may not include the name "Roku", text related to a trial or discount offer, or any misleading language.
:::
- **Localization**: Optionally, you can also provide a localized product name by selecting 'Add product name in another language', selecting a language, and entering the product localized name. Repeat this to create another localized name.
- **Product identifier**: The product identifier is a unique ID that is used for accessing your product in development and syncing with RevenueCat. After you use a Product ID for one product within a Roku Channel Store, it can’t be used again. It helps to be a little organized here from the beginning - we recommend using a consistent naming scheme across all of your product identifiers.
### Product pricing
+
![](/images/roku/roku-product-pricing.png)
- **Purchase type**: The purchase type list will allow you to select the following types for the product being created:
- - _Monthly subscription_: A product that will auto-renew monthly.
- - _Yearly subscription_: A product that will auto-renew annually.
- - _One-time Purchase_: This product type may only be purchased a single time.
- - _One-time Purchase, Consumable - Quantity_ This is a "packet" of identical items (e.g: number of viewings permitted).
+ - _Monthly subscription_: A product that will auto-renew monthly.
+ - _Yearly subscription_: A product that will auto-renew annually.
+ - _One-time Purchase_: This product type may only be purchased a single time.
+ - _One-time Purchase, Consumable - Quantity_ This is a "packet" of identical items (e.g: number of viewings permitted).
:::warning One-time and consumable product limitations
At the moment, RevenueCat does not support One-time Purchase and One-time Purchase, Consumable - Quantity products
:::
-- **Price tier**: Roku's price tiers enforce a 99 cent or 49 cent pricing tier.
- - One to three-digit tier numbers are used for 99 cent pricing. To calculate, you can subtract 1 cent from the tier to get the corresponding price. For example, Tier 100 is $99.99 (`$100 - $0.01 = $99.99`).
- - Four-digit tier numbers are used for 49 cent pricing. To calculate this, you can add 49 cents to the last two digits in the tier. For example, Tier 1030 is $30.49 (30 is the last 2 digits → `$30 + $0.49 = $30.49`).
+- **Price tier**: Roku's price tiers enforce a 99 cent or 49 cent pricing tier.
+ - One to three-digit tier numbers are used for 99 cent pricing. To calculate, you can subtract 1 cent from the tier to get the corresponding price. For example, Tier 100 is $99.99 (`$100 - $0.01 = $99.99`).
+ - Four-digit tier numbers are used for 49 cent pricing. To calculate this, you can add 49 cents to the last two digits in the tier. For example, Tier 1030 is $30.49 (30 is the last 2 digits → `$30 + $0.49 = $30.49`).
Once you select a price tier, a chart will appear that displays the purchase price, net price, and proceeds for each country the product is available for.
+
- **Purchase price**: Reflects the amount your customer will pay.
- **Net price**: This is the pre-tax price.
- **Your proceeds**: This is the amount you will receive from Roku for the sale of the product.
### Trials and offers
+
Roku subscription products support free trials and discounted offers. Note that the root account must be creating free trials, discounted offers, or limited-time offers for subscriptions.
Under **Base offer**, select one of the following:
![](/images/roku/roku-discounted-offer.png)
-- **Discounted price**: This will provide new customers a discounted introductory price.
- - _Discounted price range_: This is the discounted price you'd like to offer. The discounted price range must be lower than the base price.
- - _Discount duration_: Enter the number of months the discount will be until the customer renews at full price.
+- **Discounted price**: This will provide new customers a discounted introductory price.
+ - _Discounted price range_: This is the discounted price you'd like to offer. The discounted price range must be lower than the base price.
+ - _Discount duration_: Enter the number of months the discount will be until the customer renews at full price.
![](/images/roku/roku-free-trial.png)
- **Free trial**: This will provide new customers with a free trial of your product.
- - _Free trial duration_: Enter the number of days or months for the trial
- - Select the unit of time (**Days** or **Months**)
+ - _Free trial duration_: Enter the number of days or months for the trial
+ - Select the unit of time (**Days** or **Months**)
### Ready for sale
-Once the product is ready to be made available to customers for purchase, select the _"Cleared for sale"_ checkbox. After selecting this checkbox, you will be able to [schedule limited-time free trials and discount offers](/getting-started/entitlements/roku-products#scheduling-offers) for the product.
+
+Once the product is ready to be made available to customers for purchase, select the _"Cleared for sale"_ checkbox. After selecting this checkbox, you will be able to [schedule limited-time free trials and discount offers](/getting-started/entitlements/roku-products#scheduling-offers) for the product.
### Scheduling offers
+
Once your product is cleared for sale, you can schedule limited-time free trials and discount offers on your subscription products.
-Within your product details, you can select 'Schedule offer' > 'Create new offer'.
+Within your product details, you can select 'Schedule offer' > 'Create new offer'.
![](/images/roku/roku-schedule-offer.png)
Please refer to the [Trials and offers](/getting-started/entitlements/roku-products#trials-and-offers) section of this documentation for additional instructions on creating an offer. When scheduling an offer, you must input a **Start date** and **End date**.
Note that a customer can only receive one free trial or discount offer, regardless if it is a scheduled offer or part of your base product. For example, if you have a monthly subscription product with the following offers:
+
- Time-limited offer: Two-month free trial
- Base offer: Three-month 50% discount
When your customer accepts a two-month free trial, once that trial is over the customer will be billed at full price. If your subscription product does not contain a time-limited offer, the customer would be billed for the first three months at 50% then convert to paying full price.
## Editing / deleting products
+
### Edit products
-You can edit a product by selecting the **Product name** in your **Manage In-Channel Products** index page. You may want to edit a product if you no longer wish to list a product for sale.
+
+You can edit a product by selecting the **Product name** in your **Manage In-Channel Products** index page. You may want to edit a product if you no longer wish to list a product for sale.
:::warning Editing cleared for sale
Note that changing the **Cleared for Sale** to "No" will cancel all existing subscriptions of the product and will not renew at the end of the billing period.
:::
### Deleting products
-Deleted products cannot be recovered.
+
+Deleted products cannot be recovered.
:::warning Deleting products that are cleared for sale
Note that deleting a product without first changing its **Cleared for Sale** status to "No" will keep the current subscriptions of the product active and will prevent additional purchases of the subscription product.
:::
## Product groups
+
Product groups are used for upgrade/downgrade functionality and to prevent double billing your customers. For more information regarding upgrades/downgrades, please visit our documentation on [_Upgrades, Downgrades, & Management_](/subscription-guidance/managing-subscriptions#roku).
To set up a product group, navigate to your _'Manage In-Channel Products' > 'All product groups' > 'Add a new group'_
diff --git a/docs/getting-started/installation/flutter.mdx b/docs/getting-started/installation/flutter.mdx
index 2afaf806..34ad7596 100644
--- a/docs/getting-started/installation/flutter.mdx
+++ b/docs/getting-started/installation/flutter.mdx
@@ -4,6 +4,7 @@ slug: flutter
excerpt: Instructions for installing Purchases SDK for Flutter
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -17,13 +18,11 @@ Minimum target: iOS 11.0+
[![Release](https://img.shields.io/github/release/RevenueCat/purchases-flutter.svg?style=flat)](https://github.com/RevenueCat/purchases-flutter/releases)
-To use this plugin, add `purchases_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/) (and run an implicit dart pub get):
+To use this plugin, add `purchases_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/) (and run an implicit dart pub get):
import content from "!!raw-loader!@site/code_blocks/getting-started/installation/flutter_1.yaml";
-
+
Alternatively run this command:
@@ -32,14 +31,17 @@ Alternatively run this command:
```
### iOS Deployment Target
+
RevenueCat is compatible with iOS 11.0 or higher. Flutter does not automatically set the iOS deployment target for your project. You need to make sure that the deployment target is set to 11.0 or higher. To do that, simply edit `ios/Podfile` and add the following line if it's not already there:
```
platform :ios, '11.0'
```
+
Set it to 11.0 or a higher version for RevenueCat to work.
### iOS Swift Version
+
RevenueCat requires Swift >= 5.0 to work. If the `Podfile` in your project's `ios` folder specifies a Swift version, make sure that it's at least 5.0, otherwise you may run into build issues.
### Set the correct launchMode for Android
@@ -48,9 +50,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -60,9 +64,7 @@ You should now be able to import `purchases_flutter`.
import content2 from "!!raw-loader!@site/code_blocks/getting-started/installation/flutter_2.kt";
-
+
:::info Enable In-App Purchase capability for iOS projects in Xcode
Don't forget to enable the In-App Purchase capability for your iOS project under `Project Target -> Capabilities -> In-App Purchase`
@@ -75,12 +77,14 @@ Don't forget to enable the In-App Purchase capability for your iOS project under
:::warning
If you're using other plugins like [mobx](https://pub.dev/packages/flutter_mobx), you may run into conflicts with types from other plugins having the same name as those defined in `purchases_flutter`.
If this happens, you can resolve the ambiguity in the types by adding an import alias, for example:
+
```dart
import 'package:purchases_flutter/purchases_flutter.dart' as purchases;
```
+
After that, you can reference the types from `purchases_flutter` as `purchases.Foo`, like `purchases.PurchaserInfo`.
:::
## Next Steps
-* Now that you've installed the Purchases SDK in Flutter, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in Flutter, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/ios.mdx b/docs/getting-started/installation/ios.mdx
index 9351c05a..e9290f28 100644
--- a/docs/getting-started/installation/ios.mdx
+++ b/docs/getting-started/installation/ios.mdx
@@ -4,6 +4,7 @@ slug: ios
excerpt: Instructions for installing RevenueCat SDK for iOS
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -12,26 +13,29 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
[![Release](https://img.shields.io/github/release/RevenueCat/purchases-ios.svg?style=flat)](https://github.com/RevenueCat/purchases-ios/releases)
-RevenueCat for iOS can be installed either via [CocoaPods](/getting-started/installation/ios#section-install-via-cocoapods), [Carthage](ios#section-install-via-carthage), or [Swift Package Manager](/getting-started/installation/ios#section-install-via-swift-package-manager).
+RevenueCat for iOS can be installed either via [CocoaPods](/getting-started/installation/ios#section-install-via-cocoapods), [Carthage](ios#section-install-via-carthage), or [Swift Package Manager](/getting-started/installation/ios#section-install-via-swift-package-manager).
:::info
Already have 4.x installed? View our [migration guide to 5.x →](/sdk-guides/ios-native-4x-to-5x-migration)
:::
-
+
### Install via Swift Package Manager
-You can use Swift Package Manager to add RevenueCat to your Xcode project.
+You can use Swift Package Manager to add RevenueCat to your Xcode project.
:::tip Speed up the Swift Package Manager installation
-Use a mirror of the main repository by selecting `File » Add Packages Dependencies...` and entering the repository URL (`https://github.com/RevenueCat/purchases-ios-spm.git`) into the search bar (top right).
+Use a mirror of the main repository by selecting `File » Add Packages Dependencies...` and entering the repository URL (`https://github.com/RevenueCat/purchases-ios-spm.git`) into the search bar (top right).
This will integrate far more quickly than using the main repository directly.
:::
-Set the Dependency Rule to `Up to next major`, and the version number to `5.0.0 < 6.0.0`.
+Set the Dependency Rule to `Up to next major`, and the version number to `5.0.0 < 6.0.0`.
When "Choose Package Products for purchases-ios" appears, only select `RevenueCat` and `RevenueCatUI` and click "Add Package".
@@ -45,25 +49,23 @@ To always use the latest release, add the following to your Podfile:
import iosPodfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_1.ruby";
-
+
Alternatively, pin to a specific minor version:
import iosRubyContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_2.ruby";
-
+
And then run:
import iosTerminalContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_3.ruby";
-
+
This will add `RevenueCat.framework` to your workspace.
@@ -73,28 +75,26 @@ To always use the latest release, add the following to your Cartfile:
import iosCartfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_4.txt";
-
+
Alternatively, pin to a specific minor version:
import iosTextContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_5.txt";
-
+
#### Carthage with XCFrameworks
-If you're using Carthage version >= 0.37, you can use RevenueCat as an XCFramework instead of a Universal Framework. This makes setup easier, since you don't have to set up build phases at all.
+If you're using Carthage version >= 0.37, you can use RevenueCat as an XCFramework instead of a Universal Framework. This makes setup easier, since you don't have to set up build phases at all.
To use XCFrameworks with Carthage, you need to pass in `--use-xcframeworks`.
import iosShellContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_6.shell";
-
+
More information on using XCFrameworks with Carthage is available at https://github.com/carthage/Carthage/#building-platform-independent-xcframeworks-xcode-12-and-above
@@ -108,9 +108,9 @@ Run:
import iosTextContent2 from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_7.txt";
-
+
## Import the SDK
@@ -123,10 +123,12 @@ You should now be able to `import RevenueCat`.
import iosSwiftContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_8.swift";
import iosObjectiveCContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_9.m";
-
+
:::info Enable In-App Purchase capability for your project
Don't forget to enable the In-App Purchase capability for your project under `Project Target -> Capabilities -> In-App Purchase`
@@ -136,4 +138,4 @@ Don't forget to enable the In-App Purchase capability for your project under `Pr
## Next Steps
-* Now that you've installed the SDK in your iOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
+- Now that you've installed the SDK in your iOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/reactnative.mdx b/docs/getting-started/installation/reactnative.mdx
index eb84aba4..3a623006 100644
--- a/docs/getting-started/installation/reactnative.mdx
+++ b/docs/getting-started/installation/reactnative.mdx
@@ -4,6 +4,7 @@ slug: reactnative
excerpt: Instructions for installing Purchases SDK for React Native
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/where-does-revenuecat-fit-in-your-app) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -12,12 +13,12 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
[![Release](https://img.shields.io/github/release/RevenueCat/react-native-purchases.svg?style=flat)](https://github.com/RevenueCat/react-native-purchases/releases)
-Make sure that the deployment target for iOS is at least 13.4 and Android is at least 6.0 (API 23) [as defined here](https://github.com/facebook/react-native#-requirements).
+Make sure that the deployment target for iOS is at least 13.4 and Android is at least 6.0 (API 23) [as defined here](https://github.com/facebook/react-native#-requirements).
### Option 1: React-Native package
Purchases for React-Native can be installed either via npm or yarn.
-We recommend using the latest version of React Native, or making sure that the version is at least greater than 0.64.
+We recommend using the latest version of React Native, or making sure that the version is at least greater than 0.64.
#### Option 1.1: Using auto-linking
@@ -26,25 +27,29 @@ Recent versions of React Native will automatically link the SDK, so all that's n
import reactNativeNpmContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_1.shell";
import reactNativeYarnContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_2.shell";
-
+
#### Option 1.2: Manual linking
-
+
After that, you should link the library to the native projects by doing:
import reactNativeShellContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_5.shell";
-
+
### Option 2: Using Expo
@@ -72,9 +77,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -84,9 +91,7 @@ You should now be able to import `Purchases`.
import reactNativeJsContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_7.js";
-
+
:::info Include BILLING permission for Android projects
Don't forget to include the `BILLING` permission in your AndroidManifest.xml file
@@ -94,9 +99,15 @@ Don't forget to include the `BILLING` permission in your AndroidManifest.xml fil
import reactNativeXmlContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_8.xml";
-
+
:::info Enable In-App Purchase capability for your iOS project
Don't forget to enable the In-App Purchase capability for your project under `Project Target -> Capabilities -> In-App Purchase`
@@ -106,4 +117,4 @@ Don't forget to enable the In-App Purchase capability for your project under `Pr
## Next Steps
-* Now that you've installed the Purchases SDK in your React Native app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in your React Native app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/roku.mdx b/docs/getting-started/installation/roku.mdx
index d95f23e8..4aa5f426 100644
--- a/docs/getting-started/installation/roku.mdx
+++ b/docs/getting-started/installation/roku.mdx
@@ -10,11 +10,15 @@ RevenueCat's Roku support is currently in beta.
:::
## General setup
+
### Prerequisites
+
#### Setting up your Roku developer account
+
Follow the [First Steps](https://developer.roku.com/en-gb/docs/developer-program/getting-started/first-steps.md) guide to create a Roku developer account, log in to your Roku device and enable developer mode on your Roku device.
#### Setting up your Roku channel
+
Once you have your developer account created, head to the [dashboard](https://developer.roku.com/dev/dashboard)
1. First, [create a new Channel](https://developer.roku.com/en-gb/docs/developer-program/publishing/channel-publishing-guide.md#create-a-channel).
@@ -23,6 +27,7 @@ Once you have your developer account created, head to the [dashboard](https://de
4. Under "Monetization" -> "Product", follow the process to submit the tax documents, and after you're approved, you can [create in-channel products](/getting-started/entitlements/roku-products).
### App configuration
+
1. Make sure your project has been enabled to create Roku apps. If you're not sure, talk to your RevenueCat contact.
2. Open the RevenueCat dashboard, select your project, and click on "Add app" > "Roku Channel Store".
@@ -41,8 +46,8 @@ Once you have your developer account created, head to the [dashboard](https://de
![](/images/roku/roku-notification-url.png)
5. Back to the RevenueCat dashboard, click on "Public API Key" and copy over the value which should start with "roku_XXXXXX". You will need it to configure the SDK later.
@@ -50,6 +55,7 @@ Once you have your developer account created, head to the [dashboard](https://de
![](/images/roku/revenuecat-api-key.png)
### Multi-channel support
+
The Roku channel ID is required for supporting multiple channels on a single Roku account. If your Roku account has more than one Roku Channel, you will need to enter your Channel ID for each Roku app on the RevenueCat dashboard.
1. Navigate to your [Roku Developer Dashboard](https://developer.roku.com/dev/dashboard).
@@ -63,23 +69,23 @@ The Roku channel ID is required for supporting multiple channels on a single Rok
![](/images/roku/roku-multi-channel.png)
### Product configuration
+
After you have configured the Roku Store app on RevenueCat, you should [create your in-channel products](/getting-started/entitlements/roku-products) and then follow RevenueCat's regular setup of [entitlements, products, and offerings](/getting-started/entitlements).
## Installing the SDK
[![Release](https://img.shields.io/github/release/RevenueCat/purchases-roku.svg?style=flat)](https://github.com/RevenueCat/purchases-roku/releases)
+
1. Clone the repository:
import rokuClone from "!!raw-loader!@site/code_blocks/getting-started/installation/configuring-roku_1.shell";
-
+
2. Copy the `components/purchases` folder into your app's `components` folder.
3. Copy the `source/Purchases.brs` file into your app's `source` folder.
@@ -87,22 +93,24 @@ import rokuClone from "!!raw-loader!@site/code_blocks/getting-started/installati
import rokuXML from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-import-sdk.xml";
-
+
## Configuring the SDK
+
**Important:** The SDK should be used only from SceneGraph components. Calling it from the main thread or from a Task component is not supported.
Initialize the SDK with your api key. You typically do this inside the `init()` method of your main scene.
import rokuConfigure from "!!raw-loader!@site/code_blocks/getting-started/installation/configuring-roku_2.brs";
-
+
## Callbacks and error handling
+
In methods of the SDK which perform async operations, you can get the result by passing a sub routine or a callback name.
- The first parameter will contain the result.
@@ -112,9 +120,15 @@ In methods of the SDK which perform async operations, you can get the result by
import rokuCallbacksErrorHandling from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-callbacks-error-handling.brs";
-
+
## Models
@@ -125,26 +139,53 @@ import rokuLoginLogout from "!!raw-loader!@site/code_blocks/getting-started/inst
import rokuSubscriberInfo from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-subscriber-info.brs";
import rokuSubscriberAttributes from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-subscriber-attributes.brs";
-
+
### Offerings
+
import rokuGetOfferings from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-get-offerings.brs";
import rokuOffersObject from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-offerings-object.txt";
import rokuPlacements from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-placements.brs";
-
+
### Purchase
+
#### Making a purchase
+
As a parameter to the `purchase()` method, you can pass an associative array containing one of the following keys:
- `code`: A string containing the product id.
@@ -156,43 +197,55 @@ Additionally,you can pass the following optional parameters:
- `action`: To perform a product change. Valid values: `Upgrade` or `Downgrade`
#### Sync purchases
+
This method will post all purchases associated with the current Roku account to RevenueCat and become associated with the current User ID. It should only be used if you're migrating from using your own Roku Pay implementation and want to track previous purchases in RevenueCat.
import rokuPurchaseObject from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-purchase-object.txt";
import rokuMakePurchase from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-make-purchase.brs";
import rokuSyncPurchases from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-sync-purchases.brs";
-
+
### Error
+
The error model contains two fields: `code` and `message`
import rokuError from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-error.txt";
-
+
### Tying everything together
+
For most apps, the usage of the SDK would look like this:
1. Initialise the SDK
2. Log in the user
-4. Check if the entitlement is active
-5. Fetch offerings and show your paywall UI
-6. Make a purchase
+3. Check if the entitlement is active
+4. Fetch offerings and show your paywall UI
+5. Make a purchase
import rokuTyingTogether from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-tying-together.brs";
-
+
## Testing
+
:::warning
Only the "root account user" can test billing on device. If you get added as a collaborator to someone else's developer account, billing testing will not work. You'll need to create your own developer account.
:::
@@ -200,17 +253,18 @@ Only the "root account user" can test billing on device. If you get added as a c
Roku transactions **do not** have an "associated" environment. Both types of transactions arrive via push notifications, however, there are key differences between them.
- **Price differentiation**:
- - _Test purchases_: Always have a price of **0**
- - _Production purchases_: Will have a non-zero price (unless it's a trial)
+ - _Test purchases_: Always have a price of **0**
+ - _Production purchases_: Will have a non-zero price (unless it's a trial)
- **Charges**:
- - _Test purchases_: The end customer will not be charged for a test purchase
- - _Production purchases_: The end customer will be charged according to the product details (e.g: pricing tier, trials, offers, etc)
+ - _Test purchases_: The end customer will not be charged for a test purchase
+ - _Production purchases_: The end customer will be charged according to the product details (e.g: pricing tier, trials, offers, etc)
In order to perform a test purchase, a [test user must be created](https://developer.roku.com/en-gb/docs/developer-program/roku-pay/quickstart/test-users.md) and associated with the channel.
After that, the test user will be able to make test purchases on the channel, regardless of the installation method: Public, Beta or Sideloaded (Billing Testing must be enabled). However, you can only use one Roku channel at a time for testing.
### RevenueCat limitations
+
Since Roku transactions do not have an associated environment, RevenueCat defines a **"sandbox"** purchase as any purchase made in a **Sideloaded** channel. A **"production"** purchase is defined as any purchase made in either a **beta** or **public** channel, regardless of whether the end customer was actually charged or not for it.
This also means for any events RevenueCat dispatches containing an [`environment` field](/integrations/webhooks/event-types-and-fields#events-format), the Roku channel where the purchase was made will determine whether the value is set to `SANDBOX` or `PRODUCTION`.
@@ -222,23 +276,27 @@ To ensure a clear separation between your "testing" and "production" purchases,
Roku's beta channels are a special channel type to assist with testing your channel in a production-like environment before publishing.
#### Beta channel rules
+
- **120 days**: A beta channel can exist for only 120 days after you create it. After 120 days, the channel will be (1) deleted and removed from your Developer Dashboard and (2) disabled for all users who have it installed
- **10 channels**: There is a maximum of 10 beta channels at a time
- **20 test users**: There can only be 20 beta test users per beta channel at any given time
## Beta limitations
+
This feature is currently in beta and has a number of known limitations.
RevenueCat features not yet supported:
+
- [RevenueCat paywalls](/tools/paywalls)
- [Trusted entitlements](/customers/trusted-entitlements)
- [Offline entitlements](/customers/customer-info#offline-entitlements)
- [Customer Center](/tools/customer-center)
Functionality not yet supported:
+
- Detecting price changes
- Chargebacks
- Extending subscriptions
- Identifying customers upon configuration
-If your use case is not supported above, reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support) so we can discuss more on how to support you!
\ No newline at end of file
+If your use case is not supported above, reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support) so we can discuss more on how to support you!
diff --git a/docs/integrations/third-party-integrations/firebase-integration.mdx b/docs/integrations/third-party-integrations/firebase-integration.mdx
index 56b3f1f9..bcc1823f 100644
--- a/docs/integrations/third-party-integrations/firebase-integration.mdx
+++ b/docs/integrations/third-party-integrations/firebase-integration.mdx
@@ -199,20 +199,20 @@ Follow [this installation link](https://console.firebase.google.com/project/_/ex
##### Available Events:
-| Event | Description |
-| :--------------------- | :------------------------------------------------------------------------------------------------------------------------- |
-| `test` | Occurs whenever a test event issued through the RevenueCat dashboard. |
-| `initial_purchase` | Occurs whenever a new subscription has been purchased or a lapsed user has resubscribed. |
+| Event | Description |
+| :---------------------- | :------------------------------------------------------------------------------------------------------------------------- |
+| `test` | Occurs whenever a test event issued through the RevenueCat dashboard. |
+| `initial_purchase` | Occurs whenever a new subscription has been purchased or a lapsed user has resubscribed. |
| `non_renewing_purchase` | Occurs whenever a customer has made a purchase that will not auto-renew. |
-| `renewal ` | Occurs whenever an existing subscription has been renewed. |
-| `product_change` | Occurs whenever a subscriber has changed the product of their subscription. |
-| `cancellation` | Occurs whenever a subscription or non-renewing purchase has been cancelled. See cancellation reasons for more details. |
-| `uncancellation ` | Occurs whenever an auto-renew status has been re-enabled for a subscription. |
-| `billing_issue` | Occurs whenever there has been a problem trying to charge the subscriber. This does not mean the subscription has expired. |
-| `subscriber_alias` | Deprecated. Occurs whenever a new app_user_id has been registered for an existing subscriber. |
-| `subscription_paused` | Occurs whenever a subscription has been paused. |
-| `transfer ` | Occurs whenever a transfer of transactions and entitlements was initiated between one App User ID(s) to another. |
-| `expiration ` | Occurs whenever a subscription has expired and access should be removed. |
+| `renewal ` | Occurs whenever an existing subscription has been renewed. |
+| `product_change` | Occurs whenever a subscriber has changed the product of their subscription. |
+| `cancellation` | Occurs whenever a subscription or non-renewing purchase has been cancelled. See cancellation reasons for more details. |
+| `uncancellation ` | Occurs whenever an auto-renew status has been re-enabled for a subscription. |
+| `billing_issue` | Occurs whenever there has been a problem trying to charge the subscriber. This does not mean the subscription has expired. |
+| `subscriber_alias` | Deprecated. Occurs whenever a new app_user_id has been registered for an existing subscriber. |
+| `subscription_paused` | Occurs whenever a subscription has been paused. |
+| `transfer ` | Occurs whenever a transfer of transactions and entitlements was initiated between one App User ID(s) to another. |
+| `expiration ` | Occurs whenever a subscription has expired and access should be removed. |
- Select 'Install extension'. This will take about 3-5 minutes to complete
diff --git a/docs/platform-resources/apple-platform-resources/handling-refund-requests.md b/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
index 7c3383f4..2d24f861 100644
--- a/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
+++ b/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
@@ -4,16 +4,18 @@ slug: handling-refund-requests
hidden: false
---
-The Apple App Store evaluates several factors when deciding whether to approve or deny your customer's refund request. RevenueCat can help influence this process by providing Apple additional data about your customer's consumption of the purchase, along with your preferred resolution at the time of their refund request. Apple will use this information to help inform their refund decisions.
+The Apple App Store evaluates several factors when deciding whether to approve or deny your customer's refund request. RevenueCat can help influence this process by providing Apple additional data about your customer's consumption of the purchase, along with your preferred resolution at the time of their refund request. Apple will use this information to help inform their refund decisions.
RevenueCat charges no extra fees for refund request handling. For additional insights in your refund requests, check out our [App Store Refund Requests Chart](/dashboard-and-metrics/charts/app-store-refund-requests-chart).
## Prerequisites
-In order for RevenueCat to be notified of refund requests, you must have Apple App Store Server Notifications configured. If you do not have this set up yet, follow our setup instructions [here](/platform-resources/server-notifications/apple-server-notifications).
+
+In order for RevenueCat to be notified of refund requests, you must have Apple App Store Server Notifications configured. If you do not have this set up yet, follow our setup instructions [here](/platform-resources/server-notifications/apple-server-notifications).
Regardless of if you're on V1 or V2 of Apple App Store Server Notifications, RevenueCat supports both versions and we will be able to detect refund requests from Apple. For the best reliability, we recommend using V2 of the notifications.
## Handling of Refund Requests
+
To allow RevenueCat to send additional data of your customer's purchases to Apple, navigate to your RevenueCat app settings page and expand the **"Handling of refund requests"** section.
![](/images/apple-handling-refunds.png)
@@ -21,6 +23,7 @@ To allow RevenueCat to send additional data of your customer's purchases to Appl
The dropdown selector under **"Refund requests handling preference"** allows you to choose your preferred outcome for the refund request. Note that your refund preference is one of the several factors that Apple will use to inform its refund decisions.
For all refund requests, you can select from the following options:
+
- **Do not handle**: RevenueCat will not respond to Apple's refund request on your behalf.
- **Always prefer granting refunds**: You prefer that Apple grants the refund.
- **Always prefer declining refunds**: You prefer that Apple declines the refund.
@@ -29,9 +32,11 @@ For all refund requests, you can select from the following options:
Choose the option that best fits the majority of your use cases.
### Overriding refund preference
+
If, for example, you chose "Always prefer declining refunds", but have a specific customer or certain conditions under which you'd prefer Apple to grant a refund, you can override this preference before your customer submits their refund request directly to Apple.
To do so, you can use RevenueCat's [customer attributes](/customers/customer-attributes) to set a specific preference for any customer. RevenueCat provides a reserved customer attribute field, `$appleRefundHandlingPreference`, where you can set values such as:
+
- `DO_NOT_HANDLE`: Refund requests will not be handled for this customer. You can use this option to disable the feature for customers that have not provided consent.
- `GRANT_REFUND`: You prefer that Apple grants the refund for this customer.
- `DECLINE_REFUND`: You prefer that Apple declines the refund for this customer.
@@ -46,6 +51,7 @@ Overriding the customer's refund preference will only apply if you have enabled
:::
### Obtaining customer consent
+
By enabling this feature, you confirm that you have obtained consent from your customers to share their consumption data with Apple.
Here's a template to help get you started:
@@ -59,22 +65,23 @@ For general guidelines from Apple, visit their [documentation](https://developer
If you have a use case where you only update your Terms & Conditions (or an equivalent document) for new customers, while existing customers remain on the original terms, contact [RevenueCat support](https://app.revenuecat.com/settings/support) for assistance.
## Data RevenueCat sends to Apple
+
Below are the [properties](https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest) and data that RevenueCat will send to Apple when a refund request comes in.
-| Property | Description | What RevenueCat sends |
-|----------------------------|-----------------------------|------------------------------------------|
-| accountTenure | The age of the customer’s account. |
If customer exists in RC: Calculate age based on the creation date of that customer and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/accounttenure).
If customer does not exist in RC: 0 (*undeclared*)
|
-| appAccountToken | The optionally UUID of the in-app user account that completed the in-app purchase transaction. | Empty string |
-| consumptionStatus | A value that indicates the extent to which the customer consumed the in-app purchase. | 0 (*undeclared*) |
-| customerConsented | A Boolean value of true or false that indicates whether the customer consented to provide consumption data. | true, by turning this on this functionality, we assume you are asking your customers for consent. |
-| deliveryStatus | A value that indicates whether the app successfully delivered an in-app purchase that works properly. |
If the transaction exists in RC: 0 (*The app delivered the consumable in-app purchase and it’s working properly.*)
If the transaction does not exist in RC: 5 (*The app didn’t deliver the consumable in-app purchase for other reasons.*)
|
-| lifetimeDollarsPurchased | A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms. | Calculate the total of non-refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased). |
-| lifetimeDollarsRefunded | A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms. | Calculate the total of refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded). |
-| platform | A value that indicates the platform on which the customer consumed the in-app purchase. |
If your customer only has transactions from the App Store: 1 (*An Apple platform*)
If your customer has transactions from multiple stores: 0 (*undeclared*)
|
-| playTime | A value that indicates the amount of time that the customer used the app. | 0 (*undeclared*) |
-| refundPreference | A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund. |
The value for your customer's reserved customer attribute `$appleRefundHandlingPreference`
Otherwise, we will fall back to the option you chose in the dropdown selector
|
-| sampleContentProvided | A Boolean value of true or false that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality. | true |
-| userStatus | The status of the customer’s account. |
If the transaction exists in RC: 1 (*The customer’s account is active.*)
If the transaction does not exist in RC: 0 (*undeclared*)
|
+| Property | Description | What RevenueCat sends |
+| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| accountTenure | The age of the customer’s account. |
If customer exists in RC: Calculate age based on the creation date of that customer and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/accounttenure).
If customer does not exist in RC: 0 (_undeclared_)
|
+| appAccountToken | The optionally UUID of the in-app user account that completed the in-app purchase transaction. | Empty string |
+| consumptionStatus | A value that indicates the extent to which the customer consumed the in-app purchase. | 0 (_undeclared_) |
+| customerConsented | A Boolean value of true or false that indicates whether the customer consented to provide consumption data. | true, by turning this on this functionality, we assume you are asking your customers for consent. |
+| deliveryStatus | A value that indicates whether the app successfully delivered an in-app purchase that works properly. |
If the transaction exists in RC: 0 (_The app delivered the consumable in-app purchase and it’s working properly._)
If the transaction does not exist in RC: 5 (_The app didn’t deliver the consumable in-app purchase for other reasons._)
|
+| lifetimeDollarsPurchased | A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms. | Calculate the total of non-refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased). |
+| lifetimeDollarsRefunded | A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms. | Calculate the total of refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded). |
+| platform | A value that indicates the platform on which the customer consumed the in-app purchase. |
If your customer only has transactions from the App Store: 1 (_An Apple platform_)
If your customer has transactions from multiple stores: 0 (_undeclared_)
|
+| playTime | A value that indicates the amount of time that the customer used the app. | 0 (_undeclared_) |
+| refundPreference | A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund. |
The value for your customer's reserved customer attribute `$appleRefundHandlingPreference`
Otherwise, we will fall back to the option you chose in the dropdown selector
|
+| sampleContentProvided | A Boolean value of true or false that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality. | true |
+| userStatus | The status of the customer’s account. |
If the transaction exists in RC: 1 (_The customer’s account is active._)
If the transaction does not exist in RC: 0 (_undeclared_)
|
:::info Share your feedback
If you have any feedback about this feature, please reach out to our [RevenueCat support](https://app.revenuecat.com/settings/support) and we'll be happy to discuss your feedback or feature request!
diff --git a/docs/tools/paywalls-v2/creating-paywalls/components.mdx b/docs/tools/paywalls-v2/creating-paywalls/components.mdx
index 7b3b2e91..712449cd 100644
--- a/docs/tools/paywalls-v2/creating-paywalls/components.mdx
+++ b/docs/tools/paywalls-v2/creating-paywalls/components.mdx
@@ -83,7 +83,7 @@ An image can have a overlay applied of a solid color or a gradient, along with a
Alt text can be configured for each image to make them more accessible.
-To configure alt text, first open that image in the media gallery, which you can accesss by clicking on `Replace image` within an image component's properties. Then, hover of the image you want to edit and click the eye icon that appears to view its details.
+To configure alt text, first open that image in the media gallery, which you can access by clicking on `Replace image` within an image component's properties. Then, hover of the image you want to edit and click the eye icon that appears to view its details.
![Image details](/images/paywalls-image-details.png)
diff --git a/docs/web/revenuecat-billing.mdx b/docs/web/revenuecat-billing.mdx
index fa499d74..b214bbed 100644
--- a/docs/web/revenuecat-billing.mdx
+++ b/docs/web/revenuecat-billing.mdx
@@ -297,16 +297,16 @@ The following table lists the sandbox renewal periods for subscriptions of vario
#### Subscription Renewal Periods
| Production Subscription Period | Sandbox Subscription Period |
-| ------------------------------ | ---------------------------- |
-| 1 day (P1D) | 5 minutes |
-| 3 days (P3D) | 5 minutes |
-| 1 week (P1W) | 5 minutes |
-| 2 weeks (P2W) | 5 minutes |
-| 1 month (P1M) | 5 minutes |
-| 2 months (P2M) | 10 minutes |
-| 3 months (P3M) | 15 minutes |
-| 6 months (P6M) | 30 minutes |
-| 1 year (P1Y) | 60 minutes |
+| ------------------------------ | --------------------------- |
+| 1 day (P1D) | 5 minutes |
+| 3 days (P3D) | 5 minutes |
+| 1 week (P1W) | 5 minutes |
+| 2 weeks (P2W) | 5 minutes |
+| 1 month (P1M) | 5 minutes |
+| 2 months (P2M) | 10 minutes |
+| 3 months (P3M) | 15 minutes |
+| 6 months (P6M) | 30 minutes |
+| 1 year (P1Y) | 60 minutes |
#### Time-based Subscription Features
diff --git a/docs/web/revenuecat-billing/lifecycle-emails.mdx b/docs/web/revenuecat-billing/lifecycle-emails.mdx
index 4707a105..ca23abd8 100644
--- a/docs/web/revenuecat-billing/lifecycle-emails.mdx
+++ b/docs/web/revenuecat-billing/lifecycle-emails.mdx
@@ -4,6 +4,7 @@ slug: lifecycle-emails
excerpt: Details of emails sent to subscribers about their purchases and subscriptions
hidden: false
---
+
:::warning Beta Feature
RevenueCat Billing and the RevenueCat Web SDK are currently in beta.
:::
@@ -11,11 +12,13 @@ RevenueCat Billing and the RevenueCat Web SDK are currently in beta.
Customers purchasing through RevenueCat Billing will receive emails related to their subscriptions and other purchases on the web.
Emails sent to customers:
+
- Come from a RevenueCat domain
- Display your **app name** as the sender (configured in RevenueCat Billing settings)
-- Use your **support email address** as the *reply-to* (configured in the RevenueCat Billing app settings, if set) or `noreply@revenuecat.com` by default”
+- Use your **support email address** as the _reply-to_ (configured in the RevenueCat Billing app settings, if set) or `noreply@revenuecat.com` by default”
## Email customization
+
Lifecycle emails are lightly customized according to your brand colors configured in the RevenueCat dashboard (see [Customization](/web/revenuecat-billing/customization)).
Only the `Page background` and `Primary button` colors are used to brand emails. Text colors are automatically determined, based on contrast with the background.
@@ -26,17 +29,16 @@ Only the `Page background` and `Primary button` colors are used to brand emails.
You can find a complete list of customer emails below, in addition to the triggers that are used to send them.
-|Email | Trigger | Call to action |
-|--- |--- |--- |
-|Free trial start |The customer started a free trial | n/a |
-|Initial purchase |The customer made a successful purchase (either a subscription or one-time purchase) | Redeem purchase (when [Redemption Links](/web/revenuecat-billing/redemption-links) enabled) |
-|Redemption link refresh |The customer attempted to use an expired redemption link, so a new one was sent to them | Redeem purchase (when [Redemption Links](/web/revenuecat-billing/redemption-links) enabled) |
-|Customer portal login |The customer initiated access to the [customer portal](/web/revenuecat-billing/customer-portal) | Manage subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
-|Subscription renewal |The customer's subscription automatically renewed at the end of their billing period | n/a |
-|Failed payment |A renewal payment failed (after several retries) | Manage subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
-|Subscription cancelation |The customer canceled their subscription | Renew subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
-|Subscription renewed (after cancelation) |The customer renewed their subscription after previously canceling, before it expired| n/a |
-|Subscription expiry |The customer's subscription expired and will not be renewed | n/a |
-|Chargeback detected |RevenueCat detected a chargeback from the customer, and the subscription was immediately canceled as a result | n/a |
-|Refund issued |A refund was issued to the customer | n/a |
-
+| Email | Trigger | Call to action |
+| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
+| Free trial start | The customer started a free trial | n/a |
+| Initial purchase | The customer made a successful purchase (either a subscription or one-time purchase) | Redeem purchase (when [Redemption Links](/web/revenuecat-billing/redemption-links) enabled) |
+| Redemption link refresh | The customer attempted to use an expired redemption link, so a new one was sent to them | Redeem purchase (when [Redemption Links](/web/revenuecat-billing/redemption-links) enabled) |
+| Customer portal login | The customer initiated access to the [customer portal](/web/revenuecat-billing/customer-portal) | Manage subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
+| Subscription renewal | The customer's subscription automatically renewed at the end of their billing period | n/a |
+| Failed payment | A renewal payment failed (after several retries) | Manage subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
+| Subscription cancelation | The customer canceled their subscription | Renew subscription in [customer portal](/web/revenuecat-billing/customer-portal) |
+| Subscription renewed (after cancelation) | The customer renewed their subscription after previously canceling, before it expired | n/a |
+| Subscription expiry | The customer's subscription expired and will not be renewed | n/a |
+| Chargeback detected | RevenueCat detected a chargeback from the customer, and the subscription was immediately canceled as a result | n/a |
+| Refund issued | A refund was issued to the customer | n/a |
diff --git a/docs/web/revenuecat-billing/product-setup.md b/docs/web/revenuecat-billing/product-setup.md
index cc60b2c2..352f7712 100644
--- a/docs/web/revenuecat-billing/product-setup.md
+++ b/docs/web/revenuecat-billing/product-setup.md
@@ -22,17 +22,17 @@ In the "new product" screen, you can set up the following properties of the prod
- **Description**: Customer-facing description of the Product. Available from the Web SDK, eg. to show on your paywall.
- **Display name**: An optional human readable name for the Product, will be shown on the dashboard instead of the identifier.
- **Product type**: The type of product being sold:
- - *Auto-renewing subscription*: A recurring subscription purchase, that continues on a given interval until canceled.
- - *Consumable*: A non-recurring purchase that can be purchased one or more times (repeated).
- - *Non-consumable*: A non-recurring purchase that can only be purchased once.
-- **Duration**: The billing cycle (period length) of the subscription. *See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode.*
-- **Free trial period**: The duration of a free trial. *See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode.*
+ - _Auto-renewing subscription_: A recurring subscription purchase, that continues on a given interval until canceled.
+ - _Consumable_: A non-recurring purchase that can be purchased one or more times (repeated).
+ - _Non-consumable_: A non-recurring purchase that can only be purchased once.
+- **Duration**: The billing cycle (period length) of the subscription. _See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode._
+- **Free trial period**: The duration of a free trial. _See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode._
- **Trial eligibility**: Which customers have access to the free trial:
- - *Everyone*: Every customer will start a subscription to this product with a trial, even if they had a trial before. *Please note:* If you choose this option, it means that customers could continuously cancel their trial and start another trial to keep getting free access.
- - *Has never made any purchase*: Only customers that have never made any purchase in this Project (including non-subscription purchases and purchases in other Apps of this project) are eligible for a trial.
- - *Didn't have any subscription yet*: Only customers that have never had any subscription in this Project (including in other Apps of the project) are eligible for a trial.
- - *Didn't have this subscription yet*: Only customers that have never subscribed to this product are eligible for a trial.
-- **Grace period**: Length of the subscription access retention after a billing issue. *See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode.*
+ - _Everyone_: Every customer will start a subscription to this product with a trial, even if they had a trial before. _Please note:_ If you choose this option, it means that customers could continuously cancel their trial and start another trial to keep getting free access.
+ - _Has never made any purchase_: Only customers that have never made any purchase in this Project (including non-subscription purchases and purchases in other Apps of this project) are eligible for a trial.
+ - _Didn't have any subscription yet_: Only customers that have never had any subscription in this Project (including in other Apps of the project) are eligible for a trial.
+ - _Didn't have this subscription yet_: Only customers that have never subscribed to this product are eligible for a trial.
+- **Grace period**: Length of the subscription access retention after a billing issue. _See [Sandbox testing](/web/revenuecat-billing#renewals-in-sandbox) for more information about durations in sandbox mode._
- **Price**: The price that will be charged for every period of the subscription in each currency. You can add prices in additional currencies by clicking "Add price". Only one price can be set per currency. [Read more about multi-currency support in RevenueCat Billing](/web/revenuecat-billing/multi-currency-support).
![New product configuration page](/images/rc-billing/new-product-configuration.png)