---
title: "RevenueCat Affiliate Tracking: The Complete Setup Guide"
description: "How to attribute RevenueCat subscriptions to creators: the affiliate id path, webhook events that move money, refund clawbacks and the edge cases."
canonical: https://www.myappaffiliate.com/blog/revenuecat-affiliate-tracking
published: 2026-09-12
author: "Cuma Ali Kesici"
category: "RevenueCat"
tags: [RevenueCat, iOS, Android, Stripe]
source: MyAppAffiliate
---

# RevenueCat Affiliate Tracking: The Complete Setup Guide

RevenueCat affiliate tracking means attaching a creator identifier to a subscriber before they buy, then joining it to the RevenueCat webhook events that report the purchase, the renewals and the refund. RevenueCat ships no affiliate feature, so you supply the identifier, the join and the commission ledger. This guide is for a founder whose app runs on RevenueCat and who pays creators without knowing which creator earned what.

What follows is a design you can implement in a week.

## Key takeaways

- RevenueCat has no built-in affiliate feature and its community has asked since 2022.
- The affiliate id must reach RevenueCat before the purchase, or the webhook cannot be joined.
- Manual creator codes are the most durable attribution path on iOS.
- Renewals, refunds and the store cut are commission decisions, not technical ones.
- Sandbox and transfer events will corrupt a naive commission ledger.

## What is RevenueCat affiliate tracking?

RevenueCat affiliate tracking is the practice of carrying a creator identifier from a link click or a code into a RevenueCat customer record, usually as a subscriber attribute, so that every webhook about that subscriber can be joined to the creator who produced them.

Three systems have to agree on one string. Your link service knows which creator owns the click. Your app knows a user id. RevenueCat knows an `app_user_id`, a product and a price. Nothing joins them automatically, and a wrong join is unrecoverable: RevenueCat will not retroactively say where a subscriber came from.

