What differs between RevenueDot and RevenueCat?
RevenueDot answers the RevenueCat SDKs, REST API v1 and v2, and webhook payloads in RevenueCat's shapes, so purchases, entitlements, offerings and customer info work the same. The differences are: stock SDKs report failed signature checks, a few SDK features answer empty because they are not built yet, some webhook event types are never sent, and paywalls, experiments, charts and several stores are planned for later tiers. This page lists every known difference as of 2026-09-30.
SDK behaviour#
Signature checks (Trusted Entitlements)
- The stock SDKs verify responses with RevenueCat's signing key, which RevenueDot cannot use. Every RevenueDot response reads as verification failed.
- iOS, Android and Unity default to informational: they log the failure and still grant access. Set disabled. React Native, Flutter and Kotlin Multiplatform default to disabled. Capacitor passes no default, so the native informational default applies. Cordova has no option. purchases-js does not verify.
- Enforced mode fails every request with a stock SDK against RevenueDot.
- RevenueDot signs responses with its own Ed25519 key when
REVENUEDOT_SIGNING_KEYis set, and the RevenueDot forks trust RevenueDot Cloud's key. See Trusted Entitlements. - Source:
prd/sdk-forks/PRD.md, section 4.
Traffic that bypasses the proxy URL in stock SDKs
- Android sends diagnostics, paywall events and ad events to RevenueCat's hosts even with a proxy URL.
- purchases-js sends analytics events to RevenueCat unless you set
flags: { collectAnalyticsEvents: false }. - Flutter web ignores
setProxyURL, so web calls still go to RevenueCat. - The RevenueDot forks fix all three. Source:
prd/sdk-forks/PRD.md, section 2.
SDK features that answer empty today
| SDK feature | What RevenueDot answers | Effect in the app |
|---|---|---|
| Customer Center | GET /v1/customercenter/{id} answers 404 with code 7259; support tickets answer {"sent": false} |
The Customer Center screen shows its error state |
| Virtual currencies | {"virtual_currencies": {}} |
Balances are always empty |
| Paywalls built in RevenueCat's editor | Offerings carry no paywall | Remote paywall designs do not appear |
| Targeting and placements | Offerings carry no placements | Every user gets the current offering |
Remote config (/v1/config/...) |
204, no body | Nothing to apply |
Analytics and diagnostics (/v1/events, /v1/diagnostics) |
Accepted, then dropped | No effect |
Web purchase redemption (redeemWebPurchase) |
400 with code 7849 | The SDK returns invalidToken: there are no web purchases to redeem |
Web checkout (iOS hosted checkout, purchases-js with rcb_ keys) |
400 with code 7000; branding answers the app's name | The checkout fails with an error and is not retried |
Rewarded ad verification (pollRewardVerification) |
status: failed |
Polling stops after one request and returns failed |
| Amazon receipt lookup (Android) | 400 with code 7662 | The Amazon purchase fails and stays unconsumed |
| SDK health report | Always "passed" | No effect |
Source: apps/server/src/routes/sdk.ts.
Attribution and promotional offers work
setAttributesand the reserved setters,collectDeviceIdentifiers(RevenueDot fills in$ipand$deviceVersion), the deprecated Apple Search AdsaddAttributionDataandenableAdServicesAttributionTokenCollectionare stored as the reserved attributes, such as$mediaSource,$campaignand the$appleAds*ids. RevenueDot looks the AdServices token up with Apple's attribution API. Apple returns campaign ids, not names.- Promotional offers (
POST /v1/offers) are signed with the App Store app's In-App Purchase key. Without the key the SDK gets code 7234 for that offer. - The full list of SDK calls and what each answers is in
prd/sdk-api/PRD.md.
Stores and receipts
- RevenueDot accepts purchases only for App Store, Mac App Store, Google Play and Test Store apps. Receipts for Amazon, Web Billing (
rcb_), Stripe, Paddle and Roku apps answer HTTP 400 with code 7662. - purchases-js therefore works only with Test Store (
test_) keys. - StoreKit 1 receipts need the App Store in-app purchase key on the app. Without it RevenueDot answers code 7234 as HTTP 500, so the SDK retries after you add the key. For development,
allow_unsigned_receiptsskips this. - The app-specific shared secret is stored but not used.
- Temporary failures, RevenueDot's or a store's, answer 5xx so the SDK retries. A 4xx means the purchase is permanently bad. See Receipt errors: 4xx vs 5xx.
Test Store
- Test Store prices are set on the product with
test_store_price(amount_micros,currency) on product create and update, not with RevenueCat's separatetest_store_pricesendpoint. Read them withexpand=indicative_price. - Servers older than the 2026-09-30 fix send
cycle_count: nullinGET /rcbilling/v1/subscribers/{id}/products, and the native iOS SDK then reports "No base price found for product". Update the server if you see it. - Test Store purchases are always sandbox purchases. See Test Store.
Other SDK details
- Unity has no public
SetProxyURLmethod; use the Proxy URL field on the Purchases component. See Unity. - Restores follow the project's
transfer_behavior:transfer(default),transfer_if_no_active,keeporshare. Withkeep, a restore of a receipt another user owns fails with code 7102. See Customers and app user IDs.
API#
- Keys: the same prefixes as RevenueCat. Public app keys are
appl_,mac_,goog_,test_,amzn_,strp_,rcb_,pdl_androku_; secret keys aresk_and belong to one project. See Projects, apps and API keys. - REST API v1: all 15 endpoints, with RevenueCat's shapes. See REST API v1.
- REST API v2: projects, apps, products, entitlements, offerings, packages, customers, subscriptions, purchases and webhook integrations, with RevenueCat's shapes, pagination and errors. The rest of RevenueCat's v2 API, the audit log and team roles are planned for Tier 2. See REST API v2.
- Extensions that RevenueCat's API does not have: the import endpoints,
notification_forward_urlon apps,POST /v2/projects/{project_id}/test_purchases, store settings and credential checks, mass subscription extension, and webhook delivery logs with retry. See REST API extensions. - Dashboard sessions can call
/v2for every project you belong to; a secret key covers one project. - The importer is RevenueDot's own; see The importer.
Webhooks#
- Payload: RevenueCat's shape,
{ "api_version": "1.0", "event": { ... } }, sent as aPOSTwith JSON. - Headers: an optional
Authorizationheader you configure, plusX-RevenueCat-Webhook-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>signed with yourwhsec_...secret, andUser-Agent: RevenueDot-Webhooks/1.0. - Delivery: only HTTP 200 counts as delivered. Failed deliveries retry after 5, 10, 20, 40 and 80 minutes, then stop. Each attempt times out after 60 seconds. You can retry by hand in the dashboard or the API.
- Event types sent today:
INITIAL_PURCHASE,RENEWAL,CANCELLATION,UNCANCELLATION,NON_RENEWING_PURCHASE,SUBSCRIPTION_PAUSED,EXPIRATION,BILLING_ISSUE,PRODUCT_CHANGE,SUBSCRIPTION_EXTENDED,REFUND_REVERSED,TRANSFER,PRICE_INCREASE_CONSENT_REQUIRED,PRICE_INCREASE_CONSENT_APPROVEDandTEST. - Accepted in filters but never sent yet:
TEMPORARY_ENTITLEMENT_GRANT,VIRTUAL_CURRENCY_TRANSACTION,INVOICE_ISSUANCE,EXPERIMENT_ENROLLMENT,PURCHASE_REDEEMEDandSUBSCRIBER_ALIAS. - Refunds arrive as
CANCELLATIONwithcancel_reason: "CUSTOMER_SUPPORT"and a negative price. - Imported history sends no webhooks, unless you import with
--emit-events. - Integrations: webhooks are the only integration today. Slack, Segment, Amplitude, Mixpanel, PostHog, Firebase, BigQuery, AppsFlyer, Adjust and Meta are planned for Tier 2.
Details: Webhooks and Webhook events. Source: apps/server/src/services/webhooks.ts.
Migration#
- Not imported: paywalls, targeting rules, experiments, virtual currency balances, integrations other than webhooks, and store credentials.
- Refunded subscriptions import as expired, because RevenueCat's API v2 subscription object does not show refunds.
- RevenueCat Billing subscriptions keep renewing through RevenueCat; only their current access is imported.
- Google Play purchase tokens are not in RevenueCat's API v2, which gives order ids. Until RevenueDot finds a token, the subscription is marked
needs_token_refreshand the customer keeps access.
Source: prd/migration/PRD.md.
Features not built yet, by tier#
Tier 1 (the current build), not finished
- SDK fork packages are built but not published to any registry.
- Real App Store and Google Play sandbox purchases have not run end to end; store handling is tested against mocked Apple and Google APIs.
Tier 2 (planned)
- The full REST API v2, the audit log and team roles.
- All 21 webhook event types and the integrations listed above; scheduled data exports to S3, R2 or GCS.
- All 42 charts, with the SQL published.
- Paywalls: serving the paywall designs the SDKs render, a visual editor and an asset CDN.
- Targeting, placements and experiments (offering A/B tests).
- Customer Center configuration, virtual currencies, offline entitlements, promotional-offer signing and win-back offers.
- Amazon Appstore, and Stripe subscriptions from your own Stripe account.
- Moving between self-host and cloud in one step, and a full export.
Tier 3 (planned)
- SSO/SAML, SCIM, custom roles, several organizations, data-location controls and compliance exports.
- High-availability self-host (Helm, Terraform, clustering).
- Web billing with hosted checkout, web-to-app funnels and redemption links.
- Failed-payment recovery, refund defense and win-back flows.
- Paddle, Roku and Galaxy stores; forwarding attribution to ad networks; benchmarks.
Source: prd/SCOPE.md.