# Reglas

> Añade, lista y borra las reglas de borde de una zona, reglas de IP y país, excepciones del WAF y límites de peticiones.

Reglas de borde de una zona, que el borde aplica a todos los nombres con proxy o solo a los que lista `hosts`. Hay cuatro tipos, `ip`, `geo`, `waf_exception` y `rate_limit`. Consulta [WAF](https://developers.openwaf.dev/es/waf/) y [Reglas](https://developers.openwaf.dev/es/rules/).

| Operación | Ruta |
|---|---|
| [Listar reglas](https://developers.openwaf.dev/es/api/rules/#list-rules) | `GET /v1/orgs/{org}/zones/{zone}/rules` |
| [Crear una regla](https://developers.openwaf.dev/es/api/rules/#create-rule) | `POST /v1/orgs/{org}/zones/{zone}/rules` |
| [Borrar una regla](https://developers.openwaf.dev/es/api/rules/#delete-rule) | `DELETE /v1/orgs/{org}/zones/{zone}/rules/{rule}` |

## Listar reglas

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

Lista las reglas de borde de la zona con sus ids y los nombres a los que se limita cada una (`hosts`; vacío significa todos).

**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 [ZoneRule](https://developers.openwaf.dev/es/api/schemas/#zone-rule).

| Campo | Tipo | Descripción |
|---|---|---|
| `items[].kind` | string | Uno de `ip`, `geo`, `waf_exception`, `rate_limit`. |
| `items[].ip` | string | IP o CIDR. |
| `items[].action` | string | Uno de `block`, `allow`. |
| `items[].country_code` | string | Código de país ISO 3166-1 alfa-2. Patrón `^[A-Za-z]{2}$`. |
| `items[].rule_id` | integer | Id de la regla. Mínimo 0. |
| `items[].path_pattern` | string | "" o * = todas; acabado en * = prefijo; si no, exacta. |
| `items[].method` | string |  |
| `items[].rpm` | integer | Mínimo 0. |
| `items[].burst` | integer | Por defecto `0`. Mínimo 0. |
| `items[].note` | string | Como mucho 500 caracteres. |
| `items[].hosts` | array de string | Nombres a los que se aplica; ausente = todos los nombres de la zona. |
| `items[].id` | integer | Id. |
| `items[].zone_id` | string (uuid) | Id de la zona. |
| `items[].created_at` | string (date-time) | Fecha de creación. |

#### Ejemplo

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/rules" \
  -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.listRules({
  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_rules(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d")
```



```json
{
  "items": [
    {
      "id": 3,
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "kind": "ip",
      "ip": "203.0.113.0/24",
      "action": "block",
      "note": "Abusive scanner",
      "hosts": [],
      "created_at": "2026-10-27T09:30:00Z"
    }
  ]
}
```

## Crear una regla

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

Añade una regla de borde. Los campos dependen de `kind`:

| `kind` | Campos |
|---|---|
| `ip` | `ip` (dirección o CIDR), `action` |
| `geo` | `country_code`, `action` |
| `waf_exception` | `rule_id` (`0` = todas las reglas del WAF), `path_pattern` |
| `rate_limit` | `path_pattern`, `method`, `rpm`, `burst` |

Las reglas `rate_limit` son los límites de peticiones avanzados, por ruta; el límite básico por IP es `rate_limit_rpm` de los [ajustes de borde](https://developers.openwaf.dev/es/api/edge-settings/#update-zone-edge). `hosts` limita la regla a esos nombres (la zona o por debajo); un nombre sin registro con proxy da un aviso.

**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: [RuleInput](https://developers.openwaf.dev/es/api/schemas/#rule-input).

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `kind` | string | Sí | Uno de `ip`, `geo`, `waf_exception`, `rate_limit`. |
| `ip` | string | No | IP o CIDR. |
| `action` | string | No | Uno de `block`, `allow`. |
| `country_code` | string | No | Código de país ISO 3166-1 alfa-2. Patrón `^[A-Za-z]{2}$`. |
| `rule_id` | integer | No | Id de la regla. Mínimo 0. |
| `path_pattern` | string | No | "" o * = todas; acabado en * = prefijo; si no, exacta. |
| `method` | string | No |  |
| `rpm` | integer | No | Mínimo 0. |
| `burst` | integer | No | Por defecto `0`. Mínimo 0. |
| `note` | string | No | Como mucho 500 caracteres. |
| `hosts` | array de string | No | Nombres de la zona (la zona o por debajo) a los que se aplica; ausente o vacío = todos. |

#### Respuesta

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

| Campo | Tipo | Descripción |
|---|---|---|
| `kind` | string | Uno de `ip`, `geo`, `waf_exception`, `rate_limit`. |
| `ip` | string | IP o CIDR. |
| `action` | string | Uno de `block`, `allow`. |
| `country_code` | string | Código de país ISO 3166-1 alfa-2. Patrón `^[A-Za-z]{2}$`. |
| `rule_id` | integer | Id de la regla. Mínimo 0. |
| `path_pattern` | string | "" o * = todas; acabado en * = prefijo; si no, exacta. |
| `method` | string |  |
| `rpm` | integer | Mínimo 0. |
| `burst` | integer | Por defecto `0`. Mínimo 0. |
| `note` | string | Como mucho 500 caracteres. |
| `hosts` | array de string | Nombres a los que se aplica; ausente = todos los nombres de la zona. |
| `id` | integer | Id. |
| `zone_id` | string (uuid) | Id de la zona. |
| `created_at` | string (date-time) | Fecha de creación. |

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. |
| `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/rules" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Block an abusive network" \
  -H 'If-Match: "12"' \
  -H "Content-Type: application/json" \
  --data '{
    "kind": "ip",
    "ip": "203.0.113.0/24",
    "action": "block",
    "note": "Abusive scanner"
  }'
```

**TypeScript**


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

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.createRule({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  body: {
    kind: "ip",
    ip: "203.0.113.0/24",
    action: "block",
    note: "Abusive scanner"
  }
}, {
  reason: "Block an abusive network",
  ifMatch: 12
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.create_rule(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    body={
        "kind": "ip",
        "ip": "203.0.113.0/24",
        "action": "block",
        "note": "Abusive scanner"
    },
    reason="Block an abusive network",
    if_match=12,
)
```



```json
{
  "id": 3,
  "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  "kind": "ip",
  "ip": "203.0.113.0/24",
  "action": "block",
  "note": "Abusive scanner",
  "hosts": [],
  "created_at": "2026-10-27T09:30:00Z"
}
```

## Borrar una regla

```http
DELETE /v1/orgs/{org}/zones/{zone}/rules/{rule}
```

Quita una regla de borde de la zona.

**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)). |
| `rule` | ruta | integer | Sí | Id de la regla. |
| `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`: Borrada. 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. |
| `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/rules/3" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: The network is no longer abusive" \
  -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.deleteRule({
  zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  rule: 3
}, {
  reason: "The network is no longer abusive",
  ifMatch: 12
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token de OPENWAF_TOKEN
result = owf.delete_rule(
    zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    rule=3,
    reason="The network is no longer abusive",
    if_match=12,
)
```
