Link stats API
GET /v1/urls/{slug}/stats returns pre-aggregated analytics for one of your links. Owner-scoped, cookie-less, aggregate-only (no per-click rows, no visitor identifiers — see How we count). The /x/urls/{slug}/stats web-app route returns the identical body.
Request
GET /v1/urls/{slug}/stats?from=YYYY-MM-DD&to=YYYY-MM-DD
Authorization: Bearer YOUR_TOKEN_HERE
Generate a token in your account settings.
| Param | Where | Required | Default | Notes |
|---|---|---|---|---|
slug | path | yes | — | A link you own (else 404). |
from | query | no | to − 29 days | Window start, UTC date YYYY-MM-DD. |
to | query | no | today (UTC) | Window end, UTC date; never the future. |
Window semantics (clamp, don't reject). from is clamped to your plan's analytics retention. A window longer than your retention is not an error — it is clamped and the effective start is echoed in range.clampedTo (with retentionDays and storedDays). A malformed window (from after to, or an unparseable date) is a 400.
Rate limit. Per subscriber, 60 requests/minute; over the limit returns 429 with a Retry-After header.
Response 200
{
"stats": {
"slug": "spring-sale",
"zoneDomain": "snipzr.li",
"range": { "from": "2026-06-14", "to": "2026-07-13", "clampedTo": "2026-06-14", "retentionDays": 30, "storedDays": 122 },
"allTime": { "total": 5120, "preTracking": 4900, "trackingSince": "2026-07-13" },
"totals": { "human": 82, "bots": 61, "requests": 143, "qr": 12, "click": 70 },
"series": [ { "date": "2026-07-12", "n": 90, "b": 40 }, { "date": "2026-07-13", "n": 53, "b": 21 } ],
"hourly": { "fromUtc": "2026-07-12T16:00:00Z", "buckets": [0,0,1,2,3,4,6,8,7,9,5,6,4,3,2,2,1,3,4,2,1,0,0,0] },
"geo": [ { "k": "US", "v": 40 }, { "k": "DE", "v": 22 }, { "k": "unknown", "v": 3 } ],
"referrers": [ { "k": "~direct", "v": 31 }, { "k": "reddit.com", "v": 18 }, { "k": "~other", "v": 4 } ],
"devices": [ { "k": "desktop", "v": 51 }, { "k": "mobile", "v": 28 } ],
"browsers": [ { "k": "chrome", "v": 40 } ],
"os": [ { "k": "windows", "v": 25 } ],
"languages": [ { "k": "en", "v": 60 } ],
"source": { "click": 70, "qr": 12 },
"freshness": "todayLive"
}
}
Fields
| Field | Meaning |
|---|---|
range | Effective window + retention/clamp metadata (clampedTo = effective start; storedDays may exceed retentionDays). |
allTime | Lifetime hits decomposed into pre-tracking vs tracked era. |
totals | Window sums. human = requests − bots is the headline; requests (raw, incl. bots/monitors) — don't bill or alert on it. |
series | Per-UTC-day {date, n, b} (human = n − b), ascending, zero-days omitted. |
hourly | Rolling last 24 hours of human clicks by UTC hour, independent of the window (empty for a purely-historical window). |
geo,referrers,devices,browsers,os,languages | [{k, v}], sorted by v desc. Referrers are host-only; sentinels ~direct (no referrer) and ~other (folded tail). Country key unknown when undeterminable. |
source | {click, qr} split of human clicks. |
freshness | todayLive | final | degraded. |
Counts are monotonic non-decreasing per UTC day except a brief dip during an hourly consolidation window — they settle within the hour. Don't treat a transient same-day decrease as data loss.
Errors
| Status | When |
|---|---|
400 | malformed window (from > to, bad date) or invalid slug |
404 | slug not found for this owner |
429 | over the per-token rate limit (Retry-After header) |
503 | analytics store unreachable and no live data covers the window |
A degraded 200 (store down but recent live data available) is distinct from a 503 (nothing serveable) — surface freshness: "degraded" as "recent data only".
Example
curl -H "Authorization: Bearer $SNIPZR_TOKEN" \
"https://api.snipzr.com/v1/urls/spring-sale/stats?from=2026-06-14&to=2026-07-13"
JSON Schema
The response is described by a published JSON Schema (2020-12): https://snipzr.com/schemas/v1/link-stats.schema.json. Point your validator or code generator at that URL.
Versioning
Additive, backward-compatible fields may appear without a version bump — tolerate unknown fields. Removals/renames are a new major version. The web app can export this same data as CSV (long format date,metric,key,value); the API is JSON-only.