Authentication
All API requests require authentication using an API key. Pass the key in the Authorization header as a Bearer token. The API key must start with the nxd_ prefix.
Authorization: Bearer nxd_your_api_key_here
The API authentication layer is stateless – each request is authenticated independently. There are no sessions or cookies.
Keep your API key secret. Do not share it in client-side code, public repositories, or URLs. If a key is compromised, revoke it immediately and create a new one.
Authentication Errors
| Status | Cause |
|---|---|
401 |
Missing or invalid API key, expired key, or cancelled account |
403 |
API key lacks the required permission for the endpoint |
Response Format
All responses are JSON. Successful responses have the following structure:
Single Resource
{
"status": "success",
"data": {
"id": 42,
"public_id": "xK9mP2",
"name": "example.com",
...
}
}
Paginated List
{
"status": "success",
"data": [ ... ],
"meta": {
"total": 150,
"page": 1,
"per_page": 25,
"last_page": 6
}
}
Error Response
{
"status": "error",
"error": {
"code": "validation_error",
"message": "Validation failed.",
"details": {
"name": ["Domain name is required."]
}
}
}
Public IDs
Every resource is identified by an opaque id (for example xK9mQ2), used in URL paths. Raw numeric database IDs are never exposed or accepted.
Pagination
List endpoints that return paginated results accept the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number (minimum 1) |
per_page |
integer | 25 | Items per page (1–100) |
Zones
Manage DNS zones. Requires zones.read for read operations and zones.write for write operations.
GET /v1/zones
List all zones for the authenticated user.
Query parameters
search– filter zones by namepage,per_page– pagination
Response fields
id, name, type (master/slave), status, ns_group, created_at, updated_at
GET /v1/zones/{id}
Get detailed information about a specific zone, including SOA data, nameservers, and record count.
Additional response fields
records_count, soa (primary_ns, admin_email, serial, refresh, retry, expire, minimum), nameservers (array), ns_group (id, slug, name)
POST /v1/zones
Create a new DNS zone. Zone creation is blocked if the user has overdue invoices.
Request body (JSON)
{
"name": "example.com",
"type": "master",
"ns_group_id": 1,
"master_ip": ""
}
name(required) – domain nametype–"master"(default) or"slave"ns_group– NS group to assign the zone to (optional, uses default if omitted)master_ip– required for slave zones; must be a valid IP address
Returns 201 Created with the zone object.
DELETE /v1/zones/{id}
Delete a zone and all its records.
Returns 204 No Content on success.
GET /v1/zones/{id}/export
Export a zone in BIND format or as structured JSON.
Query parameters
format–"bind"(default) returns BIND zone file text;"json"returns a structured array of records with name, type, content, and ttl
Records
Manage DNS records within a zone. All record endpoints are nested under a zone. Requires records.read for read operations and records.write for write operations.
GET /v1/zones/{zoneId}/records
List all records in a zone.
Query parameters
type– filter by record type (e.g.A,CNAME,MX)name– filter by record name (substring match)search– search in both name and content
Response fields
id, name, type, content, ttl, disabled, fields (type-specific parsed fields)
GET /v1/zones/{zoneId}/records/{recordId}
Get a single record by its ID.
POST /v1/zones/{zoneId}/records
Create a new DNS record.
Request body (JSON)
{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}
type(required) – record type (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS, PTR, ALIAS, DNAME, DS, TLSA)name– record name relative to the zone (default:@for zone apex)ttl– time to live in seconds (default: 3600)content– record value (IP for A/AAAA, hostname for CNAME/NS/PTR, text for TXT, mail server for MX)
Type-specific fields
- MX:
priority(default: 10) - SRV:
priority,weight,port - CAA:
flags(default: 0),tag(default: "issue") - DS:
keytag,algorithm,digest_type - TLSA:
usage,selector,matching_type
Returns 201 Created with the record object.
PUT /v1/zones/{zoneId}/records/{recordId}
Update an existing record. Only include the fields you want to change; omitted fields retain their current values.
{
"content": "93.184.216.35",
"ttl": 7200
}
Returns 200 OK with the updated record object. Note: the record ID may change after an update since it is computed from the record’s name, type, and content.
DELETE /v1/zones/{zoneId}/records/{recordId}
Delete a record from the zone.
Returns 204 No Content on success.
DNSSEC
Manage DNSSEC for your zones. Requires zones.read to view status and zones.write to enable or disable.
GET /v1/zones/{id}/dnssec
Get DNSSEC status for a zone, including keys and DS records.
Response fields
enabled (boolean), keys (array of DNSKEY records), ds_records (array of DS records to set at registrar)
POST /v1/zones/{id}/dnssec/enable
Enable DNSSEC for a zone. Generates signing keys automatically.
Returns DNSSEC status with generated keys and DS records.
POST /v1/zones/{id}/dnssec/disable
Disable DNSSEC for a zone. Removes all signing keys.
Returns {"enabled": false, "keys": [], "ds_records": []}.
NS Groups
List the available nameserver groups. Use a group's id as ns_group when creating a zone. Any valid API key can read this endpoint.
GET /v1/ns-groups
List the active nameserver groups.
Response fields per group
id, name, slug
Account
View account information and manage API keys.
GET /v1/account
Get current account information, including subscription details.
Response fields
id (UUID), email, name, role, status, language, timezone, created_at
subscription – object with plan, billing_cycle, status, current_period_start, current_period_end (or null if no subscription)
GET /v1/account/api-keys
List all API keys for the authenticated user.
Response fields per key
id, name, key_prefix (first 8 chars), permissions (array), last_used_at, expires_at, created_at
POST /v1/account/api-keys
Create a new API key.
Request body (JSON)
{
"name": "CI/CD Pipeline",
"permissions": ["zones.read", "records.read", "records.write"],
"expires_at": "2027-01-01"
}
name(required) – human-readable name (max 255 characters)permissions(required) – array of permissions (at least one required):zones.read,zones.write,records.read,records.write,webhooks.read,webhooks.writeexpires_at– optional expiration date (ISO 8601 orYYYY-MM-DD); must be in the future
The response includes the full API key in the
keyfield. This is the only time the full key is returned. Store it securely.
Returns 201 Created with the key details including the full key value.
DELETE /v1/account/api-keys/{id}
Revoke (permanently delete) an API key.
Returns 204 No Content on success.
Billing
View subscription, plans, and invoices. These endpoints are read-only.
GET /v1/billing/subscription
Get current subscription details. Returns null if no active subscription.
Response fields
id, plan, billing_cycle, status, current_period_start, current_period_end, created_at
GET /v1/billing/plans
List all available plans with pricing and features.
Response fields per plan
id, name, slug, description, price_monthly, price_yearly, currency, max_domains, max_records, features (array)
GET /v1/billing/invoices
List the authenticated user's invoices, newest first.
Query parameters
status– filter by status (draft,issued,sent,void)page,per_page– pagination
GET /v1/billing/invoices/{id}
Get a single invoice by its <code>id</code>.
Response fields
id, number, status, amount (gross), net_amount, tax_amount, tax_rate, currency, issued_at, created_at. Monetary values are plain decimal strings.
Webhooks
Manage outgoing webhook subscriptions to receive real-time notifications about zone and record changes. Requires webhooks.read for read operations and webhooks.write to create, update, or delete.
GET /v1/webhooks
List all webhook subscriptions for the authenticated user.
Response fields per webhook
id, url, events (array), description, is_active, failure_count, last_triggered_at, created_at
POST /v1/webhooks
Create a webhook subscription.
Request body (JSON)
{
"url": "https://example.com/webhook",
"events": ["zone.created", "record.created"],
"description": "Production webhook"
}
url(required) – HTTPS endpoint that will receive the event payloadsevents(required) – array of event types to subscribe todescription– optional human-readable label
The response includes a
secretused to verify webhook signatures (HMAC). This is the only time the secret is returned. Store it securely.
Returns 201 Created with the webhook id and secret.
GET /v1/webhooks/{id}
Get a single webhook subscription together with its most recent deliveries.
PUT /v1/webhooks/{id}
Update a webhook subscription. Include only the fields you want to change.
Returns 200 OK with the updated webhook object.
DELETE /v1/webhooks/{id}
Delete a webhook subscription.
Returns 204 No Content on success.
POST /v1/webhooks/{id}/test
Send a test event to the webhook endpoint to verify it is reachable.
Queues a test delivery with a "type": "test" payload.
Available event types
Subscribe to any combination of these event types:
zone.created, zone.deleted, record.created, record.updated, record.deleted, dnssec.enabled, dnssec.disabled, zone.health.problem, zone.health.resolved
Error Codes
All errors follow a consistent format with an error code string and a human-readable message.
| HTTP Status | Error Code | Description |
|---|---|---|
400 |
validation_error |
Request body failed validation. Check details for field-specific errors. |
401 |
unauthorized |
Missing, invalid, or expired API key. |
403 |
forbidden |
API key lacks the required permission, or the action is not allowed (e.g. overdue invoices block zone creation). |
404 |
not_found |
The requested resource does not exist or is not accessible by the authenticated user. |
409 |
conflict |
Resource already exists (e.g. duplicate zone name). |
429 |
rate_limit_exceeded |
Too many requests. Check Retry-After header. |
500 |
server_error |
An unexpected internal error occurred. Please try again, or contact support if it persists. |
Code Examples
All examples use curl. Replace nxd_your_api_key with your actual API key.
List your zones
curl -s "https://api.nexdns.tech/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key"
Create a zone
curl -s -X POST "https://api.nexdns.tech/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "example.com"}'
Add an A record
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}'
Add an MX record
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "MX",
"name": "@",
"ttl": 3600,
"content": "mail.example.com",
"priority": 10
}'
Update a record
curl -s -X PUT "https://api.nexdns.tech/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"content": "93.184.216.35", "ttl": 7200}'
Delete a record
curl -s -X DELETE "https://api.nexdns.tech/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key"
Export a zone (BIND format)
curl -s "https://api.nexdns.tech/v1/zones/{zoneId}/export" \
-H "Authorization: Bearer nxd_your_api_key"
Enable DNSSEC
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/dnssec/enable" \
-H "Authorization: Bearer nxd_your_api_key"
Create an API key
curl -s -X POST "https://api.nexdns.tech/v1/account/api-keys" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Read-only key",
"permissions": ["zones.read", "records.read"],
"expires_at": "2027-12-31"
}'
Get account info
curl -s "https://api.nexdns.tech/v1/account" \
-H "Authorization: Bearer nxd_your_api_key"