Skip to content

Commit baac6c8

Browse files
authored
Virtual currency FAQ docs section (#1028)
* introduces 2 faq docs and some minor doc updates * typos * incorporate feedback * feedback and minor updates * update sidebar text * minor update
1 parent f31d646 commit baac6c8

14 files changed

+228
-17
lines changed

docs/offerings/virtual-currency.mdx

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -234,23 +234,6 @@ Virtual currency adjustments made through the [API](/offerings/virtual-currency#
234234

235235
For more information about virtual currency events, including customer timeline events and webhook events, see our [Virtual Currency Events](/offerings/virtual-currency/events) documentation.
236236

237-
### RevenueCat's Firebase Extension integration
238-
239-
If you have the [Firebase Extension integration](/integrations/third-party-integrations/firebase-integration#4-send-customer-information-to-firestore) enabled, RevenueCat will include the customer's virtual currency balance in the dispatched events' payload. Balance changes due to other reasons, such as manual adjustments through our Developer API endpoints **will not** trigger an event.
240-
241-
When an event is dispatched, the Firebase Extension event payload will include a `virtual_currencies` object containing the customer's **total balance** for each currency after the purchase. The below example shows the customer's total balance for "GLD" is 80, while "SLV" is 40.
242-
243-
import firebaseExtensionPayload from "@site/code_blocks/virtual-currency/firebase-balance.json?raw";
244-
245-
<RCCodeBlock
246-
tabs={[
247-
{
248-
type: "json",
249-
content: firebaseExtensionPayload,
250-
},
251-
]}
252-
/>
253-
254237
## Best practices and security considerations
255238

256239
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.

docs/offerings/virtual-currency/events.mdx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,23 @@ Example of a multi-currency transaction:
121121
- **Fraud Detection**: Monitor for unusual patterns in virtual currency transactions
122122
- **Customer Support**: Use timeline events to help customers understand their transaction history
123123

124+
## RevenueCat's Firebase Extension integration
125+
126+
If you have the [Firebase Extension integration](/integrations/third-party-integrations/firebase-integration#4-send-customer-information-to-firestore) enabled, RevenueCat will include the customer's virtual currency balance in the dispatched events' payload. Balance changes due to other reasons, such as manual adjustments through our Developer API endpoints **will not** trigger an event.
127+
128+
When an event is dispatched, the Firebase Extension event payload will include a `virtual_currencies` object containing the customer's **total balance** for each currency after the purchase. The below example shows the customer's total balance for "GLD" is 80, while "SLV" is 40.
129+
130+
import firebaseExtensionPayload from "@site/code_blocks/virtual-currency/firebase-balance.json?raw";
131+
132+
<RCCodeBlock
133+
tabs={[
134+
{
135+
type: "json",
136+
content: firebaseExtensionPayload,
137+
},
138+
]}
139+
/>
140+
124141
## Next Steps
125142

126143
- [Webhook Event Types and Fields](/integrations/webhooks/event-types-and-fields#virtual-currency-transaction-fields)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
title: Balance Source of Truth
3+
sidebar_label: Balance Source of Truth
4+
slug: balance-source-of-truth
5+
hidden: false
6+
---
7+
8+
When implementing virtual currencies in your app, an important architectural decision is choosing where the source of truth for the customer's balance should be maintained.
9+
10+
There are two common approaches:
11+
12+
- RevenueCat as the source of truth
13+
- Your backend as the source of truth
14+
15+
Which path you choose depends on your starting point and existing infrastructure.
16+
17+
## Approach 1: RevenueCat as Source of Truth (Recommended for New Setups)
18+
19+
RevenueCat is designed to be the **single source of truth** for virtual currency balances and transaction history. If you're implementing virtual currencies for the first time (no existing balance logic or storage), we recommend using RevenueCat as the system of record.
20+
21+
With this approach:
22+
23+
- RevenueCat tracks balances
24+
- Currencies are granted automatically after successful purchases
25+
- RevenueCat validates and deducts currencies during spend operations
26+
- Your app can fetch the current balance via the SDK
27+
28+
### How It Works
29+
30+
The following diagrams walk through the flow of a check balance, purchase, and spend where RevenueCat manages the balance.
31+
32+
![](/docs_images/virtual-currency/VC_RC_FLOW_CHECK_BALANCE.png)
33+
34+
#### 🔹 Balance Check Flow
35+
36+
1. The customer opens the app
37+
2. The app calls `.virtualCurrencies()` to fetch the customer's balance. For code samples see our [docs](/offerings/virtual-currency#from-the-sdk)
38+
3. RevenueCat responds with the balance
39+
4. The app displays the balance
40+
41+
:::warning
42+
The balance is cached. You should call `invalidateVirtualCurrenciesCache()` before fetching again if you want fresh data (e.g. after a purchase or spend).
43+
:::
44+
45+
![](/docs_images/virtual-currency/VC_RC_FLOW_PURCHASE.png)
46+
47+
#### 🔹 Purchase Flow (Buy Coins)
48+
49+
1. The customer taps “Buy 100 Coins”
50+
2. The app calls purchase(product) via RevenueCat
51+
3. RevenueCat validates the transaction with the Store
52+
4. RevenueCat grants the coins automatically and updates the balance server-side
53+
5. The app can re-fetch the balance and display the new amount
54+
55+
:::success
56+
RevenueCat tracks the balance and grants coins directly. No backend logic is needed for purchases.
57+
:::
58+
59+
![](/docs_images/virtual-currency/VC_RC_FLOW_SPEND.png)
60+
61+
#### 🔹 Spend Flow (Use Coins)
62+
63+
1. The customer tries to spend 10 coins
64+
2. The app notifies your backend to spend the coins, which would call RevenueCat via a [`POST /virtual_currencies/transactions`](https://www.revenuecat.com/docs/api-v2#tag/Customer/operation/create-virtual-currencies-transaction) request
65+
3. RevenueCat checks if the customer has sufficient balance and, if so, subtracts the amount
66+
4. RevenueCat will notify your backend the request was successful
67+
5. The app fetches the new balance (remember to invalidate cache)
68+
6. The app grants what the coins unlocked
69+
70+
:::info
71+
Your backend is only responsible for interpreting what the 10 coins should unlock. RevenueCat handles validation and deduction.
72+
:::
73+
74+
## Approach 2: Your Backend as Source of Truth
75+
76+
If you've already implemented a virtual currency system on your backend (e.g: for web), it likely makes sense to continue treating your backend as the source of truth and rely on RevenueCat webhooks to update balances when purchases are made or when subscription lifecycle changes.
77+
78+
In this model:
79+
80+
- RevenueCat handles purchase validation and emits `VIRTUAL_CURRENCY_TRANSACTION` webhooks
81+
- Your backend listens for these webhooks and updates the customer's balance
82+
- Your app fetches balances directly from your backend
83+
- Spending is initiated from the app → your backend, which performs balance validation and deducts currency accordingly
84+
85+
This approach allows you to keep centralized control of balances, while leveraging RevenueCat’s virtual currency logic to determine the correct amount of currency to grant for each purchase.
86+
87+
### How It Works
88+
89+
This diagrams illustrate how your backend listens to RevenueCat webhooks and handles balance management.
90+
91+
![](/docs_images/virtual-currency/VC_BACKEND_FLOW_CHECK_BALANCE.png)
92+
93+
#### 🔹 Balance Check Flow
94+
95+
1. The customer wants to see their balance
96+
2. The app requests the balance from your backend
97+
3. The backend responds with the current balance
98+
4. The app displays the balance to the customer
99+
100+
![](/docs_images/virtual-currency/VC_BACKEND_FLOW_PURCHASE.png)
101+
102+
#### 🔹 Purchase Flow (Buy Coins)
103+
104+
1. The customer initiates a purchase in the app
105+
2. The app uses the RevenueCat SDK to call purchase(product)
106+
3. RevenueCat validates the transaction with the Store
107+
4. Once verified, RevenueCat emits a [`VIRTUAL_CURRENCY_TRANSACTION` webhook](/offerings/virtual-currency/events#webhook-events)
108+
5. Your backend receives this webhook and updates the customer's balance accordingly
109+
6. The app can then fetch and display the updated balance
110+
111+
:::info
112+
RevenueCat tracks the amount of virtual currency granted from purchases and subscriptions. As a result, the balance shown in RevenueCat may get out of sync with your system if spending occurs outside of RevenueCat.
113+
:::
114+
115+
![](/docs_images/virtual-currency/VC_BACKEND_FLOW_SPEND.png)
116+
117+
#### 🔹 Spend Flow (Use Coins)
118+
119+
1. The customer chooses to spend 10 coins in the app
120+
2. The app sends a message to your backend: “Spend 10 coins”
121+
3. Your backend contains the business logic to determine what the coins unlock (e.g., an item or feature)
122+
4. Your backend checks if the customer has enough balance, and if so, deducts the amount and returns a success response
123+
5. The app updates the UI and shows what was unlocked
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
title: Virtual Items
3+
sidebar_label: Virtual Items
4+
slug: virtual-items
5+
hidden: true
6+
---
7+
8+
RevenueCat’s Virtual Currency feature is designed to help you track and manage balances of in-app currencies, such as coins, tokens, or minutes granted via purchases. While we don’t natively support managing "virtual items" (e.g., consumable items like tickets, skins, or passes that are bought using virtual currency), it’s possible to work around this limitation using a creative implementation of multiple virtual currencies.
9+
10+
This guide walks you through how to implement this pattern.
11+
12+
## Treat Items as Virtual Currencies
13+
14+
If your app has a **small and fixed set of virtual items**, you can represent each item as its own virtual currency.
15+
16+
:::warning 100 virtual currency limit
17+
RevenueCat has a limit of 100 virtual currencies per project that can be configured.
18+
:::
19+
20+
Example scenario:
21+
You want to sell:
22+
23+
- Tickets (cost: 2 coins)
24+
- Passes (cost: 5 coins)
25+
26+
Set up the following virtual currencies in RevenueCat:
27+
28+
- `Coins`: Your primary currency
29+
- `Tickets`: Treated as a currency, but really represents an owned item
30+
- `Passes`: Same as above
31+
32+
## Purchasing a Virtual Item
33+
34+
### 1. Customer Initiates Item Purchase
35+
36+
![](/docs_images/virtual-currency/VIRTUAL_ITEMS_PURCHASE.png)
37+
38+
The customer decides to buy a virtual item (e.g., a ticket) using their coins.
39+
40+
- **Action:** Customer taps "Buy Ticket (2 coins)" in the app.
41+
- **App → Your backend request:**
42+
```http
43+
POST /api/purchase-ticket
44+
Content-Type: application/json
45+
{
46+
"app_user_id": "app_user_id",
47+
"item": "ticket"
48+
}
49+
```
50+
51+
### 2. Your Backend Contacts RevenueCat API
52+
53+
![](/docs_images/virtual-currency/VIRTUAL_ITEMS_BACKEND_TO_RC.png)
54+
55+
- **API Request to RevenueCat:**
56+
```http
57+
curl --location 'https://api.revenuecat.com/v2/projects/<YOUR_PROJECT_ID>/customers/<YOUR_CUSTOMER_ID>/virtual_currencies/transactions' \
58+
--header 'Content-Type: application/json' \
59+
--header 'Authorization: Bearer sk_***************************' \
60+
--data '{
61+
"adjustments": {
62+
"Coins": -2,
63+
"Tickets": +1
64+
}
65+
}'
66+
```
67+
- **Validation:** RevenueCat checks that the customer has enough coins and that the transaction is atomic (both succeed or both fail).
68+
69+
### 3. Your App Processes Result
70+
71+
![](/docs_images/virtual-currency/VIRTUAL_ITEMS_APP.png)
72+
73+
- On success:
74+
- After any purchases or spends, make sure to invalidate the virtual currencies cache through `invalidateVirtualCurrenciesCache()`
75+
- Call RevenueCat's `.virtualCurrencies()` SDK method to fetch the updated balance. In this scenario, the updated balance will contain the coin's balance of 8 and ticket's balance of 1
76+
- On failure:
77+
- This means the customer did not have enough balance to perform the transaction. You should show them a paywall to top-up and/or show an insufficient balance message

sidebars.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ const offeringsCategory = Category({
321321
Page({ slug: "subscriptions" }),
322322
Page({ slug: "refunds" }),
323323
Page({ slug: "events" }),
324+
SubCategory({
325+
label: "Virtual Currency FAQs",
326+
itemsPathPrefix: "faq/",
327+
items: [Page({ slug: "balance-source-of-truth" })],
328+
index: {
329+
title: "Virtual Currency FAQs",
330+
link: "/faq",
331+
description:
332+
"Additional guidance for the Virtual Currency feature.",
333+
},
334+
}),
324335
],
325336
}),
326337
Page({ slug: "offerings/troubleshooting" }),
158 KB
Loading
262 KB
Loading
207 KB
Loading
163 KB
Loading
354 KB
Loading

0 commit comments

Comments
 (0)