# Base44 RevenueCat Setup: StoreKit and Play Billing

Apple rejected your app because it takes payments through Stripe or Base44 payments. Base44 integrates with neither StoreKit nor Google Play Billing, so the usual advice is to ship a PWA and keep your low processing fee, which also means you never get on the App Store. The fix is RevenueCat, and most of the wiring is one prompt. This covers why the rejection happens, what genuinely changed in the US in 2025 and 2026, and the exact setup.

%[https://www.youtube.com/watch?v=M9NlOd3XDCI] 

## Why Apple rejected your Base44 app

The guideline is 3.1.1. If your app unlocks digital content, features, subscriptions, or credits, Apple requires that purchase to run through In-App Purchase, which means StoreKit. Google Play's Payments policy says the same about Play Billing for digital goods.

Stripe is not the problem in itself. Stripe on your website is fine and always has been. The problem is the flow inside the app binary. A Base44 app shipped to the stores with a Stripe checkout for a premium tier is selling digital content through a payment system the store does not control, and review ends there.

Base44 has acknowledged this directly. Its own store submission documentation tells you not to use Stripe for digital goods in a mobile app because the app will be rejected, and says a StoreKit and Play Billing integration is in progress. Until that ships, the native purchase layer has to come from somewhere else.

Two things that are not the same as a payment rejection, and get confused with it constantly:

*   **Guideline 4.2, minimum functionality.** Rejection for being a website in a shell. Separate problem, separate fix, covered in [Base44 App Store Approval](https://blog.despia.com/base44-app-store-approval-the-rejection-checklist).
    
*   **In-app purchase products not submitted for review.** Your billing is correct and Apple still bounces the build, because products in App Store Connect have to be attached to the version. See [In-App Purchases Not Submitted for Review](https://blog.despia.com/in-app-purchases-not-submitted-for-review-the-fix).
    

## Can I just link out to Stripe now that Apple lost to Epic?

This comes up in every Base44 thread on the subject, and the answer is more interesting than either side usually admits.

It is true that the rules changed. Following the April 2025 injunction in Epic v. Apple, Apple updated Guideline 3.1.1(a) so that apps on the United States storefront can include buttons, external links, and other calls to action pointing at outside purchase methods, with no entitlement required. The 27% commission on those external purchases was struck down. In December 2025 the Ninth Circuit held that Apple may charge a commission covering the costs genuinely necessary to coordinate external links, but the district court has not set a rate, so the effective rate on US external purchases is currently zero.

Android moved the same direction on a separate track. After Epic v. Google, Google's US policy no longer requires Play Billing, permits alternative in-app payment methods, and allows linking out. That injunction runs to November 2027, with a revised settlement filed in March 2026 and a proposed global program carrying service fees, still awaiting court approval.

So the honest version is: linking out is allowed in the US, right now, for free. And it is still the wrong default for a Base44 app, for four reasons that have nothing to do with legality.

*   **It is US only.** Outside the United States the old restrictions stand. A global build that shows external purchase UI to a user in Germany or Japan is a rejection, so you are region-gating on the storefront and maintaining two purchase paths anyway.
    
*   **You still cannot take the payment in-app.** The allowance is for links out to a browser. The user leaves your app, completes a web checkout, and comes back. That is not a purchase sheet.
    
*   **Conversion falls off the redirect.** A native sheet with Face ID and a stored card converts differently from a browser handoff and a card form. Whether the gap is worth the commission is a real question with a real answer, and you should measure it rather than assume the cheaper fee wins.
    
*   **The fee picture is unsettled.** A cost-based commission on US external purchases is expected, the rate is undetermined, and Google's global program is pending approval. Building your monetisation on a number that is currently zero because a court has not ruled yet is a business risk, not a saving.
    

Rules current as of July 2026 and moving. Check Apple's and Google's own policy pages before you build around them.

## Where RevenueCat sits, and what StoreKit actually is

StoreKit is Apple's framework for selling digital goods. Google Play Billing is the Android equivalent. Both are native, meaning code compiled into the binary, which is why a web app cannot reach them from JavaScript on its own.

RevenueCat wraps both behind one API and one dashboard. You define products, entitlements, and offerings once, and it handles StoreKit and Play Billing underneath, along with receipt validation, subscription state, and the customer record. This is why "Base44 StoreKit" and "Base44 Play Billing" both resolve to the same answer: you do not integrate either one directly, you integrate RevenueCat and it integrates them.

The missing piece for Base44 is the native layer. RevenueCat's own support position is that a Base44 app running in a WebView has no native bridge to the RevenueCat iOS SDK, so the integration cannot be done from Base44 alone. That is accurate. Despia is the part that closes it: your Base44 app ships as a real iOS and Android binary, the RevenueCat SDK compiles in, and your web code calls it with one JavaScript function. One codebase, no native project to maintain.

Commission, since it is usually the real question: Apple and Google both charge 15% on the first million dollars of annual proceeds and 30% above it. Most people reading this are in the 15% tier, not the 30% one.

## Connect the Despia MCP first, or the prompt will not land

Skip this and your agent writes plausible code against an API it has never read. The usual result is `window.despia` as an environment check, which does not exist, so the condition is false on every device and every native call inside it is silently skipped. The paywall never opens, nothing errors, and you spend four rounds and four builds debugging a runtime that is fine.

The Despia MCP server is a documentation server. It hands your builder the real reference for the `despia-native` package, so it stops inventing method names.

In Base44: profile icon, Settings, then MCP connections under Account. Add custom MCP, name it Despia, URL `https://setup.despia.com/mcp`, authentication not required. Test, then Test and add. It needs a Builder plan or higher.

The full setup for every tool, plus the three things agents invent without it, is in [Despia MCP Server: Stop Burning Credits on Bad Code](https://blog.despia.com/despia-mcp-server-stop-burning-credits-on-bad-code).

## The prompt

Paste this into your Base44 agent as-is. It points at the markdown version of the implementation guide, which is what you want an agent reading rather than the rendered page.

```text
Read https://blog.despia.com/base44-in-app-purchases-without-webhooks-revenuecat.md
and implement it in this app exactly as written.

Context:
- This app ships to iOS and Android with Despia. Native features come from the
  despia-native npm package.
- Detect the native runtime with the user agent. Never use window.despia, it
  does not exist.
- Do not add Capacitor, Cordova, or any second native project.

Implement:
1. Install despia-native.
2. A paywall launch that calls revenuecat://launchPaywall with the logged-in
   user id as external_id and the "default" offering, gated behind the user
   agent check.
3. An access gate that reads real entitlements with getpurchasehistory://, runs
   on load and again from window.onRevenueCatPurchase, and unlocks premium on
   the entitlement id. Assign the callback outside the gate so it exists before
   the native side fires it.
4. A Base44 backend function that asks the RevenueCat REST API whether a given
   app user id has an active entitlement, using a secret key held server-side.
   Every premium-only server action calls it before doing the work.
5. No webhooks and no subscriptions table.

Then list every value I have to supply myself: RevenueCat SDK keys, project id,
secret key, entitlement id, offering id.
```

That last instruction matters more than it looks. It forces the agent to surface the configuration it would otherwise fill with placeholders you never notice.

## What the prompt cannot do

Three things stay yours, and the third is the one that generates support tickets.

**The RevenueCat project.** Create it at app.revenuecat.com, add an App Store app with your iOS bundle id and an App Store Connect API key with App Manager access plus an in-app purchase key, then add a Play Store app with the same package name and your Google Play service account JSON. Nothing an agent can do without your store credentials.

**Products, entitlements, and pricing.** Create your entitlement, import your store products, attach each product to the entitlement, group them into an offering, and design the paywall. Whether the monthly tier is 4.99 or 9.99 is a business decision and it belongs to you.

**SDK keys, then a fresh build.** In the Despia Editor open App, Settings, Integrations, RevenueCat, paste the iOS and Android public SDK keys, and trigger a new build. The RevenueCat SDK compiles into the binary, so it cannot arrive over the air like your web code does. Until you rebuild, the integration stays dormant even with the keys saved: purchases fail quietly and entitlement checks return nothing.

## Let RevenueCat build the paywall, not your Base44 agent

The paywall is the one screen worth not vibe coding, and RevenueCat has an AI editor that removes the reason to.

In the Paywalls editor, choose Create paywall, then Generate with AI. Describe the layout, colours, plan structure, and style, or point it at your App Store listing and it pulls your app's description and tone from there. You can also describe the app manually and attach a logo and screenshots. To change an existing paywall, open it and use the AI Editor tab in the left-hand sidebar, then ask in plain language: rewrite the headline, restyle for dark mode, move the testimonials above the pricing cards, add a comparison table. It is in public beta as of mid 2026.

Two features on it earn their place for a Base44 builder specifically. You can attach a screenshot of a paywall you like and have it used as a visual reference, and you can drop in a `design.md` with your brand colours and fonts so the output matches the rest of your app. Before you publish, ask it to audit the paywall, and it flags conversion problems like low-contrast buttons and a missing restore link.

You can build the paywall in Base44 instead. Despia supports a custom purchase flow, and the [reference](https://setup.despia.com/payments/revenuecat/reference) covers it. It is the wrong default for most people here, for reasons that have nothing to do with taste:

*   **Prices are the store's, not yours.** RevenueCat renders each user's price in their own currency and local format, straight from App Store Connect and Play Console. A hand-built paywall has to fetch and format that itself, and a hardcoded 9.99 shown to someone paying in yen is both a support ticket and a review risk.
    
*   **Apple checks the paywall, not just the payment.** A subscription screen needs the price, the billing period, links to your terms and privacy policy, and a working restore option. Guideline 3.1.1 and 3.1.2 rejections often land on a missing one of those rather than on the purchase itself. Templates ship with them, and the AI audit catches what you removed.
    
*   **It is the fiddliest screen to prompt.** Pricing cards, selected states, trial copy, and safe area handling are exactly where an agent burns credits going in circles. Spend those prompts on your actual product.
    
*   **You can change it without shipping anything.** Paywalls are configured remotely, so you can restyle or reprice from the dashboard and run Targeting and Experiments against it without a build and without touching your app.
    

Build the custom one when the paywall is genuinely part of your product's UI, or when you have a specific design you already own. Otherwise take the template, spend ten minutes in the AI editor, and move on.

Start here: [RevenueCat Paywalls](https://www.revenuecat.com/docs/tools/paywalls) and [Creating Paywalls](https://www.revenuecat.com/docs/tools/paywalls/creating-paywalls).

## Check that the agent actually read the docs

Before you spend a build, ask it:

> How do I detect that my app is running inside Despia, and what package do I import for native features?

You want the user agent check and `despia-native`. If it answers `window.despia`, or reaches for a Capacitor plugin, it is not reading the server. Reconnect it and name the MCP in your next prompt.

Then read the code it wrote. The environment check should look like this, with the native calls inside the gate and the callback outside it:

```javascript
import despia from 'despia-native'

const isDespia = navigator.userAgent.toLowerCase().includes('despia')

if (isDespia) {
  despia(`revenuecat://launchPaywall?external_id=${userId}&offering=default`)
}

// native side fires this, so it lives outside the gate
window.onRevenueCatPurchase = refreshAccess
```

One more check that costs five seconds and saves a build: search the project for the function your agent claims it called. Agents sometimes write diagnostics panels reporting that an SDK method ran when no such call exists anywhere in the bundle. If your logs claim a function fired, grep for the function before you believe a word of it.

## Why there are no webhooks in any of this

Most RevenueCat guides route you into webhook handlers, signature checks, and a subscription table you keep in sync forever. That table is a second source of truth, and keeping it honest means handling retries, replays, and out-of-order events for the life of the app.

RevenueCat already tracks who is subscribed. Your app has two questions, and neither needs a mirror: what to show this user, which a restore on the device answers, and whether the server should run a protected action, which one direct API call answers. What you give up is the instant push, so a cancellation does not cut a live session on the same second. You learn about it at the user's next check, which is usually their next request anyway.

The full implementation, including the server-side function and the sandbox behaviour that trips people up, is in [Base44 In-App Purchases Without Webhooks](https://blog.despia.com/base44-in-app-purchases-without-webhooks-revenuecat).

## Common questions

### Does Base44 support StoreKit or Google Play Billing?

Not today. Base44's store submission documentation says a built-in StoreKit and Play Billing integration is in progress, and its own feedback board carries multiple open requests for it. Until it ships, native purchases come from a native runtime around your Base44 app.

### Does RevenueCat work with Base44?

Not on its own. RevenueCat support has stated that a Base44 app runs in a WebView with no native bridge to the RevenueCat iOS SDK, so it cannot be connected directly. It works when the app ships as a real binary with the SDK compiled in, which is what Despia does, and your Base44 code then calls it in JavaScript.

### Can I use Stripe in my Base44 mobile app?

For physical goods and real-world services, yes, and the store rules do not apply. For digital content, not as an in-app payment. On the US storefront you may now link out to a Stripe checkout in a browser, subject to Apple's current rules. Outside the US, no. Stripe on your website is unaffected in every case.

### Why does my entitlement check return nothing after I added the keys?

Almost always a missing rebuild. The RevenueCat SDK is compiled into the binary and cannot arrive over the air, so saving the keys is not enough. Trigger a fresh build. In sandbox, the v2 active entitlements endpoint can also read empty while the entitlement is live, so cross-check with the older subscriber lookup while testing.

### Do I need webhooks for in-app purchases?

No. Restore on the device for display decisions and one direct API call server-side for protected actions covers a normal subscription app. Add a webhook later if you need real-time cancellation handling.

### Will Apple test my purchases during review?

Yes. Reviewers run the purchase and the restore in sandbox, so your first in-app purchase has to be submitted together with the version and your products have to load. This is the single most common reason a technically correct billing setup still gets bounced.

### What commission will I actually pay?

15% on the first million dollars of annual proceeds on both stores, 30% above it. Compare that against your Stripe rate honestly, including the conversion difference between a native purchase sheet and a browser redirect, before deciding the fee is the deciding factor.

### Do I need a Mac to ship this?

No. Code signing and submission run from the browser. The longer answer, including what the no-Mac claim actually depends on, is in [Do You Need a Mac to Publish an iOS App](https://blog.despia.com/do-you-need-a-mac-to-publish-an-ios-app).

## When you want an answer from a person, not a model

Shipping your first app is stressful, and an AI builder makes it worse in a specific way: it does not tell you when it is unsure. It tells you what you asked to hear, confidently, and you find out four builds later.

If you are stuck on something with Despia and Base44 and you want a human to look at it, email `humans@despia.com`. A developer with five or more years of experience reads it and writes back about your actual setup, not a template.

Worth knowing what you are asking for. A person will sometimes tell you your approach is wrong, that the roadblock is upstream of the thing you are debugging, or that the feature you want is not the one that gets you approved. That is the point of asking a human. If you would rather have a fast machine answer that works within the plan you already have, connect the MCP and keep prompting.

## Get it on the stores

Take the Base44 app you already built and ship it to iOS and Android without a CLI or a Mac. Native purchases are one call away, code signing and submission run from the browser, and your web app stays the single source of truth.

[See the setup docs at setup.despia.com](https://setup.despia.com)
