{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://snipzr.com/schemas/v1/link-stats.schema.json",
"title": "snipzr /v1 link stats response",
"description": "Response body of GET /v1/urls/{slug}/stats (and the identical /x/ web-app route). Versioned contract: additive fields may be introduced in a backward-compatible way; removals/renames are a new major schema. All counts are non-negative integers; all dates are UTC. human = totals.requests - totals.bots.",
"type": "object",
"additionalProperties": false,
"required": ["stats"],
"properties": {
"stats": {
"type": "object",
"additionalProperties": false,
"required": [
"slug", "zoneDomain", "range", "allTime", "totals", "series",
"hourly", "geo", "referrers", "devices", "browsers", "os", "languages", "source", "freshness"
],
"properties": {
"slug": { "type": "string", "description": "The link slug." },
"zoneDomain": { "type": "string", "description": "The link's domain (zone)." },
"range": {
"type": "object",
"additionalProperties": false,
"required": ["from", "to", "clampedTo", "retentionDays", "storedDays"],
"properties": {
"from": { "type": "string", "format": "date", "description": "Requested window start (UTC date, YYYY-MM-DD) as echoed back." },
"to": { "type": "string", "format": "date", "description": "Effective window end (UTC date); never in the future." },
"clampedTo": { "type": "string", "format": "date", "description": "Effective window start after the plan's retention floor. Equals `from` when nothing was clamped; later than `from` when the request exceeded the plan's readable window (the request is clamped, never rejected)." },
"retentionDays": { "type": "integer", "minimum": 0, "description": "How many days of analytics the caller's plan can read (Free 30 / Basic 365 / Pro 730)." },
"storedDays": { "type": "integer", "minimum": 0, "description": "Total days of data stored for the link (may exceed retentionDays — older data is retained but not readable on the current plan)." }
}
},
"allTime": {
"type": "object",
"additionalProperties": false,
"required": ["total", "preTracking", "trackingSince"],
"properties": {
"total": { "type": "integer", "minimum": 0, "description": "Lifetime hit counter incl. bots and pre-tracking clicks." },
"preTracking": { "type": "integer", "minimum": 0, "description": "Hits accrued before per-day tracking began (a one-time snapshot). tracked-era hits ≈ total - preTracking." },
"trackingSince": { "type": "string", "format": "date", "description": "First UTC day for which per-day data exists." }
}
},
"totals": {
"type": "object",
"additionalProperties": false,
"required": ["human", "bots", "requests", "qr", "click"],
"properties": {
"human": { "type": "integer", "minimum": 0, "description": "Human clicks over the window (requests - bots). The headline number." },
"bots": { "type": "integer", "minimum": 0, "description": "Bot / HEAD / prefetch / link-preview requests over the window." },
"requests": { "type": "integer", "minimum": 0, "description": "All requests over the window (human + bots). Not adversarial-grade; do not bill on it." },
"qr": { "type": "integer", "minimum": 0, "description": "Human clicks that came from a QR scan." },
"click": { "type": "integer", "minimum": 0, "description": "Human clicks that came from a direct short-link click." }
}
},
"series": {
"type": "array",
"description": "Per-UTC-day points across the (clamped) window, ascending by date. Days with no data are omitted.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["date", "n", "b"],
"properties": {
"date": { "type": "string", "format": "date", "description": "UTC day." },
"n": { "type": "integer", "minimum": 0, "description": "All requests that day (human + bots)." },
"b": { "type": "integer", "minimum": 0, "description": "Bot requests that day (human = n - b)." }
}
}
},
"hourly": {
"type": "object",
"additionalProperties": false,
"description": "Rolling last-24-hours histogram of human clicks by UTC hour, independent of the requested window. Populated when the window includes the recent days; empty for a purely-historical window.",
"required": ["fromUtc", "buckets"],
"properties": {
"fromUtc": { "type": "string", "format": "date-time", "description": "UTC top-of-hour at which buckets[0] starts (the hour 23 hours ago). buckets[23] is the current partial hour." },
"buckets": { "type": "array", "minItems": 24, "maxItems": 24, "items": { "type": "integer", "minimum": 0 } }
}
},
"geo": { "$ref": "#/$defs/kvList", "description": "Human clicks by country. Key is an ISO-3166 alpha-2 code, or \"unknown\" when the country could not be determined." },
"referrers": { "$ref": "#/$defs/kvList", "description": "Human clicks by referring host (host only, never a full URL). Sentinels: \"~direct\" (no referrer sent), \"~other\" (folded tail / over the per-day host budget). Real hosts are unescaped." },
"devices": { "$ref": "#/$defs/kvList", "description": "Human clicks by device family (e.g. desktop, mobile, tablet)." },
"browsers": { "$ref": "#/$defs/kvList", "description": "Human clicks by browser family." },
"os": { "$ref": "#/$defs/kvList", "description": "Human clicks by operating-system family." },
"languages": { "$ref": "#/$defs/kvList", "description": "Human clicks by Accept-Language primary subtag (allowlisted), or \"~other\"." },
"source": {
"type": "object",
"additionalProperties": false,
"required": ["click", "qr"],
"properties": {
"click": { "type": "integer", "minimum": 0 },
"qr": { "type": "integer", "minimum": 0 }
}
},
"freshness": {
"type": "string",
"enum": ["todayLive", "final", "degraded"],
"description": "todayLive = window includes today and is merged with live data; final = window entirely in the past (fully consolidated); degraded = analytics store was unreachable and only recent live data is shown."
}
}
}
},
"$defs": {
"kvList": {
"type": "array",
"description": "Dimension breakdown, sorted by value descending. k = bucket key, v = count.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["k", "v"],
"properties": {
"k": { "type": "string" },
"v": { "type": "integer", "minimum": 0 }
}
}
}
}
}