Four plan-tiered endpoints: pull reports into your BI, track events server-side (ad-blocker proof), power realtime widgets, and manage sites programmatically.
Every plan includes the API. Scopes unlock as you upgrade — rate limits are per key.
| Feature / Permission | Description | FREE | PRO | BUSINESS |
|---|---|---|---|---|
| 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 |
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.
# 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.
Base URL: https://topstat.top/api/v1. All responses are JSON; every reply carries X-RateLimit-Limit and X-RateLimit-Remaining headers.
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.
{
"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" }
]
}
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.
{
"ok": true,
"site": "example.com",
"period": "7d",
"totals": { "visitors": 1240, "pageviews": 3891, "online": 7 },
"series": [ { "bucket": "2026-08-29", "visitors": 152, "pageviews": 470 } ]
}
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.
{
"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.
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.
{
"ok": true,
"site": { "id": 42, "domain": "blog.example.com", "name": "Blog", "events": 0 }
}
| Status | When | error |
|---|---|---|
400 | Missing site parameter or invalid body | missing_site / invalid_json / invalid_path / invalid_domain |
401 | Key missing, invalid or revoked | missing_key / invalid_key |
403 | Scope not on the key, or your plan does not include it | scope_not_allowed / plan_required / site_not_on_key |
404 | Site not found or not owned by the key's account | not_found |
429 | Rate 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.
Replace YOUR_KEY with your API key. Full reports require metrics=full on Pro and above.
# 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"}'
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));
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")
Dashboard → Public API → Create key. Paste, ship, and build on your data.
Open dashboard