# Manage DNS records (https://developer.godaddy.com/en/docs/api-users/manage-domains/dns)

***

title: Manage DNS records
description: Manage DNS records and nameservers using the v3 API. Add, read, and delete individual DNS records, and replace authoritative nameservers with a single PUT request.
agentNotes:
permissions: \["DNS Management"]
scopes: \["domains.domain:read", "domains.dns:update", "domains.nameserver:update"]
idempotent: false
destructive: true
failureRecovery: "Read operations are safe to retry. Deletes are irreversible — confirm the recordId before calling DELETE. Re-read the zone after failures to verify state."
related:
apis:

* title: "Domains v3 — DNS records"
  href: "/docs/references/rest/domains/v3/records"
  guides:
* title: "Registered domains"
  href: "/docs/api-users/manage-domains/list"
* title: "Forward a domain"
  href: "/docs/api-users/manage-domains/forwarding"
* title: "Troubleshoot DNS"
  href: "/docs/api-users/troubleshoot-dns"
  concepts:
* title: "Handle errors"
  href: "/docs/api-users/errors"
* title: "Rate limits"
  href: "/docs/api-users/rate-limits"

***

## Overview

Create, read, and delete DNS records for domains hosted on GoDaddy's authoritative nameservers, and replace the authoritative nameservers themselves. All operations use the v3 API.

This page covers two related operations:

| Operation       | Description                                                                                                              |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **DNS records** | Create and retrieve A, AAAA, CNAME, MX, TXT, SRV, NS, and CAA records on a domain hosted by GoDaddy's authoritative DNS. |
| **Nameservers** | Change which authoritative nameservers the registry returns for a domain.                                                |

This page uses three OAuth scopes: `domains.domain:read` to list records, `domains.dns:update` to create and delete records, and `domains.nameserver:update` to replace nameservers. Go to [Authentication](https://developer.godaddy.com/docs/api-users/auth) for more information.

## List DNS records

`GET /v3/domains/zones/{zone}/dns-records` returns a paginated collection of records for the zone. Use `type` and `name` query parameters to filter results.

The following procedure retrieves DNS records for a zone.

* Run the following command for your preferred language:

```bash tab="curl"
# All records
curl -s "https://api.godaddy.com/v3/domains/zones/example.com/dns-records" \
  -H "Authorization: Bearer $GODADDY_PAT"

# Filter by type
curl -s "https://api.godaddy.com/v3/domains/zones/example.com/dns-records?type=A" \
  -H "Authorization: Bearer $GODADDY_PAT"

# Filter by type and name
curl -s "https://api.godaddy.com/v3/domains/zones/example.com/dns-records?type=TXT&name=_acme-challenge" \
  -H "Authorization: Bearer $GODADDY_PAT"
```

```js tab="Node"
const pat = process.env.GODADDY_PAT;
const zone = "example.com";
const url = new URL(`https://api.godaddy.com/v3/domains/zones/${zone}/dns-records`);
url.searchParams.set("type", "TXT");
url.searchParams.set("name", "_acme-challenge");

const res = await fetch(url, {
  headers: { Authorization: `Bearer ${pat}` },
});
const records = await res.json();
console.log(records.items);
```

```python tab="Python"
import os, requests

pat = os.environ["GODADDY_PAT"]
zone = "example.com"

res = requests.get(
    f"https://api.godaddy.com/v3/domains/zones/{zone}/dns-records",
    params={"type": "TXT", "name": "_acme-challenge"},
    headers={"Authorization": f"Bearer {pat}"},
)
res.raise_for_status()
for record in res.json()["items"]:
    print(record["name"], record["type"], record["data"])
```

```go tab="Go"
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
    "os"
)

