Developer docs

JSON API

Create distributed checks, poll results, and list active nodes. Responses use application/json. Send Accept: application/json on every request.

01 Authentication & CSRF

Creating a check from a browser (or any client that uses the site session cookie) requires a CSRF token.

  1. Open the homepage once to receive the session cookie
  2. Read the hidden _csrf field from the check form, or reuse a token from that page
  3. Send it as form field _csrf or header X-CSRF-Token

GET /api/result.php and GET /api/nodes.php do not require CSRF.

02 Create a check

Endpoint: POST https://netstats.ir/api/check.php

Content-Type: application/x-www-form-urlencoded

Parameters

NameRequiredDescription
hostyesHostname, IPv4/IPv6, URL, host:port, or [ipv6]:port
typeyesping, http, tcp, dns, or udp
max_nodesnoMax nodes to use (capped by site settings)
nodenoRepeatable node id to force specific nodes
_csrfyes*CSRF token (*or X-CSRF-Token header)

Example

curl -c cookies.txt -b cookies.txt \
  -H "Accept: application/json" \
  -H "X-CSRF-Token: YOUR_CSRF_TOKEN" \
  -d "host=example.com&type=ping&max_nodes=5" \
  https://netstats.ir/api/check.php
curl -c cookies.txt -b cookies.txt \
  -H "Accept: application/json" \
  -H "X-CSRF-Token: YOUR_CSRF_TOKEN" \
  --data-urlencode "host=[2001:db8::1]:443" \
  -d "type=tcp&max_nodes=3" \
  https://netstats.ir/api/check.php

Success response

{
  "ok": 1,
  "request_id": "a1b2c3d4e5f6g7h8",
  "permanent_link": "https://netstats.ir/report.php?id=a1b2c3d4e5f6g7h8",
  "nodes": {
    "us-nyc-1a2b": ["us", "United States", "New York", "1.2.3.4", "AS13335"]
  }
}

Each node value is [country_code, country, city, ip, asn].

03 Get check results

Endpoint: GET https://netstats.ir/api/result.php?id=REQUEST_ID

Poll until every node value is non-null (or until your client timeout). Pending nodes return null.

curl -H "Accept: application/json" \
  "https://netstats.ir/api/result.php?id=REQUEST_ID"
{
  "ok": 1,
  "command": "ping",
  "created": 1710000000,
  "host": "example.com",
  "nodes": { "...": ["us", "United States", "New York", "1.2.3.4", "AS13335"] },
  "results": {
    "us-nyc-1a2b": [[["OK", 0.042, "93.184.216.34"], ["OK", 0.041, "93.184.216.34"]]],
    "de-fra-9x8y": null
  }
}

Node agents may also POST signed results to the same endpoint; that path is for nodes only, not public clients.

04 List nodes

Endpoint: GET https://netstats.ir/api/nodes.php

curl -H "Accept: application/json" \
  https://netstats.ir/api/nodes.php
{
  "nodes": {
    "us-nyc-1a2b": {
      "asn": "AS13335",
      "ip": "1.2.3.4",
      "location": ["us", "United States", "New York"]
    }
  }
}

Only active nodes are returned. Tokens and secrets are never exposed.

05 Check types & host formats

TypeHost examplesNotes
pingexample.com, 1.1.1.1, 2001:db8::1IPv4 and IPv6
httphttps://example.com, http://[2001:db8::1]/Status and timing
tcpexample.com:443, [2001:db8::1]:443Port required
udpexample.com:53, [2001:db8::1]:53Port required
dnsexample.comA and AAAA (+ TTL when available)

Private, loopback, link-local, ULA, CGNAT, and cloud-metadata targets are rejected for both IPv4 and IPv6. Hostnames prefer AAAA when available.

06 Errors & limits

Error bodies look like:

{ "ok": 0, "error": "Rate limit exceeded" }
HTTPMeaning
400Invalid host, type, or input
403CSRF failure or forbidden callback
404Unknown request id
405Wrong method (use POST to create)
429Rate limit exceeded
500Server / dispatch error (e.g. no active nodes)

IP Info / WHOIS is available on the website at /ip.php (form UI). Distributed checks use the endpoints above.