Two primary sources define the surface: [RevenueCat's webhook reference](https://www.revenuecat.com/docs/integrations/webhooks) and the [customer attributes documentation](https://www.revenuecat.com/docs/customers/customer-attributes), which allows "up to 50 unique custom attributes per subscriber, with key names up to 40 characters long and values up to 500 characters long" (verified 12 September 2026). One attribute is all this needs.

We have onboarded apps that ran creator programs for a year on RevenueCat exports and a spreadsheet. Those exports carry revenue and product ids and no creator column, so the year is gone. Set the attribute on day one of any creator experiment. The attribute is free. The missing history is not.

## Does RevenueCat have a built-in affiliate program?

No. RevenueCat has no affiliate, creator commission or partner payout feature as of 12 September 2026. It sells subscription infrastructure: entitlements, paywalls, charts and webhooks. Affiliate attribution sits a layer above, and RevenueCat's answer has been to point developers at a third party.

Four threads on RevenueCat's own community, spanning four years, ask variations of the same thing:

| Thread | Posted | Outcome |
| --- | --- | --- |
| [Cross-platform offer code affiliate program](https://community.revenuecat.com/general-questions-7/best-way-to-introduce-a-cross-platform-offer-code-affiliate-program-1410) | 22 March 2022 | Community workarounds and Branch |
| [Referral program with influencer tracking](https://community.revenuecat.com/dashboard-tools-52/how-to-implement-a-referral-program-with-influencer-tracking-and-generate-monthly-sales-reports-4929) | 9 August 2024 | Zero replies |
| [Built-in affiliate platform](https://community.revenuecat.com/third-party-integrations-53/built-in-affiliate-platform-6227) | 16 April 2025 | Staff: not a feature, use a technology partner |
| [Tracking redemptions for custom codes](https://community.revenuecat.com/dashboard-tools-52/can-we-track-redemptions-for-specific-custom-codes-in-reports-or-the-revenuecat-dashboard-7427) | 10 February 2026 | Staff acknowledge the difficulty |

On that last thread a RevenueCat support engineer wrote that they "have heard of many developers having challenges attributing In-App Purchases with native App Store Promo/Offer Code redemptions" (verified 12 September 2026). Candid, from the vendor closest to the data.

RevenueCat's growth content splits the same way. Their [referral program guide](https://www.revenuecat.com/blog/growth/how-to-build-a-referral-program-for-mobile-apps), published October 2022 and updated June 2024, covers users inviting users, where nothing is owed to a third party. Their [influencer campaign post](https://www.revenuecat.com/blog/growth/build-influencer-campaign-with-branch-revenuecat/) from October 2023 sends you to Branch, which "allows you to easily manage your links and track their performance combined with RevenueCat analytics."

We think the boundary is right, and not merely convenient for them. Entitlement state has to be correct in milliseconds on a paywall. A creator ledger has to be correct in dollars across refunds and payout rails weeks later, and a product that does both usually does the second badly. What annoys us is that four years of threads still leave founders assembling the answer from forum replies.

## The four ways to attribute a subscription to a creator

Four mechanisms tie a RevenueCat subscription to a creator: store offer codes redeemed in the App Store or Google Play, manual creator codes typed inside your app, deep links captured by an SDK on first open, and web checkout where the creator id rides into billing metadata.

**Pick deep links with a manual code as the fallback if you want this to hold; pick store offer codes only when the discount is the campaign.**

| Method | Accuracy | What breaks it | Cross-platform | Effort |
| --- | --- | --- | --- | --- |
| Store offer codes | High, but only on discounted purchases | 6 month expiry, one code per customer per offer | Partly, limits differ per store | Low, then high to administer |
| Manual creator code | High, independent of the install path | Nobody types it, or the paywall is ungated | Yes, everywhere | Low |
| Deep link plus SDK | Highest when click and first open share a device | Reinstalls, a purchase that beats the claim | Universal Links, Install Referrer | Medium to high |
| Web checkout capture | Highest: the browser session is continuous | Redirects that strip the query string | Web purchases only | Low |

Read the store limits from the primary sources. [App Store Connect allows 10 active offers per subscription and 1 million codes per app per quarter](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes/), custom codes capped at 25,000 redemptions with a six month expiry (verified 12 September 2026). [Google Play caps subscription promo codes at 10,000 per quarter per product](https://support.google.com/googleplay/android-developer/answer/6321495) and grants a free trial of 3 to 90 days rather than a discount (verified 12 September 2026). The [2022 thread](https://community.revenuecat.com/general-questions-7/best-way-to-introduce-a-cross-platform-offer-code-affiliate-program-1410) hit that asymmetry: "As Android you can only offer free trials not a percentage off a product."

One widely repeated claim needs correcting, ours included. RevenueCat's [event reference](https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields) documents an `offer_code` field, the "Offer or promotion code used for the transaction," for App Store and Google Play (verified 12 September 2026). Per-code joins through webhooks work today. Only dashboard reporting per code is missing.

Manual creator codes are the most underrated of the four and we default to them for a first launch. They survive a user who sees a video on a phone, installs three days later on an iPad, and subscribes the following week. No device graph survives that. The cost is a conversion tax, since everyone who ignores the field goes unattributed. We take a durable minority over a fragile majority, because a wrong attribution pays the wrong creator.

## How the affiliate id actually reaches the webhook

The affiliate id reaches a RevenueCat webhook by being written into the customer record before the transaction happens. RevenueCat copies subscriber attributes into the event payload it sends you, so the id has to exist on that customer, under a user id your backend also knows, at the moment the purchase clears. Ten steps, in order.

1. **Log the click.** The branded link hits your link service, which records the affiliate and a timestamp, then redirects.
2. **Issue a claim token.** A short-lived token lets the app claim that click later without fingerprinting.
3. **Let the install happen.** Nothing you control runs here, and on iOS this gap kills most attribution schemes.
4. **Claim on first open.** `MyAppAffiliate.start(apiKey:)` claims a pending click by itself. Call `MyAppAffiliate.attribute(url:)` for a Universal Link that opened the app, or `MyAppAffiliate.applyCode("LUMI")` for a typed code.
5. **Store it twice.** Locally for offline reads, and server side so a reinstall does not erase it.
6. **Bind your user id.** Call `MyAppAffiliate.identify(userId:)` with exactly the id you pass to `Purchases.shared.logIn(...)`. This is the join key, and the only step that cannot be automated.
7. **Optionally mirror the id into RevenueCat.** Read `MyAppAffiliate.attributedAffiliateId()` and write it as `affiliate_id` through `Purchases.shared.attribution.setAttributes`. Our commission join never reads it, so this buys you a cross-check and RevenueCat-side reporting, nothing more.
8. **Let the purchase run.** RevenueCat syncs attributes when the app is foregrounded, backgrounded or making a purchase, per the [customer attributes documentation](https://www.revenuecat.com/docs/customers/customer-attributes) (verified 12 September 2026).
9. **Receive the webhook.** The event carries `app_user_id`, `subscriber_attributes`, `product_id`, `price` and `period_type`. RevenueCat says most are "usually delivered within 5 to 60 seconds of the event occurring" (verified 12 September 2026).
10. **Join and price it.** Match `app_user_id` to your stored attribution, apply the rate, write a ledger row.

![Ten step flow from creator link click to attributed commission in a RevenueCat app](https://www.myappaffiliate.com/blog-images/revenuecat-affiliate-tracking/revenuecat-affiliate-tracking-attribution-flow.webp "Every step where the affiliate id can be lost.")

The id lands in two independent places, on your own server at step 5 and inside RevenueCat at step 7. That redundancy looks wasteful until the first time the Keychain value is present while the RevenueCat attribute is missing. We join on `app_user_id` against our own record and treat the subscriber attribute as a cross-check, never as the source of truth. Step 6 is where we hold the strongest view, having debugged it twice: never let the app invent its own id for RevenueCat.

## Step by step: wiring it up

Wiring RevenueCat affiliate tracking into an iOS app takes two required SDK calls and one webhook endpoint. Start the SDK at launch, bind the user id, then point the webhook at a receiver that verifies and joins. The three steps after that are optional, and each one buys a specific thing.

1. **Start it once at launch.** This runs before any attribution call, in your app delegate or the SwiftUI `App` init. There is no API URL to pass: the SDK compiles the host in.

```swift
import MyAppAffiliate

MyAppAffiliate.start(apiKey: "pk_live_…")   // your app's SDK key

// SwiftUI, one line: this also forwards incoming Universal Links.
ContentView().myAppAffiliate(apiKey: "pk_live_…")
```

The SDK now has a device id in the Keychain, retries anything a previous offline launch failed to send, and asks for a deferred match on a fresh install.

2. **Capture the Universal Link.** The SwiftUI modifier above already does this. In UIKit, attach the handler at the root so a cold launch from a creator link is not dropped.

```swift
// SwiftUI
.onOpenURL { url in MyAppAffiliate.attribute(url: url) }
```

Associated Domains must be enabled for the link to open the app at all.

3. **Capture the manual code.** Give the user one field, usually on onboarding, and pass the raw string through.

```swift
MyAppAffiliate.applyCode("LUMI")
```

This works on a device that never clicked anything, which is why we ship it alongside links.

4. **Bind the user id.** Call this with the same identifier you hand to RevenueCat, not a device id and not an email hash.

```swift
MyAppAffiliate.identify(userId: yourUserId)
```

Your backend can now resolve an `app_user_id` to a stored attribution without guessing.

5. **Optionally copy the affiliate id into RevenueCat.** [Store the affiliate id as a subscriber attribute](/blog/revenuecat-subscriber-attributes-affiliate-id) before the paywall can complete a purchase. Our commission join runs on `app_user_id` from step 4 whether or not you do this, so treat it as reporting and a cross-check.

```swift
import RevenueCat

if let affiliateId = MyAppAffiliate.attributedAffiliateId() {
  Purchases.shared.attribution.setAttributes(["affiliate_id": affiliateId])
}
```

RevenueCat now carries the value on the customer and echoes it back in every event for that subscriber.

6. **Point the webhook at your receiver.** In the RevenueCat dashboard under Integrations then Webhooks, set the URL and `Authorization` header, per our [webhook setup guide](https://docs.myappaffiliate.com/webhooks).

> **Warning:** Set the subscriber attribute before the purchase completes, not after. An attribute written a second late still appears on future events, but the `INITIAL_PURCHASE` payload you already received will not have it, and that is the event that opens the commission. Write it when attribution resolves, never in the paywall's success handler.

The whole integration is about forty lines. Almost every failure we have debugged was an ordering problem, not a code problem, which is why that callout runs longer than most steps.

## Which webhook events move money

Only three RevenueCat event types create a positive commission: `INITIAL_PURCHASE` outside a trial, `RENEWAL`, and `NON_RENEWING_PURCHASE`. An `INITIAL_PURCHASE` carrying `period_type: TRIAL` is worth zero and belongs in the funnel, not the ledger. Refunds and transfers subtract or reassign. Everything else, including `BILLING_ISSUE`, should leave balances untouched.

**Map every event to one of three outcomes, credit, debit or ignore, and refuse to let a fourth category exist.**

| RevenueCat event | Our normalized type | Effect on the ledger |
| --- | --- | --- |
| `INITIAL_PURCHASE` | `purchase` | Credit at the snapshotted rate |
| `INITIAL_PURCHASE` with `period_type: TRIAL` | `trial_start` | Zero. Counts in the funnel |
| `RENEWAL` | `renewal` | Credit, subject to the renewal cap |
| `NON_RENEWING_PURCHASE` | `purchase` | Credit |
| `CANCELLATION` with `cancel_reason: CUSTOMER_SUPPORT` | `refund` | Debit against the original commission |
| `CANCELLATION`, any other `cancel_reason` | `cancel` | No financial effect |
| `EXPIRATION` | `expiration` | No financial effect |
| `REFUND_REVERSED` | `purchase` | Re-credit, App Store only |
| `BILLING_ISSUE`, `PRODUCT_CHANGE`, others | ignored | None |

*Event names verified against RevenueCat's reference on 12 September 2026.*

Two rows in that table trip up almost every implementation, ours included.

There is **no `REFUND` event type**. RevenueCat's [event reference](https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields) lists nineteen types and `REFUND` is not among them. A refund arrives as `CANCELLATION`, which the reference describes as "A subscription or non-renewing purchase was canceled or refunded," and only `cancel_reason` tells you which of those two happened. Key on the event name alone and refunds land in the same bucket as ordinary churn, so nothing is ever clawed back. If your mapping table has a `REFUND` row, it is dead code.

Ours had one until we wrote this post and went to check. Fixing it turned up the same shape of mistake in two more of our billing integrations, so it is worth grepping your own.

The trial branch is the other one. A trial start is a payload detail rather than a separate event: it arrives as `INITIAL_PURCHASE` and only `period_type` distinguishes it. Key on event type alone and you pay commission on every free trial.

Three fields answer most of what the ledger asks. `period_type` separates a trial from a paid period. `is_trial_conversion`, present only on `RENEWAL`, marks a trial becoming money. `price_in_purchased_currency` is the amount actually charged, which is why our normalizer prefers it over `price`.

Our unpopular opinion concerns `CANCELLATION`: it should change nothing. Founders ask us to freeze a creator's balance the moment a subscriber cancels, because it feels like revenue leaving. It is not. The period was paid and the money landed, so reversing punishes creators for churn they cannot control. For the field-by-field treatment, see [how each webhook event changes a commission balance](/blog/revenuecat-webhooks-affiliate-commissions).

## The five things that break attribution in production

Five failure modes account for nearly every dropped commission we have investigated: a purchase made while the customer is anonymous, an alias merge that rewrites the id you joined on, a subscription transferred between App Store accounts, sandbox traffic in the live ledger, and a reinstall that wipes the attribution. All five are identity problems, not billing.

1. **The anonymous purchase.** RevenueCat generates anonymous App User IDs prefixed `$RCAnonymousID:` when you have not called `logIn`, per the [identifying customers documentation](https://www.revenuecat.com/docs/customers/identifying-customers) (verified 12 September 2026). If the paywall converts before authentication, `INITIAL_PURCHASE` arrives with an id your backend has never seen and no `affiliate_id`.
2. **The alias merge.** When an anonymous customer logs in, RevenueCat merges the identities, and their documentation states that afterwards "there will be only one App User ID within the `original_app_user_id` field," with the rest in an `aliases` array. Resolve against all three or you will miss events.
3. **The transfer.** RevenueCat's default restore behavior is "Transfer to new App User ID," per their [restore behavior page](https://www.revenuecat.com/docs/projects/restore-behavior) (verified 12 September 2026), emitting a `TRANSFER` event with `transferred_from` and `transferred_to`. We stop future accrual and leave matured commissions alone.
4. **Sandbox pollution.** Every event carries an `environment` field valued `SANDBOX` or `PRODUCTION`, and RevenueCat notes it "is only determined by the type of transaction received from the store." TestFlight and StoreKit 2 sandbox purchases are both flagged this way, so a receiver that ignores the field credits creators for your QA sessions.
5. **The reinstall.** Anonymous ids are cached locally and cleared on reinstall. If the only copy of the affiliate id lived on the device, it is gone, which is why step 5 above writes it server side too.

![Two timelines showing subscriber attributes set before and after purchase, and the resulting webhook payloads](https://www.myappaffiliate.com/blog-images/revenuecat-affiliate-tracking/revenuecat-affiliate-tracking-identify-ordering.webp "The ordering bug that silently drops commissions.")

The first one hits new integrations within days. In the setups we have reviewed, identify ordering was wrong more often than every other failure combined, and it stays invisible in testing because a developer account is always logged in. You find it when a creator asks why their dashboard shows 40 installs and 2 sales while your revenue chart shows 11 new subscribers. So, an opinion that costs conversions: gate the paywall behind an account, because no webhook cleverness recovers an id that was never written.

## The commission decisions subscriptions force on you

Subscriptions force four decisions a one-time purchase never raises: whether a free trial earns anything, how long renewals keep earning, what a refund does to a commission already credited, and whether the rate applies to the price paid or to what the store deposits. None are technical, and all belong in writing before the first creator signs up.

Follow one subscriber. A $9.99 per month plan, a 20 percent commission recurring for 12 months, a 30 day attribution window and a 30 day hold. A 7 day free trial starts 1 March, converts on 8 March, renews on 8 April and 8 May, then is refunded on 20 May.

**The same schedule pays $4.00 on gross and $2.80 on revenue net of Apple's standard cut, which is the entire argument in one line.**

| Date | RevenueCat event | Commission on gross | Commission net of a 30% store cut |
| --- | --- | --- | --- |
| 1 Mar | `INITIAL_PURCHASE`, `period_type: TRIAL` | $0.00 | $0.00 |
| 8 Mar | `RENEWAL`, `is_trial_conversion: true` | +$2.00 | +$1.40 |
| 8 Apr | `RENEWAL` | +$2.00 | +$1.40 |
| 8 May | `RENEWAL` | +$2.00 | +$1.40 |
| 20 May | Refund of the 8 May period | -$2.00 | -$1.40 |
|  | **Payable** | **$4.00** | **$2.80** |

The arithmetic in cents, since our formula works in integers: 999 × 2000 / 10000 = 199.8, rounded to 200 cents per period. Three paid periods credit 600, the refund debits 200, so $4.00 is payable. Net of a 30 percent cut the base is 999 × 0.70 = 699.3, each period pays 699.3 × 2000 / 10000 = 139.86, rounded to 140. That leaves 420 minus 140, or $2.80.

The 30 day hold earns its keep here. The 8 May commission is still `pending` when the refund lands on 20 May, so it reverses before maturing and no negative balance reaches a payout. Set the hold to 7 days and the same subscriber leaves you collecting a clawback from a human being.

Apple's rates make the net column unstable as well as smaller. Apple's [subscriptions page](https://developer.apple.com/app-store/subscriptions/) states that in a subscriber's first year "you receive 70% of the subscription price at each billing cycle, minus applicable taxes," rising to 85% after a year of paid service (verified 12 September 2026). The [App Store Small Business Program](https://developer.apple.com/app-store/small-business-program/) gives 85% from the start below 1 million USD in prior-year proceeds. Under it the same period pays 999 × 0.85 × 0.20 = 169.83, rounded to 170 cents.

Three different commissions, one unchanged deal. Pay on gross: the number a creator reads off your paywall is the number they get a percentage of, and it does not move when Apple's terms do. If gross feels expensive, lower the rate. Fourteen percent of gross equals 20 percent of a 70 percent net, and defends itself in an email.

Thirty days is our default window because creator traffic converts late, and it governs the first purchase only. Renewals inherit the original attribution, otherwise a 12 month program would expire halfway through its term.

## Testing without shipping to the App Store

You can exercise the entire RevenueCat affiliate tracking loop without an App Store release. RevenueCat sends a `TEST` event from the dashboard, sandbox and TestFlight purchases produce real webhooks with `environment: SANDBOX`, and a stored payload replays as often as you like.

Five assertions are worth automating, in this order.

1. **Assert honest failure.** RevenueCat's [webhook documentation](https://www.revenuecat.com/docs/integrations/webhooks) requires a 200 response and states that "Any other status code will be considered a failure" (verified 12 September 2026). Return 200 only after the raw payload is stored.
2. **Assert idempotency.** Replay one payload twice and confirm exactly one event and one commission exist. RevenueCat retries "up to 5 times with an increasing delay (5, 10, 20, 40, and 80 minutes)" and reuses the same event `id`, so a unique constraint is the whole defence.
3. **Assert the rate.** Feed a $9.99 payload at 20 percent and check the ledger row is 200 cents, not 199 or 1998. Rounding bugs are silent and cumulative.
4. **Assert the trial branch.** Send an `INITIAL_PURCHASE` with `period_type: TRIAL` and confirm the commission is zero while the funnel still counts it.
5. **Assert the reversal.** Refund a purchase you already credited and confirm the balance returns to where it started, including inside the hold period.

Our receiver stores the raw payload before parsing, which is why a parser bug has never cost us a financial event. Those payloads double as the test corpus: when a customer reports a missing commission we replay their real event against a fixed parser.

Delivery is at least once, not exactly once: RevenueCat makes a "best effort for 'at least one delivery' of webhooks" (verified 12 September 2026). Build for duplicates from the first commit. Retrofitting idempotency onto a ledger that already double-paid a creator is an apology and a credit note.

Without a device, we rehearse the loop against the live database with one command:

```shell
pnpm --filter @maa/api smoke
```

It walks click, attribution, webhook and commission in sequence, our pre-flight check before a first real purchase.

## Build it yourself or buy it

Building RevenueCat affiliate tracking in house means shipping seven components: a link service, an attribution SDK, an idempotent webhook receiver, an attribution engine, a commission ledger with clawbacks, a payout rail with tax forms, and a creator dashboard. The receiver is the easy part.

**Build it if creator revenue is a rounding error and you enjoy this; buy once creators start emailing about their balances, because that is a support surface, not a feature.**

| Component | What it takes | Ongoing burden |
| --- | --- | --- |
| Link service and AASA hosting | Redirects, click logging, an `apple-app-site-association` file per domain | Painful on domain changes |
| Attribution SDK | Link capture, code entry, Keychain storage, a claim handshake, twice for Android | Every OS release is a regression risk |
| Webhook receiver | Token check, persist before parse, unique constraint on the event id | Low |
| Attribution engine | Window logic, alias resolution, transfers, sandbox filtering | Grows with RevenueCat |
| Commission ledger | Rate snapshots, pending and matured states, refund reversals, caps | Where money bugs live |
| Payouts | Stripe Connect onboarding, thresholds, tax forms, failed transfers | Monthly, forever |
| Creator dashboard | Auth, per-creator funnel and earnings | Scales with creator count |

Our estimate, from having built this: an engineer who knows the stack gets the receiver, the ledger and a CSV export working in two focused weeks. Payouts and the creator dashboard are the other 80 percent of the calendar. What founders underestimate is not the code. It is reconciling refunds monthly, chasing a creator whose Stripe onboarding stalled, and answering "why is my balance different".

MyAppAffiliate is the layer that performs the join this post describes. It owns the link and code layer, receives the RevenueCat webhook, applies the commission rules including refund clawbacks, and pays the creator. Flat monthly [pricing](/pricing), no percentage of attributed revenue. First-party attribution with no IDFA and no fingerprinting: the iOS SDK stores a generated device id and the attributed affiliate id. RevenueCat and Stripe are native sources, click to payout in one system. Adapty and Superwall ingest is planned, not shipped.

That is the only pitch here, with a caveat. If your program is two friends with promo codes, a spreadsheet is cheaper than anything we sell. We also [compared every tool in the category](/blog/best-affiliate-software-mobile-apps), with the same columns applied to ourselves.

## FAQ

### Does RevenueCat have an affiliate program built in?

No. RevenueCat has no affiliate or creator commission feature as of 12 September 2026, and a support engineer answering the April 2025 community request pointed the asker to a third-party partner. RevenueCat gives you the revenue events; the creator ledger and the payouts are yours.

### Can I use Apple offer codes as creator codes?

Yes, with limits. App Store Connect custom codes let you name a code per creator, cap redemptions at 25,000, and set an expiry within six months. RevenueCat's webhook payload carries an `offer_code` field for App Store and Google Play, so a per-creator join is possible.

### Which RevenueCat webhook event should trigger a commission?

`INITIAL_PURCHASE` and `RENEWAL` carry the money, and `NON_RENEWING_PURCHASE` covers lifetime opens up. An `INITIAL_PURCHASE` with `period_type: TRIAL` is a funnel event worth zero, so check the field rather than the type. `CANCELLATION` and `EXPIRATION` change no balance, and `BILLING_ISSUE` and `PRODUCT_CHANGE` should be ignored by the ledger entirely.

### What happens to the commission if the subscriber refunds?

The commission for that billing period is clawed back. In our ledger a refund writes a negative row against the original commission, so a creator credited $2.00 for May carries minus $2.00 into the next payout. Reverse the refunded period only.

### Does this work on Android, React Native and Flutter?

The design does. The click to id to subscriber attribute to webhook path is platform independent, and RevenueCat's webhook shape is the same for Play Store purchases. MyAppAffiliate ships a Swift SDK today, with Android Kotlin planned. Android's deferred primitive is the Play Install Referrer.

### Do I need an MMP like Branch or AppsFlyer for this?

Not for creator attribution. RevenueCat's own influencer campaign post routes you to Branch for link management, which does work. But an MMP is built for paid ad networks and SKAdNetwork, and none of them keep a commission ledger or pay a creator.

## What to do next

Set the `affiliate_id` subscriber attribute in your app today, before deciding anything else about creator commissions. It costs one call, it is free within [RevenueCat's 50 attribute allowance](https://www.revenuecat.com/docs/customers/customer-attributes), and it is the only step here whose absence cannot be fixed retroactively.

Ship it in your next build with a hardcoded test value if you have to, then work through the [iOS SDK guide](https://docs.myappaffiliate.com/sdk-ios) and set it for real. Last month's creator traffic is gone. Next month's is not.