func main() {
    pat := os.Getenv("GODADDY_PAT")
    zone := "example.com"

    u, _ := url.Parse(fmt.Sprintf("https://api.godaddy.com/v3/domains/zones/%s/dns-records", zone))
    q := u.Query()
    q.Set("type", "TXT")
    q.Set("name", "_acme-challenge")
    u.RawQuery = q.Encode()

    req, _ := http.NewRequest("GET", u.String(), nil)
    req.Header.Set("Authorization", "Bearer "+pat)

    res, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer res.Body.Close()

    var body struct {
        Items []map[string]any `json:"items"`
    }
    json.NewDecoder(res.Body).Decode(&body)
    fmt.Println(body.Items)
}
```

The response is a `DNSRecords` object with an `items` array of `DNSRecord` entries. Each record includes a `recordId` needed for delete operations. Go to the [DNSRecord schema](#dnsrecord-schema) for the full field reference.

### DNSRecord schema

Every entry in `items[]` is a `DNSRecord` object.

| Field      | Required  | Description                                                                                               | Note                                                                          |
| ---------- | --------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `recordId` | Read-only | Server-assigned stable identifier for the record.                                                         |                                                                               |
| `name`     | Yes       | Record name relative to the zone apex.                                                                    | Use `@` for the apex. Wildcards (`*`) supported for A, AAAA, and CNAME.       |
| `type`     | Yes       | Record type: `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `SRV`, `NS`, `CAA`, `ALIAS`, or `SOA` (SOA is read-only). |                                                                               |
| `data`     | Yes       | Record value.                                                                                             | Format depends on type: IP for A/AAAA, hostname for CNAME, text for TXT, etc. |
| `ttl`      | Yes       | Time-to-live in seconds.                                                                                  | Minimum 600 (10 min), maximum 86400 (24 hrs).                                 |
| `priority` | MX, SRV   | Priority value.                                                                                           | Lower value equals higher preference.                                         |
| `weight`   | SRV       | Relative weight among equal-priority targets.                                                             |                                                                               |
| `port`     | SRV       | Target port number.                                                                                       |                                                                               |
| `service`  | SRV       | Service name.                                                                                             | Prefixed with an underscore (for example, `_http`).                           |
| `protocol` | SRV       | Transport protocol.                                                                                       | Prefixed with underscore (for example,  `_tcp`).                              |
| `flag`     | CAA       | Restriction flags byte.                                                                                   | Use `0` for non-critical, `128` for critical.                                 |
| `tag`      | CAA       | Property tag: `issue`, `issuewild`, or `iodef`.                                                           |                                                                               |

### Pagination

Results are page-based. Use `page` (1-based, default `1`) and `pageSize` (1–100, default `25`) to navigate.

The following procedure paginates through DNS records.

* Navigate pages:

```bash
curl -s "https://api.godaddy.com/v3/domains/zones/example.com/dns-records?page=2&pageSize=50" \
  -H "Authorization: Bearer $GODADDY_PAT"
```

Add `totalRequired=true` to include `totalItems` and `totalPages` in the response — omitted by default to avoid count-query overhead on large zones. The response `links` array contains HATEOAS navigation links (`self`, `first`, `last`, `next`, `prev`) where applicable.

## Add a record

`POST /v3/domains/zones/{zone}/dns-records` creates a single DNS record in the zone. Changes are applied synchronously — no polling required.

The following procedure adds a DNS record to a zone.

* Create a record:

```bash tab="curl"
curl -s -X POST "https://api.godaddy.com/v3/domains/zones/example.com/dns-records" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -d '{ "type": "TXT", "name": "_acme-challenge", "data": "verification-string", "ttl": 600 }'
```

```js tab="Node"
const pat = process.env.GODADDY_PAT;
const zone = "example.com";

const res = await fetch(
  `https://api.godaddy.com/v3/domains/zones/${zone}/dns-records`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${pat}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type: "TXT", name: "_acme-challenge", data: "verification-string", ttl: 600 }),
  },
);
const record = await res.json();
console.log("Created record", record.recordId);
```

```python tab="Python"
import os, requests

pat = os.environ["GODADDY_PAT"]
zone = "example.com"

res = requests.post(
    f"https://api.godaddy.com/v3/domains/zones/{zone}/dns-records",
    json={"type": "TXT", "name": "_acme-challenge", "data": "verification-string", "ttl": 600},
    headers={
        "Authorization": f"Bearer {pat}",
        "Content-Type": "application/json",
    },
)
res.raise_for_status()
print("Created record", res.json()["recordId"])
```

```go tab="Go"
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

