Requests over time, for period-over-period comparison
const url = 'https://api.nsin.ir/analytics/requests-compare?granularity=hour';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.nsin.ir/analytics/requests-compare?granularity=hour' \ --header 'Authorization: Bearer <token>'Request counts in whole-day windows, for charts that overlay one period
on another. Unlike /analytics/requests — which ends now and takes a
period — this window always starts at a local midnight, so every
bucket covers a complete day and days can be compared like for like.
granularity: hourreturns hourly buckets, meant to be drawn as one line per day (hour-by-hour overlay).daysdefaults to 3, max 14.granularity: dayreturns one bucket per day for day-over-day change.daysdefaults to 14, max 35 — the ClickHouse row retention, beyond which no data exists.
Scope is one domain (domain_id), or — by default — every active domain
you can see. The response has the time-series shape of
/analytics/requests, except that each timestamp is the bucket’s
start as Asia/Tehran wall-clock time, YYYY-MM-DD HH:MM:SS with no
zone (not RFC 3339): 2026-09-28 00:00:00 is 2026-09-27T20:30:00Z.
Buckets with no traffic are omitted rather than zero-filled.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters ”Bucket size. Anything other than day is treated as hour.
Number of whole days to return, counting back from today. Clamped to
the granularity’s maximum. 0 or omitted uses the default.
Numeric domain id — note this endpoint scopes by id, not by the domain name the rest of the API uses. Omit to cover every active domain you can see.
Responses
Section titled “ Responses ”Time series.
object
One bucket of /analytics/requests-compare.
object
Bucket start as Asia/Tehran wall-clock time (UTC+03:30), with no zone designator — not RFC 3339.
Example
{ "data": [ { "timestamp": "2026-09-28 00:00:00" } ]}Missing, malformed, revoked or expired API key. (A valid key whose
account has been deactivated gets 403 account is inactive instead.)
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Examples
{ "error": "invalid API key"}No such domain, or it is not visible to this account. Domains you cannot access are reported as not found rather than forbidden.
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Example
{ "error": "read-only API key"}The key exceeded its request budget (300 requests per minute by default).
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Examples
{ "error": "rate limit exceeded"}Either the analytics backend is temporarily unreachable (retry; no data
is lost), or the answer is still being computed. The per-domain
sections and the cached account-wide views (domains-overview,
global-summary, global-summary/peak, requests-compare,
bandwidth-overview, nodes-overview) wait at most about 25 seconds
for their query; past that they answer 503 with pending: true and
a Retry-After header, while the query keeps running and caches its
result, so the retry is served from that cache instead of starting the
same scan again. Identical concurrent requests share one computation.
object
Human-readable description of what went wrong.
true when the query is still running rather than
failing. Retry after Retry-After seconds.
Examples
{ "error": "analytics unavailable"}{ "error": "still computing — try again in a few seconds", "pending": true}Headers
Section titled “Headers ”Example
5Seconds to wait before retrying. Sent only with pending.