# Códigos de error

> Los estados HTTP y códigos de error que devuelve la API para zonas, registros, comprobaciones de delegación, lotes, fusiones y la comprobación del correo.

Los errores llegan como JSON con un `code` estable, un `message` legible y, en los errores de validación, el campo
erróneo en `field`:

```json
{"error": {"code": "invalid", "message": "must be between 60 and 86400 seconds", "field": "ttl"}}
```

Programa contra `code`, no contra `message`. La CLI termina con `1` ante errores, `2` ante errores de uso y `3` ante
un conflicto de versión.

## Errores de petición y de permisos

| Estado | Código | Cuándo |
|---|---|---|
| 400 | `bad_request` | JSON mal formado, campos desconocidos, valores de `If-Match` o `dry_run` no válidos |
| 401 | `unauthorized` | Falta el token, o no es válido, ha caducado o se ha revocado |
| 403 | `forbidden` | El rol o el alcance no permiten la acción (por ejemplo un token `readonly` que escribe registros, o un token limitado a un dominio que da de alta zonas) |
| 403 | `token_scope` | Un token que solo purga ha llamado a algo distinto de la purga de caché |
| 404 | `not_found` | La zona, el registro o el recurso no existe o está fuera de tu alcance |
| 413 | `too_large` | Un fichero de zona BIND de más de 1 MiB |

## Validación

| Estado | Código | Cuándo |
|---|---|---|
| 422 | `invalid` | Un campo no es válido: mira `field` y `message`. Ejemplos: un tipo de registro no admitido, un TTL fuera de 60–86 400, una prioridad en un registro `A`, un comodín con proxy, una [regla de convivencia](https://developers.openwaf.dev/es/dns/record-types/#coexistence), un sufijo público como nombre de zona, más de 500 operaciones en un lote (`field` indica la operación, como `create[2].content`) |
| 422 | `reason_required` | Un cambio de configuración sin `X-Change-Reason` (de 1 a 500 caracteres) |

## Zonas

| Estado | Código | Cuándo |
|---|---|---|
| 403 | `zone_limit` | La organización ha llegado a su límite de dominios. Borra los que no uses o pide a soporte que lo amplíe |
| 409 | `zone_exists` | El dominio ya está dado de alta en OpenWAF |
| 409 | `zone_overlaps` | El dominio es padre o subdominio de un dominio que gestiona otra organización u otro cliente |
| 409 | `zone_not_external` | Una operación solo para zonas externas (como `GET …/hosts`) sobre una zona delegada |
| 409 | `conflict` | La zona está desactivada, la operación no vale para una zona externa (por ejemplo importar registros) o un nombre ya está ocupado |
| 409 | `zone_merged` | La zona se fusionó en otra y está en solo lectura |
| 409 | `merge_not_equivalent` | Una fusión cambiaría lo que sirve algún nombre, o no se puede expresar; mira `plan.problems` |
| 409 | `merge_not_reversible` | La zona padre cambió después de la fusión |
| 409 | `missing_certs` | El cambio dejaría un sitio sin certificado válido; `hostnames` los enumera |
| 412 | `version_conflict` | `If-Match` (o `expected_version`) no coincide con la versión actual de la zona; `current_version` la indica |
| 428 | `if_match_required` | Una vuelta atrás sin `If-Match` |

## Servicios y disponibilidad

| Estado | Código | Cuándo |
|---|---|---|
| 502 | `dns_backend` | Los servidores DNS rechazaron el cambio; no se ha aplicado nada. Reinténtalo y escribe a soporte si persiste |
| 502 | `dns_out_of_sync` | El cambio se ha deshecho porque no se pudo publicar; escribe a soporte |
| 502 | `dns_unavailable` | La comprobación del correo no ha obtenido respuesta del DNS público |
| 503 | `busy` | Hay demasiadas comprobaciones de correo en marcha; reinténtalo en unos segundos |
| 503 | `unavailable` | La función no está disponible temporalmente |

## Clientes y marca blanca

| Estado | Código | Cuándo |
|---|---|---|
| 409 | `client_has_zones` | Borrar un cliente que todavía tiene dominios |
| 409 | `host_taken` | El dominio del panel o el nombre del servidor de nombres pertenece a otra organización |
| 409 | `conflict` | Quitar o degradar al último propietario, o un nombre de cliente que ya existe |