func main() {
    pat := os.Getenv("GODADDY_PAT")
    zone := "example.com"

    body := bytes.NewReader([]byte(
        `{"type":"TXT","name":"_acme-challenge","data":"verification-string","ttl":600}`))
    req, _ := http.NewRequest("POST",
        fmt.Sprintf("https://api.godaddy.com/v3/domains/zones/%s/dns-records", zone), body)
    req.Header.Set("Authorization", "Bearer "+pat)
    req.Header.Set("Content-Type", "application/json")

    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()

    var record struct{ RecordID string `json:"recordId"` }
    json.NewDecoder(res.Body).Decode(&record)
    fmt.Println("Created record", record.RecordID)
}
```

A successful response returns `201` with the created `DNSRecord` in the body. The `Location` header contains the URL for the new record, with the `recordId` you'll need for deletes.

Replaying a `POST` after a `5xx` may create a duplicate record. Save the `recordId` from the `Location` header on success so you can clean up if needed. See [Errors → Retry semantics](https://developer.godaddy.com/docs/api-users/errors#retry-semantics).

## Delete a record

`DELETE /v3/domains/zones/{zone}/dns-records/{recordId}` permanently removes a single record from the zone. Changes are applied synchronously.

The following procedure deletes a DNS record from a zone.

* Delete a record:

```bash tab="curl"
curl -s -X DELETE "https://api.godaddy.com/v3/domains/zones/example.com/dns-records/$RECORD_ID" \
  -H "Authorization: Bearer $GODADDY_PAT"
```

```js tab="Node"
const pat = process.env.GODADDY_PAT;
const zone = "example.com";
const recordId = process.env.RECORD_ID;

const res = await fetch(
  `https://api.godaddy.com/v3/domains/zones/${zone}/dns-records/${recordId}`,
  {
    method: "DELETE",
    headers: { Authorization: `Bearer ${pat}` },
  },
);
console.log(res.status); // expect 204
```

```python tab="Python"
import os, requests

pat = os.environ["GODADDY_PAT"]
zone = "example.com"
record_id = os.environ["RECORD_ID"]

res = requests.delete(
    f"https://api.godaddy.com/v3/domains/zones/{zone}/dns-records/{record_id}",
    headers={"Authorization": f"Bearer {pat}"},
)
print(res.status_code)  # expect 204
```

```go tab="Go"
package main

import (
    "fmt"
    "net/http"
    "os"
)

func main() {
    pat := os.Getenv("GODADDY_PAT")
    zone := "example.com"
    recordID := os.Getenv("RECORD_ID")

    req, _ := http.NewRequest("DELETE",
        fmt.Sprintf("https://api.godaddy.com/v3/domains/zones/%s/dns-records/%s", zone, recordID), nil)
    req.Header.Set("Authorization", "Bearer "+pat)

    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()
    fmt.Println(res.StatusCode) // expect 204
}
```

A successful response returns `204` with no body.

A `404` is returned if the `recordId` does not exist — deleting an already-deleted record is not a no-op. GoDaddy-managed SOA and NS records cannot be deleted; attempting to do so returns `409 Conflict`.

## Manage nameservers

`PUT /v3/domains/domain-names/{domain-name}/nameservers` replaces the authoritative nameservers for a domain. Accepts a plain array of 2–13 nameserver hostnames.

The following procedure replaces the authoritative nameservers for a domain.

* Replace a nameserver for a domain:

```bash tab="curl"
curl -s -X PUT "https://api.godaddy.com/v3/domains/domain-names/example.com/nameservers" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -d '["ns1.example-dns.com", "ns2.example-dns.com"]'
```

```js tab="Node"
const pat = process.env.GODADDY_PAT;

const res = await fetch(
  "https://api.godaddy.com/v3/domains/domain-names/example.com/nameservers",
  {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${pat}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(["ns1.example-dns.com", "ns2.example-dns.com"]),
  },
);
console.log(res.status); // expect 202
```

```python tab="Python"
import os, requests

res = requests.put(
    "https://api.godaddy.com/v3/domains/domain-names/example.com/nameservers",
    json=["ns1.example-dns.com", "ns2.example-dns.com"],
    headers={
        "Authorization": f"Bearer {os.environ['GODADDY_PAT']}",
        "Content-Type": "application/json",
    },
)
print(res.status_code)  # expect 202
```

```go tab="Go"
package main

import (
    "bytes"
    "fmt"
    "net/http"
    "os"
)

