Cross-platform subscriptions and coupons
Moved from vulture-ios/Docs/cross-platform-subscriptions.md
How a Vulture Pro subscription could be shared between the Apple apps and
an Android app, and how one coupon could work on both. Written 2026-10-19
as a plan: nothing here has been built, and the RevenueCat endpoint and
dashboard names are from memory — check them against RevenueCat’s current
documentation before building on them. The Android side is the subject of
Docs/swift-on-android-investigation.md.
Where things stand
Section titled “Where things stand”RevenueCat ties a subscription to an App User ID, never to a store. Two
apps that log in with the same ID see the same all entitlement, wherever
it was bought.
AppStoreSubscription.identifyUser()
(Modules/App/Sources/Services/Subscriptions/AppStoreSubscription.swift)
logs in with the CloudKit user record name of
iCloud.be.fousa.vulture.cloud, falling back to RevenueCat’s anonymous ID
when iCloud gives none. That is why a subscription already follows a pilot
across iPhone, iPad and Mac. Android cannot read a CloudKit user record, so
it has no way to arrive at the same ID by itself.
1. One subscription on iOS and Android
Section titled “1. One subscription on iOS and Android”An account both platforms can sign in to
Section titled “An account both platforms can sign in to”Without one, RevenueCat sees two customers. The candidates are Sign in with Apple (which Android can use through its web flow), email, or an account on the vulture.aero backend.
The CloudKit record name stays the RevenueCat ID
Section titled “The CloudKit record name stays the RevenueCat ID”When an iOS pilot creates or links an account, the account stores their
CloudKit record name as its RevenueCat ID. Android signs in, reads that ID
from the account and calls Purchases.logIn(id). A pilot who started on
Android has no CloudKit ID: the account gets a fresh ID, and the iOS app
logs in with the account’s ID instead of the record name.
Existing subscribers need no migration this way, because their purchases already sit under the record name. Switching iOS to a new account ID instead would lean on aliasing or on restores transferring purchases, which is where it gets messy.
The RevenueCat dashboard
Section titled “The RevenueCat dashboard”- The Play Store app joins the same project.
- The Google products attach to the same
allentitlement as the Apple ones. - Restore behavior: the default, transfer to the new App User ID, lets a restore move a subscription between accounts; keeping it with the original App User ID is stricter and stops one subscription serving several accounts.
Store rules to live with
Section titled “Store rules to live with”- A subscription is managed and cancelled in the store it was bought in.
Link to RevenueCat’s
managementURL, which names the right store, never to the App Store directly. - Prices are set per store.
- The paywall stays away when the entitlement is already active from the
other store, so nobody pays twice. The app reads the
allentitlement (PurchaserInfo+Active.swift), not the store, so it does this already.
2. One coupon on both platforms
Section titled “2. One coupon on both platforms”Apple’s Offer Codes and Google’s promo codes each belong to one store; no code is accepted by both. RevenueCat leaves two ways around that, and both need the shared account of the previous section, or the code reaches only the device that redeemed it.
A. Free time: promotional entitlements
Section titled “A. Free time: promotional entitlements”Our own codes on our own backend, each with a duration (“one month of
Pro”). Redeeming one calls RevenueCat’s REST API to grant a promotional
entitlement to the account’s App User ID (v1:
POST /subscribers/{app_user_id}/entitlements/{entitlement_id}/promotional
with a duration; the v2 API has an equivalent grant). Pro unlocks on every
platform at once.
It is not a subscription: nothing renews, and when it ends the paywall comes back. It suits gifts, clubs and competitions.
B. A discounted subscription: Web Billing
Section titled “B. A discounted subscription: Web Billing”A subscription sold on the web through RevenueCat Web Billing, or Stripe connected to RevenueCat, with Stripe promotion codes for the discount. It renews, the entitlement reaches iOS and Android once the pilot is logged in, and the codes are entirely ours.
App Review
Section titled “App Review”No code field in the iOS app that unlocks Pro. Guideline 3.1.1 bars apps from “their own mechanisms to unlock content”, license keys and the like among them. The code is redeemed on a web page (vulture.aero/redeem, say) where the pilot signs in. Guideline 3.1.3(b), Multiplatform Services, then lets the app honour access bought or granted elsewhere, as long as Pro is also for sale through in-app purchase — which it is.
Order of work
Section titled “Order of work”- The account, keeping the CloudKit record name as the RevenueCat ID. Everything else depends on it.
- A web redeem page granting promotional entitlements through the REST API — cheap, and enough for free months.
- Web Billing with Stripe codes, only if renewing discounted subscriptions are wanted.
