---
title: "How to monetize an app with virtual currencies"
description: "Monetize an app with credits: how grants and spending work, why credits need a backend, Apple's expiry rules, and what breaks after you launch."
url: "https://adapty.io/blog/monetize-app-virtual-currencies/"
language: "en"
slug: "monetize-app-virtual-currencies"
category: "build-integrate"
date: "2026-08-03T10:15:23.856Z"
date_modified: "2026-08-03T10:21:10.474Z"
author: "Victoria Kharlan"
---

# How to monetize an app with virtual currencies

## TL;DR

- A virtual currency turns a purchase into a balance your app spends. Grant, spend, and track.
- App Store and Google Play purchases grant credits automatically. Anything else, including web payments, rewards, and promos, you grant through the API.
- Spending runs from your server today, with SDK methods in the works.
- Purchased credits and subscription-granted credits are stored separately, which is why only the second kind can expire.

Credits fit when something in your app costs you money every time someone uses it. A generation, a render, an export, an episode. If your costs stay flat no matter how much people use the product, a subscription tier is the simpler answer, and you can stop here.

For everyone else, setting up a currency in the dashboard takes an afternoon. What takes longer is everything after: getting Apple to approve a consumable before your credits UI exists, deciding what happens to a balance when someone reinstalls, and finding out which credits you're allowed to expire.

One thing to know before you start. Credits are granted automatically when someone buys a linked product on the App Store or Google Play. Sell through Stripe or Paddle and no grant fires on its own, so your backend calls the grant API after your own webhook confirms the payment.

If you haven't created a currency yet, [the quickstart](https://adapty.io/docs/virtual-currency-quickstart) covers the dashboard side. This covers the rest.

## What is a virtual currency in an app?

A virtual currency is a balance your app grants and spends on the user's behalf. Someone buys 500 coins for $4.99, then spends 50 to unlock an episode, 10 to generate an image, and 200 to buy a course. Credits also arrive without a purchase behind them: a referral bonus, a daily free allowance, a goodwill gesture after something went wrong. Your app moves the number either way.

