---
title: "Add and remove DNS records of a bought name (A, AAAA, CNAME, MX, TXT; or a preset). Applied onto the zone as it stands, every other record kept; a zone that changed since `version` answers 409 dns_changed. Records that follow the project cannot be changed"
method: POST
path: "/domain-registrations/domains/{domainId}/dns"
tags: ["Domains"]
---

# Add and remove DNS records of a bought name (A, AAAA, CNAME, MX, TXT; or a preset). Applied onto the zone as it stands, every other record kept; a zone that changed since \`version\` answers 409 dns_changed. Records that follow the project cannot be changed

`POST /domain-registrations/domains/{domainId}/dns`

## Request

- Base URL: `https://hostingsurge.com/api/v1`
- URL: `https://hostingsurge.com/api/v1/domain-registrations/domains/{domainId}/dns`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `__Host-hs_session`

## Path parameters

- `domainId` string, uuid, required

## Request body

- object
  - `version` string, required: the version the change is based on (from the list); a zone that changed meanwhile answers conflict
  - `add` object[]
    - `type` 'A' | 'AAAA' | 'CNAME' | 'MX' | 'TXT', required: what can be added here; Dynadot's API takes no CAA records and no SRV records in a documented format (ones already there are kept)
    - `name` string: "@" (or empty) for the name itself, else labels such as www, blog or _dmarc; the full name works too
    - `value` string, required: A: an IPv4 address; AAAA: an IPv6 address; CNAME and MX: a hostname; TXT: the text itself (SPF, DKIM, DMARC, a verification string; at most 2048 characters, no quotation marks)
    - `priority` integer: MX only, and required there: lower is tried first
  - `remove` string[]: ids of records to remove
  - `preset` object: adds the preset's records (as the preset preview shows them)
    - `id` 'google_workspace' | 'microsoft_365' | 'hostingsurge_mail', required: google_workspace: Google's MX record; microsoft_365: the MX value from the Microsoft 365 admin center, Autodiscover and SPF; hostingsurge_mail: the records the team's Hostingsurge Mail needs for the name (add the name under Email first)
    - `mxHost` string: microsoft_365: the MX value the Microsoft 365 admin center shows (…mail.protection.outlook.com)
  - `replace` boolean: records added take the place of the ones they clash with (the MX records there for a preset's MX, another SPF or DMARC record, records next to a CNAME); without it such a change answers conflict (conflicting_records) and nothing changes

## Response `200`

Saved

- object
  - `domainId` string, uuid, required
  - `domain` string, required
  - `projectId` string, uuid, nullable, required
  - `projectName` string, nullable, required
  - `kind` 'dynadot_dns' | 'parking' | 'external' | 'unreadable' | 'not_in_account', required: dynadot_dns: Dynadot's DNS serves the name (the records below); parking: Dynadot's parking page (adding a record switches it to Dynadot's DNS); external: other nameservers serve it (manage its DNS there); unreadable: Dynadot's answer could not be read completely (nothing is changed unseen); not_in_account: the name is not in our registrar account (manage its DNS where it is registered)
  - `editable` boolean, required: records can be changed here (Dynadot's DNS or its parking page, read completely)
  - `message` string, nullable, required: why they cannot, in plain words
  - `nameservers` string[], required: external: the nameservers that serve the name, when Dynadot lists them
  - `version` string, nullable, required: the zone as read; send it with a change
  - `ttl` integer, nullable, required: Dynadot keeps one TTL (seconds) for all of a name's records; null when its answer does not say
  - `records` object[], required
    - `id` string, required: stable while the record is unchanged; pass it to remove the record
    - `type` string, required: A, AAAA, CNAME, MX, TXT, or a type Dynadot has of its own (SRV, FORWARD, STEALTH, EMAIL): kept as it is
    - `name` string, required: "@" for the name itself, else the labels below it (www, blog, _dmarc, …)
    - `value` string, required
    - `priority` integer, nullable, required: MX only: lower is tried first
    - `extra` string, nullable, required: Dynadot's second value of its own types (a forward's 301/302, …); null otherwise
    - `managed` 'project' | 'ownership' | 'null', nullable, required: null: the team's own record. project: a web record (@ or www) that points the name at its project and follows it (moving the name changes it); ownership: the _hostingsurge TXT that proves the name is yours. Managed records cannot be changed here
  - `limits` object, required: at most this many records for the name itself (main) and below it (sub)
    - `main` integer, required
    - `sub` integer, required
  - `types` string[], required: the types that can be added
  - `presets` object[], required
    - `id` 'google_workspace' | 'microsoft_365' | 'hostingsurge_mail', required: google_workspace: Google's MX record; microsoft_365: the MX value from the Microsoft 365 admin center, Autodiscover and SPF; hostingsurge_mail: the records the team's Hostingsurge Mail needs for the name (add the name under Email first)
    - `available` boolean, required
    - `needsMxHost` boolean, required
  - `changed` object, required
    - `added` integer, required
    - `removed` integer, required
    - `replaced` integer, required
    - `alreadyThere` integer, required

## Other responses

- `400`: Invalid request (code invalid_request); details.reason says what to fix
- `401`: Missing or invalid session/token (code unauthorized)
- `403`: Authenticated but not permitted (code forbidden); operator writes may need a fresh session (details.reauthenticate)
- `404`: Not found or not visible to the caller (code not_found)
- `409`: Conflicting state (code conflict): details.reason taken, premium, owned, pending_order, price_changed, dns_changed (reload the records), dns_busy, dns_not_here, conflicting_records (details.records), …
- `429`: Too many searches or DNS requests (code rate_limited); see Retry-After
- `501`: Not set up on this server (code not_configured), e.g. no registrar key yet
- `503`: The registrar did not answer (code provider_unavailable)

---

[API](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api.md) · [All operations](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api/revisions/4d08337cdff1?raw)
