# Rule reference

> Fields of the four edge rule kinds (ip, geo, waf_exception, rate_limit) and of rate limiting rules, with their limits and defaults.

## Edge rules

Edge rules are created with `POST /v1/orgs/{org}/zones/{zone}/rules` (`rules add` in the CLI, `add_rule` in MCP) and deleted with `DELETE …/rules/{rule}` (`rules rm`, `remove_rule`). They can't be edited: delete and recreate. Only the fields of the rule's kind apply.

| Field | Kinds | Rules |
|---|---|---|
| `kind` | all | `ip`, `geo`, `waf_exception` or `rate_limit`. Required. |
| `ip` | `ip` | IPv4 or IPv6 address, or CIDR range. Stored in canonical form. |
| `action` | `ip`, `geo` | `block` or `allow`. |
| `country_code` | `geo` | ISO 3166-1 alpha-2; stored in upper case. |
| `rule_id` | `waf_exception` | Integer ≥ 0. `0` = every WAF rule; `1001`–`1008` = a [shield](https://developers.openwaf.dev/waf/shields/). Required. |
| `path_pattern` | `waf_exception`, `rate_limit` | Empty or `*` = every path; ending in `*` = prefix; otherwise exact. Must start with `/` otherwise. |
| `method` | `rate_limit` | HTTP method in upper case; empty = any. |
| `rpm` | `rate_limit` | Requests per minute per IP, ≥ 0. `0` blocks every matching request. Required. |
| `burst` | `rate_limit` | Extra requests per minute, ≥ 0. Default `0`. |
| `note` | all | Up to 500 characters. |
| `hosts` | all | Names of the zone (the zone or below it) the rule applies to. Omitted or empty = every name. |

The response adds `id`, `zone_id` and `created_at`. `GET …/rules` lists them in id order.

## Rate limiting rule fields

[Rate limiting rules](https://developers.openwaf.dev/waf/rate-limiting/#per-path-rules) live in the edge setting `rate_rules` (and `hosts.<name>.rate_rules`).

| Field | Default | Rules |
|---|---|---|
| `id` | from `name` | `a-z`, `0-9` and `-`, up to 40 characters, unique in the list. `Login` becomes `login`; a repeated one `login-2`. Events name the rule `rate_rule:<id>`. |
| `name` | — | Up to 100 characters. |
| `enabled` | `true` | A disabled rule is kept but not sent to the edge. |
| `hosts` | `[]` | Names of the zone; `[]` = every name. Always `[]` in a name's own list. |
| `path_prefix` / `path_exact` | — | Exactly one. A prefix matches at a segment boundary (`/auth/login` matches `/auth/login` and `/auth/login/x`, not `/auth/loginx`; `/` = everything). An exact path ignores a trailing `/`. Both ignore case and are stored in lower case. |
| `methods` | `[]` | E.g. `["POST"]`; `[]` = any. |
| `header_present` | — | Only requests that carry this header (lower-case name). |
| `query_present` | — | Only requests that carry this query parameter. |
| `key` | `ip` | `ip`, `header`, `cookie` or `body_field`. |
| `key_name` | — | Header name, cookie name or JSON path (`a.b`, up to 4 levels). Empty for `ip`. |
| `requests` | — | 1–1,000,000. Required. |
| `period` | — | Seconds, 1–86,400. Required. |
| `algorithm` | `sliding_window` | `sliding_window` or `gcra`. |
| `action` | `block` | `block`, `challenge` or `log`. |
| `mitigation_timeout` | `0` | Seconds, 0–86,400. |
| `per_node_divisor` | `true` | Split `requests` between the edge nodes that serve the site. |
