5.1 KiB
| name | description |
|---|---|
| revenuecat-sync | Optional adapter that keeps a RevenueCat project's catalog in step with the storebound config - one RevenueCat product per store item (Apple product id, Play one-time id or subscriptionId:basePlanId), entitlements with their products attached, one offering with packages ($rc_monthly, $rc_annual, $rc_lifetime, custom). Read-only parity report first (storebound revenuecat diff), then a create-and-attach-only sync after the owner agrees. Use when the app uses RevenueCat (Purchases SDK) and the user wants the RevenueCat products, entitlements or default offering to match the store catalog, asks why a product is missing in RevenueCat, or sets up RevenueCat after creating products with storebound. Not for runtime entitlements, receipts, customers, webhooks or paywalls. |
Mirror the catalog into RevenueCat
CLI: storebound (or bunx storebound in a project that has it, or bun <toolchain>/cli/index.ts). Optional: only
for apps that use RevenueCat. The source of truth stays the config (products[], subscriptions[]); the store side
is made by play products / subscriptions and apple iap / subscriptions (skills store-iap-setup,
store-subscriptions). This adapter only copies that catalog into RevenueCat.
What stays RevenueCat's job (out of scope)
storebound mirrors the catalog only. It never touches: runtime entitlements per user, receipt and purchase token validation, customer info and history, webhooks and integrations, paywalls and experiments, App Store Server Notifications / Play real-time notifications setup, and the store credentials inside RevenueCat (the App Store in-app purchase key, the Play service account). Set those up in the RevenueCat dashboard.
Prerequisites (owner)
- A RevenueCat project with an App Store app and / or a Play Store app (Project settings > Apps), each connected to its store in RevenueCat.
- A v2 secret API key: Project settings > API keys > + New secret API key, version V2, permissions:
- Project configuration > Apps: read.
- Products, Entitlements, Offerings, Packages: read (enough for
diff), or read & write (forsync). Leave Customer information and Charts & metrics without access: storebound does not use them.
- The owner puts the key in the environment or
.storebound/credentials.json(gitignored) asREVENUECAT_SECRET_KEY(sk_...). Never ask for it in chat, never print it, never commit it.
Config
revenuecat: {
projectId: 'proj1ab2c3d4', // Project settings
apps: { apple: 'app...', play: 'app...' }, // optional: else matched by bundle id / package name
entitlements: { pro: ['com.example.app.pro_monthly', 'com.example.app.lifetime'] }, // optional
offering: 'default', // optional lookup key, default "default"
}
- Default entitlement:
prowith every non-consumable, non-renewing product and subscription. Consumables never unlock an entitlement. - Products: Apple uses the product id; Play subscriptions are
<subscriptionId>:<basePlanId>(the base plan id from the config, else the default by period: monthly, yearly, ...); Play one-time products use the product id. Anon_renewingproduct is a non-renewing subscription on Apple and a consumable on Play (the app tracks the expiry). - Packages of the offering: subscriptions by period
$rc_weekly,$rc_monthly,$rc_two_month,$rc_three_month,$rc_six_month,$rc_annual(first subscription per period; others get a custom package named by product id), a non-consumable in an entitlement$rc_lifetime, every other item a custom package named by its product id.
Steps
storebound revenuecat diff(read-only;--jsonfor{ projectId, apps, outOfSync, rows[], scope }). Rows aremissing,mismatch,extra(in RevenueCat, not in the config),infoorok. Exit 1 when anything is missing or mismatched; extras do not fail it.storebound revenuecat sync --dry: the numbered plan (create products, create entitlements, attach products, create the offering, create packages, attach products) and what is left alone. Show it to the owner.- After a clear yes:
storebound revenuecat sync(asks in a terminal;--yesskips the question). Without a terminal and without--yesnothing is sent. Re-running is safe: the plan comes from a fresh read. storebound revenuecat diffagain: expect 0 differences.
The owner's decisions
--currentmakes the configured offering the current (default) one. That changes what every app shows by default, so it is never part of a plain sync. Ask first.- Mismatches sync never fixes: a product with another type, an archived product / entitlement / offering, a package that already holds another product for the same store app. The owner changes these in RevenueCat.
- Extras (products, entitlements, packages, attachments RevenueCat has but the config lacks) are left alone. Deleting, archiving or detaching is the owner's job in the dashboard.
Notes
- Rate limit: 60 requests per minute for project configuration; on HTTP 429 the CLI waits for
Retry-After. - 401 / 403: the key is wrong, is a v1 key, or lacks a permission listed above.
- Never via MCP for
sync.diffis read-only.