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



## 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:

<Tabs items={['curl', 'Node', 'Python', 'Go']}>
  <>
    <Tab value="curl">
      ```bash
      # 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"
      ```
    </Tab>

    <Tab value="Node">
      ```js
      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);
      ```
    </Tab>

    <Tab value="Python">
      ```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"])
      ```
    </Tab>

    <Tab value="Go">
      ```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)
      }
      ```
    </Tab>
  </>
</Tabs>

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:

<Tabs items={['curl', 'Node', 'Python', 'Go']}>
  <>
    <Tab value="curl">
      ```bash
      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 }'
      ```
    </Tab>

    <Tab value="Node">
      ```js
      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);
      ```
    </Tab>

    <Tab value="Python">
      ```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"])
      ```
    </Tab>

    <Tab value="Go">
      ```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)
      }
      ```
    </Tab>
  </>
</Tabs>

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.

<Callout type="warning" title="Not idempotent">
  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).
</Callout>

## 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:

<Tabs items={['curl', 'Node', 'Python', 'Go']}>
  <>
    <Tab value="curl">
      ```bash
      curl -s -X DELETE "https://api.godaddy.com/v3/domains/zones/example.com/dns-records/$RECORD_ID" \
        -H "Authorization: Bearer $GODADDY_PAT"
      ```
    </Tab>

    <Tab value="Node">
      ```js
      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
      ```
    </Tab>

    <Tab value="Python">
      ```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
      ```
    </Tab>

    <Tab value="Go">
      ```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
      }
      ```
    </Tab>
  </>
</Tabs>

A successful response returns `204` with no body.

<Callout type="warning" title="Not idempotent">
  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`.
</Callout>

## 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:

<Tabs items={['curl', 'Node', 'Python', 'Go']}>
  <>
    <Tab value="curl">
      ```bash
      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"]'
      ```
    </Tab>

    <Tab value="Node">
      ```js
      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
      ```
    </Tab>

    <Tab value="Python">
      ```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
      ```
    </Tab>

    <Tab value="Go">
      ```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
      }
      ```
    </Tab>
  </>
</Tabs>

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.

<Callout type="warning" title="Authoritative DNS hand-off">
  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.
</Callout>

## 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

<Cards>
  <Card title="Update contacts" description="Change registrant, admin, billing, or tech contacts." href="/docs/api-users/manage-domains/update-contacts" />

  <Card title="Pagination" description="Walk paginated v1 list endpoints with limit and marker." href="/docs/api-users/pagination" />
</Cards>
