# React Native referral quickstart

A referral in React Native takes two calls on `WarpLink`: `redeemInvitation(text)` reads the invitation an iPhone user pastes, and `claimReferral(installerId)` credits the install when the person signs up. On Android, the Play install referrer carries the invitation and the SDK matches it with no call of yours. This quickstart covers both platforms and Expo, then the webhook that tells your backend to grant the reward.

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

## What you need

- An app registered in WarpLink: its App Store URL for iOS, and its package name and signing certificate SHA256 fingerprint for Android.
- An SDK key from **Keys**, then **SDK keys**. If your organization has several apps, create the key for this app.
- React Native 0.75 or later and React 18 or 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

```bash
npm install @warplink/react-native
cd ios && pod install
```

The iOS SDK needs dynamic linkage. Add `use_frameworks! :linkage => :dynamic` to `ios/Podfile` first, as described in [React Native SDK setup](https://warplink.app/docs/sdks/react-native#installation).

```bash
npx expo install @warplink/react-native
npx expo prebuild
```

The SDK works in an Expo development build or a prebuild, like the rest of the SDK. It does not run in Expo Go, because `redeemInvitation` and `claimReferral` are native module calls. Build a development build with EAS Build or `npx expo prebuild`, then follow the [Expo notes](https://warplink.app/docs/sdks/react-native#expo) in the React Native SDK setup. The blog post [Expo deferred deep linking](https://warplink.app/blog/expo-deferred-deep-linking) walks through the build setup.

SDK 1.1.x cannot read an invitation. Call `WarpLink.configure` once at startup, outside any component, as shown in the [React Native SDK setup](https://warplink.app/docs/sdks/react-native#configure-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

**Android:** Google Play hands the install referrer to the SDK at first launch, and the invitation rides inside it. The match is exact (`android_referrer`) and needs no screen of yours.

**iPhone:** the install carries no data, so your first screen offers a field where the person pastes the invitation. Pass the text to `redeemInvitation`:

```ts
import { WarpLink } from '@warplink/react-native';

async function onInvitePasted(text: string) {
  try {
    const link = await WarpLink.redeemInvitation(text);
    if (link) showApplied(); // null: not an invitation, or no match
  } catch (error) {
    showMessage((error as Error).message); // says how to open the link again
  }
}
```

The package has no paste-button component. The SDK never reads the clipboard, and it sees only the text you pass in. Keep a skip option: the paste step is an offer, not a gate, and onboarding continues when it returns `null` or throws.

A refused invitation rejects with a `WarpLinkError` whose code is `E_SERVER_ERROR`. After a network failure the native SDK keeps the invitation and tries again on a later launch. That later result arrives through `getAttributionResult()` and `claimReferral`, not through `onLink`.

## Claim the install

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

```ts
import { WarpLink, type ReferralClaimResult } from '@warplink/react-native';

async function claimForNewUser(installerId: string): Promise<ReferralClaimResult | null> {
  try {
    return await WarpLink.claimReferral(installerId);
  } catch (error) {
    // E_NETWORK_ERROR, E_INVALID_API_KEY, E_NOT_CONFIGURED, or E_SERVER_ERROR
    // for an empty or too long installer id.
    reportError(error);
    return null;
  }
}
```

`claimReferral` 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

```ts
const claim = await claimForNewUser(user.warplinkId);
switch (claim?.status) {
  case 'claimed':
    break; // credited inside the window. Your webhook grants the reward.
  case 'flagged':
    break; // credited after the window: claim.flags has "outside_window"
  case 'ignored':
    break; // already credited: see claim.duplicateOf
  case 'none':
    break; // no referral link brought this install
}
```

| `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 |

`none` is an ordinary answer, not an error. The result also carries `referralId`, `linkId`, `linkUrl`, `matchMethod`, `isExact`, `matchConfidence`, `flags`, `duplicateOf`, `updated` and `replayState`.

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 phone with a development build, not Expo Go. On Android, install from a Google Play internal testing track. On iPhone, install from TestFlight or the App Store, then paste the invitation. [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)
- [React Native attribution](https://warplink.app/docs/sdks/react-native/attribution) for match types and evidence fields
- [iOS quickstart](https://warplink.app/docs/guides/referrals/ios), [Android quickstart](https://warplink.app/docs/guides/referrals/android), [Flutter quickstart](https://warplink.app/docs/guides/referrals/flutter)
