API reference

One base URL,
nine endpoints

REST over HTTPS, JSON in and out. Base URL https://api.cadence.dev/v1 — or eu.api.cadence.dev/v1 for EU-resident workspaces.

Authentication

Every request carries a bearer token. Server keys (sk_live_…) can write events and read data; public keys (pk_live_…) can only write events and are safe in client code. Keys are scoped to one project and can be rotated without downtime — the old key keeps working for one hour.

request header
Authorization: Bearer sk_live_2f7a9c41d8e60b3f
Content-Type: application/json
Cadence-Version: 2026-05-12
Pin Cadence-Version to the date you built against. Without it you get the latest version, and response shapes can change on a documented deprecation schedule.

Ingest

POST/v1/eventspk or sk

Records a single event. Returns 202 as soon as the event is durably queued — typically visible in queries within one second.

Body

eventstringEvent name in object_verb form.required
user_idstringYour identifier for the user. One of user_id or anonymous_id is required.
anonymous_idstringPre-signup identifier. Stitched onto the user on the next identify call.
propertiesobjectFlat map of scalars. Nested objects are flattened one level.
occurred_atISO 8601Defaults to receipt time. Accepted up to 48 hours in the past.
idempotency_keystringDeduplicated for 48 hours. Safe to retry.
curl https://api.cadence.dev/v1/events \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "checkout_completed",
    "user_id": "u_1842",
    "properties": {
      "plan": "business",
      "seats": 12,
      "amount_cents": 18300
    },
    "idempotency_key": "chk_9f31c0"
  }'
POST/v1/batchpk or sk

Up to 1,000 events or identify calls in one request, 5 MB maximum. Partial success is possible — the response lists the index and reason for anything rejected, and everything else is still accepted.

curl https://api.cadence.dev/v1/batch \
  -H "Authorization: Bearer sk_live_…" \
  -d '{
    "events": [
      { "event": "board_created", "user_id": "u_1842" },
      { "event": "invite_sent",   "user_id": "u_1842" },
      { "event": "board_shared",  "user_id": "u_2011" }
    ]
  }'
POST/v1/identifypk or sk

Attaches traits to a user and stitches any anonymous history onto them. Traits are merged, not replaced — send only what changed. Pass null to unset a trait.

user_idstringYour identifier for the user.required
anonymous_idstringIf present, all events under this ID are re-attributed retroactively.
traitsobjectFlat map. Values matching PII patterns are hashed at the edge.

Read

GET/v1/funnels/{id}sk only

Runs a saved funnel and returns per-step counts. Results are computed live — there is no cache to invalidate — so expect 0.6–2.0s depending on volume.

from, toISO 8601 dateWindow. Defaults to the funnel's saved range.
breakdownstringProperty or trait to split by, e.g. plan.
window_daysintegerConversion window, 1–90. Defaults to 30.
200 OK
{
  "funnel_id": "fnl_activation",
  "window_days": 30,
  "steps": [
    { "name": "visited_site",    "users": 128400, "rate": 1.000 },
    { "name": "account_created", "users": 41220,  "rate": 0.321 },
    { "name": "activated",       "users": 18940,  "rate": 0.147 }
  ],
  "computed_in_ms": 1140
}
GET/v1/cohortssk only

Lists saved cohorts with their current size. Add ?include=members to page through user IDs, 10,000 per page via the cursor parameter.

POST/v1/exportssk only

Queues a raw event export as Parquet or NDJSON and returns a job. Poll /v1/exports/{id} for a signed download URL, valid for 24 hours. Available on every plan, including Free.

Rate limits

Limits are per project, measured over a sliding minute. Every response carries X-RateLimit-Remaining and X-RateLimit-Reset. On 429, honour the Retry-After header — the SDKs do this for you.

Endpoint groupFreeTeamBusinessEnterprise
Ingest (events, batch, identify)600 / min6,000 / min60,000 / minNegotiated
Read (funnels, cohorts)20 / min120 / min600 / minNegotiated
Exports2 / day20 / day200 / dayUnlimited

Errors

Errors are JSON with a stable machine-readable code. Never parse the message — it is written for humans and we reword it.

StatusCodeWhat to do
400invalid_event_nameName is empty, over 128 chars, or not UTF-8
401invalid_keyKey is wrong, revoked, or from another project
403insufficient_scopeRead endpoint called with a pk_ key
413payload_too_largeSplit the batch; the limit is 5 MB
422property_quarantinedA value looked like PII and was dropped — the event was still recorded
429rate_limitedBack off for Retry-After seconds
503region_failoverRetry with backoff; ingest is queued, nothing is lost

Get started

Ship on Monday.
Understand it by Tuesday.

Free for 30 days on the full product. Five-minute install, no card, no onboarding call unless you want one.

  • SOC 2 Type II
  • EU & US data residency
  • Cancel in one click