The [`@refcampaign/sdk`](https://www.npmjs.com/package/@refcampaign/sdk) package exposes two clients:

* `RefCampaignBrowser` captures the affiliate session in the browser and can attach an email hash after signup or login.
* `RefCampaignServer` injects the captured session into Stripe metadata or sends manual conversions from your backend.

## Quickstart

<Steps>
  <Step>
    ### Add browser capture

    For no-code sites, simple websites, or SaaS frontends where you do not want another bundled dependency, paste the CDN script in your `<head>`:

    ```html
    <script src="https://sdk.refcampaign.com/v1.js" async></script>
    ```

    The script captures the session from the URL, cookie, or local storage and exposes `window.RefCampaignBrowser`.
  </Step>

  <Step>
    ### Install the server SDK

    ```bash
    pnpm add @refcampaign/sdk
    # or
    npm install @refcampaign/sdk
    ```

    Use the server SDK anywhere you create Stripe payments or subscriptions.
  </Step>

  <Step>
    ### Add Stripe metadata

    ```ts
    import { RefCampaignServer } from '@refcampaign/sdk'

    const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)

    const metadata = rc.getStripeMetadata(sessionId)
    ```

    Pass this metadata when creating the Stripe payment object that represents the customer purchase.
  </Step>
</Steps>

## Pick an install path

### CDN script tag

Use this path for Webflow, Framer, WordPress, Wix, static HTML, or any site that lets you paste custom code:

```html
<script src="https://sdk.refcampaign.com/v1.js" async></script>
```

This captures clicks. Stripe conversion attribution still needs the server SDK below.

### CDN browser + npm server SDK

This is the recommended SaaS setup: keep browser capture on the CDN and use npm only in your backend.

```ts
import { RefCampaignServer } from '@refcampaign/sdk'

const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)
```

### Full npm

Use full npm when you prefer everything in your application bundle:

```ts
import { RefCampaignBrowser, RefCampaignServer } from '@refcampaign/sdk'

RefCampaignBrowser.captureSession()

const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)
```

Choose one browser path only: CDN script tag or `RefCampaignBrowser.captureSession()` from npm. The server SDK is still required for Stripe metadata.

## Stripe attribution

### Checkout Sessions

For Stripe Checkout subscriptions, set metadata both on the Checkout Session and on `subscription_data` so recurring invoices keep the attribution:

```ts
import { RefCampaignServer } from '@refcampaign/sdk'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)

export async function POST(req: Request) {
  const { priceId, sessionId } = await req.json()
  const metadata = rc.getStripeMetadata(sessionId)

  const checkout = await stripe.checkout.sessions.create({
    line_items: [{ price: priceId, quantity: 1 }],
    mode: 'subscription',
    metadata,
    subscription_data: { metadata },
    success_url: 'https://yoursite.com/success',
    cancel_url: 'https://yoursite.com/cancel',
  })

  return Response.json({ url: checkout.url })
}
```

### One-time payments

For one-time payments, put the metadata on the Payment Intent:

```ts
await stripe.paymentIntents.create({
  amount: 4900,
  currency: 'eur',
  metadata: rc.getStripeMetadata(sessionId),
})
```

### Direct subscriptions

For direct subscription creation, put the metadata on the Subscription:

```ts
await stripe.subscriptions.create({
  customer: customer.id,
  items: [{ price: 'price_xxx' }],
  metadata: rc.getStripeMetadata(sessionId),
})
```

## Identify customers

Call `identify()` after login or signup to improve attribution when cookies are lost, Safari ITP expires storage, or the customer converts on another device.

```ts
import { RefCampaignBrowser } from '@refcampaign/sdk'

RefCampaignBrowser.identify(currentUser.email)
```

The browser SDK hashes the email client-side with SHA-256 before sending it to RefCampaign.

## Manual conversion tracking

For non-Stripe payments, send the conversion from your backend:

```ts
import { RefCampaignServer } from '@refcampaign/sdk'

const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)

const result = await rc.trackConversion({
  sessionId,
  amount: 4900,
  currency: 'EUR',
  metadata: { orderId: 'ord_42' },
})

if (!result.success) {
  console.error(result.error)
}
```

Amounts are integer cents. Use `sessionId` from the browser SDK session cookie, local storage, or your own checkout payload.

## Staging

The browser SDK defaults to `https://app.refcampaign.com`. Override it before calling `identify()` when testing against staging:

```ts
import { RefCampaignBrowser } from '@refcampaign/sdk'

RefCampaignBrowser.configure({
  apiBase: 'https://app.test.refcampaign.com',
})
```

The server SDK uses `apiUrl`:

```ts
const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!, {
  apiUrl: 'https://app.test.refcampaign.com',
})
```

## Pure REST alternative

If you cannot add a dependency, call the endpoints directly. See [server-to-server postback](/docs/api/integration/postback).
