API Reference
The MARnet Tools REST API lets you run DNS zone checks programmatically. Submit a domain and its nameserver list; receive structured validation results including per-NS SOA queries, glue IP checks, serial consistency, and NS delegation status. No authentication required — requests are rate-limited per IP.
Rate limits
The API enforces a per-IP rate limit to ensure fair access.
This is configured in
config.py → API_RATE_LIMIT.
The server returns HTTP 429 with a Retry-After header when exceeded.
When the limit is exceeded, the response includes a retry_after field with the number
of seconds to wait before retrying.
Endpoint
Accepts a JSON body with a domain name and 2–8 nameserver entries. Performs server-side DNS queries directly to each nameserver and returns structured results.
Request body
Content-Type: application/json
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
| domain | string | required | Fully qualified domain name, e.g. example.mk |
| ns_entries | array | required | Array of nameserver objects. Minimum 2, maximum 8. |
ns_entries object
| Field | Type | Description | |
|---|---|---|---|
| ns | string | required | Nameserver hostname, e.g. ns1.example.mk |
| ipv4 | string | optional* | Glue IPv4 address. Required when NS hostname falls within the delegated domain (in-zone). |
| ipv6 | string | optional | Glue IPv6 address for in-zone nameservers. |
ns1.example.mk for example.mk), at least one glue IP (ipv4 or ipv6) must be provided.{
"domain": "example.mk",
"ns_entries": [
{
"ns": "ns1.example.mk",
"ipv4": "194.149.137.1",
"ipv6": "2001:db8::1"
},
{
"ns": "ns2.example.mk",
"ipv4": "194.149.137.2"
}
]
}
Response
Successful responses return HTTP 200 with a JSON envelope.
{
"api_version": "1.0",
"data": {
"domain": "example.mk",
"summary": {
"overall_ok": true,
"all_soa_ok": true,
"all_resolve": true,
"glue_issues": false,
"serial_consistent": true,
"all_authoritative": true,
"serials": [2024040801],
"ns_match": true
},
"registered_ns": ["ns1.example.mk", "ns2.example.mk"],
"ns_checks": [
{
"ns": "ns1.example.mk",
"in_zone": true,
"query_ip": "194.149.137.1",
"resolved_a": ["194.149.137.1"],
"resolved_aaaa":["2001:db8::1"],
"glue_ipv4": "194.149.137.1",
"glue_ipv6": null,
"glue_check": {
"ipv4_entered": "194.149.137.1",
"ipv4_resolved": ["194.149.137.1"],
"ipv4_match": true
},
"soa": {
"status": "ok",
"authoritative": true,
"rcode": "NOERROR",
"soa": {
"mname": "ns1.example.mk",
"rname": "hostmaster.example.mk",
"serial": 2024040801,
"refresh": 3600,
"retry": 900,
"expire": 604800,
"minimum": 86400,
"ttl": 3600
}
}
}
]
}
}
soa.status values
soa object is populated.message field contains details.Error responses
{"error":"validation_failed","details":[...]}{"error":"rate_limit_exceeded","retry_after":N}dnspython is not installed.curl
curl -s -X POST https://tools.marnet.mk/api/v1/dnscheck \ -H 'Content-Type: application/json' \ -d '{ "domain": "example.mk", "ns_entries": [ {"ns": "ns1.example.mk", "ipv4": "194.149.137.1"}, {"ns": "ns2.example.mk", "ipv4": "194.149.137.2"} ] }' | jq '.data.summary'
Python
import requests resp = requests.post( "https://tools.marnet.mk/api/v1/dnscheck", json={ "domain": "example.mk", "ns_entries": [ {"ns": "ns1.example.mk", "ipv4": "194.149.137.1"}, {"ns": "ns2.example.mk", "ipv4": "194.149.137.2"}, ], }, timeout=30, ) resp.raise_for_status() data = resp.json()["data"] print("Overall OK:", data["summary"]["overall_ok"]) for ns in data["ns_checks"]: print(ns["ns"], "→", ns["soa"]["status"])
JavaScript (fetch)
const res = await fetch("https://tools.marnet.mk/api/v1/dnscheck", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ domain: "example.mk", ns_entries: [ { ns: "ns1.example.mk", ipv4: "194.149.137.1" }, { ns: "ns2.example.mk", ipv4: "194.149.137.2" }, ], }), }); if (res.status === 429) { const err = await res.json(); console.error(`Rate limited. Retry after ${err.retry_after}s`); } else { const { data } = await res.json(); console.log("Overall OK:", data.summary.overall_ok); }