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 | GET /v1/orgs/{org}/zones/{zone}/records |
| Crear un registro | POST /v1/orgs/{org}/zones/{zone}/records |
| Crear registros en bloque | POST /v1/orgs/{org}/zones/{zone}/records/bulk |
| Lote de registros | POST /v1/orgs/{org}/zones/{zone}/records/batch |
| Ver un registro | GET /v1/orgs/{org}/zones/{zone}/records/{record} |
| Modificar un registro | PATCH /v1/orgs/{org}/zones/{zone}/records/{record} |
| Borrar un registro | DELETE /v1/orgs/{org}/zones/{zone}/records/{record} |
| Buscar los registros existentes | GET /v1/orgs/{org}/zones/{zone}/import |
| Leer un fichero de zona BIND | POST /v1/orgs/{org}/zones/{zone}/import/bind |
| Ver las respuestas DNS del borde | GET /v1/orgs/{org}/zones/{zone}/dns/answers |
Listar registros
GET /v1/orgs/{org}/zones/{zone}/recordsLista 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). |
Respuesta
200: Devuelveitems, un array de 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 "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/records" \
-H "Authorization: Bearer $OPENWAF_TOKEN"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"
});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"){
"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
POST /v1/orgs/{org}/zones/{zone}/recordsCrea 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 · If-Match (opcional) · X-Change-Reason (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). |
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.
| 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: Condry_run=1, el plan del cambio (Applied); no se guarda nada.201: Creado y publicado. Devuelve 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 -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
}'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
});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,
){
"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
POST /v1/orgs/{org}/zones/{zone}/records/bulkCrea 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 · If-Match (opcional) · X-Change-Reason (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). |
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 | 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: Condry_run=1, el plan del cambio (Applied); no se guarda nada.201: Creados (una sola versión). Devuelveitems, un array de 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 -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
}
]
}'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"
});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",
){
"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
POST /v1/orgs/{org}/zones/{zone}/records/batchCrea, 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 · If-Match (opcional) · X-Change-Reason (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). |
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.
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 | 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 condry_run). Devuelve BatchResult.
| 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 | Cambios. |
warnings | array de string | Avisos (el cambio sigue siendo válido). |
records | array de 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 -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"
]
}'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
});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,
){
"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
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). |
record | ruta | string (uuid) | Sí | Id del registro (consulta Listar registros). |
Respuesta
200: Devuelve 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 "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"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"
});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",
){
"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
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 · If-Match (opcional) · X-Change-Reason (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). |
record | ruta | string (uuid) | Sí | Id del registro (consulta Listar registros). |
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.
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, condry_run, el plan (Applied). Devuelve Record o 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 -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"
}'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
});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,
){
"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
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 · If-Match (opcional) · X-Change-Reason (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). |
record | ruta | string (uuid) | Sí | Id del registro (consulta Listar registros). |
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: Condry_run=1, el plan del cambio (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 -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"'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
});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
GET /v1/orgs/{org}/zones/{zone}/importConsulta 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 o a Lote de registros.
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). |
Respuesta
200: Devuelve ImportResult.
| 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 "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/import" \
-H "Authorization: Bearer $OPENWAF_TOKEN"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"
});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"){
"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
POST /v1/orgs/{org}/zones/{zone}/import/bindLee 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. 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). |
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.
| 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 -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.zoneimport { 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: ""
});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=""){
"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
GET /v1/orgs/{org}/zones/{zone}/dns/answersEn 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). |
Respuesta
200: Devuelve ZoneAnswers.
| 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 "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/dns/answers" \
-H "Authorization: Bearer $OPENWAF_TOKEN"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"
});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"){
"ipv4": [
"example"
],
"ipv6": [
"example"
],
"names": [
{
"name": "example.com",
"in_sync": false,
"rrsets": [
{}
]
}
]
}