#The One Setting That Decides If a Sale Gets Paid Once, Twice, or Never
There's a toggle buried in most affiliate integrations that founders flip without reading twice, and it decides whether a $9.99 renewal pays your influencer once, twice, or not at all.
Every subscription app needs proof a purchase actually happened before it pays a commission on it. There are exactly two ways to get that proof: ask RevenueCat to relay the event to you, or ask Apple and Google directly. Both work. Neither is "more correct." The problem is that both paths ultimately query the same backend – so running them together on one purchase doesn't add a second opinion, it just asks the same question twice and pays for both answers.
#How Each Path Actually Confirms Someone Paid

RevenueCat's path is a relay. Your app's SDK sets a subscriber attribute – a tag like a referral code – when someone installs through an affiliate link. RevenueCat stores that attribute against the subscriber, and it's write-only from the SDK and immutable once set, so nobody can quietly rewrite who gets credit after the fact. On subscribe and every renewal, RevenueCat fires a webhook to your server carrying that attribute. Attribution data ships embedded in the INITIAL_PURCHASE and RENEWAL events themselves.
Store-Direct skips the relay. Your server calls Apple's App Store Server API or Google's Play service account directly and asks: did this transaction happen, is it valid, is it still active? Apple's 2025 update added a signed transaction object and new endpoints built specifically for this kind of server-side check – no device or third party involved.
These aren't two independent sources of truth. RevenueCat is querying the exact same Apple or Google backend you'd hit yourself. It's a wrapper, not a second checkpoint.
#The Math on Running Both Anyway
The figures below are an illustrative model – not real InfluTo transaction data – built to show the mechanics, not to report an incidence rate.
The instinct to run both "for safety" is understandable – redundancy is usually good engineering. It's wrong here specifically because there's nothing redundant to check: one transaction, one ledger entry on Apple's servers, two doors asking about it.
Take a $9.99/month subscription at a 20% commission – $2.00 owed per renewal. With both paths active, RevenueCat's webhook fires on renewal and your system logs $2.00, marks it paid. Minutes later your Store-Direct job runs its own check against Apple, sees the same renewal, and – with nothing telling it this one was already counted – logs another $2.00. One $9.99 sale, $4.00 out the door. That's every renewal both paths catch, every cycle, until someone notices.
Now flip it: only Store-Direct is active, but the job never receives the referral code because it was never wired into the App Store Server API call – that mapping has to be built explicitly, Apple's API doesn't carry it natively. The renewal happens. Apple confirms it. The validation call succeeds. But nothing links the transaction to an affiliate, so the $2.00 that should exist never gets created. No error, no failed job, nothing in a log to grep for. Just an influencer noticing, three months later, that a subscriber they referred never shows up on a statement.
Run either scenario across dozens of subscribers and several billing cycles and the gap between owed and paid stops being a rounding error – in opposite directions, from the same root cause: two systems, or the wrong one alone, both looking at data that was never ambiguous in the first place.
#Where Each Path Breaks in Ways the Other Doesn't
Neither path is safe from every failure – they just fail differently, and knowing which failure you're exposed to matters more than picking a "winner."
Refunds. RevenueCat's webhooks are "at least once" delivery by design, so a refund event can theoretically arrive twice – your clawback logic needs to be idempotent or you'll double-reverse a commission that was only paid once. Store-Direct has no such delivery quirk, but it also won't push a refund to you – you have to poll for status changes yourself.
Trial-to-paid conversion. RevenueCat models this as one continuous lifecycle out of the box. Store-Direct treats each state as a separate lookup you're responsible for stitching together.
Family Sharing and restores. This is where store-side identity earns its keep. Apple's originalTransactionId and Google's purchaseToken both stay stable across a restore or a shared purchase – that's the identifier either path ultimately keys off of for dedup, so a restored purchase doesn't get re-attributed to a new referral code.
Mid-campaign migration. Switching validation paths mid-flight without a clean cutover is how you get a gap: purchases made in the transition window can land in neither system, or both.
#When Store-Direct Wins, When RevenueCat Wins
There's no universally "better" path – the right one depends on what's already sitting in your stack.
Pick RevenueCat's webhook path if you're already using RevenueCat to manage subscriptions, or if you sell on both iOS and Android and want one dashboard for subscriber state instead of two separate store integrations. You're trading a dependency on a third party for less plumbing.
Pick Store-Direct if you want zero third-party subscription manager in the request path between your app and Apple or Google – some founders need that for compliance, latency, or control – or if you're not using RevenueCat at all and adding it purely for attribution would be a new dependency for no other benefit.
| Your situation | Recommended path |
|---|---|
| Already run RevenueCat for subscriptions | RevenueCat webhook |
| iOS + Android, want one subscriber view | RevenueCat webhook |
| Want no third-party in the purchase-check path | Store-Direct |
| No RevenueCat, simple single-platform app | Store-Direct |
#How to Decide Without Getting It Wrong
Pick one path. Confirm the other is fully off – not "unused," disabled. That's the whole decision, and getting it wrong costs money in both directions.
Before you ship it: verify only one validation source is writing commission events into your ledger, test a refund and a restore against whichever path you chose, and check that referral attribution survives the trial-to-paid transition if your app offers trials. Then watch your first real payout cycle closely – a doubled or missing commission on day one is the cheapest bug you'll ever find.
For what happens after a duplicate or missing event reaches your ledger, see Stop Paying Influencers Twice on the Same Renewal and Pay Influencers by Revenue? One Purchase Could Pay Two. If you're building on InfluTo, both validation paths are supported natively – the platform enforces exactly one active at a time so this class of bug can't ship by accident.
Can I switch from RevenueCat to Store-Direct later without losing my commission history?
Yes – commission records already logged stay tied to the store transaction identity that generated them, since that identity (Apple's originalTransactionId or Google's purchaseToken) doesn't change when you switch validation paths. What matters is not running both during the cutover window.
Does Google Play's service account validation work the same way as Apple's App Store Server API?
The mechanism is analogous – a server-to-server credential lets you query purchase state directly from Google – but the identifiers and API shapes differ, so the two aren't drop-in equivalents even though the architectural role is identical.
What happens to purchases InfluTo already tracked if I turn off the currently active validation path?
Already-attributed and already-paid commissions aren't retroactively affected. Turning off a path only stops new events from that source going forward – which is exactly why you confirm the replacement path is fully live before disabling the old one.