![The same credit mechanic across four app categories, with paywalls showing audio generation credits, episode coins in a drama app, a gem store in a game, and data credits for an eSIM app, from Adapty's virtual currencies page.](https://adapty.io/uploads/Types_of_virtual_currencies.png)
*Four apps, four names for the same balance: credits for audio generation, coins per episode, gems in a game store, and credits for mobile data.*

Names change by category. AI apps say credits or tokens, drama apps say coins, games say gems or gold, and language apps say hearts. Same mechanic underneath, sold in both stores as consumable in-app purchases.

Three parts make it work.

**Grant** adds to the balance, either automatically when someone buys a linked product or renews a subscription, or through an API call when you want to hand out credits for any other reason.

**Spend** deducts against an action in your app.

**Track** records every change so you can answer the support ticket that says credits went missing.

Store purchases and renewals grant on their own. Everything on the spend side is code you write.

## Do you need a backend?

For spending, today, yes.

Your app ships with a public API key, and pulling it out of the binary takes a few minutes. User IDs are just as easy to find. If the client could spend credits with only those two values, someone could drain any user's balance from outside your app entirely, and no amount of app-side code would stop them.

The secret key never leaves your server, so that's where spending happens. SDK methods for reading and spending a balance are in the works, and the security model is why they're taking the time they are.

![Credits cannot be spent from the client because the public API key and user ID can both be extracted from an app binary. Only your server, which holds the secret key, calls Adapty's spend API to deduct credits.](https://adapty.io/uploads/Credit_spending_backend_diagram_selection.png)
*The public key and user ID sit in the app binary where anyone can read them, so only your server, holding the secret key, can call the spend API*

One endpoint that takes a user and an action, charges the balance, does the work, and returns the rest. You don't need your own database for the balance.

> **Note:** Send the spend request before you run the expensive work, not after. The deduction is then your check, and the only thing left for you is refunding the credit when a generation fails. More on that refund below, because it has a wrinkle.

## What makes a credit balance trustworthy?

A credit balance is money you've collected and haven't earned yet, which puts it closer to a bank account than to a score in a game. Bank accounts have properties that a number in a database doesn't have, and this is where most homegrown implementations come apart.

Start with history. Every grant, spend, expiry, and refund lands on the user's profile with the reason attached, so when someone writes in claiming their coins disappeared you can go and look. Homegrown balances usually store the current number and nothing else, and that support ticket has no answer.

Then there's what happens when two spends arrive at once. A spend lock that user's balance while it runs, so the second request waits its turn, finds the balance short, and gets an error instead of pushing the balance negative. Retries are covered separately: send an idempotency key, and a repeated request returns the original result rather than charging again.

The part that surprises people is that credits remember where they came from. The ones a user bought sit apart from the ones a subscription granted, and that separation is what lets you expire the allowance without touching the packs. Expiring credits are also spent first, so a user burns through this month's allowance before touching the pack they paid for.

All of it sits on Adapty's servers with each transaction encrypted, SOC2 Type II certified, and GDPR compliant, which is the answer when your security review asks whose holding the balance.

## What happens when a generation fails after you've charged for it?

You give the credit back through the API, and the credit you give back is permanent.

Credits granted through the API carry no expiry rule, since expiry is configured on the link between a currency and a product, and an API grant has no product behind it. So every refunded generation converts a piece of a user's expiring allowance into a balance that never resets. An app with a 5% failure rate quietly accumulates permanent credits on its heaviest users, which is the opposite of what the allowance is for.

Two ways to live with it. Track refunded credits on your side and account for them when you size the next allowance. Or hold the charge until the generation returns, which means keeping the spend request until you have a result and accepting the concurrency risk in the gap. A first-class hold-and-confirm operation is on the roadmap and will make this cleaner.

Either way, log the refund with the reason. When a user asks why their balance moved, you want an answer.

## How do you test the purchase flow before Apple approves your consumable?

Use a StoreKit configuration file in Xcode.

The trap catches a lot of teams. Your product list comes back empty until Apple approves the consumable. Apple won't approve the consumable until your app demonstrates the credits implementation they're reviewing. So you build the entire economy without ever seeing a purchase response, and if a client wants proof that the flow works before you build it, you have nothing to show.

A [StoreKit configuration file](https://adapty.io/docs/local-sk-files) breaks the loop. Define products locally in Xcode, and StoreKit serves them to your app without App Store Connect involvement. The purchase dialog appears, your handler runs, and you can demo the full flow against products that don't exist yet. Sandbox accounts test the real store path afterward, once the product is approved.

Build against a local configuration file, submit once the credits UI exists, and verify in the sandbox. Same sequence on [iOS](https://adapty.io/blog/in-app-purchase-tutorial-for-ios/), [React Native](https://adapty.io/blog/react-native-in-app-purchases-tutorial/), and [Flutter](https://adapty.io/blog/flutter-in-app-purchases-tutorial/).

## Can credits expire?

Subscription allowances, yes. Purchased credits, no.

Apple's guideline 3.1.1 says credits or in-game currencies bought through in-app purchase may not expire, and that you should have a restore mechanism for restorable purchases. That covers coin packs and credit bundles. Someone paid cash for those, and they stay.

A subscription allowance is a different thing. Guideline 3.1.2(a) permits subscriptions to include consumable credits, gems, and in-game currencies, and the monthly grant is a benefit of the current billing period rather than a purchase of credits. Because the two pools are tracked separately, expiry applies only to the granted one.

Expiring the allowance is worth doing. A subscriber who banks credits month over month eventually holds enough to cancel and keep using the product, and your churn report will blame something else. Reset the allowance at renewal, and the unused balance stops being an exit, while heavy users buy packs instead of drawing down a hoard. Spending expiring credits first supports this: a user with both pools works through the allowance before touching what they bought, so the allowance stays the thing they're paying to renew.

Reviewers read product descriptions literally. One rejection came back saying the credits provided by the developer's IAP product had an expiration time; their currency didn't expire, a 30-day access window bundled into the consumable did. Describe packs as permanent and allowances as part of the subscription period, and don't blur them in one product.

> **Note:** Two related rules: Apple requires currency bought through IAP to be consumed inside the app rather than spent on real-world goods, and Google restricts in-app virtual currencies to the app they were purchased in.

## What happens to a balance when someone logs out or reinstalls?

A balance belongs to a profile, so this comes down to whether you have a durable ID for the user when you grant credits.

Anonymous users are where it breaks. Someone buys 500 coins, reinstalls, and the balance is gone because the new install produced a new anonymous profile. Adapty's docs say this outright: an anonymous user keeps their balance on the device where they earned it.

Restore doesn't rescue it either. Restore replay purchases; it doesn't rebuild a balance the user already spent down, and it shouldn't.

Identify before you grant. If a user can buy credits before you have a durable ID for them, the balance is already at risk, and every edge case after that gets harder to reason about.

## What about purchases made before you added credits?

Nothing is granted retroactively. Credits start accruing from the moment the currency is linked to a product, so a user who bought a pack last month has a balance of zero when you launch.

Plan for it, because this is the ticket you'll get most in week one. Loop your existing customers and grant their balances through the API before launch, or communicate the start date in-app and let subscribers pick up their first allowance at the next renewal.

## Outro

The dashboard work is an afternoon. The decisions that cost you are the quiet ones: granting credits to an anonymous profile, describing a pack in a way that trips review, launching without telling existing users their balance starts at zero.

Adapty grants credits on purchase and renewal, keeps the balance per profile with a lock on every spend, separates purchased credits from granted ones, and logs every change. [Book a demo](https://adapty.io/schedule-demo/) or start with the [quickstart](https://adapty.io/docs/virtual-currency-quickstart).

## FAQ

### What is a virtual currency in an app?

A virtual currency is a balance your app grants and spends on a user's behalf. Someone buys 500 coins for $4.99, then spends 50 to unlock an episode or 10 to generate an image. AI apps call them credits or tokens, drama apps call them coins, games call them gems, language apps call them hearts. On the App Store and Google Play they are sold as consumable in-app purchases.

### What is an in-app currency called in the App Store?

A consumable in-app purchase. Developers search for in-app currency or credits, while the store documentation uses a different name, which is why the setup docs can be hard to find. Create the product as a consumable and grant credits when it is purchased.

### Do I need a backend to use virtual currencies?

For spending, today, yes. Your app ships with a public API key that can be pulled out of the binary, and user IDs are just as easy to find. If the client could spend credits with those two values, anyone could drain a user's balance from outside your app. The secret key stays on your server, so spending happens there. SDK methods for reading and spending a balance are in the works.

### Does virtual currency work with Stripe or Paddle?

Not automatically. Only App Store and Google Play purchases grant credits on their own. For web payments, call the grant API from your backend once your payment processor confirms the charge.

### Can I give users credits without a purchase?

Yes. Grant credits through the API for referral bonuses, daily free allowances, promotional giveaways, or making good on a failed generation.

### Should I deduct credits before or after an expensive operation?

Before. If you check the balance, run the generation, then deduct, two requests can both pass the check with one credit left, and a deduct call that times out gives the work away. Sending the spend request first makes the deduction itself the check, leaving only the refund on failure for your code to handle.

### Can I test the purchase flow before Apple approves my consumable?

Yes, with a StoreKit configuration file in Xcode. Your product list stays empty until Apple approves the product, and Apple wants to see the credits implementation before approving it. Define products locally in Xcode, and StoreKit serves them to your app without App Store Connect involvement.

### Can credits expire?

Subscription allowances can. Purchased credits cannot. Apple's guideline 3.1.1 says credits bought through in-app purchase may not expire, while guideline 3.1.2(a) allows a subscription to include consumable credits as a benefit of the billing period. Credits granted through the API do not expire either, since expiry is configured on the link between a currency and a product.

### Which credits get spent first?

Expiring ones. A user holding both a subscription allowance and a purchased pack works through the allowance first, so the pack they paid for stays intact.

### What happens to credits when Apple refunds a purchase?

Refunding a consumable pack removes that transaction's entire grant, floored at zero, so the balance never goes negative. A user who bought two packs and had one refunded keeps the credits from the other. Subscription refunds are handled proportionally.

### Do credits transfer when a user restores purchases?

No. Restore replay purchases and do not rebuild a balance that the user has already spent down. Tie the balance to an identified profile rather than to purchase history.

### What happens to a credit balance when a user reinstalls the app?

An anonymous user keeps their balance on the device where they earned it, so a reinstall creates a new profile with an empty balance. Identify users before granting credits so the balance follows them.

### Do users get credits for purchases made before I set up the currency?

No. Grants start from the moment the currency is linked to a product, so a customer who bought a pack last month starts at zero. Seed existing balances through the API before launch if you need to.

### Can I read a credit balance from the SDK?

Not today. Balances are read and spent through the server-side API, so a balance shown in your UI should come from your own backend and be treated as a display value. SDK methods are in the works.

### Can users spend in-app credits outside the app?

No. Apple requires currency bought through in-app purchase to be consumed inside the app rather than spent on real-world goods, and Google restricts in-app virtual currencies to the app they were purchased in.

### How many virtual currencies can one app have?

Up to 20 per app in Adapty, which covers a soft and a hard currency, with room to test others.
