# Registros DNS

> Lista, crea, modifica y borra los registros DNS de una zona, en bloque o en un lote, e importa los registros existentes.

Registros DNS de una zona. Los A/AAAA/CNAME pueden ir con proxy: el nombre responde entonces con las direcciones del borde y el contenido del registro pasa a ser el origen. En una zona externa solo se admiten A/AAAA/CNAME con proxy (son los sitios que sirve el borde). Cada escritura crea una versión de configuración.

| Operación | Ruta |
|---|---|
| [Listar registros](https://developers.openwaf.dev/es/api/dns-records/#list-records) | `GET /v1/orgs/{org}/zones/{zone}/records` |
| [Crear un registro](https://developers.openwaf.dev/es/api/dns-records/#create-record) | `POST /v1/orgs/{org}/zones/{zone}/records` |
| [Crear registros en bloque](https://developers.openwaf.dev/es/api/dns-records/#bulk-create-records) | `POST /v1/orgs/{org}/zones/{zone}/records/bulk` |
| [Lote de registros](https://developers.openwaf.dev/es/api/dns-records/#batch-records) | `POST /v1/orgs/{org}/zones/{zone}/records/batch` |
| [Ver un registro](https://developers.openwaf.dev/es/api/dns-records/#get-record) | `GET /v1/orgs/{org}/zones/{zone}/records/{record}` |
| [Modificar un registro](https://developers.openwaf.dev/es/api/dns-records/#update-record) | `PATCH /v1/orgs/{org}/zones/{zone}/records/{record}` |
| [Borrar un registro](https://developers.openwaf.dev/es/api/dns-records/#delete-record) | `DELETE /v1/orgs/{org}/zones/{zone}/records/{record}` |
| [Buscar los registros existentes](https://developers.openwaf.dev/es/api/dns-records/#list-import-candidates) | `GET /v1/orgs/{org}/zones/{zone}/import` |
| [Leer un fichero de zona BIND](https://developers.openwaf.dev/es/api/dns-records/#parse-bind-zone) | `POST /v1/orgs/{org}/zones/{zone}/import/bind` |
| [Ver las respuestas DNS del borde](https://developers.openwaf.dev/es/api/dns-records/#get-dns-answers) | `GET /v1/orgs/{org}/zones/{zone}/dns/answers` |

## Listar registros

```http
GET /v1/orgs/{org}/zones/{zone}/records
```

Lista los registros DNS de una zona con sus ids.

**Rol necesario:** `readonly` o superior.

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |

#### Respuesta

- `200`: Devuelve `items`, un array de [Record](https://developers.openwaf.dev/es/api/schemas/#record).

| Campo | Tipo | Descripción |
|---|---|---|
| `items[].id` | string (uuid) | Id. |
| `items[].org_id` | string (uuid) | Id de la organización. |
| `items[].zone_id` | string (uuid) | Id de la zona. |
| `items[].type` | string |  |
| `items[].name` | string | Nombre completo sin punto final. |
| `items[].content` | string | Contenido de origen. |
| `items[].ttl` | integer | TTL en segundos. |
| `items[].priority` | integer | Prioridad de MX y SRV (null en los demás tipos). |
| `items[].proxied` | boolean | Servido a través del borde de OpenWAF. |
| `items[].comment` | string | Comentario (vacío si no hay). |
| `items[].tags` | array de string | Etiquetas (lista vacía si no hay). |
| `items[].created_at` | string (date-time) | Fecha de creación. |
| `items[].updated_at` | string (date-time) | Último cambio. |

#### Ejemplo

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.listRecords({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.list_records(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d")
```



```json
{
  "items": [
    {
      "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
      "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "type": "A",
      "name": "www.example.com",
      "content": "203.0.113.10",
      "ttl": 300,
      "priority": null,
      "proxied": true,
      "comment": "Web servers",
      "tags": [
        "web"
      ],
      "created_at": "2026-03-02T10:25:00Z",
      "updated_at": "2026-10-27T09:00:00Z"
    }
  ]
}
```

## Crear un registro

```http
POST /v1/orgs/{org}/zones/{zone}/records
```

Crea un registro DNS. En una zona externa solo se admiten A/AAAA/CNAME con proxy (son los sitios que se publican al borde); no se publican en el DNS, que sigue en el otro proveedor.

**Rol necesario:** `tech` o superior.

**Controles de cambio:** [`dry_run`](https://developers.openwaf.dev/es/api/#configuration-changes) · [`If-Match`](https://developers.openwaf.dev/es/api/#configuration-changes) (opcional) · [`X-Change-Reason`](https://developers.openwaf.dev/es/api/#configuration-changes) (obligatorio)

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `X-Change-Reason` | cabecera | string | Sí | Motivo del cambio: 1-500 caracteres UTF-8 tras recortar espacios, sin caracteres de control. Si falta o no es válido: 422 `reason_required`. De 1 a 500 caracteres. |
| `If-Match` | cabecera | string | No | Versión de configuración esperada, p. ej. `"12"` (se admite `W/`). Si no es la actual: 412 `version_conflict`. |
| `dry_run` | consulta | string | No | `1`/`true` simula el cambio: responde 200 con el plan (`Applied`) y no guarda nada. Admite `0`/`false`; otro valor: 400. Uno de `1`, `true`, `0`, `false`. |

#### Cuerpo de la petición

Tipo de contenido `application/json`. Esquema: [RecordInput](https://developers.openwaf.dev/es/api/schemas/#record-input).

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `type` | string | Sí | Uno de `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`. |
| `name` | string | No | `@`, relativo (`www`) o nombre completo; `*` para comodín. Por defecto `@`. |
| `content` | string | Sí | A/AAAA: dirección. CNAME/NS/MX: nombre de host. TXT: texto sin comillas (se trocea en cadenas de 255). SRV: `peso puerto destino`. CAA: `flags etiqueta "valor"`. |
| `ttl` | integer | No | TTL en segundos. Por defecto `3600`. De 60 a 86400. |
| `priority` | integer | No | Obligatoria en MX y SRV; prohibida en el resto. De 0 a 65535. |
| `proxied` | boolean | No | Solo A/AAAA/CNAME. El nombre responde con las IPs del borde (TTL 300) y el contenido se guarda como origen. Todos los A/AAAA/CNAME de un nombre comparten el valor. Un CNAME sin proxy en el apex se publica como ALIAS (aplanado). Por defecto `false`. |
| `comment` | string | No | Atributo del registro (no se publica en el DNS; entra en las versiones de la zona). Sin caracteres de control. Como mucho 100 caracteres. |
| `tags` | array de string | No | Atributo del registro, como el comentario. Se pasan a minúsculas y se quitan las repetidas. Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |

#### Respuesta

- `200`: Con `dry_run=1`, el plan del cambio ([Applied](https://developers.openwaf.dev/es/api/schemas/#applied)); no se guarda nada.
- `201`: Creado y publicado. Devuelve [Record](https://developers.openwaf.dev/es/api/schemas/#record).

| Campo | Tipo | Descripción |
|---|---|---|
| `id` | string (uuid) | Id. |
| `org_id` | string (uuid) | Id de la organización. |
| `zone_id` | string (uuid) | Id de la zona. |
| `type` | string |  |
| `name` | string | Nombre completo sin punto final. |
| `content` | string | Contenido de origen. |
| `ttl` | integer | TTL en segundos. |
| `priority` | integer | Prioridad de MX y SRV (null en los demás tipos). |
| `proxied` | boolean | Servido a través del borde de OpenWAF. |
| `comment` | string | Comentario (vacío si no hay). |
| `tags` | array de string | Etiquetas (lista vacía si no hay). |
| `created_at` | string (date-time) | Fecha de creación. |
| `updated_at` | string (date-time) | Último cambio. |

Cabeceras de la respuesta: `ETag`, `X-Config-Version`.

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `409` | Zona desactivada o `zone_merged`. |
| `412` | `version_conflict`: If-Match no coincide con la versión actual. |
| `422` | Error de validación (`invalid`) o motivo ausente/no válido (`reason_required`). |

#### Ejemplo

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Add the API host" \
  -H 'If-Match: "12"' \
  -H "Content-Type: application/json" \
  --data '{
    "type": "A",
    "name": "api",
    "content": "203.0.113.20",
    "proxied": true
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.createRecord({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  body: {
    type: "A",
    name: "api",
    content: "203.0.113.20",
    proxied: true
  }
}, {
  reason: "Add the API host",
  ifMatch: 12
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.create_record(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    body={
        "type": "A",
        "name": "api",
        "content": "203.0.113.20",
        "proxied": True
    },
    reason="Add the API host",
    if_match=12,
)
```



```json
{
  "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  "type": "A",
  "name": "www.example.com",
  "content": "203.0.113.10",
  "ttl": 300,
  "priority": null,
  "proxied": true,
  "comment": "Web servers",
  "tags": [
    "web"
  ],
  "created_at": "2026-03-02T10:25:00Z",
  "updated_at": "2026-10-27T09:00:00Z"
}
```

## Crear registros en bloque

```http
POST /v1/orgs/{org}/zones/{zone}/records/bulk
```

Crea hasta 1000 registros de forma atómica, todos o ninguno, en una sola versión (por ejemplo una importación revisada). Un error de validación indica el registro en `field` (`records[i].campo`).

**Rol necesario:** `tech` o superior.

**Controles de cambio:** [`dry_run`](https://developers.openwaf.dev/es/api/#configuration-changes) · [`If-Match`](https://developers.openwaf.dev/es/api/#configuration-changes) (opcional) · [`X-Change-Reason`](https://developers.openwaf.dev/es/api/#configuration-changes) (obligatorio)

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `X-Change-Reason` | cabecera | string | Sí | Motivo del cambio: 1-500 caracteres UTF-8 tras recortar espacios, sin caracteres de control. Si falta o no es válido: 422 `reason_required`. De 1 a 500 caracteres. |
| `If-Match` | cabecera | string | No | Versión de configuración esperada, p. ej. `"12"` (se admite `W/`). Si no es la actual: 412 `version_conflict`. |
| `dry_run` | consulta | string | No | `1`/`true` simula el cambio: responde 200 con el plan (`Applied`) y no guarda nada. Admite `0`/`false`; otro valor: 400. Uno de `1`, `true`, `0`, `false`. |

#### Cuerpo de la petición

Tipo de contenido `application/json`.

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `records` | array de [RecordInput](https://developers.openwaf.dev/es/api/schemas/#record-input) | Sí | Como mucho 1000 elementos. |
| `records[].type` | string | Sí | Uno de `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`. |
| `records[].name` | string | No | `@`, relativo (`www`) o nombre completo; `*` para comodín. Por defecto `@`. |
| `records[].content` | string | Sí | A/AAAA: dirección. CNAME/NS/MX: nombre de host. TXT: texto sin comillas (se trocea en cadenas de 255). SRV: `peso puerto destino`. CAA: `flags etiqueta "valor"`. |
| `records[].ttl` | integer | No | TTL en segundos. Por defecto `3600`. De 60 a 86400. |
| `records[].priority` | integer | No | Obligatoria en MX y SRV; prohibida en el resto. De 0 a 65535. |
| `records[].proxied` | boolean | No | Solo A/AAAA/CNAME. El nombre responde con las IPs del borde (TTL 300) y el contenido se guarda como origen. Todos los A/AAAA/CNAME de un nombre comparten el valor. Un CNAME sin proxy en el apex se publica como ALIAS (aplanado). Por defecto `false`. |
| `records[].comment` | string | No | Atributo del registro (no se publica en el DNS; entra en las versiones de la zona). Sin caracteres de control. Como mucho 100 caracteres. |
| `records[].tags` | array de string | No | Atributo del registro, como el comentario. Se pasan a minúsculas y se quitan las repetidas. Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |

#### Respuesta

- `200`: Con `dry_run=1`, el plan del cambio ([Applied](https://developers.openwaf.dev/es/api/schemas/#applied)); no se guarda nada.
- `201`: Creados (una sola versión). Devuelve `items`, un array de [Record](https://developers.openwaf.dev/es/api/schemas/#record).

| Campo | Tipo | Descripción |
|---|---|---|
| `items[].id` | string (uuid) | Id. |
| `items[].org_id` | string (uuid) | Id de la organización. |
| `items[].zone_id` | string (uuid) | Id de la zona. |
| `items[].type` | string |  |
| `items[].name` | string | Nombre completo sin punto final. |
| `items[].content` | string | Contenido de origen. |
| `items[].ttl` | integer | TTL en segundos. |
| `items[].priority` | integer | Prioridad de MX y SRV (null en los demás tipos). |
| `items[].proxied` | boolean | Servido a través del borde de OpenWAF. |
| `items[].comment` | string | Comentario (vacío si no hay). |
| `items[].tags` | array de string | Etiquetas (lista vacía si no hay). |
| `items[].created_at` | string (date-time) | Fecha de creación. |
| `items[].updated_at` | string (date-time) | Último cambio. |

Cabeceras de la respuesta: `ETag`, `X-Config-Version`.

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `409` | `zone_merged`: la zona está fusionada en otra (solo lectura hasta que se separe o se purgue). |
| `412` | `version_conflict`: If-Match no coincide con la versión actual. |
| `422` | Error de validación (`field` indica `records[i].campo`) o `reason_required`. |

#### Ejemplo

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records/bulk" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Import reviewed records" \
  -H "Content-Type: application/json" \
  --data '{
    "records": [
      {
        "type": "A",
        "name": "@",
        "content": "203.0.113.10",
        "proxied": true
      },
      {
        "type": "MX",
        "name": "@",
        "content": "mail.example.com",
        "priority": 10
      }
    ]
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.bulkCreateRecords({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  body: {
    records: [
      {
        type: "A",
        name: "@",
        content: "203.0.113.10",
        proxied: true
      },
      {
        type: "MX",
        name: "@",
        content: "mail.example.com",
        priority: 10
      }
    ]
  }
}, {
  reason: "Import reviewed records"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.bulk_create_records(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    body={
        "records": [
            {
                "type": "A",
                "name": "@",
                "content": "203.0.113.10",
                "proxied": True
            },
            {
                "type": "MX",
                "name": "@",
                "content": "mail.example.com",
                "priority": 10
            }
        ]
    },
    reason="Import reviewed records",
)
```



```json
{
  "items": [
    {
      "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
      "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "type": "A",
      "name": "www.example.com",
      "content": "203.0.113.10",
      "ttl": 300,
      "priority": null,
      "proxied": true,
      "comment": "Web servers",
      "tags": [
        "web"
      ],
      "created_at": "2026-03-02T10:25:00Z",
      "updated_at": "2026-10-27T09:00:00Z"
    }
  ]
}
```

## Lote de registros

```http
POST /v1/orgs/{org}/zones/{zone}/records/batch
```

Crea, modifica y borra registros como un único cambio, todo o nada, con una sola versión, un solo motivo y una entrada de auditoría por registro. Activar o desactivar el proxy de un A/AAAA/CNAME cambia también los demás A/AAAA/CNAME del mismo nombre que no estén en el lote. La respuesta (`200`) es el plan del cambio más los registros de la zona resultantes.

**Rol necesario:** `tech` o superior.

**Controles de cambio:** [`dry_run`](https://developers.openwaf.dev/es/api/#configuration-changes) · [`If-Match`](https://developers.openwaf.dev/es/api/#configuration-changes) (opcional) · [`X-Change-Reason`](https://developers.openwaf.dev/es/api/#configuration-changes) (obligatorio)

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `X-Change-Reason` | cabecera | string | Sí | Motivo del cambio: 1-500 caracteres UTF-8 tras recortar espacios, sin caracteres de control. Si falta o no es válido: 422 `reason_required`. De 1 a 500 caracteres. |
| `If-Match` | cabecera | string | No | Versión de configuración esperada, p. ej. `"12"` (se admite `W/`). Si no es la actual: 412 `version_conflict`. |
| `dry_run` | consulta | string | No | `1`/`true` simula el cambio: responde 200 con el plan (`Applied`) y no guarda nada. Admite `0`/`false`; otro valor: 400. Uno de `1`, `true`, `0`, `false`. |

#### Cuerpo de la petición

Tipo de contenido `application/json`. Esquema: [RecordBatch](https://developers.openwaf.dev/es/api/schemas/#record-batch).

Hasta 500 operaciones en total. Cada registro se actualiza o borra una sola vez. Se aplican los borrados, luego las actualizaciones y luego las altas; las reglas de convivencia se comprueban sobre el estado final.

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `create` | array de [RecordInput](https://developers.openwaf.dev/es/api/schemas/#record-input) | No |  |
| `create[].type` | string | Sí | Uno de `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`. |
| `create[].name` | string | No | `@`, relativo (`www`) o nombre completo; `*` para comodín. Por defecto `@`. |
| `create[].content` | string | Sí | A/AAAA: dirección. CNAME/NS/MX: nombre de host. TXT: texto sin comillas (se trocea en cadenas de 255). SRV: `peso puerto destino`. CAA: `flags etiqueta "valor"`. |
| `create[].ttl` | integer | No | TTL en segundos. Por defecto `3600`. De 60 a 86400. |
| `create[].priority` | integer | No | Obligatoria en MX y SRV; prohibida en el resto. De 0 a 65535. |
| `create[].proxied` | boolean | No | Solo A/AAAA/CNAME. El nombre responde con las IPs del borde (TTL 300) y el contenido se guarda como origen. Todos los A/AAAA/CNAME de un nombre comparten el valor. Un CNAME sin proxy en el apex se publica como ALIAS (aplanado). Por defecto `false`. |
| `create[].comment` | string | No | Atributo del registro (no se publica en el DNS; entra en las versiones de la zona). Sin caracteres de control. Como mucho 100 caracteres. |
| `create[].tags` | array de string | No | Atributo del registro, como el comentario. Se pasan a minúsculas y se quitan las repetidas. Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |
| `update` | array de objeto | No |  |
| `update[].id` | string (uuid) | Sí | Id. |
| `update[].type` | string | No |  |
| `update[].name` | string | No | Nombre. |
| `update[].content` | string | No |  |
| `update[].ttl` | integer | No | TTL en segundos. |
| `update[].priority` | integer o null | No | Prioridad de MX y SRV (null en los demás tipos). |
| `update[].proxied` | boolean | No | Servido a través del borde de OpenWAF. |
| `update[].comment` | string | No | Como mucho 100 caracteres. |
| `update[].tags` | array de string | No | Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |
| `delete` | array de string (uuid) | No |  |

#### Respuesta

- `200`: Aplicado (o simulado con `dry_run`). Devuelve [BatchResult](https://developers.openwaf.dev/es/api/schemas/#batch-result).

| Campo | Tipo | Descripción |
|---|---|---|
| `dry_run` | boolean | `true` en una simulación. |
| `from_version` | integer | Versión actual antes del cambio. |
| `to_version` | integer | Versión que crea el cambio (la misma si no cambia nada). |
| `diff` | [Diff](https://developers.openwaf.dev/es/api/schemas/#diff) | Cambios. |
| `warnings` | array de string | Avisos (el cambio sigue siendo válido). |
| `records` | array de [Record](https://developers.openwaf.dev/es/api/schemas/#record) | Registros de la zona tras el cambio (simulado con `dry_run`). |

Cabeceras de la respuesta: `ETag`, `X-Config-Version`.

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `409` | Zona desactivada o `zone_merged`. |
| `412` | `version_conflict`: If-Match no coincide con la versión actual. |
| `422` | Error de validación (`field` indica la operación: `create[i].campo`, `update[i].campo`, `delete[i]`; vacío si el lote está vacío o supera 500 operaciones) o `reason_required`. |

#### Ejemplo

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records/batch?dry_run=1" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Move the site to the new origin" \
  -H "Content-Type: application/json" \
  --data '{
    "create": [
      {
        "type": "CNAME",
        "name": "shop",
        "content": "shops.example.net",
        "proxied": true
      }
    ],
    "update": [
      {
        "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
        "content": "203.0.113.30"
      }
    ],
    "delete": [
      "1b3d5f7a-9c2e-4a6b-8d0f-2a4c6e8b0d2f"
    ]
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.batchRecords({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  body: {
    create: [
      {
        type: "CNAME",
        name: "shop",
        content: "shops.example.net",
        proxied: true
      }
    ],
    update: [
      {
        id: "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
        content: "203.0.113.30"
      }
    ],
    delete: [
      "1b3d5f7a-9c2e-4a6b-8d0f-2a4c6e8b0d2f"
    ]
  }
}, {
  reason: "Move the site to the new origin",
  dryRun: true
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.batch_records(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    body={
        "create": [
            {
                "type": "CNAME",
                "name": "shop",
                "content": "shops.example.net",
                "proxied": True
            }
        ],
        "update": [
            {
                "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
                "content": "203.0.113.30"
            }
        ],
        "delete": [
            "1b3d5f7a-9c2e-4a6b-8d0f-2a4c6e8b0d2f"
        ]
    },
    reason="Move the site to the new origin",
    dry_run=True,
)
```



```json
{
  "dry_run": false,
  "from_version": 12,
  "to_version": 12,
  "diff": {
    "from": 0,
    "to": 0,
    "changes": [
      {
        "path": "rules[id=12]",
        "op": "add",
        "from": "example",
        "to": "example"
      }
    ]
  },
  "warnings": [],
  "records": [
    {
      "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
      "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "type": "A",
      "name": "www.example.com",
      "content": "203.0.113.10",
      "ttl": 300,
      "priority": null,
      "proxied": true,
      "comment": "Web servers",
      "tags": [
        "web"
      ],
      "created_at": "2026-03-02T10:25:00Z",
      "updated_at": "2026-10-27T09:00:00Z"
    }
  ]
}
```

## Ver un registro

```http
GET /v1/orgs/{org}/zones/{zone}/records/{record}
```

Devuelve un registro. En un registro con proxy, `content` es el origen.

**Rol necesario:** `readonly` o superior.

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `record` | ruta | string (uuid) | Sí | Id del registro (consulta [Listar registros](https://developers.openwaf.dev/es/api/dns-records/#list-records)). |

#### Respuesta

- `200`: Devuelve [Record](https://developers.openwaf.dev/es/api/schemas/#record).

| Campo | Tipo | Descripción |
|---|---|---|
| `id` | string (uuid) | Id. |
| `org_id` | string (uuid) | Id de la organización. |
| `zone_id` | string (uuid) | Id de la zona. |
| `type` | string |  |
| `name` | string | Nombre completo sin punto final. |
| `content` | string | Contenido de origen. |
| `ttl` | integer | TTL en segundos. |
| `priority` | integer | Prioridad de MX y SRV (null en los demás tipos). |
| `proxied` | boolean | Servido a través del borde de OpenWAF. |
| `comment` | string | Comentario (vacío si no hay). |
| `tags` | array de string | Etiquetas (lista vacía si no hay). |
| `created_at` | string (date-time) | Fecha de creación. |
| `updated_at` | string (date-time) | Último cambio. |

#### Errores

| Estado | Descripción |
|---|---|
| `404` | No existe o el token no lo ve (`not_found`). |

#### Ejemplo

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records/0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.getRecord({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  record: "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.get_record(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    record="0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
)
```



```json
{
  "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  "type": "A",
  "name": "www.example.com",
  "content": "203.0.113.10",
  "ttl": 300,
  "priority": null,
  "proxied": true,
  "comment": "Web servers",
  "tags": [
    "web"
  ],
  "created_at": "2026-03-02T10:25:00Z",
  "updated_at": "2026-10-27T09:00:00Z"
}
```

## Modificar un registro

```http
PATCH /v1/orgs/{org}/zones/{zone}/records/{record}
```

Cambia campos de un registro; los campos ausentes conservan su valor.

**Rol necesario:** `tech` o superior.

**Controles de cambio:** [`dry_run`](https://developers.openwaf.dev/es/api/#configuration-changes) · [`If-Match`](https://developers.openwaf.dev/es/api/#configuration-changes) (opcional) · [`X-Change-Reason`](https://developers.openwaf.dev/es/api/#configuration-changes) (obligatorio)

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `record` | ruta | string (uuid) | Sí | Id del registro (consulta [Listar registros](https://developers.openwaf.dev/es/api/dns-records/#list-records)). |
| `X-Change-Reason` | cabecera | string | Sí | Motivo del cambio: 1-500 caracteres UTF-8 tras recortar espacios, sin caracteres de control. Si falta o no es válido: 422 `reason_required`. De 1 a 500 caracteres. |
| `If-Match` | cabecera | string | No | Versión de configuración esperada, p. ej. `"12"` (se admite `W/`). Si no es la actual: 412 `version_conflict`. |
| `dry_run` | consulta | string | No | `1`/`true` simula el cambio: responde 200 con el plan (`Applied`) y no guarda nada. Admite `0`/`false`; otro valor: 400. Uno de `1`, `true`, `0`, `false`. |

#### Cuerpo de la petición

Tipo de contenido `application/json`. Esquema: [RecordPatch](https://developers.openwaf.dev/es/api/schemas/#record-patch).

Campos que cambian; los ausentes se conservan.

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `type` | string | No |  |
| `name` | string | No | Nombre. |
| `content` | string | No |  |
| `ttl` | integer | No | TTL en segundos. |
| `priority` | integer o null | No | Prioridad de MX y SRV (null en los demás tipos). |
| `proxied` | boolean | No | Servido a través del borde de OpenWAF. |
| `comment` | string | No | Como mucho 100 caracteres. |
| `tags` | array de string | No | Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |

#### Respuesta

- `200`: Registro modificado (con X-Config-Version y ETag) o, con `dry_run`, el plan (`Applied`). Devuelve [Record](https://developers.openwaf.dev/es/api/schemas/#record) o [Applied](https://developers.openwaf.dev/es/api/schemas/#applied).

| Campo | Tipo | Descripción |
|---|---|---|
| `id` | string (uuid) | Id. |
| `org_id` | string (uuid) | Id de la organización. |
| `zone_id` | string (uuid) | Id de la zona. |
| `type` | string |  |
| `name` | string | Nombre completo sin punto final. |
| `content` | string | Contenido de origen. |
| `ttl` | integer | TTL en segundos. |
| `priority` | integer | Prioridad de MX y SRV (null en los demás tipos). |
| `proxied` | boolean | Servido a través del borde de OpenWAF. |
| `comment` | string | Comentario (vacío si no hay). |
| `tags` | array de string | Etiquetas (lista vacía si no hay). |
| `created_at` | string (date-time) | Fecha de creación. |
| `updated_at` | string (date-time) | Último cambio. |

Cabeceras de la respuesta: `ETag`, `X-Config-Version`.

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `409` | `zone_merged`: la zona está fusionada en otra (solo lectura hasta que se separe o se purgue). |
| `412` | `version_conflict`: If-Match no coincide con la versión actual. |
| `422` | Error de validación (`invalid`) o motivo ausente/no válido (`reason_required`). |

#### Ejemplo

**curl**


```sh
curl -X PATCH "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records/0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Point www at the new origin" \
  -H 'If-Match: "12"' \
  -H "Content-Type: application/json" \
  --data '{
    "content": "203.0.113.30"
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.updateRecord({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  record: "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
  body: {
    content: "203.0.113.30"
  }
}, {
  reason: "Point www at the new origin",
  ifMatch: 12
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.update_record(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    record="0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
    body={
        "content": "203.0.113.30"
    },
    reason="Point www at the new origin",
    if_match=12,
)
```



```json
{
  "id": "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  "type": "A",
  "name": "www.example.com",
  "content": "203.0.113.10",
  "ttl": 300,
  "priority": null,
  "proxied": true,
  "comment": "Web servers",
  "tags": [
    "web"
  ],
  "created_at": "2026-03-02T10:25:00Z",
  "updated_at": "2026-10-27T09:00:00Z"
}
```

## Borrar un registro

```http
DELETE /v1/orgs/{org}/zones/{zone}/records/{record}
```

Borra un registro. Borrar un registro con proxy deja de servir su sitio.

**Rol necesario:** `tech` o superior.

**Controles de cambio:** [`dry_run`](https://developers.openwaf.dev/es/api/#configuration-changes) · [`If-Match`](https://developers.openwaf.dev/es/api/#configuration-changes) (opcional) · [`X-Change-Reason`](https://developers.openwaf.dev/es/api/#configuration-changes) (obligatorio)

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `record` | ruta | string (uuid) | Sí | Id del registro (consulta [Listar registros](https://developers.openwaf.dev/es/api/dns-records/#list-records)). |
| `X-Change-Reason` | cabecera | string | Sí | Motivo del cambio: 1-500 caracteres UTF-8 tras recortar espacios, sin caracteres de control. Si falta o no es válido: 422 `reason_required`. De 1 a 500 caracteres. |
| `If-Match` | cabecera | string | No | Versión de configuración esperada, p. ej. `"12"` (se admite `W/`). Si no es la actual: 412 `version_conflict`. |
| `dry_run` | consulta | string | No | `1`/`true` simula el cambio: responde 200 con el plan (`Applied`) y no guarda nada. Admite `0`/`false`; otro valor: 400. Uno de `1`, `true`, `0`, `false`. |

#### Respuesta

- `200`: Con `dry_run=1`, el plan del cambio ([Applied](https://developers.openwaf.dev/es/api/schemas/#applied)); no se guarda nada.
- `204`: Borrado. Sin cuerpo.

Cabeceras de la respuesta: `ETag`, `X-Config-Version`.

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `404` | No existe o el token no lo ve (`not_found`). |
| `409` | `zone_merged`: la zona está fusionada en otra (solo lectura hasta que se separe o se purgue). |
| `412` | `version_conflict`: If-Match no coincide con la versión actual. |
| `422` | Error de validación (`invalid`) o motivo ausente/no válido (`reason_required`). |

#### Ejemplo

**curl**


```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records/0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Remove an unused host" \
  -H 'If-Match: "12"'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.deleteRecord({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  record: "0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d"
}, {
  reason: "Remove an unused host",
  ifMatch: 12
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.delete_record(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    record="0c9a7e4d-2b1f-4e6a-8d3c-5f7b9a1c3e5d",
    reason="Remove an unused host",
    if_match=12,
)
```



## Buscar los registros existentes

```http
GET /v1/orgs/{org}/zones/{zone}/import
```

Consulta a los servidores autoritativos actuales (o a resolvedores públicos) el ápice, los nombres habituales, los TXT de correo, los SRV y los nombres vistos en los registros de Certificate Transparency, y los devuelve para revisarlos. No aplica nada; la lista revisada se envía a [Crear registros en bloque](https://developers.openwaf.dev/es/api/dns-records/#bulk-create-records) o a [Lote de registros](https://developers.openwaf.dev/es/api/dns-records/#batch-records).

**Rol necesario:** `tech` o superior.

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |

#### Respuesta

- `200`: Devuelve [ImportResult](https://developers.openwaf.dev/es/api/schemas/#import-result).

| Campo | Tipo | Descripción |
|---|---|---|
| `domain` | string |  |
| `servers` | array de string |  |
| `wildcard` | boolean |  |
| `warnings` | array de string | Avisos (el cambio sigue siendo válido). |
| `candidates` | array de objeto |  |
| `candidates[].type` | string | Uno de `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`. |
| `candidates[].name` | string | `@`, relativo (`www`) o nombre completo; `*` para comodín. Por defecto `@`. |
| `candidates[].content` | string | A/AAAA: dirección. CNAME/NS/MX: nombre de host. TXT: texto sin comillas (se trocea en cadenas de 255). SRV: `peso puerto destino`. CAA: `flags etiqueta "valor"`. |
| `candidates[].ttl` | integer | TTL en segundos. Por defecto `3600`. De 60 a 86400. |
| `candidates[].priority` | integer | Obligatoria en MX y SRV; prohibida en el resto. De 0 a 65535. |
| `candidates[].proxied` | boolean | Solo A/AAAA/CNAME. El nombre responde con las IPs del borde (TTL 300) y el contenido se guarda como origen. Todos los A/AAAA/CNAME de un nombre comparten el valor. Un CNAME sin proxy en el apex se publica como ALIAS (aplanado). Por defecto `false`. |
| `candidates[].comment` | string | Atributo del registro (no se publica en el DNS; entra en las versiones de la zona). Sin caracteres de control. Como mucho 100 caracteres. |
| `candidates[].tags` | array de string | Atributo del registro, como el comentario. Se pasan a minúsculas y se quitan las repetidas. Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |
| `candidates[].source` | string | Uno de `dns`, `crtsh`. |

#### Ejemplo

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/import" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.listImportCandidates({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.list_import_candidates(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d")
```



```json
{
  "domain": "example",
  "servers": [
    "example"
  ],
  "wildcard": false,
  "warnings": [],
  "candidates": [
    {
      "type": "A",
      "name": "example.com",
      "content": "203.0.113.10",
      "ttl": 3600,
      "priority": 0,
      "proxied": false,
      "comment": "Web servers",
      "tags": [
        "web"
      ],
      "source": "dns"
    }
  ]
}
```

## Leer un fichero de zona BIND

```http
POST /v1/orgs/{org}/zones/{zone}/import/bind
```

Lee un fichero de zona BIND (de hasta 1 MiB) y devuelve sus registros para revisarlos. No aplica nada; los candidatos elegidos se aplican con [Lote de registros](https://developers.openwaf.dev/es/api/dns-records/#batch-records). No disponible en zonas externas.

Entiende `$ORIGIN`, `$TTL`, `@`, nombres relativos, dueños heredados, paréntesis, comentarios y TXT de varias cadenas. Deja fuera, con su motivo, el SOA y los NS del ápice (los pone OpenWAF), otras directivas, tipos o clases no admitidos, nombres fuera de la zona, registros no válidos, los que ya existen en la zona y los repetidos.

**Rol necesario:** `tech` o superior.

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |
| `proxied` | consulta | boolean | No | Con proxy los A/AAAA/CNAME cuyo nombre puede ser un sitio (ni comodines ni `_`). Por defecto `false`. |

#### Cuerpo de la petición

Tipo de contenido `text/plain`.

Como mucho 1048576 caracteres.

#### Respuesta

- `200`: Devuelve [BINDImport](https://developers.openwaf.dev/es/api/schemas/#bind-import).

| Campo | Tipo | Descripción |
|---|---|---|
| `items` | array de objeto |  |
| `items[].type` | string | Uno de `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SRV`, `CAA`. |
| `items[].name` | string | `@`, relativo (`www`) o nombre completo; `*` para comodín. Por defecto `@`. |
| `items[].content` | string | A/AAAA: dirección. CNAME/NS/MX: nombre de host. TXT: texto sin comillas (se trocea en cadenas de 255). SRV: `peso puerto destino`. CAA: `flags etiqueta "valor"`. |
| `items[].ttl` | integer | TTL en segundos. Por defecto `3600`. De 60 a 86400. |
| `items[].priority` | integer | Obligatoria en MX y SRV; prohibida en el resto. De 0 a 65535. |
| `items[].proxied` | boolean | Solo A/AAAA/CNAME. El nombre responde con las IPs del borde (TTL 300) y el contenido se guarda como origen. Todos los A/AAAA/CNAME de un nombre comparten el valor. Un CNAME sin proxy en el apex se publica como ALIAS (aplanado). Por defecto `false`. |
| `items[].comment` | string | Atributo del registro (no se publica en el DNS; entra en las versiones de la zona). Sin caracteres de control. Como mucho 100 caracteres. |
| `items[].tags` | array de string | Atributo del registro, como el comentario. Se pasan a minúsculas y se quitan las repetidas. Como mucho 10 elementos. Elementos con el patrón `^[a-z0-9][a-z0-9:_-]{0,31}$`. |
| `items[].source` | string | Siempre `file`. |
| `skipped` | array de object | Como mucho 200 entradas; skipped_total las cuenta todas. |
| `skipped[].line` | integer | Línea donde empieza la entrada. |
| `skipped[].text` | string | Entrada sin comentarios (hasta 200 bytes). |
| `skipped[].reason` | string | Motivo del cambio. |
| `skipped_total` | integer | Entradas dejadas fuera (todas, aunque skipped liste solo las 200 primeras). |
| `truncated` | boolean | El fichero tenía más de 5000 entradas: solo se han leído las primeras 5000. |

#### Errores

| Estado | Descripción |
|---|---|
| `400` | Petición mal formada (`bad_request`). |
| `404` | No existe o el token no lo ve (`not_found`). |
| `409` | Zona externa. |
| `413` | `too_large`: el fichero pasa de 1 MiB. |

#### Ejemplo

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/import/bind" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: text/plain" \
  --data-binary @example.com.zone
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.parseBindZone({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  body: ""
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.parse_bind_zone(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d", body="")
```



```json
{
  "items": [
    {
      "type": "A",
      "name": "example.com",
      "content": "203.0.113.10",
      "ttl": 3600,
      "priority": 0,
      "proxied": false,
      "comment": "Web servers",
      "tags": [
        "web"
      ],
      "source": "file"
    }
  ],
  "skipped": [
    {
      "line": 0,
      "text": "example",
      "reason": "Point www at the new origin"
    }
  ],
  "skipped_total": 128,
  "truncated": false
}
```

## Ver las respuestas DNS del borde

```http
GET /v1/orgs/{org}/zones/{zone}/dns/answers
```

En una zona delegada, devuelve las direcciones que publica el DNS de OpenWAF para cada nombre con proxy (las del borde) y si la respuesta publicada está al día (`in_sync`; si no, se corrige sola).

**Rol necesario:** `readonly` o superior.

#### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `org` | ruta | string (uuid) | Sí | Id de la organización. Cada ruta comprueba que es la del token (si no, `404`). |
| `zone` | ruta | string (uuid) | Sí | Id de la zona (consulta [Listar zonas](https://developers.openwaf.dev/es/api/zones/#list-zones)). |

#### Respuesta

- `200`: Devuelve [ZoneAnswers](https://developers.openwaf.dev/es/api/schemas/#zone-answers).

| Campo | Tipo | Descripción |
|---|---|---|
| `ipv4` | array de string |  |
| `ipv6` | array de string |  |
| `names` | array de object |  |
| `names[].name` | string | Nombre. |
| `names[].in_sync` | boolean |  |
| `names[].rrsets` | array de object |  |

#### Errores

| Estado | Descripción |
|---|---|
| `404` | No existe o el token no lo ve (`not_found`). |
| `409` | `conflict`: la zona es externa (su DNS lo sirve otro proveedor). |
| `503` | El servicio DNS no está disponible ahora. |

#### Ejemplo

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/dns/answers" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.getDnsAnswers({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.get_dns_answers(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d")
```



```json
{
  "ipv4": [
    "example"
  ],
  "ipv6": [
    "example"
  ],
  "names": [
    {
      "name": "example.com",
      "in_sync": false,
      "rrsets": [
        {}
      ]
    }
  ]
}
```
