Skip to content
IForevents Docs
IForevents Docs
InicioPanelGitHubPrivacidadTérminosSeguridadIntroducción
DestinationsWebhookConnectorsReplay
Soporte y SLA
Destinations

Webhook

Receive events on your own HTTPS endpoint, signed

The webhook destination POSTs a JSON array of events to the URL you give it. Answer 2xx within 15 seconds; anything else is retried as described in Destinations.

Payload

{
  "schema": 1,
  "project_uuid": "…",
  "events": [
    {
      "uuid": "…",
      "type": "track",
      "name": "purchase",
      "user_uuid": "…",
      "custom_id": "user-42",
      "created_at": "2026-09-21T21:15:33.856Z",
      "properties": { "amount": "9.99" },
      "traits": { "email": "[email protected]" },
      "context": { "ip": "203.0.113.9", "user_agent": "…", "sdk": "iforevents-js/0.3.0" }
    }
  ]
}

traits is present on identify events only. Property values are strings, as stored.

Signature

When the destination has a signing secret, every request carries

X-IForevents-Signature: t=<unix seconds>,v1=<hex>
X-IForevents-Destination: <destination uuid>

where v1 = HMAC-SHA256(secret, "<t>." + body). Recompute it over the raw body and compare in constant time; reject timestamps older than five minutes to defeat replays.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = createHmac("sha256", secret).update(`${parts.t}.`).update(rawBody).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && timingSafeEqual(Buffer.from(parts.v1, "hex"), Buffer.from(expected, "hex"));
}

Idempotency

Retries carry the same event uuid. Store it and ignore a second arrival.

Destinations

Forward every event to the tools your team uses (Cloud)

Connectors

What each destination needs and how events map

On this page

PayloadSignatureIdempotency