func main() {
    body := bytes.NewReader([]byte(`["ns1.example-dns.com","ns2.example-dns.com"]`))
    req, _ := http.NewRequest("PUT",
        "https://api.godaddy.com/v3/domains/domain-names/example.com/nameservers", body)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("GODADDY_PAT"))
    req.Header.Set("Content-Type", "application/json")

    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()
    fmt.Println(res.StatusCode) // expect 202
}
```

A successful request returns `202 Accepted` with a `DomainOperation` in the body and a `Location` header pointing to the operation URL. Propagation to the registry is asynchronous — poll the operation until it reaches a terminal state.

Switching nameservers moves authoritative DNS off GoDaddy. Records you manage via `/v3/domains/zones/{zone}/dns-records` will no longer be served — make sure the new nameservers are fully configured before cutting over.

## Use the CLI

After you [set up the CLI](https://developer.godaddy.com/docs/api-users/cli-setup), you can use it to list, add, replace, and delete DNS records on domains that use GoDaddy authoritative DNS.

The following procedure manages DNS records using the CLI.

* Run the command for your operation:

```bash
gddy dns list example.com
gddy dns list example.com --type A --name www
gddy dns add example.com --type A --name www --data 192.0.2.10 --ttl 600
gddy dns set example.com --type A --name www --data 192.0.2.20 --ttl 600
gddy dns delete example.com --type A --name www
```

`gddy dns add` appends records. `gddy dns set` replaces every record for the type and name. `gddy dns delete` removes every record for the type and name; it does not delete GoDaddy-managed `NS` or `SOA` records. Use `--dry-run` with destructive commands when you want a preview.

Use the REST API for nameserver delegation; the CLI focuses on DNS record management.

## Common errors

| Status | Most likely cause                                                                                                                                         |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Malformed request — missing required field, invalid field type, or unknown record type. Inspect `fields[]`.                                               |
| `401`  | Authentication credentials are missing or invalid.                                                                                                        |
| `403`  | Caller is not authorized. Check that your token includes the required scope (`domains.dns:update` or `domains.nameserver:update`).                        |
| `404`  | Record or domain not found, or not owned by the authenticated account.                                                                                    |
| `409`  | Conflict — request cannot be completed in the current state. For DNS: attempting to delete a GoDaddy-managed SOA or NS record (`dns_record_not_mutable`). |
| `422`  | Valid structure but violates a business rule (e.g. CNAME at apex).                                                                                        |
| `429`  | Rate limit exceeded.                                                                                                                                      |

Full error envelope: [Errors](https://developer.godaddy.com/docs/api-users/errors).

## DNSRecord schema

| Field      | Required  | Description                                                                                               | Note                                                                               |
| ---------- | --------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `recordId` | Read-only | Server-assigned stable identifier for the record.                                                         |                                                                                    |
| `name`     | Yes       | Record name relative to the zone apex.                                                                    | Use `@` for the apex. Wildcards (`*`) supported for A, AAAA, and CNAME.            |
| `type`     | Yes       | Record type: `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `SRV`, `NS`, `CAA`, `ALIAS`, or `SOA` (SOA is read-only). |                                                                                    |
| `data`     | Yes       | Record value.                                                                                             | Format depends on type (like IP for A/AAAA, hostname for CNAME, and text for TXT). |
| `ttl`      | Yes       | Time-to-live in seconds.                                                                                  | Minimum 600 (10 min), maximum 86400 (24 hrs).                                      |
| `priority` | MX, SRV   | Priority value.                                                                                           | Lower value equals higher preference.                                              |
| `weight`   | SRV       | Relative weight among equal-priority targets.                                                             |                                                                                    |
| `port`     | SRV       | Target port number.                                                                                       |                                                                                    |
| `service`  | SRV       | Service name.                                                                                             | Prefixed with an underscore (for example, `_http`).                                |
| `protocol` | SRV       | Transport protocol.                                                                                       | Prefixed with underscore (for example, `_tcp`).                                    |
| `flag`     | CAA       | Restriction flags byte.                                                                                   | Use `0` for non-critical, `128` for critical.                                      |
| `tag`      | CAA       | Property tag: `issue`, `issuewild`, or `iodef`.                                                           |                                                                                    |

## Reference

* [v3 API reference](https://developer.godaddy.com/docs/references/rest/domains/v3)

## Next
