Referral program
A share-with-a-friend growth loop with real install attribution — not a client-side honour-system bonus. Each user gets a unique link and a short, human-readable code (e.g. K7Q4-R9XP); a friend who taps the link or types the code and installs earns a reward for both sides, tracked server-side and capped so it can't be farmed.
How attribution works
- The app asks AppMate for the user's referral link (
appmate.cloud/r/{code}) and shares it. - A friend taps the link → the invite landing records a pending referral and stashes a one-time claim token on the clipboard, then sends them to the App Store.
- On the friend's first launch, the SDK reads the token and calls
/attribute— this is the reward trigger. Both sides become eligible; the new user's reward is granted right then. - Or, typed code:the friend enters the referrer's short code in an “Enter invite code” field. The SDK calls
/attributewith thecodeinstead of a clipboard token — no landing visit, no paste banner — and the referral is attributed on the spot. - Installed-app fast path: if the friend already has the app, the invite page opens it via your URL scheme with the code in the link (
yourscheme://retention-flow/action?type=referral&code=…), and falls back to the App Store or your app's websiteif it isn't installed (set per flow; the website comes from the app's settings). The app redeems it withRetentionFlow.redeemReferralFromURL(url)from.onOpenURL— instant attribution, no prompt. Register your scheme in the app's settings. - The referrer isn't present when the friend installs, so their app claims owed rewards on its next launch via
/rewards, which returns how many free weeks to grant (respecting the cap).
Configure the program
Author it in the dashboard's JSON editor or via the MCP update_referral_draft tool:
{
"type": "referral",
"landing": {
"eyebrow": "You've been invited",
"title": "A friend gave you a free week",
"subtitle": "Install the app and open it — your free week unlocks automatically.",
"ctaLabel": "Get the app",
"appStoreUrl": "https://apps.apple.com/app/id000000000"
},
"share": {
"messageTemplate": "I've been loving this app — here's a free week on me:"
},
"rewards": {
"referrerWeeks": 1,
"refereeEnabled": true,
"refereeWeeks": 1,
"referrerLabel": "1 free week for every friend who joins"
},
"maxRewardsPerReferrer": 10
}maxRewardsPerReferrer is a lifetime cap per user (0 or omitted = unlimited — flagged as a farming risk). The share link is appended to messageTemplate automatically.
Wire it in the app (iOS)
1. Share
// When the user taps "Invite a friend":
if let url = await RetentionFlow.referralShareLink(userId: user.id) {
presentShareSheet(text: shareMessage, url: url)
}
// Optional: a copyable "Your code" chip so people can share the code directly:
if let code = await RetentionFlow.referralShareCode(userId: user.id) {
yourCodeLabel.text = code // e.g. "K7Q4-R9XP"
}
// Do NOT grant the reward here — it's earned only when a friend installs.2. New user, on first launch
// Deferred clipboard handoff (shows the paste banner):
if let r = await RetentionFlow.attributeReferral(userId: user.id),
let reward = r.refereeReward {
grantFreeWeeks(reward.weeks) // your entitlement grant
}
// Or, from an "Enter invite code" field (no clipboard, no paste banner):
if let r = await RetentionFlow.redeemReferral(code: enteredCode, userId: user.id),
let reward = r.refereeReward {
grantFreeWeeks(reward.weeks)
}3. Referrer, on every launch
let earned = await RetentionFlow.claimReferralRewards(userId: user.id)
if earned.weeks > 0 { grantFreeWeeks(earned.weeks) }attributeReferralshows the iOS paste banner — call it at a natural “setting things up” moment on first launch.Public endpoints (raw HTTP)
The SDK calls these for you — but here are the literal contracts if you're integrating without it (or from another platform). Both are unauthenticated POSTs scoped by appSlug.
Mint / fetch a user's code — POST /api/public/referral/code
// request
{
"appSlug": "your-app-slug",
"userId": "your-end-user-id"
}
// response 200
{
"code": "K7Q4R9XP", // raw code
"displayCode": "K7Q4-R9XP", // formatted — use this in a "Your code" chip
"shareUrl": "https://appmate.cloud/r/K7Q4R9XP",
"shareMessage": "I've been loving this — a free week on me:",
"referrerWeeks": 1,
"referrerLabel": null
}Redeem an invite — POST /api/public/referral/attribute
Identify the invite with exactly one of code (a typed short code) or claimToken (the amrf_… token from the clipboard handoff).
// request — typed-code path
{
"appSlug": "your-app-slug",
"code": "K7Q4-R9XP", // case-insensitive; dashes/spaces ignored
"userId": "referee-user-id" // or "anonymousId" — optional but recommended
}
// response 200
{
"attributed": true,
"alreadyAttributed": false,
"refereeReward": { "weeks": 1, "label": null } // null if only the referrer is rewarded
}code — not referralCode or shortCode. Errors: 404 unknown/invalid code; 409 with { "selfReferral": true } if the redeemer owns the code. Redeeming is idempotent per referee.Where the data lands
- Dashboard → your app → Referral program → installs attributed — a Code issuers summary (who minted a code and how many installs/pending it drove, including how many came from a typed code), the full invite graph with a Via (link / typed code) marker, status + reward flags, and CSV export.
- Programmatically:
GET /api/v1/apps/{appId}/referralsor the MCPlist_referrals/export_referrals_csvtools.
See the API reference for the public endpoints and the iOS SDK for the full method signatures.