# TypeScript SDK

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

export const components = {
  pre: CodeSnippet,
};

The WinWinKit TypeScript SDK is a thin, promise-based wrapper around the REST API. It works in any modern JavaScript runtime — React, React Native, Expo, Node.js, and others. Every call resolves to a discriminated union: either the data you asked for, or an `errors` array.

## Installation

### Requirements

- A modern JavaScript runtime (Node.js 18+ or an evergreen browser).
- TypeScript types are bundled — no `@types/*` package needed.

### Package

The SDK is published to [npm](https://www.npmjs.com/package/@winwinkit/sdk) as `@winwinkit/sdk`. Install it with the package manager of your choice.

**pnpm**

```bash
pnpm add @winwinkit/sdk
```

**npm**

```bash
npm install @winwinkit/sdk
```

**yarn**

```bash
yarn add @winwinkit/sdk
```

**bun**

```bash
bun add @winwinkit/sdk
```

You can now `import { WinWinKit } from "@winwinkit/sdk"` from any source file.

## Configuration

Instantiate `WinWinKit` once with your API key. Use an [API Key](/developers/get-started/api-keys/) from the WinWinKit dashboard (**Settings** → **Integrations** → **API Keys**).

```ts
import { WinWinKit } from "@winwinkit/sdk";

const wwk = new WinWinKit({
  apiKey: process.env.WINWINKIT_API_KEY!,
});
```

Hold on to this instance — typically as a module singleton or a DI-provided value — and reuse it across the app.

<Warning>
  The SDK is stateless: every method takes the `appUserId` of the user the call
  applies to. Make sure you pass the correct id at each call site so activity
  isn't attributed to the wrong user.
</Warning>

<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 in `localStorage` (web), secure storage (React Native, Expo), or
  similar.
</Tip>

## Create a user

Register the user in WinWinKit with `createOrUpdateUser(...)` before calling `claimCode` or any other user-related action.

```ts
const { user, errors } = await wwk.createOrUpdateUser({
  appUserId: "your-app-user-id",
});
```

All arguments other than `appUserId` are optional. To set writable fields at creation time, see [User properties](#updatable).

## Claim a code

Call `claimCode(...)` 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 and returns errors if it's unknown, expired, ineligible, or already claimed. On success the response includes the updated `User` and any rewards granted at claim time.

```ts
const { user, rewardsGranted, errors } = await wwk.claimCode({
  appUserId: "your-app-user-id",
  code: "XYZ123",
});

if (errors) {
  // Show errors — see Error handling below.
} else {
  // Apply granted rewards in your app.
}
```

## 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. Fetch it whenever you want a fresh snapshot to unlock the matching perks in your app.

```ts
const { user } = await wwk.fetchUser({ appUserId: "your-app-user-id" });
// 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 is stateless — it doesn't cache the user. Store the result yourself (e.g. in React state or a store) so your UI can react when it changes.

## User object

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

### Updatable

Update writable fields with `createOrUpdateUser(...)`. All arguments other than `appUserId` are optional — pass only what you want to change.

```ts
const { user, errors } = await wwk.createOrUpdateUser({
  appUserId: "your-app-user-id",
  isPremium: true,
  isTrial: false,
  firstSeenAt: new Date(),
  metadata: { plan: "annual", platform: "web" },
});
```

#### Is Premium

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

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

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

#### Metadata

Attach arbitrary key-value pairs to a user.

### Provided by WinWinKit

These properties are managed by WinWinKit. Read them from the `User` returned by `fetchUser(...)` or `createOrUpdateUser(...)`.

#### 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 the 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. `operationId` is optional and lets you make the call idempotent — passing the same id twice debits only once.

```ts
const { user, withdrawResult, errors } = await wwk.withdrawCredits({
  appUserId: "your-app-user-id",
  key: "extra-levels",
  amount: 5,
  operationId: "checkout-7d3a",
});
```

### Register App Store transaction

Register an App Store transaction 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.

```ts
const { errors } = await wwk.registerAppStoreTransaction({
  appUserId: "your-app-user-id",
  originalTransactionId: "1000000123456789",
});
```

### Register Google Play transaction

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

```ts
const { errors } = await wwk.registerGooglePlayTransaction({
  appUserId: "your-app-user-id",
  purchaseToken: "abc...token",
});
```

### Refresh

To refresh the user's state, call `fetchUser(...)` again.

```ts
const { user } = await wwk.fetchUser({ appUserId: "your-app-user-id" });
```

## Error handling

Every method resolves to a discriminated union — the SDK never throws on API errors. Check the `errors` field to branch:

```ts
const { user, errors } = await wwk.fetchUser({ appUserId: "your-app-user-id" });

if (errors) {
  // errors is ErrorObject[] — show, log, or surface them.
} else {
  // user is User | null — null means the user does not exist (HTTP 404).
}
```

The shape per method:

- **Most methods** — `{ ...payload, errors: null } | { ...payload-fields-as-null, errors: ErrorObject[] }`.
- **`fetchUser`** — additionally returns `{ user: null, errors: null }` when the user does not exist.
- **`registerAppStoreTransaction` / `registerGooglePlayTransaction`** — return only `{ errors: ErrorObject[] | null }`.

Network failures and unexpected runtime errors will reject the returned promise — wrap calls in `try`/`catch` if you need to handle those distinctly from API errors.

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