## POST /api/v2/domains/{id}/dnssec

**Add a DNSSEC record**

Add one manual DS or KEY DNSSEC record to a domain through the registrar path. Do not use this as the first choice for domains delegated to HostUp-managed nameservers (`primary.ns.hostup.se`, `secondary.ns.hostup.se`, or accepted managed aliases) when automatic DNSSEC is enabled: in that case the platform periodically verifies the hosted DNSSEC material and publishes the DS record automatically. Read `GET /api/v2/domains/{id}/dnssec-auto` for automation state and `GET /api/v2/domains/{id}/nameservers` for current delegation and `dnssecAutoWillBeBlocked`. Use this endpoint when the domain needs manual registrar data, for example an external DNS provider gives you a DS/KEY record, and `GET /api/v2/domains/{id}/dnssec` reports `actions.canAdd.allowed: true`. The request body uses public v2 camelCase field names: DS uses `keyTag` and `digestType`, while KEY uses `publicKey`. The create response may not include a persisted record ID; re-read `GET /api/v2/domains/{id}/dnssec` before deleting records.

### Related Endpoints

- `GET /api/v2/domains/{id}/dnssec`: List domain DNSSEC records
- `DELETE /api/v2/domains/{id}/dnssec/{recordId}`: Delete a DNSSEC record
- `GET /api/v2/domains/{id}`: Get domain details

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scope: `write:domains`
- `Content-Type`: application/json

### Parameters

- `id` (path, string, required): Public domain ID. Get it from GET /api/v2/domains `data[].id`. Do not invent this value; use the exact ID returned by the referenced API response. Example: `dom_01hxa3b4c5d6e7f8g9h0j1k2m3`

### Request Body

- `type` (string, required) Example: `DS`
  Allowed values: DS
- `keyTag` (string, required) Example: `2371`
- `algorithm` (string, required) Example: `13`
- `digestType` (string, required) Example: `2`
- `digest` (string, required) Example: `5A1D7C1B9E7F4E6A8C2B0D5F9A3E6C7D8B1A2C3D4E5F60718293A4B5C6D7E8F9`

### Request Examples

#### Add DS record

```bash
curl -X POST "https://cloud.hostup.se/api/v2/domains/dom_01hxa3b4c5d6e7f8g9h0j1k2m3/dnssec" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "DS",
    "keyTag": "2371",
    "algorithm": "13",
    "digestType": "2",
    "digest": "5A1D7C1B9E7F4E6A8C2B0D5F9A3E6C7D8B1A2C3D4E5F60718293A4B5C6D7E8F9"
  }'
```

```json
{
  "type": "DS",
  "keyTag": "2371",
  "algorithm": "13",
  "digestType": "2",
  "digest": "5A1D7C1B9E7F4E6A8C2B0D5F9A3E6C7D8B1A2C3D4E5F60718293A4B5C6D7E8F9"
}
```

#### Add KEY record

```bash
curl -X POST "https://cloud.hostup.se/api/v2/domains/dom_01hxa3b4c5d6e7f8g9h0j1k2m3/dnssec" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "KEY",
    "flag": "257",
    "protocol": "3",
    "algorithm": "13",
    "publicKey": "p8K3pYwQ5xvM7nR2sT4uV6wX8yZaBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789"
  }'
```

```json
{
  "type": "KEY",
  "flag": "257",
  "protocol": "3",
  "algorithm": "13",
  "publicKey": "p8K3pYwQ5xvM7nR2sT4uV6wX8yZaBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789"
}
```

### Response Schema

- `recordType` (string, required) Example: `DS`
  Allowed values: DS, KEY
- `ds` (object | null, required)
- `ds.id` (string | null, required) Example: `dsr_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `ds.keyTag` (string | null, required) Example: `2371`
- `ds.algorithm` (string | null, required) Example: `13`
- `ds.digestType` (string | null, required) Example: `2`
- `ds.digest` (string | null, required) Example: `5A1D7C1B9E7F4E6A8C2B0D5F9A3E6C7D8B1A2C3D4E5F60718293A4B5C6D7E8F9`
- `key` (object | null, required)
- `key.id` (string | null, required) Example: `dsr_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `key.flag` (string | null, required) Example: `257`
- `key.protocol` (string | null, required) Example: `3`
- `key.algorithm` (string | null, required) Example: `13`
- `key.publicKey` (string | null, required) Example: `p8K3pYwQ5xvM7nR2sT4uV6wX8yZaBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789`

### Responses

#### 201 - DNSSEC record accepted by the registrar path.
```json
{
  "recordType": "DS",
  "ds": {
    "id": null,
    "keyTag": "2371",
    "algorithm": "13",
    "digestType": "2",
    "digest": "5A1D7C1B9E7F4E6A8C2B0D5F9A3E6C7D8B1A2C3D4E5F60718293A4B5C6D7E8F9"
  },
  "key": null
}
```

#### 400 - Invalid request. The response body is an RFC 7807 Problem Details document.
```json
{
  "type": "https://developer.hostup.se/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The request body failed validation.",
  "code": "invalid_request",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z",
  "errors": [
    {
      "pointer": "/items/0/domainName",
      "detail": "`domainName` is required.",
      "code": "invalid_request"
    }
  ]
}
```

#### 401 - Unauthorized. Authentication is required.
```json
{
  "type": "https://developer.hostup.se/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required.",
  "code": "unauthorized",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 403 - Forbidden. The caller lacks a required scope or does not own the resource.
```json
{
  "type": "https://developer.hostup.se/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The caller lacks a required scope or does not own the resource.",
  "code": "forbidden",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 404 - Not found. The resource does not exist or is not owned by the caller.
```json
{
  "type": "https://developer.hostup.se/errors/not_found",
  "title": "Not found",
  "status": 404,
  "detail": "The requested resource could not be found.",
  "code": "not_found",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 429 - Rate limited. Retry after the limit resets. 429 responses include `Retry-After` seconds plus `X-RateLimit-*` headers.
```json
{
  "type": "https://developer.hostup.se/errors/rate_limit_exceeded",
  "title": "Too many requests",
  "status": 429,
  "detail": "Too many requests. Retry after the limit resets.",
  "code": "rate_limit_exceeded",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 500 - Internal error. Retry later or contact support if the issue persists.
```json
{
  "type": "https://developer.hostup.se/errors/internal_error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred. Retry later or contact support if the issue persists.",
  "code": "internal_error",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```
