# Swift SDK

> Learn how to install, configure, and use our Swift SDK.

export const components = {
  pre: CodeSnippet,
};

The WinWinKit Swift SDK is a native Swift library for iOS, iPadOS and macOS. It wraps the REST API calls, exposes typed models, and ships first-class SwiftUI integration via an `Observable` object.

## Installation

### Requirements

- iOS 16.0+ / macOS 13.0+
- Swift 5.0+
- Xcode 15.0+

### Swift Package Manager

Add the package via Swift Package Manager:

1. In Xcode, choose **File** → **Add Package Dependencies**.
2. Paste the repository URL:

  ```
   https://github.com/winwinkit/winwinkit-swift.git
   ```

3. Press **Add Package**.

You can now `import WinWinKit` from any source file.

## Configuration

Configure the SDK once at app startup. Use an [API Key](/developers/get-started/api-keys/) from the WinWinKit dashboard (**Settings** → **Integrations** → **API Keys**).

```swift
import WinWinKit

Referrals.configure(apiKey: "your-api-key")
```

After `configure(apiKey:)` runs, `Referrals.shared` is the singleton you call from anywhere.

### Identify the user

Set the app user id so WinWinKit knows whose claims, rewards, and stats to track.

```swift
Referrals.shared.set(appUserId: "your-app-user-id")
```

<Warning>
  Use a UUID-like value for the app user id — never an email, phone number,
  username, or any other personally identifying information. The id ends up in
  URLs, logs, and analytics, so treat it as a public identifier.
</Warning>

<Tip>
  If your app has no sign-in flow, generate a random UUID on first launch and
  persist it yourself — Keychain is preferred since it survives app reinstalls;
  UserDefaults works as a simpler fallback.
</Tip>

When the user logs out, reset the SDK so any subsequent activity isn't attributed to the previous user:

```swift
Referrals.shared.reset()
```

## Claim a code

Call `claimCode(code:)` when a user enters a code in your app — typically from a "Got a referral code?" screen, a referral link landing flow, or a deep link handler.

Pass the code exactly as the user entered it — WinWinKit validates it server-side and throws an error if it's unknown, expired, ineligible, or already claimed. It returns the updated `User` and any rewards granted at claim time.

```swift
do {
    let (user, rewardsGranted) = try await Referrals.shared.claimCode(code: "XYZ123")
    // Apply granted rewards in your app.
} catch {
    // Handle ReferralsError — see Error handling below.
}
```

## Grant user rewards

The `User` object is the source of truth for what the user is entitled to in WinWinKit — claimed codes, active rewards, and stats. Read it after configuring the SDK (and whenever it updates) to unlock the matching perks in your app.

```swift
let user = Referrals.shared.user
// Inspect user.rewards.active and grant features accordingly.
```

What you do with each reward depends on its type:

- **Basic** — flip a feature flag or unlock content in your app.
- **Credit** — apply the balance; call `withdrawCredits` when the user spends it.
- **App Store Offer Code / Google Play Promo Code** — present the code to the user or trigger the platform redemption flow.
- **RevenueCat Entitlement** — read the entitlement state from RevenueCat and unlock the corresponding feature.
- **RevenueCat Offering** — display the matching paywall offering.

The SDK caches the user and refreshes it in the background. In SwiftUI, prefer the observable object below — your UI updates automatically when the user state changes.

## User object

The `User` object exposes properties you can update from the SDK and properties WinWinKit manages for you.

### Updatable

#### Is Premium

Marks the user as a paying customer. Drives conversion tracking, affiliate commissions, and reward activation.

```swift
Referrals.shared.set(isPremium: true)
```

<Tip>
  Is updated automatically when revenue tracking is configured — directly from
  App Store, or Google Play, and from RevenueCat, Stripe. Configure them in
  **Settings** → **Integrations**.
</Tip>

#### Is Trial

Marks the user as currently on a free trial. Conversions are not counted while a user is in trial.

```swift
Referrals.shared.set(isTrial: true)
```

<Tip>
  Is updated automatically when revenue tracking is configured — directly from
  App Store, or Google Play, and from RevenueCat, Stripe. Configure them in
  **Settings** → **Integrations**.
</Tip>

#### First Seen At

