Clients whose traffic resembles a proxy tunnel
const url = 'https://api.nsin.ir/analytics/tunnel-suspects?period=1h';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/tunnel-suspects?period=1h' \ --header 'Authorization: Bearer <token>'Clients whose WebSocket/gRPC traffic looks like a VPN or proxy tunnel run behind the CDN: sustained volume over a single fixed path, with opaque payloads and no sign of ordinary browsing (no real assets fetched, no referer).
This is a heuristic for investigation, not proof of abuse. balance is
informational — tunnels used for browsing are download-heavy, so
symmetry is not a criterion.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters ”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.
Responses
Section titled “ Responses ”Suspected tunnel clients.
object
object
The client’s network operator (AS organisation).
Detected transport. httpupgrade is Upgrade: websocket without a real WebSocket handshake.
All requests from this client to this host.
Requests with opaque payloads.
Distinct paths used — around 1 for a tunnel.
Client-to-edge bytes.
Edge-to-client bytes.
min/max of up and down. Informational only.
Longest single connection, in seconds.
The heaviest single path.
TLS fingerprint.
HTTP fingerprint.
The client’s User-Agent.
Additive tunnel score from the matched signals; higher is more tunnel-like.
The score’s band. Empty below the lowest band.
The signals that contributed to score.
object
Signal name.
The measured value.
Points it added to the score.
Human-readable explanation, when there is one.
Distinct URIs per request. High is a tunnel signal — some tunnel software puts a random token in every URI.
The client’s cache hit ratio, 0–1. A tunnel is uncacheable, so this is about 0.
Average bytes per request.
How many distinct client IPs in this result share this client’s TLS fingerprint on the same host.
Share of this client’s bytes carried over the httpupgrade transport, 0–1.
When the ranking was computed. It is served from a precomputed
store, so a 7d/30d answer can be up to an hour old.
Present (true) while a newer ranking is being computed behind this one.
Example
{ "suspects": [ { "transport": "httpupgrade", "severity": "high" } ]}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"}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.