Architecture — the server is the source of truth
Two layers, one identity (app_user_id = the account’s immutable user.id, the same id push uses):
- On device — the RevenueCat SDK makes purchases and gives an instant, offline copy of the user’s entitlements (fast UI gating).
- On the server — RevenueCat posts a webhook for every purchase/renewal/cancellation. The
API stores the result in the
entitlementstable. This is what server-enforced features trust; the device’s copy is only ever a cache of it.
Everything is off until configured, exactly like OneSignal/Sentry: no keys ⇒ the webhook
401s, the paywall hides,
requireEntitlement denies. The kit builds and runs unchanged.entitlements row
per (user, entitlement). “Active” is derived, never stored. There is no consumable/credit
ledger — deliberately out of scope.
Activation — env only
Client (shipwide_app, .env)
API (
shipwide_api, .env)
Dashboard checklist (the part env can’t do)
Store IAP inherently needs dashboard setup. The kit’s promise is no code changes, not “no setup”.1
RevenueCat
Create a project; add an app per platform you sell on (Apple, Google, Web). Copy each public
SDK key → the three
VITE_ vars; a secret key → REVENUECAT_SECRET_KEY.2
Stores
App Store Connect + Google Play Console — create the subscription + one-time products,
agreements/banking, a subscription group, license testers.
3
Web billing engine
For the web/Tauri build, connect a RevenueCat web engine: Web Billing (Stripe-backed) or
Paddle (a Merchant of Record handling global sales tax/VAT, available where Stripe isn’t).
The client (
@revenuecat/purchases-js) is the same either way — the engine is a dashboard choice.4
Entitlement, offering, webhook
Create an entitlement
pro and an offering; attach the store products. Set the webhook URL to
https://<your-api>/v1/subscriptions/webhook with the Authorization value equal to
REVENUECAT_WEBHOOK_AUTH.Server & client surface
On the client:
useRevenueCat() (one wrapper, three providers — native / web-Tauri / mock),
useSubscriptionStore() (isPro, has(id)), and RevenueCatInitializer.vue (configures on boot,
mirrors auth). Reference UI: Subscription.vue (paywall + manage) and PremiumExample.vue.
Mock mode — develop with no account
Compliance
Apple and Google require digital subscriptions to be sold through their IAP inside their apps. Web billing (Web Billing/Stripe or Paddle) is for the web build only; the iOS/Android builds must not surface a web purchase path — RevenueCat routes per platform automatically. On Capacitor 8 the native SDK is pinned to@revenuecat/purchases-capacitor 13.x.