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