|
| 1 | +--- |
| 2 | +title: Virtual Currency |
| 3 | +sidebar_label: Virtual Currency |
| 4 | +slug: virtual-currency |
| 5 | +hidden: false |
| 6 | +--- |
| 7 | + |
| 8 | +Virtual currencies are digital assets used within your app to facilitate transactions, unlock premium features, or enhance customer engagement. These currencies are typically acquired through in-app purchases, rewards, or gameplay achievements and do not have intrinsic real-world value outside the application. They can be used for purchasing virtual goods, upgrading characters, or accessing exclusive content. Common examples include tokens, coins, credits, or other units that can be replenished through purchases. You can leverage virtual currencies to monetize apps, encourage customer retention, and create a more immersive experience. |
| 9 | + |
| 10 | +:::info |
| 11 | +This feature is in an early stage and may change without notice in future releases. To request access, please do so [here](https://form.typeform.com/to/DUXgfEJN). |
| 12 | +::: |
| 13 | + |
| 14 | +## Configuration |
| 15 | + |
| 16 | +In RevenueCat, virtual currencies are defined at the project level. You can configure up to 100 virtual currencies per project and use them to enrich your app experience. |
| 17 | + |
| 18 | +1. Click the **“Virtual Currencies”** option in the **“Product catalog”** of your project sidebar in RevenueCat |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +2. Select **“+ New” button** in the top right corner. The **“New Currency”** form will appear. Enter a code and a name for your currency. |
| 23 | + |
| 24 | +- **Code**: This is used across various APIs to identify the virtual currency (e.g: GLD) |
| 25 | +- **Icon** (_optional_): Choose an icon to visually represent this currency in the dashboard |
| 26 | +- **Name**: This should be a readable name for the currency that you're creating (e.g: GOLD) |
| 27 | +- **Description** (_optional_): A description of what this currency represents or how it is used (e.g: Can be used to purchase in-app items) |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +3. You can optionally associate products with your new currency. Every time customers purchase one of these products, the defined amount of virtual currency will be added to their balance. Click **"NEW ASSOCIATED PRODUCT"**, pick a product and fill in the amount. |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +You can associate as many products as you want with your virtual currency and you can also associate a product with more than one virtual currency, meaning once it's purchased, multiple types of virtual currencies are added to the customer's balance. If you have not yet configured any products, see our [documentation](/offerings/products/setup-index) for further instructions. |
| 36 | + |
| 37 | +:::warning Only non-subscription products are supported |
| 38 | +Currently, only [non-subscription products](/platform-resources/non-subscriptions), such as consumables, are supported for currency grants. When a customer purchases a non-subscription product linked to a virtual currency, we will automatically grant the corresponding currency amount to their balance. Subscription-based products are not yet supported for this functionality. |
| 39 | +::: |
| 40 | + |
| 41 | +4. Remember to select "SAVE" in the upper right-hand corner. Repeat this process if to create more than one currency. |
| 42 | + |
| 43 | +## Dashboard balances |
| 44 | + |
| 45 | +Once your customer purchase the associated products they will get the defined amount of your virtual currency. You can inspect the virtual currency balances of your customer in the right side-panel of the customer page. |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | +## SDK Beta Installation |
| 50 | + |
| 51 | +SDK support for virtual currencies is currently in beta, and as such requires the usage of a beta build. Please note that the virtual currency APIs in these betas are subject to change without warning in future releases. The beta virtual currency features are currently available in the native iOS and Android SDKs. |
| 52 | + |
| 53 | +### iOS |
| 54 | + |
| 55 | +Use the `virtual-currency-beta` branch of the purchases-ios SDK to access the virtual currency beta features. If you’re using Swift Package Manager, you can do this in Xcode like so: |
| 56 | + |
| 57 | + |
| 58 | + |
| 59 | +### Android |
| 60 | + |
| 61 | +When adding the purchases-android SDK to your app, use the most recent `vc-beta` version when adding `purchases-android` to your `build.gradle`: |
| 62 | + |
| 63 | +[](https://github.com/RevenueCat/purchases-android/releases) |
| 64 | + |
| 65 | +```kotlin |
| 66 | +implementation 'com.revenuecat.purchases:purchases:8.14.2-vc-beta.1' |
| 67 | +``` |
| 68 | + |
| 69 | +When you use the beta virtual currency features, you’ll need to annotate your function/class with the `@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)` annotation: |
| 70 | + |
| 71 | +import androidExperimentalAPIAnnotationExample from "!!raw-loader!@site/code_blocks/virtual-currency/vc-android-experimental-api-annotation-example.kt"; |
| 72 | + |
| 73 | +<RCCodeBlock |
| 74 | + tabs={[ |
| 75 | + { |
| 76 | + type: "kotlin", |
| 77 | + content: androidExperimentalAPIAnnotationExample, |
| 78 | + }, |
| 79 | + ]} |
| 80 | +/> |
| 81 | + |
| 82 | +## Usage |
| 83 | + |
| 84 | +### Prerequisites |
| 85 | + |
| 86 | +The endpoints available for virtual currency are supported through our REST V2 API endpoints. You will need a secret key to access it. Make sure that your key at least has Read & Write permissions for Customer Purchases Configuration. See our [documentation](<https://www.revenuecat.com/docs/api-v2#tag/Overview-(v2)/Authentication>) for more details on how you can access RevenueCat’s REST V2 APIs. |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | +### Depositing or spending |
| 91 | + |
| 92 | +You can deposit or spend currency by calling the virtual currency transactions REST API V2 endpoint from the backend of your app: |
| 93 | + |
| 94 | +import content1 from "!!raw-loader!@site/code_blocks/virtual-currency/transactions.curl"; |
| 95 | + |
| 96 | +<RCCodeBlock |
| 97 | + tabs={[ |
| 98 | + { |
| 99 | + type: "curl", |
| 100 | + content: content1, |
| 101 | + }, |
| 102 | + ]} |
| 103 | +/> |
| 104 | + |
| 105 | +The example request will deduct 20 GLD and 10 SLV from the customer's balance. Upon successful execution, the response will contain the updated balances of the virtual currencies that were spent. |
| 106 | + |
| 107 | +Note that sufficient balances of both currency types are required for the transaction to succeed. If not, the transaction will fail with HTTP 422 error and no virtual currency will be deducted. |
| 108 | + |
| 109 | +import content2 from "!!raw-loader!@site/code_blocks/virtual-currency/transaction-response.json"; |
| 110 | +import failed_adjustment from "!!raw-loader!@site/code_blocks/virtual-currency/transaction-adjustment-failed.json"; |
| 111 | + |
| 112 | +<RCCodeBlock |
| 113 | + tabs={[ |
| 114 | + { |
| 115 | + type: "json", |
| 116 | + content: content2, |
| 117 | + name: "200", |
| 118 | + }, |
| 119 | + { |
| 120 | + type: "json", |
| 121 | + content: failed_adjustment, |
| 122 | + name: "422", |
| 123 | + }, |
| 124 | + ]} |
| 125 | +/> |
| 126 | + |
| 127 | +Multiple virtual currency types can be adjusted in a single transaction. Deductions and additions can also be combined. For example, you can execute the conversion of 50 GLD to 200 SLV with the following transaction: |
| 128 | + |
| 129 | +import content3 from "!!raw-loader!@site/code_blocks/virtual-currency/transaction-adjustment.json"; |
| 130 | + |
| 131 | +<RCCodeBlock |
| 132 | + tabs={[ |
| 133 | + { |
| 134 | + type: "json", |
| 135 | + content: content3, |
| 136 | + }, |
| 137 | + ]} |
| 138 | +/> |
| 139 | + |
| 140 | +### Reading balances |
| 141 | + |
| 142 | +#### From your backend |
| 143 | + |
| 144 | +The following endpoint allows you to retrieve a customer's current balance from your backend: |
| 145 | + |
| 146 | +import content4 from "!!raw-loader!@site/code_blocks/virtual-currency/balance.curl"; |
| 147 | + |
| 148 | +<RCCodeBlock |
| 149 | + tabs={[ |
| 150 | + { |
| 151 | + type: "curl", |
| 152 | + content: content4, |
| 153 | + }, |
| 154 | + ]} |
| 155 | +/> |
| 156 | + |
| 157 | +The response will include the balances for all the virtual currencies that the customer has. |
| 158 | + |
| 159 | +import content5 from "!!raw-loader!@site/code_blocks/virtual-currency/balance-response.json"; |
| 160 | + |
| 161 | +<RCCodeBlock |
| 162 | + tabs={[ |
| 163 | + { |
| 164 | + type: "json", |
| 165 | + content: content5, |
| 166 | + }, |
| 167 | + ]} |
| 168 | +/> |
| 169 | + |
| 170 | +#### From the SDK |
| 171 | + |
| 172 | +If you're using the virtual currency SDK betas, you can fetch the virtual currency balances from the [CustomerInfo](https://www.revenuecat.com/docs/customers/customer-info) object in the SDK: |
| 173 | + |
| 174 | +import fetchVCBalancesSwift from "!!raw-loader!@site/code_blocks/virtual-currency/vc-balance-sdk-ios.swift"; |
| 175 | +import fetchVCBalancesKotlin from "!!raw-loader!@site/code_blocks/virtual-currency/vc-balance-sdk-android.kt"; |
| 176 | + |
| 177 | +<RCCodeBlock |
| 178 | + tabs={[ |
| 179 | + { |
| 180 | + type: "swift", |
| 181 | + content: fetchVCBalancesSwift, |
| 182 | + name: "Swift", |
| 183 | + }, |
| 184 | + { |
| 185 | + type: "kotlin", |
| 186 | + content: fetchVCBalancesKotlin, |
| 187 | + name: "Kotlin", |
| 188 | + }, |
| 189 | + ]} |
| 190 | +/> |
| 191 | + |
| 192 | +## Best practices and security considerations |
| 193 | + |
| 194 | +Virtual currencies is a very powerful feature that RevenueCat provides, however it needs to be used correctly to ensure high standards of security. Here are some necessary requirements in order to make sure that bad actors cannot exploit your system for their benefit or to harm other users of your app. |
| 195 | + |
| 196 | +### Virtual currency transactions should be securely initiated by a backend server |
| 197 | + |
| 198 | +Transactions that add or remove virtual currencies to your customer balances, except for In-App Purchases, should be initiated by the backend of your Application. These requests require RevenueCat secret API keys to be authenticated, and these keys need to be securely stored and never be exposed to the public. |
| 199 | + |
| 200 | +It’s fine if your backend provides APIs for your app to initiate virtual currency transactions, however, these APIs should not allow direct modifications of customer balances. Instead they should only support operations that do not require direct input of amounts and they should always perform the necessary validations to ensure that the customer has the rights and meets the requirements to perform the requested transaction. |
| 201 | + |
| 202 | +See some examples of secure and unsecure backend APIs: |
| 203 | + |
| 204 | +import content9 from "!!raw-loader!@site/code_blocks/virtual-currency/do-1.txt"; |
| 205 | +import content10 from "!!raw-loader!@site/code_blocks/virtual-currency/do-not-1.txt"; |
| 206 | +import content11 from "!!raw-loader!@site/code_blocks/virtual-currency/do-2.txt"; |
| 207 | +import content12 from "!!raw-loader!@site/code_blocks/virtual-currency/do-not-2.txt"; |
| 208 | + |
| 209 | +| Do ✅ | Do not! ❌ | |
| 210 | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 211 | +| <RCCodeBlock tabs={[{type: "json", content: content9, },]}/> The backend knows the price of the product and charges accordingly. Also it should check that the customer has the right to purchase the product. | <RCCodeBlock tabs={[{type: "json", content: content10, },]}/> The backend blindly attaches the product to the customer and spends the amount that is defined in the request. | |
| 212 | +| <RCCodeBlock tabs={[{type: "json", content: content11, },]}/> The backend grants 100 Gold to the customer after checking that they indeed reached a new level in the game and the reward is not already provided. | <RCCodeBlock tabs={[{type: "json", content: content12, },]}/> The backend blindly rewards 500 GLD to the customer according the HTTP request data. | |
| 213 | + |
| 214 | +Following this will ensure that the users of your app cannot tamper / fake requests to your backend for their benefit. |
| 215 | + |
| 216 | +### Communication between your app and your backend should be encrypted and authenticated |
| 217 | + |
| 218 | +All the requests from your app to your backend that could trigger a virtual currency transaction need to be encrypted and authenticated. Make sure you use TLS or equivalent encryption technologies. Also ensure that all the requests that can trigger a virtual currency transaction are authenticated using well proved methodology. |
| 219 | + |
| 220 | +Here are a few options to consider: |
| 221 | + |
| 222 | +- Password based authentication |
| 223 | +- Two/Multifactor authentication |
| 224 | +- Token based authentication (e.g. JWT, OAuth 2.0) |
| 225 | +- Single sign on using widely used services (Google, Facebook, Apple etc) |
| 226 | +- Other equivalent or stronger technologies |
| 227 | + |
| 228 | +With this you will ensure that requests that could trigger virtual currency transactions for an account of your app can only be initiated by the actual account owner. |
0 commit comments