Skip to content
nsin docs

Traffic by edge node, across your domains

GET
/analytics/nodes-overview
curl --request GET \
--url 'https://api.nsin.ir/analytics/nodes-overview?period=1h' \
--header 'Authorization: Bearer <token>'

Per-node totals, error and cache rates, latency, a requests-over-time series, and the busiest domains on each node — aggregated over every domain you can see, or one domain with domain_id.

This is the account-wide counterpart of /analytics/traffic-by-node, which covers a single domain and splits by cache status instead.

Two kinds of row need care when reading the list:

  • node: "" — requests the serving edge did not stamp with a node name. They are counted so the per-node rows still add up to totals, but they cannot be attributed to a point of presence.
  • requests: 0 with registered: true — a node that is in service but served nothing in the period. Kept in the list so a node that stopped reporting is visible rather than silently absent.

error_rate and cache_hit_rate are percentages (0–100). Durations are in milliseconds and exclude WebSocket requests, whose lifetime is the whole upgraded connection.

period
string
default: 24h
Allowed values: 1h 3h 6h 12h 24h 48h 7d 30d

Time window, ending now. Time series are bucketed by minute for 1h, by hour up to 48h, and by day for 7d and 30d. Buckets are cut on Asia/Tehran (UTC+03:30) boundaries and emitted as UTC instants, so an hourly bucket starts at :30 UTC. An unrecognised value falls back to 24h.

domain_id
integer

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.

Per-node totals with the scope-wide total they add up to.

Media type application/json
object
data
Array<object>
object
node

Node identifier. Empty when the serving edge reported no node name.

string
node_label

Human-readable name. Absent for a node that is not registered.

string
country

ISO country code.

string
registered

Whether the name matches a registered edge node.

boolean
active

Whether the registered node is in service.

boolean
requests
integer
bandwidth

Egress bytes.

integer
bytes_in

Bytes received from clients.

integer
unique_visitors
integer
error_rate

Percentage of requests that returned 4xx or 5xx, 0–100.

number
errors_5xx
integer
cache_hit_rate

Percentage of cache lookups served from cache, 0–100.

number
cached_requests
integer
avg_duration

Mean response time in milliseconds, WebSocket requests excluded.

number
p95_duration

95th percentile response time in milliseconds, WebSocket requests excluded.

number
latest_event

Most recent request this node served in scope. Null when it served none.

string format: date-time
series

Traffic over time, one bucket per period step.

Array<object>
object
timestamp
string format: date-time
count
integer
bytes

Egress bytes in the bucket.

integer
top_domains

The busiest domains on this node, at most five.

Array<object>
object
domain_id
integer
domain_name

Empty when the traffic matched no registered domain.

string
requests
integer
bandwidth

Egress bytes.

integer
totals

What the per-node rows add up to over the same scope.

object
requests
integer
bandwidth

Egress bytes.

integer
nodes_with_traffic
integer
unattributed_requests

Requests whose row carried no node name.

integer
Example generated
{
"data": [
{
"node": "example",
"node_label": "example",
"country": "example",
"registered": true,
"active": true,
"requests": 1,
"bandwidth": 1,
"bytes_in": 1,
"unique_visitors": 1,
"error_rate": 1,
"errors_5xx": 1,
"cache_hit_rate": 1,
"cached_requests": 1,
"avg_duration": 1,
"p95_duration": 1,
"latest_event": "2026-04-15T12:00:00Z",
"series": [
{
"timestamp": "2026-04-15T12:00:00Z",
"count": 1,
"bytes": 1
}
],
"top_domains": [
{
"domain_id": 1,
"domain_name": "example",
"requests": 1,
"bandwidth": 1
}
]
}
],
"totals": {
"requests": 1,
"bandwidth": 1,
"nodes_with_traffic": 1,
"unattributed_requests": 1
}
}

Missing, malformed, revoked or expired API key. (A valid key whose account has been deactivated gets 403 account is inactive instead.)

Media type application/json

The single error shape used by every endpoint.

object
error
required

Human-readable description of what went wrong.

string
Examples
Example invalidKey
{
"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.

Media type application/json

The single error shape used by every endpoint.

object
error
required

Human-readable description of what went wrong.

string
Example
{
"error": "read-only API key"
}

The key exceeded its request budget (300 requests per minute by default).

Media type application/json

The single error shape used by every endpoint.

object
error
required

Human-readable description of what went wrong.

string
Examples
Example limited
{
"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.

Media type application/json
object
error
required

Human-readable description of what went wrong.

string
pending

true when the query is still running rather than failing. Retry after Retry-After seconds.

boolean
Examples
{
"error": "analytics unavailable"
}
Retry-After
integer
Example
5

Seconds to wait before retrying. Sent only with pending.