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
- Create an account and your first project. Every project gets a default API key.
- Copy the key from Settings → API keys in the app. Keys look like
td_… - Send an event:
$ 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:
| Field | Type | Notes |
|---|---|---|
| name | string | What happened — checkout_completed, page_view, … |
| distinct_id | string | Who did it. Any stable identifier: a user id, a device id, an anonymous session id. |
| timestamp | ISO 8601 | Optional. When it happened; defaults to arrival time. |
| properties | object | Optional. 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:
{
"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:
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 })
});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.
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
| Status | Meaning |
|---|---|
| 202 | Accepted. Body is {"accepted": n} with the number of events stored. |
| 400 | Invalid payload — a missing field, malformed timestamp, or a batch over 500 events. The body names the field. |
| 401 | Missing, 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.