Entitlements
How Amba tracks user subscription state from RevenueCat and Superwall, and how to check it from your app.
An entitlement is Amba's abstraction for "does this user have access to a feature". For the utility apps Amba targets, mobile in-app purchases come from RevenueCat (the subscription truth) with paywall metadata from Superwall — both sync into Amba via verified webhooks. For non-mobile flows that don't go through RevenueCat — Stripe / Paddle web checkout, manual support grants, gift codes, ToS-violation revokes, migrations from legacy systems — there is an admin endpoint that writes the same user_entitlements row directly. Every entitlement, regardless of origin, ends up in the same table and is read through the same client API.
Data model
user_entitlements:
| Column | Purpose |
|---|---|
app_user_id | The user who owns the entitlement |
entitlement_id | Logical identifier (e.g. "premium") |
product_id | Store product identifier |
is_active | Whether the entitlement is currently valid |
store | "app_store" / "play_store" / "stripe" / ... |
period_type | "trial" / "intro" / "normal" / ... |
purchase_date | First purchase timestamp |
expiration_date | When the current period ends (NULL for lifetime) |
The columns are whitelisted for segment targeting — see Segment operators.
Sync from RevenueCat
When RevenueCat fires a subscription event, the webhook route verifies the bearer token and Amba upserts the user_entitlements row in the background. Event mapping:
| RevenueCat event | Effect |
|---|---|
INITIAL_PURCHASE | Upsert active entitlement row |
RENEWAL | Extend expiration_date |
CANCELLATION | Mark for expiry at period end |
EXPIRATION | is_active = false |
BILLING_ISSUE | Flag on the entitlement for UI to surface |
Sync is push-only (RevenueCat → Amba). Amba is not the source of truth for purchases; RevenueCat is.
Sync from Superwall
Superwall webhooks primarily carry paywall events (shown, dismissed, purchased). Amba mirrors these as engagement_events rows named superwall_<event> so streaks, XP rules, and segments can target paywall behavior alongside first-party events. Full subscription state still flows through RevenueCat.
Server-side grants (Stripe, Paddle, manual)
When a purchase happens outside the App Store / Play Store — Stripe Checkout for a web companion, Paddle invoicing, support manually granting a comp month, gift codes, ToS-violation revokes — call the admin endpoint to upsert the user_entitlements row directly:
The handler upserts on (app_user_id, entitlement_id), so a second call for the same pair refreshes the row in place — same semantics as the RevenueCat sync activity. To revoke, pass is_active: false. To clear a column (e.g. extend a finite subscription to lifetime), pass that field as null.
For mobile in-app purchases, prefer the RevenueCat webhook — it remains the source of truth for App Store / Play Store subscriptions and handles renewal / billing-issue / cancellation transitions automatically. The admin path is for everything else.
See the full reference: POST /admin/projects/:projectId/users/:userId/entitlements.
Checking entitlements in the SDK
Both methods hit GET /client/entitlements:
UserEntitlement shape:
Example: gate a premium feature
Targeting by entitlement
Entitlement fields can drive segment rules, which in turn drive push campaigns and remote-config overrides:
See Segment operators for the full list of supported entitlement fields.
Local caching
The SDK does not cache entitlements client-side beyond the fetch lifetime. For performance-sensitive gates, fetch once on launch (after Amba.init() resolves) and keep the result in React state / a context.
Do not persist entitlement state to local storage and trust it later — subscription state can change server-side (cancellations, billing issues). Always confirm against the server before granting access to paid content.
Routes reference
| Method | Path | Description |
|---|---|---|
GET | /client/entitlements | List the current user's entitlements (active). |
POST | /admin/projects/:projectId/users/:userId/entitlements | Server-side grant / refresh for non-RevenueCat flows (Stripe, Paddle, manual). |
POST | /webhooks/revenuecat | Inbound subscription events (see Webhooks). |
POST | /webhooks/superwall | Inbound paywall events. |
Next
- RevenueCat setup — webhook and API key wiring.
- Superwall setup — paywall event sync.
- Webhooks — signature verification and retry contract.