Replace a domain's subordinate hosts

​

Points a domain at a new set of subordinate host objects, the host records that live in the domain's own zone, replacing whatever it currently has. Send the full set you want: hosts you leave out are removed, and an empty array leaves the domain with none.

The response is always a change request, never the domain. Host objects are held at the registry, so this endpoint records what you asked for and answers 202 while it is carried out. Read the set back once the change reports applied.

Where to read the set back: GET /domains/{id}/hosts, not GET /domains/{id}. The domain resource carries the nameserver delegation, which is a different thing: names anywhere on the internet, with no addresses. The host endpoint returns each host's glue as address objects, and addresses[].address from there is what this endpoint's addresses array takes, so a set read back and resent evaluates as a no-op.

Status Meaning What to do
202 Accepted and running. Poll GET /changes/{id} until state is applied or failed, then re-read GET /domains/{id}/hosts.
409 Another change already holds part of this domain. Wait for the change named in conflict.change_request_id, then try again.
422 Refused. The body lists every reason. Follow each issue's next_step.

Send ?dry_run=true to see what would happen without recording anything. The answer is a ChangeDryRun carrying the same verdict and the same reasons, and no change is created either way. A dry run draws on a rate limit of its own, wider than the one changes use, so previewing a change while you compose it does not spend the requests you need to send it.

A hostname has to be a subdomain of this domain; one that is not is refused with host_unknown. Removing a host still named in the domain's own nameservers set is refused with host_still_delegated; detach the delegation first. More hosts or addresses than the registry accepts, a malformed hostname or address, or a repeated one, is refused with payload_invalid.

Every host has to carry at least one address. A host in this set lives inside this domain's own zone, so nothing can reach the name unless this domain publishes an address for it. A host with an empty addresses array is refused with payload_invalid naming the hostname. There are two ways to clear that: give the host an address, or leave it out of the set entirely, which removes it.

Every address has to be publicly routable. The registry publishes glue to every resolver, so an address the public internet cannot reach is refused with payload_invalid, and the detail names the first such address as you sent it.

The update lock refuses this endpoint entirely. A domain carrying clientUpdateProhibited or serverUpdateProhibited is refused with domain_locked, whatever the set names: the glue under a name is where that name resolves, so editing it while the name is frozen would move the domain without changing the domain. Clear the lock through PATCH /domains/{id} with {"locks":{"update":false}}, make the host change, then set it again. PATCH /domains/{id} takes hosts beside locks, so the unlock and the host change travel in one request there and the name spends no time unlocked between them. That applies to every host in the set, including ones this domain does not itself delegate to.

Permissions
Key type Accepted Permission required Notes
Org API key yes domain:write Reaches every team in the key's org
Personal API key yes domain:write Caller must have an active membership in the org named by X-Org-ID; a domain outside their teams returns 403
Error Codes
Code HTTP Description
domain.change.unauthorized 401 No valid credentials
domain.change.no_org 403 No active organization in scope for the call
domain.change.rate_limited 429 Too many change requests; Retry-After says how long to wait
domain.change.dry_run_rate_limited 429 Too many dry runs; Retry-After says how long to wait
domain.change.invalid_id 400 Domain id is malformed
domain.change.invalid_dry_run 400 dry_run is not true or false
domain.change.subordinate_hosts.decode_failed 400 Request body is not readable JSON
domain.change.subordinate_hosts.validation_failed 400 Request body is missing hosts, or a field is out of bounds
domain.change.not_found 404 Domain not found, or it belongs to another organization
domain.change.no_team_access 403 Domain belongs to your organization but is outside your team scope
domain.change.conflict 409 Another open change already holds part of this domain
domain.change.denied 422 The change cannot be applied; see issues
domain.change.subordinate_hosts.failed 500 The change could not be recorded

Path Parameters

  • Domain typeid

Query Parameters

  • Judge the change and return the verdict without recording anything

Body·

required
application/json

The subordinate-host set

The subordinate-host set a domain should end up with.

  • The full subordinate-host set, replaced whole. An empty array leaves the domain with no host objects of its own. Required: omit it and the request is refused rather than read as an empty set.

    Properties: 2
  • The domain version this change was composed against. Send it and a domain that moved since you read it refuses the change instead of writing over the move. Omit it and nothing is asserted.

  • Your own note, kept on the change and shown wherever it is read. Never interpreted.

Responses

  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
Request Example for put/domains/{id}/hosts
curl 'https://api.nametrust.com/domains/{id}/hosts' \
  --request PUT \
  --header 'Content-Type: application/json' \
  --data '{
  "hosts": [
    {
      "hostname": "ns1.example.com",
      "addresses": [
        "1.1.1.1",
        "2606:4700:4700::1111"
      ]
    }
  ],
  "base_version": 7,
  "comment": "add a second nameserver'\''s glue"
}'
{
  "object": "change_dry_run",
  "domain_id": "dom_01h455vb4pex5vsknk084sn02q",
  "outcome": "allow",
  "applies_immediately": false,
  "kinds": [
    "domain.nameservers"
  ],
  "slots": [
    "delegation"
  ],
  "issues": [
    {
      "object": "change_issue",
      "code": "domain_locked",
      "next_step": "clear_lock",
      "detail": "clientUpdateProhibited",
      "kind": "domain.nameservers"
    }
  ]
}