Skip to content

API Reference

Every SDK talks to this endpoint under the hood. Use it directly only if you're integrating from a platform no SDK covers yet β€” otherwise prefer the JavaScript, Flutter, React Native, Swift, Kotlin, or Node.js SDK.

Ingest events

POST /api/v1/event

Body: a batch of one or more events.

{
  "events": [
    {
      "sid":  "YOUR_SITE_ID",     // required β€” site_id from Integration Hub
      "uid":  "HASHED_USER_ID",   // required β€” SHA-256 hash, never a raw id
      "p":    "/checkout",        // required β€” URL path
      "t":    "pageview",         // optional β€” event type, defaults to "pageview"
      "ref":  "https://google.com", // optional β€” referrer
      "utm":  { "source": "newsletter" }, // optional β€” UTM parameters
      "meta": { "plan": "pro" }           // optional β€” custom event properties
    }
  ]
}
FieldRequiredNotes
sidYesSite ID from the dashboard's Integration Hub.
uidNoSHA-256 hash of the visitor/user id β€” omitted entirely for anonymous visitors (no identify() call). Every SDK computes this client-side (or, for the Node.js SDK, server-side) β€” never send a raw user id, email, or name.
pYesURL path or screen name.
tNoEvent type, e.g. pageview, signup_completed.
refNoReferrer URL.
utmNoUTM campaign parameters, as a flat object.
metaNoNon-identifying custom event properties.

Authentication

Web requests are authenticated by Origin β€” the domain making the request must match what was registered for that Site ID in the dashboard (localhost is always allowed outside production).

Non-web requests (mobile, desktop, server) include the app's Secret Key, issued alongside the Site ID for non-web platforms.

Rate limits & resilience

The ingestion endpoint is rate-limited per site. Every SDK batches events (flushing periodically or on a size threshold) so transient network failures or rate-limit responses don't lose data β€” the SDKs' batching is the intended usage pattern, not per-event calls. Most SDKs also persist unsent events locally between flushes; the Node.js SDK queues in memory only (see its docs for why), and a tracking pixel has no queue at all β€” it's a single fire-and-forget request per load.

Have questions about integration or security? Drop us a line directly.