Skip to content
trackrift

Documentation

SDK

Server-side events

sendServerEvent, auth, idempotency, and integration patterns.

AI brief: sendServerEvent({ endpoint, token: SERVER_INGEST_TOKEN, event }) POSTs to /s2s/collect with source offline|server|crm. Generate event_id or pass explicit. Use for Stripe webhooks, closed-won, etc.

Server events close the loop on offline conversions: CRM closed-won, Stripe invoice.paid, Calendly bookings, support upgrades. They merge to identities via email or user_id.

actions/close-deal.ts
'use server';
import { sendServerEvent } from '@trackrift/sdk/server';

export async function onDealWon(email: string, value: number) {
  const { ok, status, eventId } = await sendServerEvent({
    endpoint: process.env.TRACKRIFT_COLLECTOR_URL ?? 'https://api.trackrift.com',
    token: process.env.SERVER_INGEST_TOKEN!,
    event: {
      event_name: 'sales_closed',
      email,
      value,
      currency: 'EUR',
      source: 'crm',
      properties: { pipeline: 'default', stage: 'closed_won' },
    },
  });
  if (!ok) throw new Error(`Trackrift s2s failed: ${status}`);
  return eventId;
}

ServerEvent fields

FieldRequiredNotes
event_nameyessnake_case — sales_closed, purchase, etc.
emailconditionalRequired if no user_id — identity merge
user_idconditionalYour app user id
value + currencyrecommendedRevenue attribution
sourceyesserver | offline | crm
event_idnoAuto-generated UUID if omitted
timestampnoISO8601 — default now
idempotent-webhook.ts

Pass stable event_id to survive webhook retries

await sendServerEvent({
  endpoint: process.env.TRACKRIFT_COLLECTOR_URL!,
  token: process.env.SERVER_INGEST_TOKEN!,
  event: {
    event_id: `stripe_${invoice.id}`,
    event_name: 'purchase',
    email: customer.email,
    value: invoice.amount_paid / 100,
    currency: invoice.currency.toUpperCase(),
    source: 'server',
  },
});

Server ingest token

Create a server token in Settings → API keys with ingest scope. Never expose it in NEXT_PUBLIC_* variables or client bundles.