Docs/Server-side events

Server-side events

A payment is confirmed on your server, not in your visitor's tab. This endpoint records facts no browser witnessed.

Why this exists

Browser events need an open tab. The customer closes it, loses the network, pays from their phone and never comes back to your success page — and the sale exists nowhere in your analytics. Anything your server knows for certain (a payment webhook, a subscription renewal, an affiliate commission paid weeks later) belongs here.

The call

curl -X POST https://kipstats.com/api/collect/server \
  -H "Authorization: Bearer $KIPSTATS_INGEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "purchase",
    "ref": "ch_3U9abcdef",
    "occurredAt": "2026-09-15T17:43:00Z",
    "data": { "amount": 900, "currency": "EUR", "plan": "pro" }
  }'

The ingest key

Authentication uses the ingest key of the site (kpi_…), shown in Dashboard → your site → Settings. It is not the tracking ID: the tracking ID sits in the HTML of every page, so it identifies a site but authorises nothing. The ingest key writes — keep it on your server, out of your client bundle and out of your repository. If it leaks, regenerate it from the same page; the old one stops working immediately.

Fields

FieldRequiredNotes
nameyesEvent name, e.g. purchase.
datanoAny JSON object. For money: amount in cents and currency.
refnoThe ID of the fact at its source (a charge ID, an invoice ID). Makes the call idempotent.
occurredAtnoISO 8601. When it happened, not when you call. A future date is replaced by now.
urlnoThe page the fact relates to, if it has one.

Replaying is safe

Send the same ref twice and the second call answers { "status": "duplicate" } without recording anything. That is the normal behaviour, not an error: payment providers retry their webhooks, and a nightly reconciliation job should be able to replay a whole month without inventing revenue.

Responses
{ "status": "ok", "ref": "ch_3U9abcdef" }         // recorded
{ "status": "duplicate", "ref": "ch_3U9abcdef" }  // same ref, already recorded
{ "statusCode": 401, "statusMessage": "Invalid ingest key" }

No session is created

A payment is not a visit. Recording one does not add a visitor, a pageview or a session — otherwise every sale would inflate your traffic and deflate your conversion rate.

Example: a Stripe webhook

Node.js
// app/api/stripe/webhook/route.ts
if (event.type === 'checkout.session.completed') {
  const session = event.data.object
  await fetch('https://kipstats.com/api/collect/server', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.KIPSTATS_INGEST_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'purchase',
      ref: session.id,
      data: {
        amount: session.amount_total,
        currency: session.currency?.toUpperCase(),
        plan: session.metadata?.plan,
      },
    }),
  })
}

Emitting purchase both from the success page and from your webhook would count the sale twice. Pick the server side and drop the browser one, or give both the same ref.