Manage DNS records
GET /api/v1/domains/zones
Section titled “GET /api/v1/domains/zones”Reads every record set in the zone.
Request
GET /api/v1/domains/zones?domainName=apiname.comResponse — 200
[ { "name": "apiname.com.", "type": "SOA", "ttl": 3600, "changeType": "", "records": [ { "content": "tr.apiname.com. hostmaster.apiname.com. 2026103001 86400 7200 1209600 300", "disabled": false } ] }, { "name": "apiname.com.", "type": "A", "ttl": 3600, "changeType": "", "records": [ { "content": "203.0.113.10", "disabled": false } ] }, { "name": "apiname.com.", "type": "MX", "ttl": 3600, "changeType": "", "records": [ { "content": "10 mail1.apiname.com.", "disabled": false }, { "content": "20 mail2.apiname.com.", "disabled": false } ] }, { "name": "www.apiname.com.", "type": "CNAME", "ttl": 3600, "changeType": "", "records": [ { "content": "apiname.com.", "disabled": false } ] }]Names come back in full form with a trailing dot. changeType is empty on reads — ignore it.
POST /api/v1/domains/zones
Section titled “POST /api/v1/domains/zones”Adds one or more values to a record set. Existing values in the same set are kept — this adds, it does not replace.
Request — domainName in the query string, body as below
| Field | Required | Notes |
|---|---|---|
zoneStruct.name |
varies | Subdomain label or full name. "" or "@" for the apex. Required for CNAME. |
zoneStruct.type |
required | Record type in uppercase. A works, a does not. |
zoneStruct.ttl |
required | 1 to 86400 seconds. 3600 is a sensible default; 300 while making changes. |
zoneStruct.contents |
required | Array of values to add to the set. |
Apex A record
POST /api/v1/domains/zones?domainName=apiname.com
{ "zoneStruct": { "name": "@", "type": "A", "ttl": 3600, "contents": ["203.0.113.10"] }}www as a CNAME to the apex
{ "zoneStruct": { "name": "www", "type": "CNAME", "ttl": 3600, "contents": ["apiname.com"] }}Two mail servers in one call
{ "zoneStruct": { "name": "@", "type": "MX", "ttl": 3600, "contents": [ "10 mail1.apiname.com", "20 mail2.apiname.com" ] }}SPF
{ "zoneStruct": { "name": "@", "type": "TXT", "ttl": 3600, "contents": ["v=spf1 include:_spf.google.com -all"] }}DMARC
{ "zoneStruct": { "name": "_dmarc", "type": "TXT", "ttl": 3600, "contents": ["v=DMARC1; p=quarantine; rua=mailto:dmarc@apiname.com"] }}CAA — restrict which CA may issue certificates
{ "zoneStruct": { "name": "@", "type": "CAA", "ttl": 3600, "contents": ["0 issue \"letsencrypt.org\""] }}Response — 204, no body
Record types and their value format
Section titled “Record types and their value format”| Type | Value format | Example | Notes |
|---|---|---|---|
| A | IPv4 address | 203.0.113.10 |
An IPv6 value here is rejected. |
| AAAA | IPv6 address | 2001:db8::1 |
An IPv4 value here is rejected. |
| CNAME | Host name | apiname.com |
name must not be empty or @ — a CNAME at the apex is invalid DNS. Use ALIAS instead. An IP value is rejected. |
| ALIAS | Host name | apiname.com |
Use this for a CNAME-like record at the apex. It resolves to the target’s address without breaking the other apex records. |
| MX | priority host |
10 mail.apiname.com |
Two fields, space-separated. Priority must be a number; lower wins. The host must not be an IP. |
| TXT | Free text | v=spf1 -all |
Send it unquoted — quotes are added for you. |
| CAA | flag tag "value" |
0 issue "letsencrypt.org" |
Exactly three space-separated fields, or it is rejected. |
| SRV | priority weight port host |
10 5 443 sip.apiname.com |
Four fields. The name is conventionally _service._proto. |
| PTR | Host name | host.apiname.com |
Reverse lookups. |
| TLSA, NAPTR, CERT, DNAME, LOC, SSHFP and others | Per the relevant standard | — | Accepted and validated by the DNS server. A syntax problem surfaces as ZoneClient:10008. |
| SOA | Full SOA string | — | Created with the zone. Only change it if you know exactly why. |
| DS, DNSKEY, RRSIG, NSEC | — | — | Do not manage DNSSEC here. Use the DNSSEC endpoints, which publish at the registry. |
Errors
| Code | Meaning and fix |
|---|---|
ZoneClientValidationError |
A CNAME was sent without a name. CNAMEs can only exist on subdomains. |
ZoneClient:10002 |
An A record’s value is not a valid IPv4 address. |
ZoneClient:10003 |
An AAAA record’s value is not a valid IPv6 address. |
ZoneClient:10004 |
The record name is required and cannot start with @. |
ZoneClient:10005 |
A CAA value is not three space-separated fields. details shows the correct format. |
ZoneClient:10008 |
The DNS server rejected the value’s syntax. Check it against the record type’s specification. |
ZoneClient:10009 |
An MX priority is not a number. |
ZoneClient:10010 |
A CNAME or MX value is an IP address. These require host names. |
Dna.DomainService:Zone:10001 |
That exact value already exists in the set, or you sent it twice. Nothing was changed. |
ZoneClient:10001 |
The DNS service is temporarily unreachable. Retry shortly. |
Dna.DomainService:Domain:10007 |
Domain not found or not yours. |
PUT /api/v1/domains/zones
Section titled “PUT /api/v1/domains/zones”Replaces a record set. Every existing value in the set is discarded and replaced with what you send.
Request — query string carries both the domain and the current record name
PUT /api/v1/domains/zones?domainName=apiname.com&recordName=www
{ "zoneStruct": { "name": "www", "type": "A", "ttl": 300, "contents": ["203.0.113.50"] }}This replaces every A value at www with the single new address and drops the TTL to 300.
| Parameter | Required | Notes |
|---|---|---|
domainName |
required | Query string. |
recordName |
required | Query string. The current name of the set. |
zoneStruct |
required | Body. The desired end state. |
Renaming a record set
Send a different zoneStruct.name from recordName. The old set is removed and the values appear under the new name. Values already present at the destination are preserved rather than silently overwritten.
PUT /api/v1/domains/zones?domainName=apiname.com&recordName=blog
{ "zoneStruct": { "name": "news", "type": "CNAME", "ttl": 3600, "contents": ["apiname.com"] }}Response — 204, no body
Errors
| Code | Meaning and fix |
|---|---|
ZoneClient:10006 |
The zone does not exist. Create a record with POST first. |
ZoneClient:10007 |
No record set matches recordName plus that type. |
Dna.DomainService:Zone:10001 |
A value repeats within contents, or already exists at the destination name. |
DELETE /api/v1/domains/zones
Section titled “DELETE /api/v1/domains/zones”Deletes one value from a record set. When it was the last value, the whole set is removed.
Request
DELETE /api/v1/domains/zones?domainName=apiname.com
{ "name": "www.apiname.com", "recordType": "A", "record": "203.0.113.11"}| Field | Required | Notes |
|---|---|---|
name |
required | The record name. Must belong to this zone — the zone itself or a subdomain of it. |
recordType |
required | Uppercase. |
record |
required | The exact value to remove. Whitespace and trailing dots are ignored when matching. |
Response — 204, no body
Errors
| Code | Meaning and fix |
|---|---|
ZoneClient:10011 |
name does not belong to this zone. details shows the expected format. Note that a name merely containing the zone — apiname.com.example.net — is correctly rejected. |
ZoneClient:10006 |
The zone does not exist. |
ZoneClient:10007 |
No such record set, or no value matching record. Read the zone with GET and copy the value exactly. |
POST /api/v1/domains/zones/apply
Section titled “POST /api/v1/domains/zones/apply”Publishes the zone by delegating the domain to our name servers. This is the step that makes your records actually resolve.
Request
POST /api/v1/domains/zones/apply?domainName=apiname.comResponse — delegation was changed
{ "nameServersChanged": true, "previousNameServers": ["ns1.otherhost.com", "ns2.otherhost.com"], "currentNameServers": ["tr.apiname.com", "eu.apiname.com"], "systemNameServers": ["tr.apiname.com", "eu.apiname.com"]}Response — already delegated, nothing to do
{ "nameServersChanged": false, "previousNameServers": ["tr.apiname.com", "eu.apiname.com"], "currentNameServers": ["tr.apiname.com", "eu.apiname.com"], "systemNameServers": ["tr.apiname.com", "eu.apiname.com"]}| Field | How to use it |
|---|---|
nameServersChanged |
false means the domain was already on our name servers. true means you just changed delegation and propagation has started — warn the customer about the wait. |
previousNameServers |
What the domain used before. Log this — it is your only record of the old setup if you need to revert. |
currentNameServers |
What it uses now. |
Errors
| Code | Meaning and fix |
|---|---|
Dna.DomainService:Domain:10007 |
Domain unknown, not yours, or deleted. |
Dna.DomainService:Dns:10003 |
The domain has no name servers at all. Set them with PUT /domains/dns/name-server first. |
Dna.DomainService:Domain:10070 |
Waiting for registry documents. |
Dna.DomainService:Dnssec:10010 |
DNSSEC is active. Disable it first, or use PUT /domains/dns/name-server with dnssecMode. |
Dna.DomainService:DomainSale:10007 |
The domain is listed for sale and uses parking records. |
Dna.DomainService:Epp:10001 |
The registry rejected the delegation change. |