storebound/skills/revenuecat-sync/SKILL.md

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)

  1. A RevenueCat project with an App Store app and / or a Play Store app (Project settings > Apps), each connected to its store in RevenueCat.
  2. 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 (for sync). Leave Customer information and Charts & metrics without access: storebound does not use them.
  3. The owner puts the key in the environment or .storebound/credentials.json (gitignored) as REVENUECAT_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: pro with 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. A non_renewing product 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

  1. storebound revenuecat diff (read-only; --json for { projectId, apps, outOfSync, rows[], scope }). Rows are missing, mismatch, extra (in RevenueCat, not in the config), info or ok. Exit 1 when anything is missing or mismatched; extras do not fail it.
  2. 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.
  3. After a clear yes: storebound revenuecat sync (asks in a terminal; --yes skips the question). Without a terminal and without --yes nothing is sent. Re-running is safe: the plan comes from a fresh read.
  4. storebound revenuecat diff again: expect 0 differences.

The owner's decisions

  • --current makes 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. diff is read-only.