Amba
Integrations

RevenueCat

Integrate RevenueCat for subscription management and entitlements.

Connect RevenueCat to sync subscription status and entitlements with Amba. When a user subscribes via RevenueCat, their entitlements are automatically updated in Amba.

The same integration also powers the Monetization Control Plane — declare your entitlements, products, and offerings as code and plan / apply them to RevenueCat (quickstart).

RevenueCat handles App Store and Play Store subscriptions. For web checkout, follow RevenueCat's documented Stripe Billing path with the built-in Web Subscriptions integration — web purchases grant the same entitlements through the same cascade. For everything else — manual support grants, gift codes, ToS-violation revokes, migrations from legacy systems — use POST /admin/projects/:projectId/users/:userId/entitlements to grant the same entitlement directly. All paths produce the same entitlement and are read through the same client API.

Setup

1. Configure the integration

Via MCP:

amba_integrations_configure({
  project_id: "proj_xxx",
  provider: "revenuecat",
  config: {
    secret_api_key: "your_revenuecat_secret_api_key",
    webhook_secret: "your_webhook_secret"
  }
})

Via Admin API:

POST /admin/integrations
{
  "provider": "revenuecat",
  "config": {
    "secret_api_key": "your_revenuecat_secret_api_key",
    "webhook_secret": "your_webhook_secret"
  }
}

secret_api_key is RevenueCat's secret REST API key (api_key is still accepted on older rows). To use the Monetization Control Plane's apply, also supply a read-write key (project_configuration:*:read_write) as secret_api_key_write — or use one full-access key for both. Keys are resolved server-side and never returned to a client.

2. Set up the webhook

The API returns a webhook URL when you configure the integration:

https://api.amba.dev/webhooks/revenuecat?project_id=proj_xxx

Add this URL in your RevenueCat dashboard under Project Settings > Integrations > Webhooks, and set the webhook's Authorization header value to Bearer <webhook_secret> — the literal word Bearer, a space, then the same webhook_secret you configured above. Amba compares the full header value on every delivery (constant-time) and rejects deliveries that do not match.

3. Webhook events

Amba processes these RevenueCat webhook events:

EventAction
INITIAL_PURCHASEGrants entitlements; fires the reward cascade
RENEWALGrants/extends entitlements; fires the reward cascade
NON_RENEWING_PURCHASEGrants entitlements; fires the reward cascade
PRODUCT_CHANGEGrants entitlements for the new product
UNCANCELLATIONRe-grants entitlements
CANCELLATIONKeeps access until the paid period ends (auto-renew off ≠ revoke)
EXPIRATIONDeactivates entitlements
REFUNDDeactivates entitlements
SUBSCRIPTION_PAUSEDDeactivates entitlements

Other event types that carry entitlement IDs are treated conservatively as grants. Every fresh event also updates the neutral subscription_* user properties (subscription_active, subscription_last_event, subscription_product_id, subscription_store), dedupes on RevenueCat's event ID, and carries an ordering watermark so a delayed EXPIRATION cannot clobber a newer RENEWAL.

Deliveries are authenticated by comparing the Authorization header against Bearer <webhook_secret> in constant time.

4. Identify the user

Configure the RevenueCat SDK with an id Amba can map back to an app user. Two conventions are supported:

  • Anonymous-first apps (no sign-up): use the Amba app user id — Amba.appUserId after signInAnonymously(), or the id returned by Amba.auth.me(). It is stable per install and survives restarts, so purchases stay attached to the same user. Amba.entitlements.restore() sends this same id when no external id is set.
  • Apps with their own user id: store it as the user's external_id and give RevenueCat the same value.
// React Native / Expo, anonymous-first
await Amba.auth.signInAnonymously();
Purchases.configure({ apiKey: REVENUECAT_PUBLIC_KEY, appUserID: Amba.appUserId });

Each webhook event's app_user_id is resolved in this order: a customer id already recorded on one of the user's entitlements, then external_id, then the Amba app user id when the value is UUID-shaped. external_id stays ahead of the app user id, so an app keyed on external ids keeps resolving to that user even for UUID-shaped values. An event whose id matches none of these fails processing after delivery has already been acknowledged, so pick one convention before the first purchase. If RevenueCat was configured anonymously on the device before the Amba id was available, call the RevenueCat SDK's logIn with the chosen id so later events carry it.

Admin API reference

MethodPathDescription
POST/admin/integrationsConfigure integration
GET/admin/integrationsList active integrations
PATCH/admin/integrations/revenuecatUpdate config
POST/admin/integrations/revenuecat/testTest connection

Checking entitlements in the SDK

const entitlements = await client.entitlements.list();
// Returns: [{ entitlement_id: "premium", is_active: true, store: "app_store",
//            product_id: "...", period_type: "normal",
//            purchase_date: "...", expiration_date: "2025-02-14T..." }]
 
const isPremium = await client.entitlements.has('premium');
// Returns: true

On this page