---
title: DNSSEC Reference
path: reference/dnssec
status: published
---

# DNSSEC Reference

DNSSEC lifecycle and key management endpoints. For concepts, see [DNSSEC](../concepts/dnssec.md). For a step-by-step guide, see [Enabling DNSSEC](../tutorials/enable-dnssec.md).

**Base path:** `/api/v1/domains/{domain_id}/dnssec`
**Required permission:** `dnssec:read`, `dnssec:enable`, `dnssec:disable`, `dnssec:rotate`

## GET /api/v1/domains/{domain_id}/dnssec

Get the current DNSSEC state for a zone.

**Response:**

```json
{
  "enabled": true,
  "status": "active",
  "algorithm": 13,
  "ksk": [
    {
      "key_tag": 12345,
      "algorithm": 13,
      "public_key": "base64...",
      "key_type": "KSK",
      "created_at": "2026-04-23T10:00:00Z",
      "expires_at": "2027-04-23T10:00:00Z",
      "active": true
    }
  ],
  "zsk": [
    {
      "key_tag": 67890,
      "algorithm": 13,
      "public_key": "base64...",
      "key_type": "ZSK",
      "created_at": "2026-04-23T10:00:00Z",
      "expires_at": "2026-05-23T10:00:00Z",
      "active": true
    }
  ],
  "ds_records": [
    {
      "key_tag": 12345,
      "algorithm": 13,
      "digest_type": 2,
      "digest": "A1B2C3..."
    }
  ]
}
```

Possible `status` values: `disabled`, `pending_ds`, `active`, `rotating_ksk`, `rotating_zsk`.

## POST /api/v1/domains/{domain_id}/dnssec/enable

Enable DNSSEC for a zone. Generates KSK and ZSK, signs the zone, and returns DS records to publish at the registrar.

**Request:**

| Field | Type | Required | Notes |
|-------|------|---------|-------|
| `algorithm` | integer | No | DNSSEC algorithm number; default 13 |

Supported algorithms: `8` (RSA/SHA-256), `10` (RSA/SHA-512), `13` (ECDSA P-256), `14` (ECDSA P-384), `15` (Ed25519).

**Response:**

```json
{
  "domain_id": "d_abc123",
  "action": "enable",
  "message": "DNSSEC enabled",
  "ksk": {...},
  "zsk": {...},
  "ds_records": [...]
}
```

**Errors:**

- `409` — DNSSEC already enabled on this zone.
- `400` — Unsupported algorithm.

## POST /api/v1/domains/{domain_id}/dnssec/disable

Disable DNSSEC and remove all signing keys.

**Response:**

```json
{
  "domain_id": "d_abc123",
  "action": "disable",
  "message": "DNSSEC disabled"
}
```

**Important:** Remove DS records at the registrar *before* calling this, or resolvers will see broken DNSSEC and return SERVFAIL.

## POST /api/v1/domains/{domain_id}/dnssec/rotate-zsk

Rotate the Zone Signing Key. Transparent to registrars; ScaiDNS manages the rollover automatically.

**Response:** New ZSK info, old ZSK marked for retirement.

## POST /api/v1/domains/{domain_id}/dnssec/rotate-ksk

Rotate the Key Signing Key. Returns the new DS record that needs to be published at the registrar. Status changes to `rotating_ksk` until `/confirm-ds-published` is called.

**Response:**

```json
{
  "domain_id": "d_abc123",
  "action": "rotate-ksk",
  "old_key": {"key_tag": 12345, ...},
  "new_key": {"key_tag": 23456, ...},
  "ds_records": [
    {"key_tag": 23456, "algorithm": 13, "digest_type": 2, "digest": "..."}
  ]
}
```

## POST /api/v1/domains/{domain_id}/dnssec/confirm-ds-published

Record that DS records have been published at the registrar. Transitions the zone out of `pending_ds` or `rotating_ksk`.

**Request:**

```json
{
  "ds_records": [
    {"key_tag": 12345, "algorithm": 13, "digest_type": 2, "digest": "A1B2C3..."}
  ]
}
```

**Response:**

```json
{
  "domain_id": "d_abc123",
  "action": "confirm-ds-published",
  "message": "DS publication confirmed"
}
```

ScaiDNS validates the provided DS records against the zone's current KSKs. Mismatches return `400`.

## POST /api/v1/domains/{domain_id}/dnssec/sync

Force a sync between ScaiDNS and PowerDNS for DNSSEC state. Use if the two get out of step (rare).

**Response:** Current state after sync.

## Algorithms reference

| Number | Name | Recommendation |
|--------|------|----------------|
| `8` | RSA/SHA-256 | Legacy; avoid for new zones |
| `10` | RSA/SHA-512 | Rarely used |
| `13` | ECDSA P-256 / SHA-256 | **Default choice** |
| `14` | ECDSA P-384 / SHA-384 | Larger signatures; usually unnecessary |
| `15` | Ed25519 | Modern; verify TLD/registrar support |

## Error codes

| Status | Meaning |
|--------|---------|
| `400` | Unsupported algorithm; invalid DS record; confirmation of non-matching DS |
| `403` | Caller lacks `dnssec:*` permission |
| `404` | Domain not found |
| `409` | Invalid state transition (e.g., enable when already enabled) |

## Related

- [DNSSEC concepts](../concepts/dnssec.md)
- [Enabling DNSSEC guide](../tutorials/enable-dnssec.md)
