# iOS referral quickstart

An iPhone install carries no data from the App Store, so the first launch asks the new person to paste the invitation. This quickstart adds that paste button, claims the install when the person signs up, and receives the webhook that tells your backend to grant the reward. It takes four code changes: install the SDK, show the button, call `claimReferral`, and handle the event.

For the whole path, including the dashboard setup, read the [referrals guide](https://warplink.app/docs/guides/referrals).

## What you need

- An iOS app registered in WarpLink with its App Store URL. Without it, **Offer referral handoff on iOS** will not turn on.
- An SDK key from **Keys**, then **SDK keys**. If your organization has several apps, create the key for this app.
- iOS 16 or later for the paste button. The SDK itself runs on iOS 15 and later.
- A webhook endpoint, added under **Referral handoff**, then **Webhook**. See [Receive referral webhooks](https://warplink.app/docs/guides/webhooks).

## Install SDK 1.2.0

Add the package in Xcode with **File**, then **Add Package Dependencies**, and enter `https://github.com/WarpLinkApp/warplink-ios-sdk`. In `Package.swift`:

```swift
dependencies: [
    .package(url: "https://github.com/WarpLinkApp/warplink-ios-sdk", from: "1.2.0")
]
```

SDK 1.1.x cannot read an invitation. Call `WarpLink.configure(apiKey:options:)` once at launch, as shown in the [iOS SDK setup](https://warplink.app/docs/sdks/ios#initialize-the-sdk).

## Mark a link as a referral link

Open a link in the dashboard and turn on **Referral link**, or send `is_referral` over REST:

```bash
curl -X POST https://api.warplink.app/v1/links \
  -H "Authorization: Bearer wl_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "YOUR_APP_ID",
    "slug": "invite-ana",
    "destination_url": "https://example.com/invite",
    "is_referral": true
  }'
```

Store the returned link id with the user who shares it. The webhook names that link, and the id tells you whose invitation earned the credit. [Create referral links](https://warplink.app/docs/guides/referrals#create-referral-links) covers converting existing links in bulk.

## Read the invitation

A friend taps the link on an iPhone without your app. They see the invitation page, which copies an invitation, then the App Store. On first launch, your app shows the paste button.

```swift
import SwiftUI
import WarpLink

@available(iOS 16.0, *)
struct WelcomeView: View {
    @State private var message: String?

    var body: some View {
        VStack(spacing: 16) {
            Text("Did a friend invite you?")
            WarpLinkPasteButton { result in
                switch result {
                case .success(let link):
                    // nil means nothing was confirmed.
                    if link != nil { message = "Invitation applied." }
                case .failure(let error):
                    message = error.localizedDescription
                }
            }
            if let message { Text(message) }
            Button("Skip") { continueOnboarding() }
        }
    }
}
```

```swift
import UIKit
import WarpLink

@available(iOS 16.0, *)
final class WelcomeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let paste = WarpLinkUIPasteButton { [weak self] result in
            switch result {
            case .success(let link):
                if link != nil { self?.showApplied() }
            case .failure(let error):
                self?.showMessage(error.localizedDescription)
            }
        }
        paste.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(paste)
        NSLayoutConstraint.activate([
            paste.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            paste.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            paste.widthAnchor.constraint(equalToConstant: 200),
            paste.heightAnchor.constraint(equalToConstant: 44),
        ])
    }
}
```

```swift
// Use this when you collect the invitation text yourself.
WarpLink.redeemInvitation(text: pastedText) { result in
    switch result {
    case .success(let link):
        if link != nil { showApplied() } // nil: not an invitation, or no match
    case .failure(let error):
        showMessage(error.localizedDescription)
    }
}
```

`WarpLinkPasteButton` (SwiftUI) and `WarpLinkUIPasteButton` (UIKit) use the system paste control. The person pastes with one tap and no prompt, and the SDK sees only the text the button hands over. The SDK never reads the pasteboard on its own. Both buttons need iOS 16. On iOS 15, show a text field and use the **Your own text** tab.

The paste step is an offer, not a gate. Keep a **Skip** button, and show the invitation as applied only when you get a link back. A `failure` carries a message that tells the person to open the invitation link again, so you can show it as it is.

## Claim the install

When the friend signs up, call `claimReferral` with an installer id: a dedicated random id for the new user, up to 128 characters. Do not use a primary key, an email address or a phone number.

```swift
WarpLink.claimReferral(installerId: user.warplinkId) { result in
    switch result {
    case .success(let claim):
        handle(claim)
    case .failure(let error):
        // Unreachable server, refused key, or an empty or too long installer id.
        log(error)
    }
}
```

`claimReferral(installerId:completion:)` is safe to repeat. The first valid claim for an app and installer id wins, and the same call again returns the same claim.

### Handle each status

`claim.status` is a `ReferralClaimResult.Status`:

```swift
func handle(_ claim: ReferralClaimResult) {
    switch claim.status {
    case .claimed:
        break // credited inside the window. Your webhook grants the reward.
    case .flagged:
        break // credited after the window closed: claim.flags holds "outside_window"
    case .ignored:
        break // this installer already holds a credit: see claim.duplicateOf
    case .none:
        break // no referral link brought this install. Not an error.
    }
}
```

| `status` | What to do in the app |
|----------|----------------------|
| `.claimed` | Nothing more. The webhook is on its way |
| `.flagged` | Nothing more. Your backend decides from the `referral.flagged` event |
| `.ignored` | Nothing. A reward is never granted twice from our side |
| `.none` | Carry on. The install did not come from a referral link |

The result also carries `referralId`, `linkId`, `linkUrl`, `matchMethod`, `isExact`, `matchConfidence`, `flags`, `duplicateOf`, `updated` and `replayState`. A match from the pasted invitation reads `install_token` with `isExact` true.

For rewards of value, claim from your backend with `POST /v1/referrals/claims` and let your own rules decide when a sign-up has earned one. See [Claim from the SDK or from your backend](https://warplink.app/docs/guides/referrals#claim-from-the-sdk-or-from-your-backend).

## Receive the webhook

Your endpoint receives `referral.claimed` within seconds of the claim. Verify the signature on the raw body, skip an event id you have seen, then grant the reward in your own system:

```js
if (event.type === 'referral.claimed') {
  await grantReward({
    inviterLinkId: event.data.link.id,
    newUserId: event.data.installer_id,
    exact: event.data.match.exact,
  });
}
```

[Receive referral webhooks](https://warplink.app/docs/guides/webhooks) has the signature code for Node.js and Python, and [Reward recipes](https://warplink.app/docs/guides/referrals/rewards) shows how to turn an event into a reward.

## Test it

Test on a real iPhone: delete the app, tap the link, install from TestFlight or the App Store, tap the paste button, sign up with a fresh installer id, and claim. [Test referrals](https://warplink.app/docs/guides/referrals/testing) lists the steps and the checks.

## Next

- [Referrals guide](https://warplink.app/docs/guides/referrals) for setup, credit windows and the report
- [Test referrals](https://warplink.app/docs/guides/referrals/testing) and [Reward recipes](https://warplink.app/docs/guides/referrals/rewards)
- [iOS attribution](https://warplink.app/docs/sdks/ios/attribution) for match types and evidence fields
- [Android quickstart](https://warplink.app/docs/guides/referrals/android), [React Native quickstart](https://warplink.app/docs/guides/referrals/react-native), [Flutter quickstart](https://warplink.app/docs/guides/referrals/flutter)
