Run a custom query over your request logs
const url = 'https://api.nsin.ir/analytics/query';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"sql":"SELECT toStartOfHour(event_time) AS h, count() AS c FROM requests WHERE status >= 500 GROUP BY h ORDER BY h"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.nsin.ir/analytics/query \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "sql": "SELECT toStartOfHour(event_time) AS h, count() AS c FROM requests WHERE status >= 500 GROUP BY h ORDER BY h" }'Runs a read-only SQL SELECT against the requests table — your raw
request log — for analyses the dedicated endpoints do not cover.
Scoping is enforced by the database engine, not by your query: a
filter restricting rows to the domains this key can access is appended
to every read of requests. You cannot read another account’s traffic,
however the query is written.
Restrictions:
- A single statement only, starting with
SELECTorWITH. - Only the
requeststable may be read. Common table expressions you define yourself are fine; other tables and anydb.tablereference are rejected. - Writes, DDL and settings changes are rejected.
- Execution is capped at 30 seconds and 10 000 returned rows —
truncatedtells you when the cap was hit.
Useful requests columns: event_time, domain_id, hostname,
method, uri, status, bytesIn, bytesOut, duration (ms),
remoteAddr, country, asn, asnOrg, userAgent, cacheStatus,
reqStatus, isWS, protocol, referer, originStatus,
originAddr, error.
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”object
The query to run.
Responses
Section titled “ Responses ”Query result.
object
Column names, in result order.
One entry per row, keyed by column name.
object
True when the 10 000-row cap was reached and results were cut short.
Example generated
{ "columns": [ "example" ], "rows": [ {} ], "row_count": 1, "truncated": true}The query was rejected by validation, or the database refused it.
detail carries the underlying message when the engine rejected it.
object
Examples
{ "error": "querying \"system.parts\" is not allowed; only the 'requests' table may be read"}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 account has no domains whose logs could be queried. (Read-only
keys may call this endpoint: it is the one POST they are
allowed, because it writes nothing.)
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Examples
{ "error": "you have no domains to query"}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.