Documentation Index
Fetch the complete documentation index at: https://setup.despia.com/llms.txt
Use this file to discover all available pages before exploring further.
AI Prompt
Add native in-app purchase functionality to my app using the Despia SDK from: https://www.npmjs.com/package/despia-nativeFirst, install the package: Use platform-specific product IDs. On Android, subscription product IDs must be prefixed with the subscription group name as configured in Google Play billing:In RevenueCat, create a single entitlement (e.g. Payment confirmation will happen via RevenueCat’s Webhooks, so make sure to include or instruct me to set up the correct backend structure.You can find the documentation about this here: https://www.revenuecat.com/docs/integrations/webhooksPlease follow the installation instructions for the “despia-native” npm package closely, and do not modify my instructions. Implementation as mentioned is critical.
npm install despia-nativeThen import it: import despia from 'despia-native'Create a payment system that uses RevenueCat URLs like: despia("revenuecat://purchase?external_id={USER_ID}&product={PRODUCT_ID}") to handle purchases through Apple App Store and Google Play billing.Detect the platform using the Despia user agent and use the correct product identifier for each store. If not running in Despia (i.e. the user is on your web app), fall back to a RevenueCat Web Purchase Link:- iOS:
monthly_premium_ios - Android:
premium:monthly_premium_android(group namepremium+:+ product ID)
Always append the user’s ID to the RevenueCat Web Purchase Link URL. This links the web payment directly to their account - so if they later open your mobile app, the purchase and entitlements are already there waiting for them.
"premium") and link both the iOS and Android products to it. This means entitlementId will be "premium" for all platforms - check with p.entitlementId === "premium". For one-time purchases, match the exact entitlementId (e.g. "no_ads").The Despia Native Runtime will call the global function
onRevenueCatPurchase() when an in-app purchase or subscription is successfully made on the client side. This should not grant access immediately on its own - but it is the right moment to either poll your backend until the RevenueCat webhook confirms the purchase, or run a client-side entitlement check via getpurchasehistory:// to instantly verify active entitlements with no backend needed. You should also call getpurchasehistory:// proactively on app load, page navigation, and before gating any premium feature. These checks are instant, offline-capable, and require no network round-trip to your server.This feature requires native capabilities which will be fully provided by the “despia-native” npm package, no additional native libraries are needed!
- Read and follow all best practices for Webhook events here: https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields
- Check out the sample Webhook event schemas here: https://www.revenuecat.com/docs/integrations/webhooks/sample-events
despia("getpurchasehistory://", ["restoredData"])This will query the native app stores and return all purchases associated with the current device/account, including active subscriptions, expired subscriptions, and one-time purchases.The response array includes objects with:transactionId- unique identifier for this specific transactionoriginalTransactionId- identifier linking to the original purchase (useful for subscription renewals)productId- the product identifier configured in App Store Connect / Google Play Consoletype- either"subscription"or"product"(one-time purchase)entitlementId- the entitlement/access level this purchase grantsisActive- boolean indicating if the purchase currently grants accesswillRenew- boolean indicating if a subscription will auto-renewpurchaseDate- ISO timestamp of the most recent transactionoriginalPurchaseDate- ISO timestamp of the initial purchaseexpirationDate- ISO timestamp when access expires (null for lifetime purchases)store- either"app_store"or"play_store"country- user’s country codeenvironment-"production"or"sandbox"receipt- the raw receipt data for server-side validation
"premium" entitlement:Installation
Install the Despia package from NPM:Usage
1. Import the SDK
2. Detect Platform & Purchase
Always check for Despia first before attempting native purchases. If not running in Despia (e.g. the user is on your web app), fall back to a RevenueCat Web Purchase Link instead.Always include the user’s ID in the Web Purchase Link URL. This ties the web payment to their account so entitlements are instantly available across both your web app and mobile app - no extra steps needed for the user.
Web Checkout Link (non-Despia fallback)
To get yourpay.rev.cat token, go to RevenueCat and create a new Web Purchase Link - select an existing offering or create a new one with your web products:
RevenueCat -> Web -> Create Purchase Link
Once created, append the user’s app_user_id directly to the URL - this is the critical part that links the web purchase to their account:
| Parameter | Description |
|---|---|
email | Pre-fills the email field on checkout - ?email=<customerEmail> |
currency | Override automatic currency selection - ?currency=EUR |
package_id | Pre-select a package and skip straight to checkout |
skip_purchase_success=true | Skip the success page and trigger your configured redirect immediately |
The
app_user_id in the URL is what RevenueCat includes in every webhook event. The user must already exist in your database before redirecting them to the checkout link - otherwise when the INITIAL_PURCHASE webhook fires, your backend won’t find the user and won’t be able to grant access.app_user_id, the user’s entitlements will be active in the mobile app too.
3. Handle the Purchase Callback
The Despia Native Runtime callsonRevenueCatPurchase() globally as soon as the store confirms a transaction. This is your signal that something happened - but not yet proof that access should be granted.
There are two patterns for what to do inside this callback:
With a backend - poll until the webhook confirms
Without a backend - run the client-side entitlement check
If you don’t have a backend, skip the polling and check the native store directly usinggetpurchasehistory://. This queries Apple or Google in real time and returns the user’s active entitlements instantly - no server, no network dependency beyond the store itself.
Never grant access based on the
onRevenueCatPurchase callback alone if you have a backend. Always wait for your backend to confirm via the RevenueCat webhook before unlocking features. The callback is a trigger to start checking - not confirmation of a valid purchase.4. Run entitlement checks proactively
Don’t wait for a purchase event to check entitlements. Callgetpurchasehistory:// proactively in three places:
| When | Why |
|---|---|
| App load / page mount | Restore state for returning users immediately, before any interaction |
| Page navigation | Re-gate features as users move through the app without requiring a full reload |
| Before any gated feature | Catch edge cases where entitlement state changed mid-session (e.g. expiry, refund) |
Complete Client-Side Example
Set up entitlements in RevenueCat
Before checking entitlements in code, set them up in your RevenueCat dashboard:- Go to RevenueCat Dashboard -> your project -> Entitlements
- Click New Entitlement and name it
premium(orno_adsfor one-time purchases) - Click into the entitlement and click Attach products
- Attach your iOS product (e.g.
monthly_premium_ios) and your Android product (e.g.premium:monthly_premium_android) - Both platforms will now resolve to the same
entitlementIdin your app
no_ads).
Check entitlements client-side
getpurchasehistory:// queries the native store directly and returns real-time entitlement state from Apple or Google. No backend required for native purchases.
Full example
Subscriptions: Set Up Webhooks for Best Practice
Client-side entitlement checks work well for simple apps, but server-side webhook events are always recommended for subscriptions. Webhooks let you:- Revoke access the moment a subscription expires - rather than waiting for the next client-side check
- Log users out of your web app when their subscription lapses
- Sync subscription state across all platforms and databases in real time
- React to cancellations, refunds, and billing issues automatically
Despia Webhook Starter Template
A full backend webhook handler template covering all RevenueCat event types, database schema, and best practices.
1. Add a webhook endpoint to your server
Create aPOST /webhooks/revenuecat endpoint. RevenueCat sends an Authorization header with a secret you define - just make up a random string and store it as an environment variable.
2. Database schema
Create auser_subscriptions table to store subscription state:
3. Register the webhook in RevenueCat
- Go to RevenueCat Dashboard -> Project -> Integrations -> Webhooks
- Click Add new webhook
- Set the URL to your endpoint - e.g.
https://yourapp.com/webhooks/revenuecat - Set the Authorization header to the same random secret you put in your env var
- Select All events
- Save - RevenueCat will now send events to your server in real time
4. Consider a cron job as backup
Webhooks can occasionally fail (server downtime, timeouts, etc.). A cron job that periodically syncs subscription status from the RevenueCat API is a reliable safety net - especially important for catching cancellations and expirations that your webhook might have missed.Cron Job Template
Our full backend template includes a self-healing cron job that runs every 5 minutes, prioritizes expiring subscriptions, and stays within RevenueCat’s API rate limits. Combined with webhooks it gives 99.9%+ sync reliability.
Restore Purchases
Despia queries the native platform’s billing system to retrieve all purchases associated with the current user’s App Store or Google Play account. This includes active subscriptions, expired subscriptions, consumables, and non-consumable (lifetime) purchases. The data is normalized into a consistent format across both iOS and Android platforms.1. Retrieve Purchase History
2. Example Response (iOS)
3. Example Response (Android)
4. Check Active Entitlements
Testing Your Integration
AI cannot test payment integrations for you. RevenueCat, native StoreKit/Google Billing, webhooks, and your backend are cross-platform processes that require real end-to-end testing with multiple accounts and devices. There is no shortcut here - a payment integration is one of the most critical parts of your app and must be thoroughly verified by you before going live.
- Log in to your web app and complete a purchase via the Web Purchase Link
- Open the mobile app logged in with the same account
- Verify entitlements are active and premium features are unlocked
- Complete a purchase on the mobile app via TestFlight (no real money - use sandbox test accounts)
- Open your web app logged in with the same account
- Verify your backend has the correct subscription state
- Go to RevenueCat Dashboard -> Integrations -> Webhooks
- Check the event log - verify events are arriving at your server
- Confirm your database is updating
is_active,subscription_status, andexpires_atcorrectly for each event type - Test
EXPIRATIONandCANCELLATIONevents to make sure access is revoked properly
- Delete and reinstall the app
- Tap the Restore Purchases button
- Verify native IAP entitlements are recovered correctly
TestFlight and sandbox purchases use test accounts and never charge real money. Always test on TestFlight before submitting to the App Store. See Apple’s sandbox testing guide and Google Play’s test purchases guide for setup instructions.
Resources
- NPM Package
- RevenueCat Webhooks Template
- RevenueCat Webhooks
- Webhook Event Types & Fields
- Sample Webhook Events