---
title: Managing Domains
path: tutorials/managing-domains
status: published
---

# Managing Domains

Everything about creating, reading, updating, and deleting zones. For the underlying concepts, see [Zones and Records](../concepts/zones-and-records.md).

**Base path:** `/api/v1/domains/`
**Required permission:** `domains:read`, `domains:create`, `domains:update`, `domains:delete`

## List zones

```bash
curl "https://scaidns.scailabs.ai/api/v1/domains/?page=1&page_size=50" \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

```python
import os, httpx

resp = httpx.get(
    "https://scaidns.scailabs.ai/api/v1/domains/",
    headers={"X-API-Key": os.environ["SCAIDNS_API_KEY"]},
    params={"page": 1, "page_size": 50},
)
for d in resp.json()["data"]:
    print(d["name"], d["status"])
```

```typescript
const resp = await fetch(
  "https://scaidns.scailabs.ai/api/v1/domains/?page=1&page_size=50",
  { headers: { "X-API-Key": process.env.SCAIDNS_API_KEY! } }
);
const { data } = await resp.json();
for (const d of data) console.log(d.name, d.status);
```

### Filters

| Param | Type | Notes |
|-------|------|-------|
| `page` | integer | 1-based, default 1 |
| `page_size` | integer | 1–100, default 50 |
| `status` | string | `pending_validation`, `active`, `inactive`, `deleted` |
| `domain_type` | string | `primary`, `secondary`, `reverse_ipv4`, `reverse_ipv6` |
| `dnssec_enabled` | boolean | Filter by DNSSEC state |
| `search` | string | Substring match on domain name |

## Create a zone

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/domains/ \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "example.com",
    "domain_type": "primary",
    "default_ttl": 3600,
    "description": "Main production zone"
  }'
```

```python
resp = httpx.post(
    "https://scaidns.scailabs.ai/api/v1/domains/",
    headers={"X-API-Key": os.environ["SCAIDNS_API_KEY"]},
    json={
        "name": "example.com",
        "domain_type": "primary",
        "default_ttl": 3600,
        "description": "Main production zone",
    },
)
resp.raise_for_status()
domain = resp.json()
```

```typescript
const resp = await fetch("https://scaidns.scailabs.ai/api/v1/domains/", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.SCAIDNS_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "example.com",
    domain_type: "primary",
    default_ttl: 3600,
    description: "Main production zone",
  }),
});
const domain = await resp.json();
```

### Request body

| Field | Type | Required | Notes |
|-------|------|---------|-------|
| `name` | string | Yes | Zone apex. Must be a valid DNS name |
| `domain_type` | string | Yes | `primary`, `secondary`, `reverse_ipv4`, `reverse_ipv6` |
| `default_ttl` | integer | No | Seconds; default 3600 |
| `description` | string | No | Free-form note |
| `template_id` | string | No | Apply a template after validation completes |
| `template_variables` | object | No | Variables for the template |
| `cidr` | string | No | For reverse zones — use [Reverse Zones](./reverse-zones.md) API instead |

Newly created zones are `pending_validation`. Until validated, no PowerDNS zone exists and records are not served.

## Get a zone

```bash
curl https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Returns the full zone object, including DNSSEC status and the most recent validation state.

## Update metadata

Only `description`, `default_ttl`, and `settings` are editable.

```bash
curl -X PATCH https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"default_ttl": 600, "description": "Updated note"}'
```

Renaming or changing the type requires deleting and recreating the zone — neither is editable in place.

## Delete

Soft delete (default):

```bash
curl -X DELETE https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

The domain row stays in the database with status `deleted`. The PowerDNS zone is also marked deleted but kept for recovery. Reads by ID return `404` unless you pass `?include_deleted=true`.

Hard delete (irreversible):

```bash
curl -X DELETE "https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID?hard=true" \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Removes the row and the PowerDNS zone permanently. Records, access grants, and DNSSEC keys are all discarded.

## Restore a soft-deleted zone

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID/restore \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Status flips back to whatever it was before deletion (usually `active`). Records are restored as they were.

## Get the SOA record

```bash
curl https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID/soa \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Returns SOA fields (serial, refresh, retry, expire, minimum). The serial increments automatically on zone changes — you don't edit it manually.

## Export a zone

```bash
curl https://scaidns.scailabs.ai/api/v1/domains/$DOMAIN_ID/export \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Returns a BIND-format zone file as text. Useful for backups and migrations. See [Import and Export](./import-export.md) for the full surface.

## What's next

- [Managing Records](./managing-records.md) — add and edit records.
- [Domain Validation](../concepts/validation.md) — how ownership is proven.
- [Domains reference](../reference/domains.md) — field-level endpoint docs.
