# DNS Operations



This guide covers DNS operations beyond the [full-flow example](/docs/03-getting-started/03-manage-dns-records). All DNS mutation operations require domain ownership (verified via on-chain NFT ownership). The client handles authentication automatically with both `API_KEY` and `EIP712` auth types.

Quick start with curl [#quick-start-with-curl]

You can manage DNS records with just `curl` and an API key — no SDK installation required:

```bash
# List existing records (no auth needed)
curl "https://api.namefi.io/v-next/dns/records?zoneName=example.com"

# Create a CNAME record
curl -X POST "https://api.namefi.io/v-next/dns/records" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"zoneName":"example.com","type":"CNAME","name":"www","rdata":"cname.vercel-dns.com.","ttl":300}'

# Create a TXT record
curl -X POST "https://api.namefi.io/v-next/dns/records" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"zoneName":"example.com","type":"TXT","name":"_verify","rdata":"some-verification-token","ttl":300}'
```

This is the recommended approach for AI agents and scripts that need simple DNS management.

Read records [#read-records]

Fetch all DNS records for a zone:

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    import { createNamefiClient } from '@namefi/api-client';

    const client = createNamefiClient({
      authentication: {
        apiKey: process.env.NAMEFI_API_KEY!,
        type: 'API_KEY',
      },
      logger: true,
    });

    const records = await client.dnsRecords.getRecords({
      zoneName: 'example.com',
    });

    for (const r of records) {
      console.log(`${r.name} ${r.type} ${r.rdata} (TTL: ${r.ttl}, ID: ${r.id})`);
    }
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    const res = await fetch(
      'https://api.namefi.io/v-next/dns/records?zoneName=example.com',
    );
    const records = await res.json();

    for (const r of records) {
      console.log(`${r.name} ${r.type} ${r.rdata} (TTL: ${r.ttl}, ID: ${r.id})`);
    }
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    curl "https://api.namefi.io/v-next/dns/records?zoneName=example.com"
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import requests

    records = requests.get(
        "https://api.namefi.io/v-next/dns/records",
        params={"zoneName": "example.com"},
    ).json()

    for r in records:
        print(f"{r['name']} {r['type']} {r['rdata']} (TTL: {r['ttl']}, ID: {r['id']})")
    ```
  </Tab>
</CodeTabs>

Create a single record [#create-a-single-record]

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    await client.dnsRecords.createDnsRecord({
      zoneName: 'example.com',
      type: 'A',
      name: '@',
      rdata: '203.0.113.10',
      ttl: 300,
    });
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    await fetch('https://api.namefi.io/v-next/dns/records', {
      method: 'POST',
      headers: {
        'x-api-key': process.env.NAMEFI_API_KEY!,
        'content-type': 'application/json',
      },
      body: JSON.stringify({
        zoneName: 'example.com',
        type: 'A',
        name: '@',
        rdata: '203.0.113.10',
        ttl: 300,
      }),
    });
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    curl -X POST "https://api.namefi.io/v-next/dns/records" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "zoneName": "example.com",
        "type": "A",
        "name": "@",
        "rdata": "203.0.113.10",
        "ttl": 300
      }'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    requests.post(
        "https://api.namefi.io/v-next/dns/records",
        headers={"x-api-key": os.environ["NAMEFI_API_KEY"]},
        json={
            "zoneName": "example.com",
            "type": "A",
            "name": "@",
            "rdata": "203.0.113.10",
            "ttl": 300,
        },
    )
    ```
  </Tab>
</CodeTabs>

Update a single record [#update-a-single-record]

Update an existing record by its ID. Fetch records first to get the ID:

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    const records = await client.dnsRecords.getRecords({
      zoneName: 'example.com',
    });

    const apex = records.find((r) => r.name === '@' && r.type === 'A');

    if (apex) {
      await client.dnsRecords.updateRecord({
        id: apex.id,
        zoneName: 'example.com',
        rdata: '198.51.100.42',
        ttl: 600,
      });
    }
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    const BASE = 'https://api.namefi.io/v-next';
    const headers = {
      'x-api-key': process.env.NAMEFI_API_KEY!,
      'content-type': 'application/json',
    };

    const recordsRes = await fetch(`${BASE}/dns/records?zoneName=example.com`, {
      headers,
    });
    const records = await recordsRes.json();

    const apex = records.find((r: any) => r.name === '@' && r.type === 'A');

    if (apex) {
      await fetch(`${BASE}/dns/record`, {
        method: 'PUT',
        headers,
        body: JSON.stringify({
          id: apex.id,
          zoneName: 'example.com',
          rdata: '198.51.100.42',
          ttl: 600,
        }),
      });
    }
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    # Fetch records first to get the ID
    curl "https://api.namefi.io/v-next/dns/records?zoneName=example.com"

    # Update by ID
    curl -X PUT "https://api.namefi.io/v-next/dns/record" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "id": "<record-id>",
        "zoneName": "example.com",
        "rdata": "198.51.100.42",
        "ttl": 600
      }'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    BASE = "https://api.namefi.io/v-next"
    HEADERS = {"x-api-key": os.environ["NAMEFI_API_KEY"]}

    records = requests.get(
        f"{BASE}/dns/records",
        params={"zoneName": "example.com"},
        headers=HEADERS,
    ).json()

    apex = next((r for r in records if r["name"] == "@" and r["type"] == "A"), None)

    if apex:
        requests.put(
            f"{BASE}/dns/record",
            headers=HEADERS,
            json={
                "id": apex["id"],
                "zoneName": "example.com",
                "rdata": "198.51.100.42",
                "ttl": 600,
            },
        )
    ```
  </Tab>
</CodeTabs>

Delete a single record [#delete-a-single-record]

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    await client.dnsRecords.deleteRecord({
      id: apex.id,
      zoneName: 'example.com',
    });
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    await fetch('https://api.namefi.io/v-next/dns/record', {
      method: 'DELETE',
      headers: {
        'x-api-key': process.env.NAMEFI_API_KEY!,
        'content-type': 'application/json',
      },
      body: JSON.stringify({
        id: apex.id,
        zoneName: 'example.com',
      }),
    });
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    curl -X DELETE "https://api.namefi.io/v-next/dns/record" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "id": "<record-id>",
        "zoneName": "example.com"
      }'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    requests.delete(
        "https://api.namefi.io/v-next/dns/record",
        headers={"x-api-key": os.environ["NAMEFI_API_KEY"]},
        json={"id": apex["id"], "zoneName": "example.com"},
    )
    ```
  </Tab>
</CodeTabs>

Batch delete records [#batch-delete-records]

Delete multiple records at once by their IDs:

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    const records = await client.dnsRecords.getRecords({
      zoneName: 'example.com',
    });

    const txtRecords = records.filter((r) => r.type === 'TXT');

    if (txtRecords.length > 0) {
      await client.dnsRecords.deleteRecords({
        zoneName: 'example.com',
        recordsIds: txtRecords.map((r) => r.id),
      });
    }
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    const BASE = 'https://api.namefi.io/v-next';
    const headers = {
      'x-api-key': process.env.NAMEFI_API_KEY!,
      'content-type': 'application/json',
    };

    const recordsRes = await fetch(`${BASE}/dns/records?zoneName=example.com`, {
      headers,
    });
    const records = await recordsRes.json();
    const txtRecords = records.filter((r: any) => r.type === 'TXT');

    if (txtRecords.length > 0) {
      await fetch(`${BASE}/dns/records/batch`, {
        method: 'DELETE',
        headers,
        body: JSON.stringify({
          zoneName: 'example.com',
          recordsIds: txtRecords.map((r: any) => r.id),
        }),
      });
    }
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    curl -X DELETE "https://api.namefi.io/v-next/dns/records/batch" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "zoneName": "example.com",
        "recordsIds": ["<record-id-1>", "<record-id-2>"]
      }'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    BASE = "https://api.namefi.io/v-next"
    HEADERS = {"x-api-key": os.environ["NAMEFI_API_KEY"]}

    records = requests.get(
        f"{BASE}/dns/records",
        params={"zoneName": "example.com"},
        headers=HEADERS,
    ).json()
    txt_ids = [r["id"] for r in records if r["type"] == "TXT"]

    if txt_ids:
        requests.delete(
            f"{BASE}/dns/records/batch",
            headers=HEADERS,
            json={"zoneName": "example.com", "recordsIds": txt_ids},
        )
    ```
  </Tab>
</CodeTabs>

Domain parking [#domain-parking]

Park a domain to serve a default landing page. This replaces DNS records with parking records:

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    // Park a domain
    await client.dnsRecords.parkDomain({
      normalizedDomainName: 'example.com',
      overrideExistingRecords: true,
    });

    // Check if a domain is parked
    const { parked } = await client.dnsRecords.isDomainParked({
      normalizedDomainName: 'example.com',
    });

    console.log('Parked:', parked);
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    const BASE = 'https://api.namefi.io/v-next';
    const headers = {
      'x-api-key': process.env.NAMEFI_API_KEY!,
      'content-type': 'application/json',
    };

    // Park a domain
    await fetch(`${BASE}/dns/park`, {
      method: 'POST',
      headers,
      body: JSON.stringify({
        normalizedDomainName: 'example.com',
        overrideExistingRecords: true,
      }),
    });

    // Check if a domain is parked
    const res = await fetch(
      `${BASE}/dns/parked?normalizedDomainName=example.com`,
      { headers },
    );
    const { parked } = await res.json();

    console.log('Parked:', parked);
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    # Park a domain
    curl -X POST "https://api.namefi.io/v-next/dns/park" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "normalizedDomainName": "example.com",
        "overrideExistingRecords": true
      }'

    # Check if a domain is parked
    curl "https://api.namefi.io/v-next/dns/parked?normalizedDomainName=example.com" \
      -H "x-api-key: $NAMEFI_API_KEY"
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    BASE = "https://api.namefi.io/v-next"
    HEADERS = {"x-api-key": os.environ["NAMEFI_API_KEY"]}

    # Park a domain
    requests.post(
        f"{BASE}/dns/park",
        headers=HEADERS,
        json={
            "normalizedDomainName": "example.com",
            "overrideExistingRecords": True,
        },
    )

    # Check if a domain is parked
    parked = requests.get(
        f"{BASE}/dns/parked",
        params={"normalizedDomainName": "example.com"},
        headers=HEADERS,
    ).json()["parked"]

    print("Parked:", parked)
    ```
  </Tab>
</CodeTabs>

Toggle parking [#toggle-parking]

Enable or disable parking without removing existing records:

<CodeTabs items="[&#x22;Node.js SDK&#x22;, &#x22;Node.js fetch&#x22;, &#x22;cURL&#x22;, &#x22;Python&#x22;]">
  <Tab value="Node.js SDK">
    ```ts
    // Disable parking, keep existing records
    await client.dnsRecords.toggleDomainParking({
      normalizedDomainName: 'example.com',
      enableParking: false,
      overrideExistingRecords: false,
    });

    // Re-enable parking
    await client.dnsRecords.toggleDomainParking({
      normalizedDomainName: 'example.com',
      enableParking: true,
      overrideExistingRecords: false,
    });
    ```
  </Tab>

  <Tab value="Node.js fetch">
    ```ts
    const BASE = 'https://api.namefi.io/v-next';
    const headers = {
      'x-api-key': process.env.NAMEFI_API_KEY!,
      'content-type': 'application/json',
    };

    // Disable parking, keep existing records
    await fetch(`${BASE}/dns/park`, {
      method: 'PUT',
      headers,
      body: JSON.stringify({
        normalizedDomainName: 'example.com',
        enableParking: false,
        overrideExistingRecords: false,
      }),
    });

    // Re-enable parking
    await fetch(`${BASE}/dns/park`, {
      method: 'PUT',
      headers,
      body: JSON.stringify({
        normalizedDomainName: 'example.com',
        enableParking: true,
        overrideExistingRecords: false,
      }),
    });
    ```
  </Tab>

  <Tab value="cURL">
    ```bash
    # Disable parking, keep existing records
    curl -X PUT "https://api.namefi.io/v-next/dns/park" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "normalizedDomainName": "example.com",
        "enableParking": false,
        "overrideExistingRecords": false
      }'

    # Re-enable parking
    curl -X PUT "https://api.namefi.io/v-next/dns/park" \
      -H "x-api-key: $NAMEFI_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "normalizedDomainName": "example.com",
        "enableParking": true,
        "overrideExistingRecords": false
      }'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    BASE = "https://api.namefi.io/v-next"
    HEADERS = {"x-api-key": os.environ["NAMEFI_API_KEY"]}

    # Disable parking, keep existing records
    requests.put(
        f"{BASE}/dns/park",
        headers=HEADERS,
        json={
            "normalizedDomainName": "example.com",
            "enableParking": False,
            "overrideExistingRecords": False,
        },
    )

    # Re-enable parking
    requests.put(
        f"{BASE}/dns/park",
        headers=HEADERS,
        json={
            "normalizedDomainName": "example.com",
            "enableParking": True,
            "overrideExistingRecords": False,
        },
    )
    ```
  </Tab>
</CodeTabs>

Supported record types [#supported-record-types]

The API supports standard DNS record types including:

`A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`, `SOA`

Notes [#notes]

* All mutation operations (`create`, `update`, `delete`, `park`, `toggleParking`) use EIP-712 signing under the hood. The client handles this transparently.
* `updateRecord` and `updateRecords` require the record `id` — use `getRecords` first.
* `overrideExistingRecords` on parking operations controls whether current records are replaced or preserved.
* All batch operations are scoped to a single `zoneName` per request.

Troubleshooting [#troubleshooting]

UNAUTHORIZED (401) on write operations [#unauthorized-401-on-write-operations]

* **API key not associated with domain owner:** The API key must be generated from the wallet that owns the domain on-chain. Go to [API Keys management](https://namefi.io/profile?tab=api-keys), connect the wallet that holds the domain NFT, and generate a new key.
* **Expired or revoked key:** Generate a fresh API key.
* **Wrong base URL:** Use `https://api.namefi.io/v-next/` (production) or `https://backend.astra.namefi.io/v-next/` (SDK default). Both point to the same backend.

FORBIDDEN (403) on write operations [#forbidden-403-on-write-operations]

* Your API key is valid but the authenticated wallet does not own the target domain. Verify ownership at [My Domains](https://namefi.io/domains).

SDK alternative: direct HTTP [#sdk-alternative-direct-http]

If you encounter issues with the `@namefi/api-client` SDK, you can always fall back to direct HTTP with `curl` or any HTTP client. Pass your API key as the `x-api-key` header. See the [curl quick start](#quick-start-with-curl) above.
