1. Mint a key
Open the dashboard’s API keys page and create a key. The plaintext key is shown exactly once at create time.
The platform REST API is reachable at /v1 on
dns-api.netquirk.com. Every endpoint the
dashboard renders is also a REST endpoint — so the same
flow that powers the UI runs unchanged from CI, from a terminal,
or from your own tooling.
Open the dashboard’s API keys page and create a key. The plaintext key is shown exactly once at create time.
POST /v1/zones provisions a zone
under your tenant. The dashboard shows the same shape
and the same response envelope.
POST /v1/zones/<zoneID>/records
adds records. Point your registrar at the platform’s
name servers and verify with dig.
Every request below authenticates with the same
X-API-Key header the dashboard’s
session establishes. Two ways to get one:
POST /v1/api-keys with a JSON body and
returns the key in api_key.key on the
response:
curl -sS \
-H "Content-Type: application/json" \
-H "X-API-Key: $SESSION_API_KEY" \
-d '{
"name": "ci-cd-key",
"scopes": [
"dns:read",
"dns:write"
]
}' \
https://dns-api.netquirk.com/v1/api-keys
{
"api_key": {
"id": "8f0a7c2e-4b1d-4d6f-9a3c-1e2b5d8a1234",
"tenant_id": "tenant-1",
"user_id": "user-1",
"name": "ci-cd-key",
"key_prefix": "dns_abcd1234",
"key": "dns_abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx",
"scopes": [
"dns:read",
"dns:write"
],
"allowed_ips": [],
"created_at": "2026-10-15T04:30:00Z"
},
"message": "API key created. Store the key in a secret manager; it will not be shown again."
}
Save the value of api_key.key into your
shell so every later command can send it:
export DNS_API_KEY="dns_abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx"
POST /v1/zones provisions a
new zone under the calling tenant. The body matches
CreateZoneRequest:
curl -sS \
-H "Content-Type: application/json" \
-H "X-API-Key: $DNS_API_KEY" \
-d '{
"name": "example.test",
"zone_type": "master",
"ttl_default": 300
}' \
https://dns-api.netquirk.com/v1/zones
{
"zone": {
"id": "44444444-4444-4444-4444-444444444444",
"tenant_id": "tenant-1",
"name": "example.test",
"zone_type": "master",
"status": "active",
"serial": 2025101504,
"ttl_default": 300,
"soa_refresh": 7200,
"soa_retry": 1800,
"soa_expire": 1209600,
"soa_minimum": 300,
"primary_ns": "ns1.netquirk.com",
"admin_email": "hostmaster.example.test",
"axfr_allow": [],
"dnssec_enabled": false,
"created_at": "2026-10-15T04:30:01Z",
"updated_at": "2026-10-15T04:30:01Z"
}
}
Hold onto the zone id from zone.id —
every later record call uses it as the
{zoneID} path segment.
export ZONE_ID="44444444-4444-4444-4444-444444444444"
POST /v1/zones/<zoneID>/records
adds a single record. The body matches
CreateRecordRequest;
ttl is optional (omit it to use the
zone’s ttl_default). Three calls cover
the most common answer records: an A, an AAAA, and a TXT.
curl -sS \
-H "Content-Type: application/json" \
-H "X-API-Key: $DNS_API_KEY" \
-d '{
"name": "www",
"type": "A",
"content": "203.0.113.10",
"ttl": 300
}' \
"https://dns-api.netquirk.com/v1/zones/$ZONE_ID/records"
{
"record": {
"id": "rec-44444444-a-0",
"zone_id": "44444444-4444-4444-4444-444444444444",
"tenant_id": "tenant-1",
"name": "www",
"type": "A",
"content": "203.0.113.10",
"ttl": 300,
"effective_ttl": 300,
"created_at": "2026-10-15T04:30:02Z",
"updated_at": "2026-10-15T04:30:02Z"
}
}
curl -sS \
-H "Content-Type: application/json" \
-H "X-API-Key: $DNS_API_KEY" \
-d '{
"name": "www",
"type": "AAAA",
"content": "2001:db8::10",
"ttl": 300
}' \
"https://dns-api.netquirk.com/v1/zones/$ZONE_ID/records"
{
"record": {
"id": "rec-44444444-aaaa-0",
"zone_id": "44444444-4444-4444-4444-444444444444",
"tenant_id": "tenant-1",
"name": "www",
"type": "AAAA",
"content": "2001:db8::10",
"ttl": 300,
"effective_ttl": 300,
"created_at": "2026-10-15T04:30:03Z",
"updated_at": "2026-10-15T04:30:03Z"
}
}
curl -sS \
-H "Content-Type: application/json" \
-H "X-API-Key: $DNS_API_KEY" \
-d '{
"name": "@",
"type": "TXT",
"content": "v=spf1 -all",
"ttl": 3600
}' \
"https://dns-api.netquirk.com/v1/zones/$ZONE_ID/records"
{
"record": {
"id": "rec-44444444-txt-0",
"zone_id": "44444444-4444-4444-4444-444444444444",
"tenant_id": "tenant-1",
"name": "@",
"type": "TXT",
"content": "v=spf1 -all",
"ttl": 3600,
"effective_ttl": 3600,
"created_at": "2026-10-15T04:30:04Z",
"updated_at": "2026-10-15T04:30:04Z"
}
}
Every supported record type — A, AAAA, CNAME, MX, NS, SRV, TXT, CAA and more — takes the same body shape. The dashboard’s zone page shows every record type and its required fields.
After you publish the zone, the dashboard lists four name servers. Update the NS records at your registrar so they match exactly:
ns1.netquirk.com.
ns2.netquirk.com.
ns3.netquirk.com.
ns4.netquirk.com.
Queries start resolving as soon as the registrar publishes the change — propagation is governed by your registrar’s TTL on the parent zone, not by the platform.
dig
Point dig directly at one of the platform
name servers to confirm the platform is answering. The
platform returns the same answer a recursive resolver
would see once the registrar publishes the delegation.
dig @ns1.netquirk.com www.example.test A +short
www.example.test. 300 IN A 203.0.113.10
dig @ns1.netquirk.com www.example.test AAAA +short
www.example.test. 300 IN AAAA 2001:db8::10
dig @ns1.netquirk.com example.test TXT +short
example.test. 3600 IN TXT "v=spf1 -all"
Drop the +short flag for the full
response — section headers, flags, the
status: NOERROR line and the answer
section — when you want to debug a refusal.
Every error response carries a structured envelope. A
script can branch on the machine-readable
error code without parsing the prose, and
the extra fields tell you which input or state tripped
the gate. The tenant-zone cap is the most common
failure mode on a fresh account and surfaces as
zone_limit_exceeded with the plan’s
limit and the current count:
{
"error": "zone_limit_exceeded",
"message": "zone cap reached for tenant",
"limit": 5,
"current": 5
}
Other codes you may see, all with the same
{ "error", "message", ... } envelope:
invalid_zone_name, record_exists,
record_name_conflict, record_ttl_too_high,
unauthorized (missing or revoked key),
forbidden (key lacks the scope the endpoint
requires), and not_found.
The dashboard is the fastest way to inspect a zone after you publish it, audit who last changed a record, and turn DNSSEC signing on with one toggle. Sign in and your zones open on the live feed.