REST API reference

The OakData read API: bearer-authed JSON endpoints for overview, sessions, visitors, journeys, live, events, and replays.

The REST API serves your analytics back as JSON. Every endpoint is GET, lives under https://oakdata.co/api/v1, and is read-only. Requests are authenticated with a secret key and scoped to exactly one project.

Authentication

Pass your secret key (oak_sec_…) as a bearer token. An x-api-key header is accepted as a fallback.

auth
bash
curl https://oakdata.co/api/v1/overview \
  -H "Authorization: Bearer oak_sec_xxxxxxxxxxxxxxxxxxxxxxxx"

Secret keys only

These endpoints reject public keys (oak_pub_…) with 403 — public keys are browser-side and can only write events. A missing or invalid key returns 401. Because a key resolves to one project, a key for project A can never read project B.

Errors

Errors return a non-2xx status with a JSON body of the shape { "error": "message" }. Common cases: 400 (invalid query parameter, e.g. a bad range), 401 (missing/invalid key), 403 (public key used), and 404 (no such session or replay).

Overview

GET/api/v1/overview

The headline view of traffic and conversion for a time window — aggregate stats plus the top dimensions.

Query paramTypeDescription
rangestringTime window: 24h, 7d, 30d, or 90d. Defaults to 7d.
exclude_botsbooleanExclude traffic classified as bots. Defaults to false.

Response:

rangestring

The resolved time window.

statsobject

pageviews, visitors, sessions, avgSessionDurationSec, avgPagesPerSession, and bounceRate.

timeSeriesarray

Per-bucket points: { bucket, visitors, pageviews, sessions } (hourly for 24h, daily otherwise).

topPages, topReferrers, topSources, topCampaigns, topCountries, topCities, browsers, operatingSystems, deviceTypesarray

Ranked breakdowns, each a list of { label, visitors, pageviews }.

eventCountnumber

Total events in the window.

Sessions

GET/api/v1/sessions

Recent visitor sessions, newest first.

Query paramTypeDescription
rangestringTime window: 24h, 7d, 30d, or 90d. Defaults to 7d.
limitnumberMax sessions to return (1–200). Defaults to 50.

Returns { range, count, sessions }, where each session carries:

session_idstring

The session identifier.

distinct_idstring

The visitor (user id if identified, else anonymous id).

started_at / last_atstring

ISO timestamps for the session's first and last event.

pageviews / eventsnumber

Counts within the session.

entry_path / exit_pathstring | null

First and last page paths.

referring_domainstring | null

Where the session came from.

country / citystring | null

Geo, derived from IP at ingest.

browser / os / device_typestring | null

Device context.

is_bot / bot_nameboolean / string | null

Bot classification for the session.

Session detail

GET/api/v1/sessions/{id}

The full ordered event timeline for one session id — every event row, oldest first. Returns 404 if the session has no events.

session_idstring

The session id you requested.

event_countnumber

Number of events returned.

eventsarray

The raw event rows in chronological order. Each row includes event, timestamp, pathname, properties, and the device/geo columns. See events & properties.

Visitor profile

GET/api/v1/visitors/{distinctId}

A single visitor's full profile, aggregated from the last 90 days. The path segment matches either the distinct_id or the anonymous_id, so activity from before sign-up is included.

distinct_idstring

The id you looked up.

user_idstring | null

The identified user id, if any.

traitsobject

Accumulated traits (replayed from $identify / $set / $set_once).

groupsobject

Group memberships, keyed by group type.

first_seen / last_seenstring | null

ISO timestamps.

total_eventsnumber

Lifetime event count in the window.

sessionsarray

Recent sessions for this visitor (same shape as /sessions).

firstTouch / lastTouchobject | null

First- and last-touch attribution (referrer, UTM, path, timestamp).

identityTimelinearray

Identity events with a human summary: { event, timestamp, summary }.

replaysarray

Replay references: { id, session_id, started_at, last_event_at, has_errors }.

Journey

GET/api/v1/journey

The aggregated path/funnel tree for a time window — the common routes visitors take and where they drop off.

Query paramTypeDescription
rangestringTime window: 24h, 7d, 30d, or 90d. Defaults to 7d.

Returns { range, totalSessions, depth, roots }. roots is a tree of nodes; each node is { label, count, children[] }, where count is the number of sessions whose path passes through that node. depth is the maximum path length analyzed (3).

Live

GET/api/v1/live

Who is on the site right now — sessions active in the last 5 minutes. Takes no parameters.

response
json
{
  "active_now": 2,
  "sessions": [
    { "session_id": "s_a1b2c3", "last_seen": "2026-06-11T14:03:21.000Z" },
    { "session_id": "s_d4e5f6", "last_seen": "2026-06-11T14:01:55.000Z" }
  ]
}

Events

GET/api/v1/events

The raw event firehose, newest first, paginated.

Query paramTypeDescription
offsetnumberRow offset for pagination. Defaults to 0 (max 1,000,000).
limitnumberMax rows (1–500). Defaults to 100.

Returns { offset, limit, rows, total }, where total is the exact count across all pages and rows are full event records.

Replays

GET/api/v1/replays

Recorded session replays for the project, newest first.

Query paramTypeDescription
limitnumberMax replays (1–200). Defaults to 100.

Returns { count, replays }. Each replay includes its recording id, session_id, distinct_id, started_at, last_event_at, duration_ms, chunks_count, entry_url, viewport and device fields, country, and has_errors.

Replay detail

GET/api/v1/replays/{sessionId}

One replay by its recording id (the id from the list above — not the analytics session id). Returns the recording metadata plus short-lived signed URLs for each rrweb chunk.

sessionobject

The replay metadata (same shape as a row from /replays).

chunk_urlsarray

A list of { url } objects — signed URLs to the gzipped NDJSON rrweb chunks, valid for ~30 minutes. A player fetches, gunzips, and merges them by timestamp.

Note

Returns 404 if no replay matches the id. Chunk URLs expire — fetch them fresh each time you need to play a recording.

Prefer to let an agent query this for you? The same data is available as MCP tools.