RefCampaign

SDK integration

Install the @refcampaign/sdk package and call track / identify from your application.

The @refcampaign/sdk package wraps the public REST API in a typed JavaScript client. It runs on the server (Node, Next.js API routes, edge functions) and ships with built-in retry handling.

Install

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

The package exports both ESM and CJS builds and supports Node 20+, Bun, and Cloudflare Workers.

Initialize

import { RefCampaign } from '@refcampaign/sdk'

const refcampaign = new RefCampaign({
  apiKey: process.env.REFCAMPAIGN_API_KEY!,
})

By default the client points at https://app.refcampaign.com. Override with apiUrl when testing against staging:

const refcampaign = new RefCampaign({
  apiKey: process.env.REFCAMPAIGN_API_KEY!,
  apiUrl: 'https://app.test.refcampaign.com',
})

Track a conversion

The most common use case: a customer just paid and you want to attribute the conversion to whichever click brought them in.

await refcampaign.conversions.track({
  sessionId: trackingSessionId,
  amount: 49.9,
  currency: 'EUR',
  metadata: { orderId: 'ord_42' },
})

The sessionId is the value the browser SDK or the tracking URL stamped onto the visitor's cookie. If you no longer have it (Safari ITP, cross-device payment, server-only flow), pass customerEmailHash instead — the SHA-256 hex of the lowercased customer email.

import { createHash } from 'node:crypto'

const customerEmailHash = createHash('sha256')
  .update(customer.email.toLowerCase())
  .digest('hex')

await refcampaign.conversions.track({
  customerEmailHash,
  amount: 49.9,
  currency: 'EUR',
})

Identify a session

Binds a known customer to an in-flight tracking session. Useful in two-stage flows: the browser SDK captures an anonymous click, the customer fills the checkout form, and your server identifies the session before the conversion lands.

await refcampaign.tracking.identify({
  sessionId: trackingSessionId,
  customerEmailHash,
})

identify() is idempotent — calling it twice with the same sessionId returns the existing binding.

Use it from a Next.js Route Handler

// app/api/checkout/complete/route.ts
import { RefCampaign } from '@refcampaign/sdk'
import { NextResponse } from 'next/server'

const refcampaign = new RefCampaign({
  apiKey: process.env.REFCAMPAIGN_API_KEY!,
})

export async function POST(req: Request) {
  const { sessionId, amount, currency, orderId } = await req.json()

  await refcampaign.conversions.track({
    sessionId,
    amount,
    currency,
    metadata: { orderId },
  })

  return NextResponse.json({ ok: true })
}

Errors

The SDK throws a RefCampaignError whose code field matches the error code returned by the API:

import { RefCampaign, RefCampaignError } from '@refcampaign/sdk'

try {
  await refcampaign.conversions.track({ /* … */ })
} catch (err) {
  if (err instanceof RefCampaignError) {
    if (err.code === 'VALIDATION_FAILED') {
      // Surface field-level details
      console.error(err.details)
    }
    if (err.code === 'RATE_LIMIT_EXCEEDED') {
      // Back off and retry
    }
  }
  throw err
}

See the full list in error handling.

Pure REST alternative

If you can't add a dependency (Lambda layer constraints, polyglot stack, internal compliance), call the endpoints directly. See server-to-server postback.

On this page