How do I use RevenueDot with Kotlin Multiplatform?
Set Purchases.proxyURL = "https://revenuedot.example.com" in common code before Purchases.configure. In purchases-kmp the proxy URL is a String, not a URL. The default verification mode is already EntitlementVerificationMode.DISABLED, so nothing else changes on Android or iOS.
Use the RevenueCat SDK you already ship (proxy mode)#
import com.revenuecat.purchases.kmp.Purchases
import com.revenuecat.purchases.kmp.PurchasesConfiguration
import com.revenuecat.purchases.kmp.models.EntitlementVerificationMode
fun initPurchases(apiKey: String) {
// Point the SDK at your RevenueDot server; nothing else in the app changes.
Purchases.proxyURL = "https://revenuedot.example.com"
Purchases.configure(PurchasesConfiguration(apiKey) {
// DISABLED is the KMP default; keep it, RevenueDot does not sign responses with RevenueCat's key.
verificationMode = EntitlementVerificationMode.DISABLED
})
}- Set
proxyURLbeforeconfigure. It applies to both the Android and the iOS targets. - Pass the
appl_...key on iOS and thegoog_...key on Android, from RevenueDot or kept by the importer. See Which key goes where. - On Android, the stock native SDK underneath still sends diagnostics, paywall events and ad events to RevenueCat. See Android.
After you migrate from RevenueCat, sync once on the first launch of the update, so current subscribers keep access:
// Once, after this update: send purchases made while the app talked to RevenueCat.
Purchases.sharedInstance.awaitSyncPurchases()awaitSyncPurchases is a suspend function in com.revenuecat.purchases.kmp.ktx. The callback form is syncPurchases(onError = { }, onSuccess = { }).
Use the RevenueDot fork#
The fork is github.com/revenuedot/purchases-kmp. Kotlin packages stay com.revenuecat.purchases.kmp.*. It builds its iOS side from RevenueDot's purchases-ios fork (a git submodule at 5.91.0) and its Android side from RevenueDot's Android fork, so both trust RevenueDot's signing key and send events to your proxy URL.
It is not published yet (2026-09-30). The planned Maven coordinates:
// build.gradle.kts, commonMain dependencies (planned; not on Maven Central yet)
implementation("app.revenuedot.purchases:purchases-kmp-core:<version>")
implementation("app.revenuedot.purchases:purchases-kmp-ui:<version>") // paywalls, optionalThe other published modules are purchases-kmp-models, -mappings, -either and -result; -core pulls in what it needs. The patch branch revenuedot/main-patches is at 3.11.0-SNAPSHOT. Building it today needs the unpublished Android fork (app.revenuedot.purchases:purchases) in a local Maven repository first, so proxy mode is the practical choice until the release.
Trusted Entitlements are off by default#
- Stock SDK: the default is
DISABLED, which is right for RevenueDot.INFORMATIONALlogs every response as a failed check, andENFORCEDwould fail every request. - Fork: it trusts RevenueDot Cloud's key. A self-hosted server signs with its own key, so keep
DISABLED, or build the forks with your own public key.
See Trusted Entitlements.
Check an entitlement and make a purchase#
import com.revenuecat.purchases.kmp.ktx.awaitCustomerInfo
import com.revenuecat.purchases.kmp.ktx.awaitOfferings
import com.revenuecat.purchases.kmp.ktx.awaitPurchase
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
val isPro = customerInfo.entitlements.active.containsKey("pro")
val offerings = Purchases.sharedInstance.awaitOfferings()
val pkg = offerings.current?.availablePackages?.firstOrNull() ?: return
val result = Purchases.sharedInstance.awaitPurchase(pkg)
val nowPro = result.customerInfo.entitlements.active.containsKey("pro")awaitPurchase throws PurchasesTransactionException when the purchase fails or the user cancels; check its userCancelled.
Test Store#
Create a test_store app in RevenueDot and pass its test_... key on a debug build. The Test Store dialog replaces the store sheet.
- Native SDKs accept
test_keys only in debug builds. - iOS: servers older than the 2026-09-30 fix could not serve Test Store products to the native iOS SDK. See iOS.
- Test Store prices come from each product's Test Store price. Set it in the dashboard (Product catalog, Edit product) or with
test_store_priceonPOST /v2/projects/{project_id}/products; a product without one shows 0.
More: Test Store.
Migrate from RevenueCat#
fun initPurchases(apiKey: String) {
+ // Point the SDK at your RevenueDot server; nothing else in the app changes. A String, set before configure.
+ Purchases.proxyURL = "https://revenuedot.example.com"
Purchases.configure(PurchasesConfiguration(apiKey) {
+ // DISABLED is the KMP default; keep it, RevenueDot does not sign responses with RevenueCat's key.
+ verificationMode = EntitlementVerificationMode.DISABLED
})
+ // Once, after this update (from a coroutine): send purchases made while the app talked to RevenueCat.
+ // Purchases.sharedInstance.awaitSyncPurchases()
}The full order of steps is in Migrate from RevenueCat.
Examples#
There is no Kotlin Multiplatform example yet. The calls match the Android guide.