API quick start

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.

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.

2. Create a zone

POST /v1/zones provisions a zone under your tenant. The dashboard shows the same shape and the same response envelope.

3. Add records and verify

POST /v1/zones/<zoneID>/records adds records. Point your registrar at the platform’s name servers and verify with dig.

0. Mint an API key

Every request below authenticates with the same X-API-Key header the dashboard’s session establishes. Two ways to get one:

  • In the dashboard. Open the dashboard, go to API keys, click Create, give it a name, choose the scopes you need, and copy the plaintext key the response shows. Store it in your secret manager before the response window closes; the platform never shows the plaintext key again.
  • From a session. If you already have an OIDC session, the same endpoint accepts a 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
Example response
{
  "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"

1. Create a zone

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
Example response
{
  "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"

2. Add records

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.

2a. A record — IPv4 address

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"
Example response
{
  "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"
  }
}

2b. AAAA record — IPv6 address

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"
Example response
{
  "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"
  }
}

2c. TXT record — SPF policy

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"
Example response
{
  "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.

3. Point your registrar at the platform name servers

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.

4. Verify with 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.

4a. A record

dig @ns1.netquirk.com www.example.test A +short
Example output
www.example.test.	300	IN	A	203.0.113.10

4b. AAAA record

dig @ns1.netquirk.com www.example.test AAAA +short
Example output
www.example.test.	300	IN	AAAA	2001:db8::10

4c. TXT record

dig @ns1.netquirk.com example.test TXT +short
Example output
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.

5. Errors

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.

Open the dashboard

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.