Documentation

The whole integration is one HTTP endpoint. This page covers all of it: keys, the event payload, batching, and snippets you can paste into any codebase.

Examples use $TIDINGS_API for your API origin — locally that's http://localhost:8000.

Quickstart

  1. Create an account and your first project. Every project gets a default API key.
  2. Copy the key from Settings → API keys in the app. Keys look like td_…
  3. Send an event:
terminalbash
$ curl -X POST $TIDINGS_API/api/v1/events/ \
    -H 'X-API-Key: td_your_key_here' \
    -H 'Content-Type: application/json' \
    -d '{"name": "first_event", "distinct_id": "user_1"}'

{"accepted": 1}

Open the events explorer — your event is already there.

Authentication

Ingestion authenticates with a per-project API key sent in the X-API-Key header. Keys are scoped to one project: events land in the project the key belongs to, and nowhere else.

  • Create as many keys as you like — one per environment (production, staging) keeps data clean.
  • Revoking a key stops its events immediately without touching data it already sent.
  • Requests with a missing, unknown, or revoked key get 401.

Send events

POST /api/v1/events/ accepts a single event object or a batch. An event has two required fields and two optional ones:

FieldTypeNotes
namestringWhat happened — checkout_completed, page_view, …
distinct_idstringWho did it. Any stable identifier: a user id, a device id, an anonymous session id.
timestampISO 8601Optional. When it happened; defaults to arrival time.
propertiesobjectOptional. Arbitrary JSON context — plan, path, country, anything you'll want to filter by later.

Batching

Wrap up to 500 events in an events array to cut round-trips — useful for backfills, mobile clients, and background workers:

request bodyjson
{
  "events": [
    {"name": "page_view", "distinct_id": "user_42"},
    {"name": "plan_upgraded", "distinct_id": "user_42", "properties": {"plan": "pro"}}
  ]
}

Snippets

Anything that speaks HTTP is already integrated. Two common shapes:

browser or Nodejs
fetch(`${TIDINGS_API}/api/v1/events/`, {
  method: "POST",
  headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ name: "signup_completed", distinct_id: user.id })
});
Pythonpy
import requests

requests.post(
    f"{TIDINGS_API}/api/v1/events/",
    headers={"X-API-Key": KEY},
    json={"name": "report_generated", "distinct_id": user_id},
)

Set up with AI

Working with Claude Code, Cursor, or another coding assistant? Paste this prompt and it will write an idiomatic tracking helper for your codebase and instrument your key events — the full API contract is included.

prompt — paste into your AI assistant
Integrate Tidings product analytics into this codebase.

Tidings is an event-analytics service. The whole integration is plain HTTP — there is no SDK to install.

API contract:
- POST $TIDINGS_API/api/v1/events/ with headers "Content-Type: application/json" and "X-API-Key: $TIDINGS_KEY".
- Single event body: {"name": "<snake_case_event>", "distinct_id": "<stable user or visit id>", "properties": {<arbitrary JSON>}, "timestamp": "<optional ISO 8601, defaults to arrival time>"}.
- Batch body: {"events": [<up to 500 event objects>]}.
- Success is HTTP 202 with {"accepted": n}. 400 = invalid payload, 401 = missing/revoked key, 429 = rate limited.

Requirements:
1. Create a small tracking helper in this project's language and house style, exposing track(name, properties).
2. Read the endpoint and key from configuration or environment (TIDINGS_API, TIDINGS_KEY). If the key is unset, every call must silently no-op.
3. Analytics must never break the product: swallow all errors, never throw, and never block the caller — fire-and-forget (use keepalive / background delivery where the platform offers it).
4. Choose a stable distinct_id: the signed-in user's id where available, otherwise a session-scoped identifier. Do not write persistent identifiers to end users' devices without consent — a session-scoped id keeps the integration cookieless.
5. Instrument this app's 3-5 most meaningful events (signup, core action completed, purchase, ...) plus page or screen views where relevant. Name events in snake_case.
6. Keep property payloads small and free of secrets or personal data beyond what is needed.

When done, list the events you instrumented and where the calls live.

Set TIDINGS_API and TIDINGS_KEY in your environment afterwards — keys live under Settings → API keys in the app. These docs are also available as plain text at /llms.txt for AI tools that fetch documentation directly.

Responses & errors

StatusMeaning
202Accepted. Body is {"accepted": n} with the number of events stored.
400Invalid payload — a missing field, malformed timestamp, or a batch over 500 events. The body names the field.
401Missing, unknown, or revoked API key.

Send with a timestamp in the past and events file into history exactly where they belong — backfills need no special treatment.