Docs pages

GoDaddy-style API#

https://api.maildns.io/v1 takes the same paths, header and JSON bodies as GoDaddy's Domains API (v1) for DNS records. Point a GoDaddy client at that base URL and give it your MailDNS key and secret.

Requests and replies#

HTTP
Authorization: sso-key KEY:SECRET
Content-Type: application/json
  • Reads reply 200 with JSON. Adds and replaces reply 200 with an empty body once the change is saved at the authoritative nameservers. DELETE replies 204.
  • {domain} is one of your hosts (advisor.example.com) or the root domain they live in (example.com). Record names are relative to it, and @ is {domain} itself. See Hosts.
  • Errors are GoDaddy's {"code", "message"}:
JSON
{"code": "ACCESS_DENIED", "message": "This API key doesn't work for nameservers."}
HTTP code Meaning
401 UNABLE_TO_AUTHENTICATE Wrong key or secret, or a call from an IP address the key is not locked to
403 ACCESS_DENIED A name outside your hosts, an NS record, a nameserver change, or anything outside DNS records
404 NOT_FOUND A domain that is not yours, or an unknown path
422 INVALID_BODY An invalid record: type, data, TTL, CNAME clash, too many records. message says which.
429 TOO_MANY_REQUESTS Too many requests, or an earlier change to the same root domain is still running. Wait Retry-After seconds and retry.
503 UNAVAILABLE The change could not be made right now. Nothing was changed.

Endpoints#

Method and path Body Does
GET /v1/domains Your hosts
GET /v1/domains/{domain} One host, with nameServers
GET /v1/domains/{domain}/records All records
GET /v1/domains/{domain}/records/{type} Records of one type
GET /v1/domains/{domain}/records/{type}/{name} Records of one type at one name
PATCH /v1/domains/{domain}/records [records] Add records
PUT /v1/domains/{domain}/records [records] Replace all records of each host the body mentions
PUT /v1/domains/{domain}/records/{type} [records] Replace all records of that type on each host the body mentions
PUT /v1/domains/{domain}/records/{type}/{name} [{data, ttl, priority}] Replace the records of that type at that name
DELETE /v1/domains/{domain}/records/{type}/{name} Delete the records of that type at that name

Records#

JSON
{"type": "TXT", "name": "@", "data": "google-site-verification=3J9tq0iV8pTt1yW5zKc2mE7aR4bN6hD0sF1gL8xQ", "ttl": 3600}
{"type": "MX", "name": "@", "data": "smtp.google.com", "priority": 1, "ttl": 3600}
{"type": "TXT", "name": "google._domainkey", "data": "v=DKIM1; k=rsa; p=MIIBIjANBgkqh...", "ttl": 3600}
{"type": "CNAME", "name": "mail", "data": "ghs.googlehosted.com", "ttl": 3600}
{"type": "A", "name": "@", "data": "203.0.113.10", "ttl": 3600}

priority is for MX only. ttl follows the TTL rule. TXT data goes without surrounding quotes, in one piece.

List hosts#

Shell
curl https://api.maildns.io/v1/domains \
  -H 'Authorization: sso-key KEY:SECRET'
JSON
[
  {"domain": "advisor.example.com", "status": "ACTIVE", "expires": "2027-01-01T00:00:00.000Z", "renewAuto": true},
  {"domain": "billing.example.com", "status": "ACTIVE", "expires": "2027-01-01T00:00:00.000Z", "renewAuto": true}
]

expires and renewAuto describe the root domain. One host, with its nameservers (read-only):

Shell
curl https://api.maildns.io/v1/domains/advisor.example.com \
  -H 'Authorization: sso-key KEY:SECRET'
JSON
{"domain": "advisor.example.com", "status": "ACTIVE", "expires": "2027-01-01T00:00:00.000Z", "renewAuto": true, "nameServers": ["ns1.example.net", "ns2.example.net"]}

Read records#

Shell
curl https://api.maildns.io/v1/domains/advisor.example.com/records/TXT \
  -H 'Authorization: sso-key KEY:SECRET'
JSON
[
  {"type": "TXT", "name": "@", "data": "v=spf1 include:_spf.google.com ~all", "ttl": 3600},
  {"type": "TXT", "name": "_dmarc", "data": "v=DMARC1; p=quarantine", "ttl": 3600}
]

Add records#

PATCH adds the records to what is there. Records already there (same type, name and data) are skipped, so repeating it is harmless.

Shell
curl -X PATCH https://api.maildns.io/v1/domains/advisor.example.com/records \
  -H 'Authorization: sso-key KEY:SECRET' -H 'Content-Type: application/json' \
  -d '[
    {"type": "MX", "name": "@", "data": "smtp.google.com", "priority": 1, "ttl": 3600},
    {"type": "TXT", "name": "@", "data": "v=spf1 include:_spf.google.com ~all", "ttl": 3600},
    {"type": "TXT", "name": "_dmarc", "data": "v=DMARC1; p=quarantine", "ttl": 3600}
  ]'

Replace records#

The three PUT calls replace, so use them with care:

  • PUT /records leaves each host the body mentions with exactly the records in the body, including the records under it. On GoDaddy itself this call replaces the whole domain; MailDNS limits it to the hosts you name.
  • PUT /records/{type} replaces every record of that type on those hosts. PUT /records/TXT with only an SPF record removes the host's verification, DKIM and DMARC records too.
  • PUT /records/{type}/{name} touches one type at one name. It is the safe way to change a single record, such as DMARC:
Shell
curl -X PUT https://api.maildns.io/v1/domains/advisor.example.com/records/TXT/_dmarc \
  -H 'Authorization: sso-key KEY:SECRET' -H 'Content-Type: application/json' \
  -d '[{"data": "v=DMARC1; p=reject", "ttl": 3600}]'

Delete records#

Deletes every record of that type at that name:

Shell
curl -X DELETE https://api.maildns.io/v1/domains/advisor.example.com/records/TXT/_dmarc \
  -H 'Authorization: sso-key KEY:SECRET'

To delete one of several TXT records at the same name, PUT /records/TXT/@ with the ones to keep.

Nameservers#

Changing nameservers (PATCH /v1/domains/{domain} with nameServers, or any NS record) is refused with HTTP 403, ACCESS_DENIED, This API key doesn't work for nameservers. Registration calls (purchase, renew, transfer, contacts) are not available either. Reading nameServers is fine.

Check that a record is live#

The live check is a Dynadot-style call, and it takes the same key:

Shell
curl https://api.maildns.io/api3.json \
  --data-urlencode key=KEY --data-urlencode command=dns_status \
  --data-urlencode domain=advisor.example.com --data-urlencode subdomain=_dmarc \
  --data-urlencode record_type=txt --data-urlencode 'value=v=DMARC1; p=quarantine'

Wait for "Live": "yes" before asking Google or Microsoft to verify.