Docs pages

Keys and limits#

What a key is, what it can reach and read, and the limits every call runs under.

Your key#

  • One key per vendor or team. It carries a name, which account_info returns as Username.
  • One key works in all six API styles. Some styles also send the key's secret:
Style How the key is sent
Dynadot key=KEY parameter
Spaceship X-API-Key: KEY and X-API-Secret: SECRET headers
Cloudflare Authorization: Bearer KEY (or X-Auth-Key: KEY with any X-Auth-Email)
GoDaddy Authorization: sso-key KEY:SECRET
Porkbun "apikey": "KEY", "secretapikey": "SECRET" in the JSON body
Namecheap ApiKey=KEY parameter (ApiUser, UserName and ClientIp can be anything)
  • A key's domains and hosts are attached when it is issued. They can't be added or removed through the API; ask whoever issued your key.
  • Prefer POST for Dynadot-style calls: the key goes in the body instead of a URL that might end up in a log.
  • Give the key to scripts and agents through an environment variable (for example MAILDNS_KEY), never inside a prompt or a file you commit.

What a key can read#

Only what it was issued for. Every list call (list_domain, GET /zones, GET /v1/domains, /domain/listAll, getList, ...) returns just the key's own domains and hosts, and every read returns just their records. Other domains in your registrar accounts don't show up anywhere: asking for one by name answers as if it didn't exist.

Nameservers: never#

No key can change nameservers, add NS records, or touch registration. In every style the answer is the same text, in that style's error shape:

This API key doesn't work for nameservers.
Style Refused calls include
Dynadot set_ns, add_ns, register_ns, NS records in set_dns2
Spaceship Nameserver updates, NS items in PUT
Cloudflare NS records; changing a zone's nameservers (HTTP 403, code 1004)
GoDaddy nameServers in PATCH /v1/domains/{domain}, NS records (HTTP 403, ACCESS_DENIED)
Porkbun /domain/updateNs/{domain}, NS records
Namecheap namecheap.domains.dns.setCustom, setDefault, namecheap.domains.ns.*, NS records in setHosts

Reading the current nameservers is fine (get_ns, zone name_servers, nameServers, /domain/getNs, namecheap.domains.dns.getList). Don't retry a refused call: it will never succeed.

IP lock#

A key can be locked to the caller IP addresses (single addresses or ranges) you give us, the way Dynadot's API IP list works. A call from any other address is treated as a wrong key:

Style What you get
Dynadot HTTP 200, {"Response": {"ResponseCode": "-1", "Error": "invalid key"}}
Spaceship HTTP 401, {"detail": "Unauthorized", "data": []}
Cloudflare HTTP 403, error code 10000
GoDaddy HTTP 401, UNABLE_TO_AUTHENTICATE
Porkbun HTTP 403, {"status": "ERROR", "message": "invalid key"}
Namecheap HTTP 200, Status="ERROR", error number 1011102

To change the list, ask whoever issued your key.

Rate limit#

10 requests per second per key, with bursts of up to 20. Over the limit:

Style What you get
Dynadot HTTP 200, {"Response": {"ResponseCode": "-1", "Error": "too many requests; retry in 0.4 seconds"}} and a Retry-After header
Spaceship HTTP 429, {"detail": "Too many requests", "data": []} and a Retry-After header
Cloudflare, GoDaddy, Porkbun HTTP 429 in the style's error shape, with a Retry-After header
Namecheap HTTP 200, Status="ERROR", error number 500000

Wait the number of seconds in Retry-After, then send the same call again. Nothing was changed by the refused call.

One change at a time per root domain#

Changes to the same root domain are applied one at a time, in the order they arrive. If an earlier change to that root is still running, your call waits for it, for up to 60 seconds.

  • Set your HTTP client's timeout to at least 90 seconds for writes.
  • If the wait runs out, the call fails with another change to this domain is still running; retry in a few seconds (HTTP 429 in the styles that use status codes). Nothing was changed; send it again.
  • To change many hosts in the same root, one call with all of them (root form, see Hosts) is faster than one call per host.

Record rules#

Rule Limit
Record types A, AAAA, CNAME, MX, TXT. Anything else is refused.
Records per host 50, counting the records at the host and under it
TXT value Up to 2,048 characters of printable ASCII (a 2048-bit DKIM key fits)
MX priority 0 to 65535
TTL Records are served with the domain's TTL (usually 3600 seconds). See below.
CNAME Can't share a name with any other record, and only one CNAME per name
Records per set_dns2 call Up to 100 main records and 100 subdomain records

TTL. MailDNS never changes a domain's TTL: it is shared with records that aren't yours. The Dynadot-style ttl parameter is accepted, so existing code keeps working, but your records get the domain's TTL. A Spaceship-style item's ttl (300 to 86400) is used where the domain supports a TTL per record; otherwise the domain's TTL applies. get_dns and GET /api/v1/dns/records show the TTL actually served.

TXT values go as one string, without surrounding quotes, even when they are longer than 255 characters. Don't split a DKIM key into quoted pieces yourself.

What a key can't do#

  • Reach names outside its domains and hosts. When a key is issued for a host such as advisor.example.com, the root domain's own records (example.com, www.example.com) are not yours: they are never shown to you and can't be changed.
  • Change nameservers: see Nameservers: never.
  • Change registration, forwarding, contacts, transfers or renewals. Dynadot commands such as register, renew, delete, push, set_forwarding, set_stealth, set_email_forward and set_whois reply {"Response": {"ResponseCode": "-1", "Error": "command not available on this account"}}; the other styles refuse them the same way.