Appearance
RevenueCat (BYO) – Implementation Plan
Scope: verify mobile IAP/subscription revenue by connecting sellers’ own RevenueCat accounts (BYO – Bring Your Own). Zero cost for AcqMarketplace; sellers cover any RevenueCat plan costs.
1. Goals / Non‑Goals
- Goals
- Enable “Verified via RevenueCat” for listings monetized via IAP/subscriptions (Apple/Google, optionally Stripe web via RC).
- Safely collect aggregates: MTR, net revenue, refunds, active subscribers, churn, ARPU, trends.
- Zero PII in UI; strict RLS; store read‑only keys in Vault.
- Hourly cron sync for free plans; near‑real‑time only if the seller has webhooks enabled.
- Non‑Goals
- No verification for ads, affiliate revenue, or off‑platform marketplace fees.
- No guarantee of total business revenue; only IAP/subscription via RC.
2. User Stories
- As a Seller, I can connect my RevenueCat account (read‑only key), select the project/app, and see a “Verified via RevenueCat (IAP only)” badge.
- As a Buyer, I can see a badge and a clear tooltip about what is verified (IAP only) plus aggregated trends.
- As an Admin, I can see sanity checks (production vs sandbox, refund rate, spikes) and last sync status.
3. Constraints & Risks
- Coverage: IAP/subscriptions only; mixed monetization remains partially verified.
- Ownership: require bundleId/packageName ≈ listing match; otherwise risk of “fake project”.
- Latency: without webhooks → hourly cron; UI displays "Last synced".
- Currency: normalize to platform currency (USD) with historical FX.
- Rate limits: backoff + pagination; staggered initial backfill.
4. High‑Level Architecture
- UI (Seller):
- Settings → Integrations → RevenueCat: form with
read‑only key, "Test connection" button, Project/App selector, environment toggle (Production only).
- Settings → Integrations → RevenueCat: form with
- Edge Functions (Supabase):
revenuecat-test-connection: validates the key and enumerates allowed Projects/Apps.revenuecat-sync: runs via hourly cron, fetches day windows, aggregates and stores.- (optional)
revenuecat-webhook: if the seller’s plan supports webhooks, ingest events and perform idempotent upserts.
- DB (Supabase): tables for integration config and daily aggregates (see §5).
- Security: keys in Vault; RLS on seller‑scoped rows; UI shows aggregates only.
5. Data Model (Supabase)
Table:
seller_integrationsiduuid pkseller_iduuid ref userstypetext check in ('revenuecat')project_idtextapp_idtextenvironmenttext check in ('production')api_key_readonly_secret_reftext (Vault reference)bundle_idstext[] (for matching/ownership)connected_attimestamptz,last_synced_attimestamptz,statustext ('active'|'error')
Table:
revenues_dailyiduuid pkseller_iduuidapp_idtextdatedatecurrencytext (original)mtr_grossnumericrefundsnumericnet_revenuenumeric (mtr_gross - refunds)active_subscribersintegernew_subscriptionsintegerchurn_ratenumericarpunumericcurrency_usd_ratenumericnet_revenue_usdnumeric (derived)- unique (
seller_id,app_id,date)
Table:
integration_auditiduuid pk,seller_id,sourcetext ('revenuecat'),attimestamptz,leveltext,messagetext,metajsonb
RLS
seller_id = auth.uid()for user‑scoped rows; admin role sees all.
6. API Surface (Edge Functions)
POST /functions/v1/revenuecat-test-connection- body:
{ apiKey: string } - response:
{ ok: boolean, projects: Array<{id,name,apps:Array<{id,name,bundleIds}>}> }
- body:
POST /functions/v1/revenuecat-sync- body:
{ sellerId?: string }(invoked by cron per seller) - action: fetch metrics by day (last N days/backfill), upsert
revenues_daily, updatelast_synced_at
- body:
POST /functions/v1/revenuecat-webhook(optional)- validates signature (if enabled), performs idempotent upserts
Notes
- All functions validate role; sellers can only act on own
seller_id. - Idempotency via composite keys (seller_id, app_id, date) + safe upserts.
- All functions validate role; sellers can only act on own
7. RevenueCat API Usage
- Auth:
Authorization: Bearer <read-only-key> - Endpoints (indicative; match current API):
- List Projects/Apps: enumerate for setup flow.
- Metrics: daily aggregates for MTR, subscribers, refunds.
- Pagination & Rate Limits: implement cursor‑based pagination, exponential backoff.
- Environments: accept only
productionon setup; filter sandbox/test.
8. Security & Privacy
- Store key in Supabase Vault; never log secrets.
- Mask secrets in UI; support revoke/regenerate.
- Aggregate‑only in UI; no App User IDs/PII.
- Audit logs in
integration_audit. - RLS enforced; admin can see cross‑seller metrics in Admin panel.
9. UX Spec
- Seller → Settings → Integrations → RevenueCat
- Step 1: Paste read‑only key → Test connection
- Step 2: Select Project + App (with bundleIds visible) → Confirm
- Step 3: Verify bundleId matches listing → Save → Start initial sync
- State: "Last synced X minutes ago"; status badges (OK/Error); Re‑sync button
- Listing Page
- Badge: "Verified via RevenueCat (IAP only)" + clarifying tooltip
- Charts: 30/90d net revenue (USD), active subs, churn, refunds rate
- Empty/Fallback states for sellers not connected
10. Rollout Plan
- Data model + RLS + Edge function skeletons
- Seller UI for connection + test connection
- Cron hourly sync (Supabase Scheduler)
- Listing badges + minimal charts (lazy load)
- Admin sanity checks dashboard
- Optional webhooks support
11. Testing
- Unit: RC response parsing, currency normalization, idempotent upserts
- E2E: connect flow, sync visible in UI, RLS off‑role denial
- Observability: audit logs, error rates, sync duration, rate‑limit handling
- Sandbox hygiene: strict
environment=productionfiltering
12. Risks & Mitigations
- Partial revenue (non‑IAP): communicate clearly via badge + tooltip
- Ownership spoofing: bundleId checks + optional DNS/app‑file verification
- Sync latency: hourly cron + visible timestamp; webhook optional
- Currency variance: daily FX snapshot; recompute on view if missing
13. Open Questions
- Support Stripe‑via‑RC for web or ask for direct Stripe as alternative?
- Minimum threshold for public metrics (k‑anonymity)?
- Initial backfill window (90d? 180d?) and rate‑limit caps?
14. Acceptance Criteria (MVP)
- Seller can connect RC, select Project/App, save config in Vault + DB.
- Cron sync runs and produces rows in
revenues_dailywithnet_revenue_usd. - Listing shows badge + at least 2 charts (revenue, active subs) with "Last synced".
- Admin sees sanity checks (refund rate, sandbox ratio, spikes) per seller/app.
- RLS tested; no secrets/PII in UI or logs.