Multi-resolver DNS debugger with six modes: query, check, trace, compare, auth compare, and DNSSEC validation. Results stream via Server-Sent Events or can be returned as a single JSON response.
See also: interactive API reference (auto-generated OpenAPI)
Query Language
All endpoints accept a query field using a dig-inspired syntax:
domain [TYPE...] [@server...] [+flag...]
| Component | Description | Examples |
|---|---|---|
| Domain | Target domain (required) | example.com |
| Types | Record types to query (default: A) | A AAAA MX NS TXT CNAME SOA SRV CAA TLSA HTTPS |
| Servers | DNS servers to use | @1.1.1.1, @cloudflare, @google, @quad9, @public, @all |
| Flags | Mode and behavior flags | +check, +trace, +compare, +auth, +dnssec, +norecurse, +short |
# Query A and MX records via Cloudflare and Google
example.com A MX @cloudflare @google
# Run a health check
example.com +check
# Trace delegation chain for AAAA
example.com AAAA +trace
Streaming vs JSON
By default, all query endpoints return Server-Sent Events (SSE). Add
?stream=false to get a single JSON response instead.
SSE mode (default)
Events stream as they arrive. Use --no-buffer with curl:
curl -s -N -X POST https://dns.netray.info/api/query \
-H 'Content-Type: application/json' \
-d '{"query": "example.com A @cloudflare"}' \
--no-buffer
SSE event types:
| Event | Description |
|---|---|
batch | A batch of results (one or more records) |
done | Stream complete |
error | An error occurred |
Raw SSE output looks like:
event: batch
data: {"records": [{"name": "example.com", "type": "A", "ttl": 300, "data": "93.184.215.14", ...}]}
event: done
data: {"key": "abc123"}
JSON mode (?stream=false)
Waits for all results and returns a single JSON object:
curl -s -X POST 'https://dns.netray.info/api/query?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com A MX"}' | jq .
{
"events": [
{"type": "batch", "data": {"records": [...]}},
...
],
"truncated": false
}
Endpoints
POST /api/query -- DNS Query
Standard DNS lookup. Fan-out across record types and servers.
# A records from default resolver
curl -s -X POST 'https://dns.netray.info/api/query?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com A"}' | jq .
# MX and TXT from all public resolvers
curl -s -X POST 'https://dns.netray.info/api/query?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com MX TXT @public"}' | jq .
POST /api/check -- Domain Health Check
Comprehensive domain health analysis: SPF, DKIM, DMARC, MTA-STS, TLSRPT, BIMI, DANE, nameserver consistency, and more.
curl -s -X POST 'https://dns.netray.info/api/check?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com"}' | jq .
POST /api/trace -- Delegation Trace
Walk the delegation chain from root to authoritative nameservers.
curl -s -X POST 'https://dns.netray.info/api/trace?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com"}' | jq .
POST /api/dnssec -- DNSSEC Validation
Validate the full DNSSEC chain of trust from root to domain.
curl -s -X POST 'https://dns.netray.info/api/dnssec?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com"}' | jq .
POST /api/compare -- Transport Comparison
Compare results across different DNS transports (UDP, TCP, DoT, DoH).
curl -s -X POST 'https://dns.netray.info/api/compare?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com A"}' | jq .
POST /api/authcompare -- Authoritative vs Recursive
Compare authoritative nameserver responses against recursive resolver responses.
curl -s -X POST 'https://dns.netray.info/api/authcompare?stream=false' \
-H 'Content-Type: application/json' \
-d '{"query": "example.com A"}' | jq .
Utility Endpoints
POST /api/parse -- Query Parser
Parse a query string and get completions. Useful for building UIs.
curl -s -X POST https://dns.netray.info/api/parse \
-H 'Content-Type: application/json' \
-d '{"query": "example"}' | jq .
GET /api/results/{key} -- Cached Results
Retrieve a cached result by its permalink key (returned in the done SSE event).
curl -s https://dns.netray.info/api/results/abc123 | jq .
GET /api/servers -- Available DNS Servers
List all available DNS servers and their aliases.
curl -s https://dns.netray.info/api/servers | jq .
GET /api/record-types -- Supported Record Types
List all supported DNS record types.
curl -s https://dns.netray.info/api/record-types | jq .
GET /api/config -- Client Configuration
Server-side configuration relevant to API clients.
curl -s https://dns.netray.info/api/config | jq .
Rate Limits
Three-tier GCRA rate limiting: per-IP, per-target domain, and global. The cost of a request is calculated as:
cost = number_of_record_types * number_of_servers
For example, querying example.com A MX @cloudflare @google costs 4 (2 types x 2 servers).
When rate-limited, you receive a 429 with a
Retry-After header.
Errors
Standard error envelope:
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Retry after 5 seconds."
}
}
In SSE mode, errors arrive as an error event:
event: error
data: {"error": {"code": "bad_request", "message": "Invalid query syntax"}}