Los ajustes de borde controlan cómo sirve el borde los nombres con proxy de una zona: modo y nivel del WAF, origen y TLS hacia el origen, HSTS, caché, puerta de acceso, agentes IA, RUM y más. Se aplican a todos los nombres con proxy de la zona, y cada nombre puede redefinirlos en hosts.
| Operación | Ruta |
|---|---|
| Ver los ajustes de borde | GET /v1/orgs/{org}/zones/{zone}/edge |
| Cambiar los ajustes de borde | PATCH /v1/orgs/{org}/zones/{zone}/edge |
| Ver la configuración efectiva de un nombre | GET /v1/orgs/{org}/zones/{zone}/hosts/{host}/effective |
Ver los ajustes de borde
GET /v1/orgs/{org}/zones/{zone}/edgeDevuelve los ajustes de borde de la zona (los valores por defecto si nunca se guardaron). La cabecera ETag lleva la versión de configuración actual.
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 ZoneEdgeSettings.
| Campo | Tipo | Descripción |
|---|---|---|
zone_id | string (uuid) | Id de la zona. |
mode | string | Uno de active, log, off. Por defecto active. |
waf_level | string | Uno de off, low, medium, high. Por defecto medium. |
rate_limit_rpm | integer | Límite básico por IP y minuto; 0 = desactivado. Por defecto 0. Mínimo 0. |
timeout_ms | integer | Por defecto 0. Mínimo 0. |
enable_feed | boolean | Por defecto true. |
stack | string | Uno de generic, wordpress, nextjs, static. Por defecto generic. |
block_page_mode | string | Uno de nginx, branded, apache, generic, custom. Por defecto branded. |
fake_server_header | string | Por defecto "". |
block_page_html | string | Como mucho 262144 caracteres. |
access_gate | object | |
access_gate.enabled | boolean | Por defecto false. |
access_gate.path | string | Por defecto /. |
access_gate.ttl_hours | integer | Por defecto 0. Mínimo 0. |
access_gate.emails | array de string | Correos que pueden pasar la puerta de acceso. |
max_body_mb | integer | Por defecto 0. Mínimo 0. |
redirect_allow_hosts | array de string | |
cors_allow_origins | array de string | |
hsts | object | |
hsts.max_age | integer | Por defecto 0. De 0 a 63072000. |
hsts.include_subdomains | boolean | |
hsts.preload | boolean | |
compression | boolean | Por defecto false. |
origin | object | upstream_url del sitio = scheme://<contenido del registro>[:port] (IPv6 entre corchetes). |
origin.scheme | string | Uno de http, https. Por defecto https. |
origin.port | integer | 0 = el del esquema. Por defecto 0. De 0 a 65535. |
origin.tls_verify | string | Verificación del certificado de un origen https: full cifra sin verificar; full_strict verifica la cadena (raíces públicas + OpenWAF Origin CA), las fechas, el nombre y la revocación (fallo = 526). Zonas nuevas: full_strict; las anteriores a la función: full. Solo afecta a orígenes https. Uno de full, full_strict. |
origin.server_name | string | Nombre de SNI y de la verificación; vacío = el host del origen (o el dominio del sitio si el origen es una IP). Como mucho 253 caracteres. |
origin.client_cert | boolean | El borde presenta su certificado de cliente al origen (mTLS). Por defecto false. |
hosts | HostSettingsMap | Ajustes propios de algunos nombres de la zona: el sitio de cada nombre usa los de la zona mezclados con los suyos campo a campo. {} sin ninguno (siempre presente en las respuestas). En un PATCH es un JSON merge patch (RFC 7396) por nombre. |
redirects | array de object | Reglas de redirección: el borde responde status con Location = target (+ el resto de la ruta tras path_prefix si preserve_path, + la query si preserve_query) sin llegar al origen. Gana el prefijo más largo del nombre. [] sin ninguna (siempre presente en las respuestas). En un PATCH se sustituye entera. El nombre necesita un registro con proxy. Como mucho 50 elementos. |
redirects[].host | string | Nombre completo de la zona (la zona o por debajo, sin comodín); se pasa a minúsculas. |
redirects[].path_prefix | string | Empieza por /; sin ?, #, espacios ni caracteres de control. Se guarda en forma canónica (lo no ASCII y los reservados con %XX en mayúsculas: /año → /a%C3%B1o). /blog casa con /blog y /blog/x, no con /blogging. Por defecto /. Como mucho 1024 caracteres. |
redirects[].target | string | URL http(s) absoluta sin credenciales, fragmento ni espacios; puede llevar query. Se guarda con el esquema en minúsculas y lo no ASCII de ruta y query con %XX; el host en ASCII (punycode). No puede apuntar a una ruta que la propia regla captura. Como mucho 2048 caracteres. |
redirects[].preserve_path | boolean | Por defecto true. |
redirects[].preserve_query | boolean | Por defecto true. |
redirects[].status | integer | Uno de 301, 302, 307, 308. Por defecto 301. |
cache | EdgeCache | Caché de respuestas en el borde, desactivada por defecto. En un PATCH es un JSON merge patch: los objetos se mezclan, las listas (rules, query.params) se sustituyen, "dev_mode_until": null apaga el modo desarrollo y "cache": null vuelve a los valores por defecto. |
cache.enabled | boolean | Sin reglas solo son elegibles las extensiones estáticas (nunca HTML ni JSON); se respeta el Cache-Control del origen. El WAF va siempre antes. Por defecto false. |
cache.dev_mode_until | string (date-time) o null | Modo desarrollo: hasta entonces no se usa la caché (no se borra nada); null = apagado. |
cache.query | CacheQuery | |
cache.browser_ttl | integer | TTL mínimo hacia el navegador en segundos (un max-age mayor del origen gana); 0 = respetar el origen. Por defecto 0. De 0 a 31536000. |
cache.deception_armor | boolean | No guardar respuestas cuyo Content-Type no encaja con la extensión. Por defecto true. |
cache.serve_stale | CacheServeStale | |
cache.max_object_mb | integer | Por defecto 100. De 1 a 512. |
cache.rules | array de EdgeCacheRule | En orden; si varias coinciden, la última gana en cada ajuste. Como mucho 25 elementos. |
early_hints | EdgeEarlyHints | 103 Early Hints, desactivadas por defecto. En un PATCH es un JSON merge patch: los campos se mezclan, extra_origins se sustituye y "early_hints": null vuelve a los valores por defecto. |
early_hints.enabled | boolean | Responder con 103 a las navegaciones HTML que van al origen. Por defecto false. |
early_hints.mode | string | De dónde se aprenden los enlaces: cabeceras Link del origen, los primeros 32 KiB del HTML o ambos. Uno de origin_links, html_head, both. Por defecto both. |
early_hints.extra_origins | array de string | Orígenes además del propio del sitio cuyos recursos se pueden anunciar: https://host[:puerto], sin ruta. Se normalizan (espacios, minúsculas, una / final y :443 fuera); repetidos o no https dan 422. Como mucho 10 elementos. |
ai_agents | ZoneEdgeAIAgents | |
rum | ZoneEdgeRUM | Medición de usuarios reales de las Core Web Vitals, desactivada por defecto. En un PATCH es un JSON merge patch: los campos dados sustituyen a los actuales (exclude_paths entera), un campo a null vuelve a su valor por defecto y "rum": null al objeto por defecto. Se valida aunque esté desactivada. |
rum.enabled | boolean | El borde inyecta /__waf/rum.js en las páginas HTML del sitio y recibe sus balizas en /__waf/rum. Por defecto false. |
rum.sample_rate | number | Fracción de las páginas vistas que llevan el script, (0, 1]. Por defecto 1. Máximo 1. |
rum.exclude_paths | array de string | Prefijos de ruta que nunca llevan el script (se recortan los espacios; las entradas vacías se descartan). Por defecto []. Como mucho 50 elementos. Elementos con el patrón ^/[^?#]*$. |
rate_rules | array de EdgeRateRule | Límites de peticiones por ruta, en orden de evaluación; ninguno por defecto. En un PATCH la lista se sustituye entera ([] los quita todos). Cada nombre puede tener su propia lista en hosts.<nombre>.rate_rules. Como mucho 25 elementos. |
updated_at | string (date-time) | Último cambio. |
Cabeceras de la respuesta: ETag.
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/edge" \
-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.getZoneEdge({
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_zone_edge(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d"){
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"mode": "active",
"waf_level": "medium",
"rate_limit_rpm": 0,
"timeout_ms": 0,
"enable_feed": true,
"stack": "generic",
"block_page_mode": "branded",
"fake_server_header": "",
"block_page_html": "",
"access_gate": {
"enabled": false,
"path": "/checkout",
"ttl_hours": 0,
"emails": [
"[email protected]"
]
},
"max_body_mb": 0,
"redirect_allow_hosts": [
"www.example.com"
],
"cors_allow_origins": [
"https://app.example.com"
],
"hsts": {
"max_age": 0,
"include_subdomains": false,
"preload": false
},
"compression": false,
"origin": {
"scheme": "https",
"port": 0,
"tls_verify": "full",
"server_name": "",
"client_cert": false
},
"hosts": {},
"redirects": [
{
"host": "www.example.com",
"path_prefix": "/api/",
"target": "https://www.example.com/new",
"preserve_path": true,
"preserve_query": true,
"status": 301
}
],
"cache": {
"enabled": false,
"dev_mode_until": "2026-10-27T09:30:00Z",
"query": {
"mode": "all",
"sort": false,
"params": [
"example"
]
},
"browser_ttl": 0,
"deception_armor": true,
"serve_stale": {
"while_revalidate": true,
"on_error_max_s": 86400
},
"max_object_mb": 100,
"rules": [
{
"id": "example",
"hosts": [],
"match": {},
"action": "block",
"edge_ttl": {},
"browser_ttl": {},
"query": {},
"serve_stale": {},
"vary_bypass_if_present": []
}
]
},
"early_hints": {
"enabled": false,
"mode": "both",
"extra_origins": [
"https://cdn.example.com"
]
},
"ai_agents": {
"enabled": false,
"mode": "log",
"spoofed_challenge": "log",
"template": "search_ok_block_training",
"policy": {
"ai_training": "allow",
"ai_search": "allow",
"ai_user_agent": "allow",
"search_engine": "allow",
"unverified_automation": "allow",
"spoofed": "allow",
"unverified_bot": "allow",
"trap_hit": "allow",
"secret_probe": "allow",
"robots_violation": "allow",
"agent_burst": "allow"
},
"bot_overrides": [
{
"bot_id": "948186e3-4508-48d6-a001-c683a3ec9626",
"action": "block"
}
],
"trap": {
"enabled": false
},
"tarpit": {
"enabled": false
},
"robots": {
"enabled": false,
"content_signals": {
"search": "yes",
"ai_input": "yes",
"ai_train": "yes"
}
},
"markdown": {
"enabled": false
},
"block_response": {
"status": 403,
"message": ""
},
"endpoints": [
{
"path_prefix": "/api/",
"methods": [
"POST"
],
"max_body_bytes": 0,
"rpm_per_ip": 0,
"rpm_per_session": 0,
"session_header": "X-Session-Id",
"session_cookie": "session",
"injection_action": "log",
"limit_action": "log",
"kind": "mcp",
"mcp": {}
}
]
},
"rum": {
"enabled": false,
"sample_rate": 1,
"exclude_paths": []
},
"rate_rules": [
{
"id": "example",
"name": "example.com",
"enabled": true,
"hosts": [
"www.example.com"
],
"path_prefix": "/auth/login",
"path_exact": "/login",
"methods": [
"POST"
],
"header_present": "X-Api-Key",
"query_present": "example",
"key": "/pricing",
"key_name": "X-Api-Key",
"requests": 128,
"period": 1,
"algorithm": "sliding_window",
"action": "block",
"mitigation_timeout": 0,
"per_node_divisor": true
}
],
"updated_at": "2026-10-27T09:30:00Z"
}Cambiar los ajustes de borde
PATCH /v1/orgs/{org}/zones/{zone}/edgeCambia cualquier subconjunto de los ajustes de borde. Los objetos anidados (access_gate, hsts, origin…) se mezclan campo a campo y las listas se sustituyen. Los ajustes se aplican a todos los nombres con proxy de la zona, salvo lo que cada nombre redefina en hosts.
hosts es un JSON merge patch (RFC 7396) por nombre: {"hosts": {"tienda.example.com": {"stack": "nextjs"}}} se mezcla con los ajustes propios de ese nombre; null en un nombre quita los suyos, null en una clave la devuelve al valor de la zona (también anidada, p. ej. "access_gate": {"enabled": null}), y "hosts": null los quita todos. Los nombres se pasan a minúsculas sin punto final, deben ser la zona o estar por debajo, y caben 100. Un nombre sin registro con proxy se admite con un aviso (el borde no lo sirve).
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: ZoneEdgeSettings.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
zone_id | string (uuid) | No | Id de la zona. |
mode | string | No | Uno de active, log, off. Por defecto active. |
waf_level | string | No | Uno de off, low, medium, high. Por defecto medium. |
rate_limit_rpm | integer | No | Límite básico por IP y minuto; 0 = desactivado. Por defecto 0. Mínimo 0. |
timeout_ms | integer | No | Por defecto 0. Mínimo 0. |
enable_feed | boolean | No | Por defecto true. |
stack | string | No | Uno de generic, wordpress, nextjs, static. Por defecto generic. |
block_page_mode | string | No | Uno de nginx, branded, apache, generic, custom. Por defecto branded. |
fake_server_header | string | No | Por defecto "". |
block_page_html | string | No | Como mucho 262144 caracteres. |
access_gate | object | No | |
access_gate.enabled | boolean | No | Por defecto false. |
access_gate.path | string | No | Por defecto /. |
access_gate.ttl_hours | integer | No | Por defecto 0. Mínimo 0. |
access_gate.emails | array de string | No | Correos que pueden pasar la puerta de acceso. |
max_body_mb | integer | No | Por defecto 0. Mínimo 0. |
redirect_allow_hosts | array de string | No | |
cors_allow_origins | array de string | No | |
hsts | object | No | |
hsts.max_age | integer | No | Por defecto 0. De 0 a 63072000. |
hsts.include_subdomains | boolean | No | |
hsts.preload | boolean | No | |
compression | boolean | No | Por defecto false. |
origin | object | No | upstream_url del sitio = scheme://<contenido del registro>[:port] (IPv6 entre corchetes). |
origin.scheme | string | No | Uno de http, https. Por defecto https. |
origin.port | integer | No | 0 = el del esquema. Por defecto 0. De 0 a 65535. |
origin.tls_verify | string | No | Verificación del certificado de un origen https: full cifra sin verificar; full_strict verifica la cadena (raíces públicas + OpenWAF Origin CA), las fechas, el nombre y la revocación (fallo = 526). Zonas nuevas: full_strict; las anteriores a la función: full. Solo afecta a orígenes https. Uno de full, full_strict. |
origin.server_name | string | No | Nombre de SNI y de la verificación; vacío = el host del origen (o el dominio del sitio si el origen es una IP). Como mucho 253 caracteres. |
origin.client_cert | boolean | No | El borde presenta su certificado de cliente al origen (mTLS). Por defecto false. |
hosts | HostSettingsMap | No | Ajustes propios de algunos nombres de la zona: el sitio de cada nombre usa los de la zona mezclados con los suyos campo a campo. {} sin ninguno (siempre presente en las respuestas). En un PATCH es un JSON merge patch (RFC 7396) por nombre. |
redirects | array de object | No | Reglas de redirección: el borde responde status con Location = target (+ el resto de la ruta tras path_prefix si preserve_path, + la query si preserve_query) sin llegar al origen. Gana el prefijo más largo del nombre. [] sin ninguna (siempre presente en las respuestas). En un PATCH se sustituye entera. El nombre necesita un registro con proxy. Como mucho 50 elementos. |
redirects[].host | string | Sí | Nombre completo de la zona (la zona o por debajo, sin comodín); se pasa a minúsculas. |
redirects[].path_prefix | string | No | Empieza por /; sin ?, #, espacios ni caracteres de control. Se guarda en forma canónica (lo no ASCII y los reservados con %XX en mayúsculas: /año → /a%C3%B1o). /blog casa con /blog y /blog/x, no con /blogging. Por defecto /. Como mucho 1024 caracteres. |
redirects[].target | string | Sí | URL http(s) absoluta sin credenciales, fragmento ni espacios; puede llevar query. Se guarda con el esquema en minúsculas y lo no ASCII de ruta y query con %XX; el host en ASCII (punycode). No puede apuntar a una ruta que la propia regla captura. Como mucho 2048 caracteres. |
redirects[].preserve_path | boolean | No | Por defecto true. |
redirects[].preserve_query | boolean | No | Por defecto true. |
redirects[].status | integer | No | Uno de 301, 302, 307, 308. Por defecto 301. |
cache | EdgeCache | No | Caché de respuestas en el borde, desactivada por defecto. En un PATCH es un JSON merge patch: los objetos se mezclan, las listas (rules, query.params) se sustituyen, "dev_mode_until": null apaga el modo desarrollo y "cache": null vuelve a los valores por defecto. |
cache.enabled | boolean | No | Sin reglas solo son elegibles las extensiones estáticas (nunca HTML ni JSON); se respeta el Cache-Control del origen. El WAF va siempre antes. Por defecto false. |
cache.dev_mode_until | string (date-time) o null | No | Modo desarrollo: hasta entonces no se usa la caché (no se borra nada); null = apagado. |
cache.query | CacheQuery | No | |
cache.query.mode | string | Sí | all: la query entera (Standard); ignore: sin query en la clave (solo extensiones estáticas); none: solo se usa la caché sin query; include/exclude: solo/todos menos params. Uno de all, ignore, none, include, exclude. |
cache.query.sort | boolean | No | Por defecto false. |
cache.query.params | array de string | No | Nombres de parámetro (include/exclude); un * final casa por prefijo (utm_*). Como mucho 32 elementos. |
cache.browser_ttl | integer | No | TTL mínimo hacia el navegador en segundos (un max-age mayor del origen gana); 0 = respetar el origen. Por defecto 0. De 0 a 31536000. |
cache.deception_armor | boolean | No | No guardar respuestas cuyo Content-Type no encaja con la extensión. Por defecto true. |
cache.serve_stale | CacheServeStale | No | |
cache.serve_stale.while_revalidate | boolean | No | Servir caducado (UPDATING) mientras se revalida en segundo plano. Por defecto true. |
cache.serve_stale.on_error_max_s | integer | No | Segundos tras caducar en que se sirve caducado si el origen falla (0 = nunca). Por defecto 86400. De 0 a 2592000. |
cache.max_object_mb | integer | No | Por defecto 100. De 1 a 512. |
cache.rules | array de EdgeCacheRule | No | En orden; si varias coinciden, la última gana en cada ajuste. Como mucho 25 elementos. |
cache.rules[].id | string | No | Único; por defecto r1, r2…. Patrón ^[A-Za-z0-9_-]{1,64}$. |
cache.rules[].hosts | array de string | No | Nombres de la zona a los que se aplica (vacío = todos; no se admite en la lista propia de un nombre). |
cache.rules[].match | object | No | Casan todas las listas presentes y, dentro de cada una, cualquier valor; sin listas casa con todo (solo GET y HEAD). |
cache.rules[].match.path_prefix | array de string | No | La ruta empieza por el valor (forma canónica). Como mucho 32 elementos. |
cache.rules[].match.path_exact | array de string | No | Como mucho 32 elementos. |
cache.rules[].match.extensions | array de string | No | Sin punto, minúsculas; "" = sin extensión. Como mucho 32 elementos. |
cache.rules[].match.cookie_present | array de string | No | Nombre de cookie; un * final casa por prefijo. Como mucho 32 elementos. |
cache.rules[].match.query_present | array de string | No | La query trae un parámetro con ese nombre (decodificado); un * final casa por prefijo. Como mucho 32 elementos. |
cache.rules[].action | string | Sí | bypass: nunca cachear (sin más parámetros); cache: elegible aunque la extensión no sea estática. Uno de bypass, cache. |
cache.rules[].edge_ttl | object | No | |
cache.rules[].edge_ttl.mode | string | No | override ignora el CC del origen, quita Set-Cookie y desactiva la armadura anti-engaño. Uno de respect_origin, bypass_by_default, override. |
cache.rules[].edge_ttl.ttl_s | integer | No | Solo con override (1..31536000). De 0 a 31536000. |
cache.rules[].edge_ttl.status | array de object | No | Como mucho 10 elementos. |
cache.rules[].edge_ttl.status[].from | integer | No | De 100 a 599. |
cache.rules[].edge_ttl.status[].to | integer | No | De 100 a 599. |
cache.rules[].edge_ttl.status[].ttl_s | integer | No | -1 = no guardar; 0 = guardar y revalidar siempre. De -1 a 31536000. |
cache.rules[].browser_ttl | object | No | |
cache.rules[].browser_ttl.mode | string | No | Uno de respect_origin, override. |
cache.rules[].browser_ttl.ttl_s | integer | No | De 0 a 31536000. |
cache.rules[].query | CacheQuery | No | |
cache.rules[].query.mode | string | Sí | all: la query entera (Standard); ignore: sin query en la clave (solo extensiones estáticas); none: solo se usa la caché sin query; include/exclude: solo/todos menos params. Uno de all, ignore, none, include, exclude. |
cache.rules[].query.sort | boolean | No | Por defecto false. |
cache.rules[].query.params | array de string | No | Nombres de parámetro (include/exclude); un * final casa por prefijo (utm_*). Como mucho 32 elementos. |
cache.rules[].serve_stale | CacheServeStale | No | |
cache.rules[].serve_stale.while_revalidate | boolean | No | Servir caducado (UPDATING) mientras se revalida en segundo plano. Por defecto true. |
cache.rules[].serve_stale.on_error_max_s | integer | No | Segundos tras caducar en que se sirve caducado si el origen falla (0 = nunca). Por defecto 86400. De 0 a 2592000. |
cache.rules[].vary_bypass_if_present | array de string | No | Solo con cache. Cabeceras de petición (se guardan en minúsculas; no accept-encoding, accept ni origin): una petición que trae alguna ni se busca ni se guarda (DYNAMIC); el Vary del origen puede listarlas sin provocar BYPASS. Cambiar la lista vuelve a claves nuevas la caché del nombre. Como mucho 32 elementos. |
early_hints | EdgeEarlyHints | No | 103 Early Hints, desactivadas por defecto. En un PATCH es un JSON merge patch: los campos se mezclan, extra_origins se sustituye y "early_hints": null vuelve a los valores por defecto. |
early_hints.enabled | boolean | No | Responder con 103 a las navegaciones HTML que van al origen. Por defecto false. |
early_hints.mode | string | No | De dónde se aprenden los enlaces: cabeceras Link del origen, los primeros 32 KiB del HTML o ambos. Uno de origin_links, html_head, both. Por defecto both. |
early_hints.extra_origins | array de string | No | Orígenes además del propio del sitio cuyos recursos se pueden anunciar: https://host[:puerto], sin ruta. Se normalizan (espacios, minúsculas, una / final y :443 fuera); repetidos o no https dan 422. Como mucho 10 elementos. |
ai_agents | ZoneEdgeAIAgents | No | |
ai_agents.enabled | boolean | No | Por defecto false. |
ai_agents.mode | string | No | log: solo cuenta lo que haría (enforced=false). Uno de log, enforce. Por defecto log. |
ai_agents.spoofed_challenge | string | No | enforce: solo los rastreadores verificados se saltan el reto PoW. Uno de log, enforce. Por defecto log. |
ai_agents.template | string | No | Uno de search_ok_block_training, verified_only, block_unverified_automation. |
ai_agents.policy | object | No | |
ai_agents.policy.ai_training | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.ai_search | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.ai_user_agent | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.search_engine | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.unverified_automation | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.spoofed | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.unverified_bot | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.trap_hit | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.secret_probe | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.robots_violation | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.policy.agent_burst | string | No | Uno de allow, log, challenge, block, tarpit. |
ai_agents.bot_overrides | array de object | No | Como mucho 100 elementos. |
ai_agents.bot_overrides[].bot_id | string | Sí | |
ai_agents.bot_overrides[].action | string | Sí | Uno de allow, log, challenge, block, tarpit. |
ai_agents.trap | object | No | Enlace trampa; la clave HMAC de la zona se genera al publicar y nunca sale por la API. |
ai_agents.trap.enabled | boolean | No | |
ai_agents.tarpit | object | No | |
ai_agents.tarpit.enabled | boolean | No | |
ai_agents.robots | object | No | |
ai_agents.robots.enabled | boolean | No | |
ai_agents.robots.content_signals | object | No | |
ai_agents.robots.content_signals.search | string | No | Uno de yes, no, "". |
ai_agents.robots.content_signals.ai_input | string | No | Uno de yes, no, "". |
ai_agents.robots.content_signals.ai_train | string | No | Uno de yes, no, "". |
ai_agents.markdown | object | No | |
ai_agents.markdown.enabled | boolean | No | |
ai_agents.block_response | object | No | |
ai_agents.block_response.status | integer | No | Uno de 401, 402, 403, 404, 410, 429, 451, 503. Por defecto 403. |
ai_agents.block_response.message | string | No | Como mucho 1024 caracteres. |
ai_agents.endpoints | array de object | No | Como mucho 20 elementos. |
ai_agents.endpoints[].path_prefix | string | No | Como mucho 256 caracteres. Patrón ^/. |
ai_agents.endpoints[].methods | array de string | No | POST, PUT, PATCH, GET; con kind mcp, POST, GET y DELETE (con POST; vacío = los tres). |
ai_agents.endpoints[].max_body_bytes | integer | No | 1-1048576; 0 con kind mcp. De 0 a 1048576. |
ai_agents.endpoints[].rpm_per_ip | integer | No | De 0 a 100000. |
ai_agents.endpoints[].rpm_per_session | integer | No | De 0 a 100000. |
ai_agents.endpoints[].session_header | string | No | |
ai_agents.endpoints[].session_cookie | string | No | |
ai_agents.endpoints[].injection_action | string | No | Vacío con kind mcp. Uno de log, block, "". |
ai_agents.endpoints[].limit_action | string | No | Vacío con kind mcp. Uno de log, block, "". |
ai_agents.endpoints[].kind | string | No | Ausente = endpoint de IA; mcp = servidor MCP protegido por MCP Shield (los campos de endpoint de IA a 0 o vacíos). Uno de mcp. |
ai_agents.endpoints[].mcp | AiMcpPolicy | No | |
ai_agents.endpoints[].mcp.methods_allowed | array de string | No | Métodos JSON-RPC exactos o prefijos x/; por defecto initialize, ping, notifications/, tools/list, tools/call, resources/list, resources/read, resources/templates/list, prompts/list, prompts/get, completion/complete, logging/setLevel. De 1 a 64 elementos. Elementos con el patrón ^[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)*(/\*)?$. |
ai_agents.endpoints[].mcp.tools_allowed | array de string | No | [] = cualquier tool no denegada. Como mucho 200 elementos. Elementos con el patrón ^[A-Za-z0-9_.:/-]{1,128}$. |
ai_agents.endpoints[].mcp.tools_denied | array de string | No | Como mucho 200 elementos. Elementos con el patrón ^[A-Za-z0-9_.:/-]{1,128}$. |
ai_agents.endpoints[].mcp.max_request_kb | integer | No | Por defecto 256. De 1 a 1024. |
ai_agents.endpoints[].mcp.inspect_requests | string | No | Uno de off, log, block. Por defecto log. |
ai_agents.endpoints[].mcp.inspect_responses | string | No | Uno de off, log, block. Por defecto log. |
ai_agents.endpoints[].mcp.rate_per_token | integer | No | Peticiones por minuto por token (Authorization); 0 = sin límite. Por defecto 0. De 0 a 100000. |
rum | ZoneEdgeRUM | No | Medición de usuarios reales de las Core Web Vitals, desactivada por defecto. En un PATCH es un JSON merge patch: los campos dados sustituyen a los actuales (exclude_paths entera), un campo a null vuelve a su valor por defecto y "rum": null al objeto por defecto. Se valida aunque esté desactivada. |
rum.enabled | boolean | No | El borde inyecta /__waf/rum.js en las páginas HTML del sitio y recibe sus balizas en /__waf/rum. Por defecto false. |
rum.sample_rate | number | No | Fracción de las páginas vistas que llevan el script, (0, 1]. Por defecto 1. Máximo 1. |
rum.exclude_paths | array de string | No | Prefijos de ruta que nunca llevan el script (se recortan los espacios; las entradas vacías se descartan). Por defecto []. Como mucho 50 elementos. Elementos con el patrón ^/[^?#]*$. |
rate_rules | array de EdgeRateRule | No | Límites de peticiones por ruta, en orden de evaluación; ninguno por defecto. En un PATCH la lista se sustituye entera ([] los quita todos). Cada nombre puede tener su propia lista en hosts.<nombre>.rate_rules. Como mucho 25 elementos. |
rate_rules[].id | string | No | Único en la lista; vacío = derivado del nombre (login, login-2…). Los eventos lo llevan como rule_name rate_rule:<id>. Patrón ^[a-z0-9][a-z0-9-]{0,39}$. |
rate_rules[].name | string | No | Nombre. Como mucho 100 caracteres. |
rate_rules[].enabled | boolean | No | Por defecto true. |
rate_rules[].hosts | array de string | No | Nombres de la zona a los que se aplica; [] = todos (siempre [] en la lista de un nombre). |
rate_rules[].path_prefix | string | No | Rutas que empiezan por él en un límite de segmento; / = todas. Se guarda en minúsculas, sin / final. Como mucho 512 caracteres. |
rate_rules[].path_exact | string | No | Solo esta ruta (una / final no cuenta). Se guarda en minúsculas. Como mucho 512 caracteres. |
rate_rules[].methods | array de string | No | Métodos; [] = cualquiera. Por defecto []. Como mucho 16 elementos. |
rate_rules[].header_present | string | No | Solo si la petición lleva esta cabecera. Como mucho 64 caracteres. |
rate_rules[].query_present | string | No | Solo si la petición lleva este parámetro. Como mucho 64 caracteres. |
rate_rules[].key | string | No | Qué se cuenta: IP (IPv6 por /64), cabecera, cookie o campo del cuerpo JSON (sin valor, se cuenta por IP). Uno de ip, header, cookie, body_field. Por defecto ip. |
rate_rules[].key_name | string | No | Cabecera, cookie o ruta del campo JSON (a.b, hasta 4 niveles); vacío con ip. Como mucho 64 caracteres. |
rate_rules[].requests | integer | Sí | Peticiones. De 1 a 1000000. |
rate_rules[].period | integer | Sí | Segundos. De 1 a 86400. |
rate_rules[].algorithm | string | No | Uno de sliding_window, gcra. Por defecto sliding_window. |
rate_rules[].action | string | No | Uno de block, challenge, log. Por defecto block. |
rate_rules[].mitigation_timeout | integer | No | Segundos que la acción sigue aplicándose a la clave tras pasarse; 0 = solo mientras se pasa. Por defecto 0. De 0 a 86400. |
rate_rules[].per_node_divisor | boolean | No | Dividir requests entre los puntos de entrada del borde que sirven el sitio, para que el límite se aplique al total. Por defecto true. |
updated_at | string (date-time) | No | Último cambio. |
Respuesta
200: Ajustes guardados (con X-Config-Version y ETag) o, condry_run, el plan (Applied). Devuelve ZoneEdgeSettings o Applied.
| Campo | Tipo | Descripción |
|---|---|---|
zone_id | string (uuid) | Id de la zona. |
mode | string | Uno de active, log, off. Por defecto active. |
waf_level | string | Uno de off, low, medium, high. Por defecto medium. |
rate_limit_rpm | integer | Límite básico por IP y minuto; 0 = desactivado. Por defecto 0. Mínimo 0. |
timeout_ms | integer | Por defecto 0. Mínimo 0. |
enable_feed | boolean | Por defecto true. |
stack | string | Uno de generic, wordpress, nextjs, static. Por defecto generic. |
block_page_mode | string | Uno de nginx, branded, apache, generic, custom. Por defecto branded. |
fake_server_header | string | Por defecto "". |
block_page_html | string | Como mucho 262144 caracteres. |
access_gate | object | |
access_gate.enabled | boolean | Por defecto false. |
access_gate.path | string | Por defecto /. |
access_gate.ttl_hours | integer | Por defecto 0. Mínimo 0. |
access_gate.emails | array de string | Correos que pueden pasar la puerta de acceso. |
max_body_mb | integer | Por defecto 0. Mínimo 0. |
redirect_allow_hosts | array de string | |
cors_allow_origins | array de string | |
hsts | object | |
hsts.max_age | integer | Por defecto 0. De 0 a 63072000. |
hsts.include_subdomains | boolean | |
hsts.preload | boolean | |
compression | boolean | Por defecto false. |
origin | object | upstream_url del sitio = scheme://<contenido del registro>[:port] (IPv6 entre corchetes). |
origin.scheme | string | Uno de http, https. Por defecto https. |
origin.port | integer | 0 = el del esquema. Por defecto 0. De 0 a 65535. |
origin.tls_verify | string | Verificación del certificado de un origen https: full cifra sin verificar; full_strict verifica la cadena (raíces públicas + OpenWAF Origin CA), las fechas, el nombre y la revocación (fallo = 526). Zonas nuevas: full_strict; las anteriores a la función: full. Solo afecta a orígenes https. Uno de full, full_strict. |
origin.server_name | string | Nombre de SNI y de la verificación; vacío = el host del origen (o el dominio del sitio si el origen es una IP). Como mucho 253 caracteres. |
origin.client_cert | boolean | El borde presenta su certificado de cliente al origen (mTLS). Por defecto false. |
hosts | HostSettingsMap | Ajustes propios de algunos nombres de la zona: el sitio de cada nombre usa los de la zona mezclados con los suyos campo a campo. {} sin ninguno (siempre presente en las respuestas). En un PATCH es un JSON merge patch (RFC 7396) por nombre. |
redirects | array de object | Reglas de redirección: el borde responde status con Location = target (+ el resto de la ruta tras path_prefix si preserve_path, + la query si preserve_query) sin llegar al origen. Gana el prefijo más largo del nombre. [] sin ninguna (siempre presente en las respuestas). En un PATCH se sustituye entera. El nombre necesita un registro con proxy. Como mucho 50 elementos. |
redirects[].host | string | Nombre completo de la zona (la zona o por debajo, sin comodín); se pasa a minúsculas. |
redirects[].path_prefix | string | Empieza por /; sin ?, #, espacios ni caracteres de control. Se guarda en forma canónica (lo no ASCII y los reservados con %XX en mayúsculas: /año → /a%C3%B1o). /blog casa con /blog y /blog/x, no con /blogging. Por defecto /. Como mucho 1024 caracteres. |
redirects[].target | string | URL http(s) absoluta sin credenciales, fragmento ni espacios; puede llevar query. Se guarda con el esquema en minúsculas y lo no ASCII de ruta y query con %XX; el host en ASCII (punycode). No puede apuntar a una ruta que la propia regla captura. Como mucho 2048 caracteres. |
redirects[].preserve_path | boolean | Por defecto true. |
redirects[].preserve_query | boolean | Por defecto true. |
redirects[].status | integer | Uno de 301, 302, 307, 308. Por defecto 301. |
cache | EdgeCache | Caché de respuestas en el borde, desactivada por defecto. En un PATCH es un JSON merge patch: los objetos se mezclan, las listas (rules, query.params) se sustituyen, "dev_mode_until": null apaga el modo desarrollo y "cache": null vuelve a los valores por defecto. |
cache.enabled | boolean | Sin reglas solo son elegibles las extensiones estáticas (nunca HTML ni JSON); se respeta el Cache-Control del origen. El WAF va siempre antes. Por defecto false. |
cache.dev_mode_until | string (date-time) o null | Modo desarrollo: hasta entonces no se usa la caché (no se borra nada); null = apagado. |
cache.query | CacheQuery | |
cache.browser_ttl | integer | TTL mínimo hacia el navegador en segundos (un max-age mayor del origen gana); 0 = respetar el origen. Por defecto 0. De 0 a 31536000. |
cache.deception_armor | boolean | No guardar respuestas cuyo Content-Type no encaja con la extensión. Por defecto true. |
cache.serve_stale | CacheServeStale | |
cache.max_object_mb | integer | Por defecto 100. De 1 a 512. |
cache.rules | array de EdgeCacheRule | En orden; si varias coinciden, la última gana en cada ajuste. Como mucho 25 elementos. |
early_hints | EdgeEarlyHints | 103 Early Hints, desactivadas por defecto. En un PATCH es un JSON merge patch: los campos se mezclan, extra_origins se sustituye y "early_hints": null vuelve a los valores por defecto. |
early_hints.enabled | boolean | Responder con 103 a las navegaciones HTML que van al origen. Por defecto false. |
early_hints.mode | string | De dónde se aprenden los enlaces: cabeceras Link del origen, los primeros 32 KiB del HTML o ambos. Uno de origin_links, html_head, both. Por defecto both. |
early_hints.extra_origins | array de string | Orígenes además del propio del sitio cuyos recursos se pueden anunciar: https://host[:puerto], sin ruta. Se normalizan (espacios, minúsculas, una / final y :443 fuera); repetidos o no https dan 422. Como mucho 10 elementos. |
ai_agents | ZoneEdgeAIAgents | |
rum | ZoneEdgeRUM | Medición de usuarios reales de las Core Web Vitals, desactivada por defecto. En un PATCH es un JSON merge patch: los campos dados sustituyen a los actuales (exclude_paths entera), un campo a null vuelve a su valor por defecto y "rum": null al objeto por defecto. Se valida aunque esté desactivada. |
rum.enabled | boolean | El borde inyecta /__waf/rum.js en las páginas HTML del sitio y recibe sus balizas en /__waf/rum. Por defecto false. |
rum.sample_rate | number | Fracción de las páginas vistas que llevan el script, (0, 1]. Por defecto 1. Máximo 1. |
rum.exclude_paths | array de string | Prefijos de ruta que nunca llevan el script (se recortan los espacios; las entradas vacías se descartan). Por defecto []. Como mucho 50 elementos. Elementos con el patrón ^/[^?#]*$. |
rate_rules | array de EdgeRateRule | Límites de peticiones por ruta, en orden de evaluación; ninguno por defecto. En un PATCH la lista se sustituye entera ([] los quita todos). Cada nombre puede tener su propia lista en hosts.<nombre>.rate_rules. Como mucho 25 elementos. |
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. |
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/edge" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "X-Change-Reason: Enable the WAF in block mode" \
-H 'If-Match: "12"' \
-H "Content-Type: application/json" \
--data '{
"mode": "active",
"waf_level": "high",
"hsts": {
"max_age": 31536000,
"include_subdomains": true
}
}'import { OpenWAF } from "./openwaf";
const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token de OPENWAF_TOKEN
const result = await owf.updateZoneEdge({
zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
body: {
mode: "active",
waf_level: "high",
hsts: {
max_age: 31536000,
include_subdomains: true
}
}
}, {
reason: "Enable the WAF in block mode",
ifMatch: 12
});from openwaf import OpenWAF
owf = OpenWAF(base_url="https://dash.openwaf.dev") # token de OPENWAF_TOKEN
result = owf.update_zone_edge(
zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
body={
"mode": "active",
"waf_level": "high",
"hsts": {
"max_age": 31536000,
"include_subdomains": True
}
},
reason="Enable the WAF in block mode",
if_match=12,
){
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"mode": "active",
"waf_level": "medium",
"rate_limit_rpm": 0,
"timeout_ms": 0,
"enable_feed": true,
"stack": "generic",
"block_page_mode": "branded",
"fake_server_header": "",
"block_page_html": "",
"access_gate": {
"enabled": false,
"path": "/checkout",
"ttl_hours": 0,
"emails": [
"[email protected]"
]
},
"max_body_mb": 0,
"redirect_allow_hosts": [
"www.example.com"
],
"cors_allow_origins": [
"https://app.example.com"
],
"hsts": {
"max_age": 0,
"include_subdomains": false,
"preload": false
},
"compression": false,
"origin": {
"scheme": "https",
"port": 0,
"tls_verify": "full",
"server_name": "",
"client_cert": false
},
"hosts": {},
"redirects": [
{
"host": "www.example.com",
"path_prefix": "/api/",
"target": "https://www.example.com/new",
"preserve_path": true,
"preserve_query": true,
"status": 301
}
],
"cache": {
"enabled": false,
"dev_mode_until": "2026-10-27T09:30:00Z",
"query": {
"mode": "all",
"sort": false,
"params": [
"example"
]
},
"browser_ttl": 0,
"deception_armor": true,
"serve_stale": {
"while_revalidate": true,
"on_error_max_s": 86400
},
"max_object_mb": 100,
"rules": [
{
"id": "example",
"hosts": [],
"match": {},
"action": "block",
"edge_ttl": {},
"browser_ttl": {},
"query": {},
"serve_stale": {},
"vary_bypass_if_present": []
}
]
},
"early_hints": {
"enabled": false,
"mode": "both",
"extra_origins": [
"https://cdn.example.com"
]
},
"ai_agents": {
"enabled": false,
"mode": "log",
"spoofed_challenge": "log",
"template": "search_ok_block_training",
"policy": {
"ai_training": "allow",
"ai_search": "allow",
"ai_user_agent": "allow",
"search_engine": "allow",
"unverified_automation": "allow",
"spoofed": "allow",
"unverified_bot": "allow",
"trap_hit": "allow",
"secret_probe": "allow",
"robots_violation": "allow",
"agent_burst": "allow"
},
"bot_overrides": [
{
"bot_id": "948186e3-4508-48d6-a001-c683a3ec9626",
"action": "block"
}
],
"trap": {
"enabled": false
},
"tarpit": {
"enabled": false
},
"robots": {
"enabled": false,
"content_signals": {
"search": "yes",
"ai_input": "yes",
"ai_train": "yes"
}
},
"markdown": {
"enabled": false
},
"block_response": {
"status": 403,
"message": ""
},
"endpoints": [
{
"path_prefix": "/api/",
"methods": [
"POST"
],
"max_body_bytes": 0,
"rpm_per_ip": 0,
"rpm_per_session": 0,
"session_header": "X-Session-Id",
"session_cookie": "session",
"injection_action": "log",
"limit_action": "log",
"kind": "mcp",
"mcp": {}
}
]
},
"rum": {
"enabled": false,
"sample_rate": 1,
"exclude_paths": []
},
"rate_rules": [
{
"id": "example",
"name": "example.com",
"enabled": true,
"hosts": [
"www.example.com"
],
"path_prefix": "/auth/login",
"path_exact": "/login",
"methods": [
"POST"
],
"header_present": "X-Api-Key",
"query_present": "example",
"key": "/pricing",
"key_name": "X-Api-Key",
"requests": 128,
"period": 1,
"algorithm": "sliding_window",
"action": "block",
"mitigation_timeout": 0,
"per_node_divisor": true
}
],
"updated_at": "2026-10-27T09:30:00Z"
}Ver la configuración efectiva de un nombre
GET /v1/orgs/{org}/zones/{zone}/hosts/{host}/effectiveMuestra la configuración que recibe un nombre de la zona en el borde, tal y como la reciben los nodos, los ajustes de la zona mezclados con los propios del nombre, las reglas que le aplican y sus redirecciones. La cabecera ETag lleva la versión de la zona.
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). |
host | ruta | string | Sí | Nombre completo (la zona o por debajo). |
Respuesta
200: Devuelve EffectiveConfig.
| Campo | Tipo | Descripción |
|---|---|---|
zone_id | string (uuid) | Id de la zona. |
host | string | |
proxied | boolean | false: el nombre no tiene registro con proxy y site es una vista previa sin upstream_url. |
items | array de object | |
items[].site | EdgeSite o any o null |
Cabeceras de la respuesta: ETag.
Errores
| Estado | Descripción |
|---|---|
404 | Zona inexistente o host_not_in_zone: el nombre no es la zona ni está por debajo. |
422 | Error de validación (invalid). |
Ejemplo
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/hosts/www.example.com/effective" \
-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.getHostEffective({
zone: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
host: "www.example.com"
});from openwaf import OpenWAF
owf = OpenWAF(base_url="https://dash.openwaf.dev") # token de OPENWAF_TOKEN
result = owf.get_host_effective(zone="6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d", host="www.example.com"){
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"host": "www.example.com",
"proxied": false,
"items": [
{
"site": {
"id": 0,
"hostname": "www.example.com",
"upstream_url": "https://203.0.113.10",
"rules": [],
"redirects": [],
"cache": {},
"early_hints": {},
"rum": {},
"rate_rules": []
}
}
]
}