The "first seen at" date controls [claim code eligibility](/docs/users/introduction/#claim-code-eligibility) (default window: 7 days). If you don't set it, WinWinKit uses the user's creation date.

```swift
Referrals.shared.set(firstSeenAt: Date())
```

#### Metadata

Attach arbitrary key-value pairs to a user.

```swift
Referrals.shared.set(metadata: ["plan": "annual", "platform": "ios"])
```

### Provided by WinWinKit

These properties are managed by WinWinKit. Read them from `Referrals.shared.user`.

#### Referral Code

The user's own referral code, generated when they are created in WinWinKit.

```json
"referral_code": "ABC123"
```

#### Referral Code Link

A hosted [Code Link](/docs/pages/code-link/) URL to user's referral code.

```json
"referral_code_link": "https://example.wwk.link/ABC123"
```

#### Claim Code Eligibility

Whether the user can claim a code right now, and until when.

```json
{
  "eligible": true,
  "eligible_until": "2026-05-05T12:00:00Z"
}
```

See [Claim Code Eligibility](/docs/users/introduction/#claim-code-eligibility) for the rules.

#### Referred By

The code that referred this user, if any. `type` is one of `affiliate`, `promo`, or `referral`.

```json
{
  "code": "XYZ123",
  "type": "referral"
}
```

#### Stats

Counters for users who claimed this user's referral code: total claims, conversions to premium, and subsequent churns.

```json
{
  "claims": 12,
  "conversions": 5,
  "churns": 1
}
```

#### Rewards

The user's active and expired rewards, grouped by reward type.

```json
{
  "active": {
    "basic": [...],
    "credit": [...],
    "offer_code": [...],
    "googleplay_promo_code": [...],
    "revenuecat_entitlement": [...],
    "revenuecat_offering": [...]
  },
  "expired": {
    "basic": [...],
    "credit": [...],
    "offer_code": [...],
    "googleplay_promo_code": [...],
    "revenuecat_entitlement": [...],
    "revenuecat_offering": [...]
  }
}
```

#### Referral Program

The referral program the user is part of, if any.

## Methods

### Withdraw credits

Spend down a credit reward balance. The amount is debited from the user's available credit for the given key.

```swift
let (user, withdrawResult) = try await Referrals.shared.withdrawCredits(
    key: "extra-levels",
    amount: 5
)
```

### Sync transactions

Sync App Store transactions with WinWinKit. Only needed when using direct App Store revenue tracking (without RevenueCat integration) — call this after a purchase completes so WinWinKit can attribute the conversion without delays.

```swift
Referrals.shared.syncTransactions()
```

### Refresh

Manually refresh the user from the backend. Useful after an out-of-band change you want reflected in the SDK immediately — for example, a server-side reward grant or a webhook-driven update.

```swift
Referrals.shared.refresh()
```

### Reset

Reset the SDK's internal state for the previously set `appUserId`. Call this when the user logs out so subsequent activity isn't attributed to them.

```swift
Referrals.shared.reset()
```

## SwiftUI integration

The SDK provides convenient Observable object to interact and observe changes in SwiftUI views.

### ReferralsObservableObject

Provides an observable `User` object, methods and states for interacting with WinWinKit.

```swift
import SwiftUI
import WinWinKit

struct ReferralView: View {
    @State private var referrals = Referrals.shared.observableObject

    var body: some View {
        VStack {
            Text("Your referral code")
            Text(referrals.user?.referralCode ?? "—")
        }
    }
}

struct ReferralClaimCodeView: View {
    @State private var referrals = Referrals.shared.observableObject
    @State private var code = ""

    var body: some View {
        VStack {
            Text("Got a referral code?")
            TextField("Enter a code", text: $code)
            Button("Claim code") {
                referrals.claimCode(code: code)
            }
            .disabled(referrals.claimCodeState.isLoading)
        }
    }
}
```

## Delegate

Optionally set a delegate to receive events from the SDK.

```swift
final class ReferralsHandler: ReferralsDelegate {
    func referrals(_ referrals: Referrals, receivedUpdated user: User?) {
        // The user changed — refresh your UI.
    }

    func referrals(_ referrals: Referrals, receivedError error: any Error) {
        // The SDK failed to fetch, create, or update the user.
    }
}

let handler = ReferralsHandler()
Referrals.shared.delegate = handler
```

## Error handling

Errors thrown or returned by the SDK conform to `Error` and can be cast to `ReferralsError`. 

See [Errors](/developers/api/errors/) for the full list of error codes the API can return.
