Skip to content
OddlyticsRelease 1.0.2

API Reference ​

The Worker is a small JSON API. The Swift package and the dashboard use it, and you can call it from anything else, such as a server, a script or another platform's app.

  • Base URL: your Worker's address, for example https://oddlytics-worker.<your-subdomain>.workers.dev.
  • API key: endpoints marked Key need the Worker's AUTH_KEY in an X-API-KEY header. Without it they answer 401 {"error": "Unauthorized"}.
  • CORS: every origin is allowed, for GET, POST, DELETE and OPTIONS, with the Content-Type and X-API-KEY headers.
  • Errors are JSON: {"error": "..."}. When ENVIRONMENT isn't production, server errors also include a message.

Endpoints ​

MethodPathKeyWhat it does
GET/Health check.
POST/trackKeyRecord one event or a batch.
GET/stats/overviewTotals, apps and top events.
GET/stats/eventsEvent counts by name.
GET/stats/timelineEvents and users per day.
GET/stats/groupsEvent counts per group for one app.
GET/stats/app/:appIdTotals for one app.
GET/stats/app/:appId/settingsOne app's display name and icon URL.
POST/stats/app/:appId/settingsKeySet one app's display name and icon URL.
GET/stats/usersUsers, newest activity first.
GET/stats/users/:userIdOne user's totals and apps.
GET/stats/users/:userId/activityOne user's latest events.
GET/aliasesEvent display names.
POST/aliasesKeySet an event's display name.
DELETE/aliasesKeyRemove an event's display name.
DELETE/events/:eventIdKeyDelete one event.
DELETE/users/:userIdKeyDelete every event for a user ID.
DELETE/apps/:appIdKeyDelete every event for an app.

The GET /stats/... responses are cached for 60 seconds, and GET /aliases and app settings for 5 minutes.

POST /track ​

Send one event as the body, or several as {"events": [...]}.

bash
curl -X POST https://oddlytics-worker.<your-subdomain>.workers.dev/track \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your-auth-key" \
  -d '{
    "event": "app_opened",
    "app_id": "MyApp",
    "session_id": "6F1C2A4E-0000-0000-0000-000000000000",
    "user_id": "user-123",
    "platform": "Android",
    "metadata": { "screen": "Home" },
    "timestamp": 1760000000
  }'
FieldRequiredNotes
eventYesNon-empty, up to 255 characters.
app_idYesNon-empty, up to 255 characters.
session_idYesNon-empty, up to 255 characters.
user_idNoStored as given, or empty.
platformNoA string. Defaults to iOS.
metadataNoA JSON object, up to 10 KB.
timestampNoSeconds since 1970. Defaults to the time the Worker receives it.

A batch may hold up to 100 events. If any event fails validation, the whole request is rejected with 400 and nothing is stored. On success:

json
{ "success": true, "count": 1 }

Reading Stats ​

GET /stats/overview ​

Query: days, a number of days such as 7 or 7d, or all (the default).

Returns total_events and total_users for the range, previous_total_events for the period of the same length before it, apps (each with app_id, total_events, total_sessions, first_seen, last_seen, icon_url and display_name, all time), and top_events (the ten most common event names, all time).

GET /stats/events ​

Query: app_id, start_date and end_date (all optional; dates as YYYY-MM-DD). Returns {"events": [{"event_name", "count"}]}, most common first.

GET /stats/timeline ​

Query: app_id (optional) and days, from 1 to 365 (default 7). Returns {"timeline": [{"date", "count", "user_count"}]}, one entry per day that has events.

GET /stats/groups ​

Query: app_id (required). Returns {"groups": [{"name", "events": [{"name", "count"}]}]}, grouped by the group key in each event's metadata.

GET /stats/app/:appId ​

Returns total_events, total_users and total_sessions for the app.

GET /stats/users ​

Query: limit (default 50), offset (default 0), search (part of a user ID) and app_id. Returns users (each with user_id, total_events, total_sessions, first_seen, last_seen and last_app) and pagination (total, limit, offset).

GET /stats/users/:userId ​

Returns user_id, stats (total_events, total_sessions, total_apps, first_seen, last_seen) and apps (app_id, event_count, last_used). Answers 404 if the user has no events.

GET /stats/users/:userId/activity ​

Query: app_id (optional) and limit (default 50). Returns {"events": [...]}, newest first, each with id, event_name, app_id, timestamp, platform, session_id and metadata.

Display Names and App Settings ​

bash
# Set a display name
curl -X POST https://<worker>/aliases \
  -H "Content-Type: application/json" -H "X-API-KEY: your-auth-key" \
  -d '{"app_id": "MyApp", "event_name": "screen_view", "alias": "Screen View"}'

# Remove it
curl -X DELETE https://<worker>/aliases \
  -H "Content-Type: application/json" -H "X-API-KEY: your-auth-key" \
  -d '{"app_id": "MyApp", "event_name": "screen_view"}'

# Set an app's display name and icon
curl -X POST https://<worker>/stats/app/MyApp/settings \
  -H "Content-Type: application/json" -H "X-API-KEY: your-auth-key" \
  -d '{"display_name": "My App", "icon_url": "https://example.com/icon.png"}'

GET /aliases takes an optional app_id and returns {"aliases": [{"app_id", "event_name", "alias"}]}.

When you post app settings, a field you leave out or send empty keeps its current value.

Deleting Data ​

bash
curl -X DELETE https://<worker>/events/42 -H "X-API-KEY: your-auth-key"
curl -X DELETE https://<worker>/users/<user-id> -H "X-API-KEY: your-auth-key"
curl -X DELETE https://<worker>/apps/MyApp -H "X-API-KEY: your-auth-key"

Each returns {"success": true, "deleted": <number of events>}. Deleting an event ID that doesn't exist answers 404.

Odd Omens is a one-person studio building privacy-first software.