Public API · v1

Build on your analytics

Four plan-tiered endpoints: pull reports into your BI, track events server-side (ad-blocker proof), power realtime widgets, and manage sites programmatically.

Create an API key See plans

Plans & rate limits

Every plan includes the API. Scopes unlock as you upgrade — rate limits are per key.

Feature / PermissionDescription FREEPROBUSINESS
Realtime Access to /realtime endpoint (Current visitors & live activity widget) ✅ Included ✅ Included ✅ Included
Reports Access to /reports endpoint (Traffic & Revenue analytics) Basic
Top-level metrics only
Full
All dimensions & filters
Full
All dimensions & filters
Ingest Access to /ingest endpoint (Server-side tracking, bypass ad blockers) ❌ — ✅ Included ✅ Included
Manage Access to /sites endpoint — manage scope (Programmatically create/delete sites) ❌ — ❌ — ✅ Included
Rate Limit Requests per minute (RPM) per API key. See note below. 60 RPM
~1 req/sec
300 RPM
~5 req/sec
600 RPM
~10 req/sec

Authentication

Create keys in the dashboard under Public API. The plaintext key is shown exactly once — store it safely. Keys can be scoped, bound to one site, and revoked anytime.

Authorization
# Either header works
Authorization: Bearer tsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-API-Key: tsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key format: tsk_ + 40 hex chars (160-bit random). Only a SHA-256 hash is stored server-side, so a leaked key can be revoked instantly and never recovered.

Endpoints

Base URL: https://topstat.top/api/v1. All responses are JSON; every reply carries X-RateLimit-Limit and X-RateLimit-Remaining headers.

GET/realtime?site=example.com&feed=1Free

Visitors active in the last 5 minutes (bots excluded). Add feed=1 for the latest 20 activity events of the last 30 minutes — perfect for a "who's visiting me" widget. CORS: open to all origins.

Response
{
  "ok": true,
  "site": "example.com",
  "online": 7,
  "ts": "2026-09-04 12:00:00",
  "feed": [
    { "path": "/pricing", "type": "pageview", "country": "US", "ts": "2026-09-04 11:58:41" }
  ]
}
GET/reports?site=example.com&period=7d&metrics=basicFree / Pro

Traffic and revenue reports. period: today | 24h | 7d | 30d. metrics=basic returns totals + timeseries on every plan; metrics=full (Pro+) adds engagement, top pages, referrers, channels, campaigns, devices, browsers, OS, countries and revenue attribution — BI-ready in one call.

Response (basic)
{
  "ok": true,
  "site": "example.com",
  "period": "7d",
  "totals": { "visitors": 1240, "pageviews": 3891, "online": 7 },
  "series": [ { "bucket": "2026-08-29", "visitors": 152, "pageviews": 470 } ]
}
POST/ingestPro+

Send events from your server: pageviews, custom events and revenue. Immune to ad blockers and privacy extensions, so conversion and revenue data stays 100% accurate.

Request body
{
  "site": "example.com",
  "path": "/checkout/complete",
  "event_type": "purchase",
  "referrer": "google.com",
  "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "summer",
  "visitor_id": "user-8f14e45f",
  "ip": "203.0.113.7", "user_agent": "Mozilla/5.0 ...", "width": 1440, "country": "US",
  "revenue": 49.9, "currency": "USD"
}

202 Accepted → { ok, visitor_id, session_id }. Only site and path are required; identity semantics below matter for server-side calls.

Identity semantics (read this)
Pass your own stable visitor_id (max 48 chars) per end user. If you omit it, identity is derived from ip + user_agent + site + day — and since all your server-side calls share one egress IP, every end user would merge into a single visitor per day. visitor_id given → session = visitor_id + day; otherwise the hash is used, matching browser-tracked visitors' semantics.
GET/sitesPOST/sitesDELETE/sites?id=NBusiness

List, create and delete tracked sites programmatically — built for agencies managing many properties. POST takes { domain, name? } (409 if the domain exists). DELETE removes the site and its API-key bindings; tracked events are kept.

POST /sites — Response 201
{
  "ok": true,
  "site": { "id": 42, "domain": "blog.example.com", "name": "Blog", "events": 0 }
}

Error codes

StatusWhenerror
400Missing site parameter or invalid bodymissing_site / invalid_json / invalid_path / invalid_domain
401Key missing, invalid or revokedmissing_key / invalid_key
403Scope not on the key, or your plan does not include itscope_not_allowed / plan_required / site_not_on_key
404Site not found or not owned by the key's accountnot_found
429Rate limit exceeded (retry after up to 60s)rate_limited

Rate limits are enforced in-memory per server instance and reset every minute — treat them as best-effort thresholds rather than exact quotas, and back off on 429 using the Retry-After header.

Quickstart

Replace YOUR_KEY with your API key. Full reports require metrics=full on Pro and above.

Terminal
# Realtime
curl "https://topstat.top/api/v1/realtime?site=example.com&feed=1" \
  -H "Authorization: Bearer YOUR_KEY"

# Report (basic on Free, metrics=full on Pro+)
curl "https://topstat.top/api/v1/reports?site=example.com&period=7d&metrics=full" \
  -H "Authorization: Bearer YOUR_KEY"

# Server-side ingest (Pro+)
curl -X POST "https://topstat.top/api/v1/ingest" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site":"example.com","path":"/signup","event_type":"signup","visitor_id":"user-8f14e45f"}'
report.js
const KEY = process.env.TOPSTAT_KEY;
const site = "example.com";

async function report(period = "7d") {
  const r = await fetch(
    `https://topstat.top/api/v1/reports?site=${site}&period=${period}&metrics=full`,
    { headers: { Authorization: `Bearer ${KEY}` } }
  );
  if (!r.ok) throw new Error(`API ${r.status}: ${(await r.json()).error}`);
  return r.json();
}

report().then(d => console.log(d.totals, d.revenue.totals));
widget.py
import os, requests

KEY = os.environ["TOPSTAT_KEY"]
r = requests.get(
    "https://topstat.top/api/v1/realtime",
    params={"site": "example.com", "feed": "1"},
    headers={"Authorization": f"Bearer {KEY}"},
    timeout=10,
)
r.raise_for_status()
print(r.json()["online"], "visitors online")

Create your first API key

Dashboard → Public API → Create key. Paste, ship, and build on your data.

Open dashboard