Edge settings

Read and change the edge settings of a zone (WAF, origin, TLS, cache, AI agents…) and the effective configuration of a name.

On this page

Edge settings control how the edge serves the proxied names of a zone: WAF mode and level, origin and origin TLS, HSTS, cache, access gate, AI agents, RUM and more. Settings apply to every proxied name of the zone, and each name can override them under hosts.

OperationEndpoint
Get edge settingsGET /v1/orgs/{org}/zones/{zone}/edge
Update edge settingsPATCH /v1/orgs/{org}/zones/{zone}/edge
Get effective configuration of a nameGET /v1/orgs/{org}/zones/{zone}/hosts/{host}/effective

Get edge settings

GET /v1/orgs/{org}/zones/{zone}/edge

Returns the edge settings of the zone (the defaults if they were never saved). The ETag header carries the current configuration version.

Required role: readonly or higher.

Parameters

NameInTypeRequiredDescription
orgpathstring (uuid)YesOrganization id. Every route checks that it is the token's organization (otherwise 404).
zonepathstring (uuid)YesZone id (see List zones).

Response

FieldTypeDescription
zone_idstring (uuid)Zone id.
modestringOne of active, log, off. Default active.
waf_levelstringOne of off, low, medium, high. Default medium.
rate_limit_rpmintegerBasic limit per IP and minute; 0 = off. Default 0. Minimum 0.
timeout_msintegerDefault 0. Minimum 0.
enable_feedbooleanDefault true.
stackstringOne of generic, wordpress, nextjs, static. Default generic.
block_page_modestringOne of nginx, branded, apache, generic, custom. Default branded.
fake_server_headerstringDefault "".
block_page_htmlstringAt most 262144 characters.
access_gateobject
access_gate.enabledbooleanDefault false.
access_gate.pathstringDefault /.
access_gate.ttl_hoursintegerDefault 0. Minimum 0.
access_gate.emailsarray of stringEmail addresses allowed through the access gate.
max_body_mbintegerDefault 0. Minimum 0.
redirect_allow_hostsarray of string
cors_allow_originsarray of string
hstsobject
hsts.max_ageintegerDefault 0. From 0 to 63072000.
hsts.include_subdomainsboolean
hsts.preloadboolean
compressionbooleanDefault false.
originobjectThe site's upstream URL = scheme://<record content>[:port] (IPv6 in brackets).
origin.schemestringOne of http, https. Default https.
origin.portinteger0 = the scheme's default. Default 0. From 0 to 65535.
origin.tls_verifystringVerification of an https origin's certificate: full encrypts without verifying; full_strict verifies the chain (public roots + OpenWAF Origin CA), dates, name and revocation (failure = 526). New zones: full_strict; zones created before the feature: full. Only affects https origins. One of full, full_strict.
origin.server_namestringSNI and verification name; empty = the origin host (or the site's domain if the origin is an IP). At most 253 characters.
origin.client_certbooleanThe edge presents its client certificate to the origin (mTLS). Default false.
hostsHostSettingsMapOwn settings of some names of the zone: each name's site uses the zone's settings merged with its own field by field. {} when there are none (always present in answers). In a PATCH it is a JSON merge patch (RFC 7396) per name.
redirectsarray of objectRedirect rules: the edge answers status with Location = target (+ the rest of the path after path_prefix if preserve_path, + the query string if preserve_query) without reaching the origin. The longest prefix of the name wins. [] when there are none (always present in answers). In a PATCH the list is replaced. The name needs a proxied record. At most 50 items.
redirects[].hoststringFull name in the zone (the zone or below it, no wildcard); lowercased.
redirects[].path_prefixstringStarts with /; no ?, #, spaces or control characters. Stored in canonical form (non-ASCII and reserved characters as uppercase %XX: /año → /a%C3%B1o). /blog matches /blog and /blog/x, not /blogging. Default /. At most 1024 characters.
redirects[].targetstringAbsolute http(s) URL without credentials, fragment or spaces; may have a query string. Stored with a lowercase scheme and non-ASCII path and query characters as %XX; the host in ASCII (punycode). It cannot point to a path that the rule itself captures. At most 2048 characters.
redirects[].preserve_pathbooleanDefault true.
redirects[].preserve_querybooleanDefault true.
redirects[].statusintegerOne of 301, 302, 307, 308. Default 301.
cacheEdgeCacheResponse cache at the edge, off by default. In a PATCH it is a JSON merge patch: objects are merged, lists (rules, query.params) are replaced, "dev_mode_until": null turns development mode off and "cache": null restores the defaults.
cache.enabledbooleanWithout rules only static extensions are eligible (never HTML or JSON); the origin's Cache-Control is respected. The WAF always runs first. Default false.
cache.dev_mode_untilstring (date-time) or nullDevelopment mode: the cache is not used until then (nothing is deleted); null = off.
cache.queryCacheQuery
cache.browser_ttlintegerMinimum browser TTL in seconds (a longer max-age from the origin wins); 0 = respect the origin. Default 0. From 0 to 31536000.
cache.deception_armorbooleanDo not store responses whose Content-Type does not match the extension. Default true.
cache.serve_staleCacheServeStale
cache.max_object_mbintegerDefault 100. From 1 to 512.
cache.rulesarray of EdgeCacheRuleIn order; if several match, the last one wins for each setting. At most 25 items.
early_hintsEdgeEarlyHints103 Early Hints, off by default. In a PATCH it is a JSON merge patch: fields are merged, extra_origins is replaced and "early_hints": null restores the defaults.
early_hints.enabledbooleanAnswer 103 to HTML navigations that go to the origin. Default false.
early_hints.modestringWhere links are learned from: the origin's Link headers, the first 32 KiB of the HTML, or both. One of origin_links, html_head, both. Default both.
early_hints.extra_originsarray of stringOrigins besides the site's own whose resources can be announced: https://host[:port], without a path. They are normalized (spaces, lowercase, a trailing / and :443 removed); duplicates or non-https values answer 422. At most 10 items.
ai_agentsZoneEdgeAIAgents
rumZoneEdgeRUMReal user measurement of Core Web Vitals, off by default. In a PATCH it is a JSON merge patch: the given fields replace the current ones (exclude_paths as a whole), a field set to null returns to its default and "rum": null restores the default object. It is validated even when off.
rum.enabledbooleanThe edge injects /__waf/rum.js in the site's HTML pages and receives its beacons at /__waf/rum. Default false.
rum.sample_ratenumberFraction of page views that get the script, (0, 1]. Default 1. Maximum 1.
rum.exclude_pathsarray of stringPath prefixes that never get the script (spaces are trimmed; empty entries are dropped). Default []. At most 50 items. Items match ^/[^?#]*$.
rate_rulesarray of EdgeRateRulePer-path rate limits, in evaluation order; none by default. In a PATCH the whole list is replaced ([] removes them all). Each name can have its own list in hosts.<name>.rate_rules. At most 25 items.
updated_atstring (date-time)Last change.

Response headers: ETag.

Errors

StatusDescription
404Not found, or not visible to the token (not_found).

Example

curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d/edge" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
200
{
  "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"
}

Update edge settings

PATCH /v1/orgs/{org}/zones/{zone}/edge

Changes any subset of the edge settings. Nested objects (access_gate, hsts, origin…) are merged field by field and lists are replaced. The settings apply to every proxied name of the zone, except what a name overrides in hosts.

hosts is a JSON merge patch (RFC 7396) per name: {"hosts": {"shop.example.com": {"stack": "nextjs"}}} is merged with that name's own settings; null for a name removes its overrides, null for a key returns it to the zone's value (also nested, e.g. "access_gate": {"enabled": null}), and "hosts": null removes them all. Names are lowercased without a trailing dot, must be the zone or below it, and up to 100 fit. A name without a proxied record is accepted with a warning (the edge does not serve it).

Required role: tech or higher.

Change controls: dry_run · If-Match (optional) · X-Change-Reason (required)

Parameters

NameInTypeRequiredDescription
orgpathstring (uuid)YesOrganization id. Every route checks that it is the token's organization (otherwise 404).
zonepathstring (uuid)YesZone id (see List zones).
X-Change-ReasonheaderstringYesReason of the change: 1-500 UTF-8 characters after trimming spaces, no control characters. If it is missing or invalid: 422 reason_required. 1 to 500 characters.
If-MatchheaderstringNoExpected configuration version, e.g. "12" (W/ accepted). If it is not the current one: 412 version_conflict.
dry_runquerystringNo1/true simulates the change: answers 200 with the plan (Applied) and saves nothing. 0/false accepted; any other value: 400. One of 1, true, 0, false.

Request body

Content type application/json. Schema: ZoneEdgeSettings.

FieldTypeRequiredDescription
zone_idstring (uuid)NoZone id.
modestringNoOne of active, log, off. Default active.
waf_levelstringNoOne of off, low, medium, high. Default medium.
rate_limit_rpmintegerNoBasic limit per IP and minute; 0 = off. Default 0. Minimum 0.
timeout_msintegerNoDefault 0. Minimum 0.
enable_feedbooleanNoDefault true.
stackstringNoOne of generic, wordpress, nextjs, static. Default generic.
block_page_modestringNoOne of nginx, branded, apache, generic, custom. Default branded.
fake_server_headerstringNoDefault "".
block_page_htmlstringNoAt most 262144 characters.
access_gateobjectNo
access_gate.enabledbooleanNoDefault false.
access_gate.pathstringNoDefault /.
access_gate.ttl_hoursintegerNoDefault 0. Minimum 0.
access_gate.emailsarray of stringNoEmail addresses allowed through the access gate.
max_body_mbintegerNoDefault 0. Minimum 0.
redirect_allow_hostsarray of stringNo
cors_allow_originsarray of stringNo
hstsobjectNo
hsts.max_ageintegerNoDefault 0. From 0 to 63072000.
hsts.include_subdomainsbooleanNo
hsts.preloadbooleanNo
compressionbooleanNoDefault false.
originobjectNoThe site's upstream URL = scheme://<record content>[:port] (IPv6 in brackets).
origin.schemestringNoOne of http, https. Default https.
origin.portintegerNo0 = the scheme's default. Default 0. From 0 to 65535.
origin.tls_verifystringNoVerification of an https origin's certificate: full encrypts without verifying; full_strict verifies the chain (public roots + OpenWAF Origin CA), dates, name and revocation (failure = 526). New zones: full_strict; zones created before the feature: full. Only affects https origins. One of full, full_strict.
origin.server_namestringNoSNI and verification name; empty = the origin host (or the site's domain if the origin is an IP). At most 253 characters.
origin.client_certbooleanNoThe edge presents its client certificate to the origin (mTLS). Default false.
hostsHostSettingsMapNoOwn settings of some names of the zone: each name's site uses the zone's settings merged with its own field by field. {} when there are none (always present in answers). In a PATCH it is a JSON merge patch (RFC 7396) per name.
redirectsarray of objectNoRedirect rules: the edge answers status with Location = target (+ the rest of the path after path_prefix if preserve_path, + the query string if preserve_query) without reaching the origin. The longest prefix of the name wins. [] when there are none (always present in answers). In a PATCH the list is replaced. The name needs a proxied record. At most 50 items.
redirects[].hoststringYesFull name in the zone (the zone or below it, no wildcard); lowercased.
redirects[].path_prefixstringNoStarts with /; no ?, #, spaces or control characters. Stored in canonical form (non-ASCII and reserved characters as uppercase %XX: /año → /a%C3%B1o). /blog matches /blog and /blog/x, not /blogging. Default /. At most 1024 characters.
redirects[].targetstringYesAbsolute http(s) URL without credentials, fragment or spaces; may have a query string. Stored with a lowercase scheme and non-ASCII path and query characters as %XX; the host in ASCII (punycode). It cannot point to a path that the rule itself captures. At most 2048 characters.
redirects[].preserve_pathbooleanNoDefault true.
redirects[].preserve_querybooleanNoDefault true.
redirects[].statusintegerNoOne of 301, 302, 307, 308. Default 301.
cacheEdgeCacheNoResponse cache at the edge, off by default. In a PATCH it is a JSON merge patch: objects are merged, lists (rules, query.params) are replaced, "dev_mode_until": null turns development mode off and "cache": null restores the defaults.
cache.enabledbooleanNoWithout rules only static extensions are eligible (never HTML or JSON); the origin's Cache-Control is respected. The WAF always runs first. Default false.
cache.dev_mode_untilstring (date-time) or nullNoDevelopment mode: the cache is not used until then (nothing is deleted); null = off.
cache.queryCacheQueryNo
cache.query.modestringYesall: the whole query string (Standard); ignore: no query string in the cache key (static extensions only); none: only requests without a query string use the cache; include/exclude: only, or all but, the params. One of all, ignore, none, include, exclude.
cache.query.sortbooleanNoDefault false.
cache.query.paramsarray of stringNoParameter names (include/exclude); a trailing * matches a prefix (utm_*). At most 32 items.
cache.browser_ttlintegerNoMinimum browser TTL in seconds (a longer max-age from the origin wins); 0 = respect the origin. Default 0. From 0 to 31536000.
cache.deception_armorbooleanNoDo not store responses whose Content-Type does not match the extension. Default true.
cache.serve_staleCacheServeStaleNo
cache.serve_stale.while_revalidatebooleanNoServe stale (UPDATING) while revalidating in the background. Default true.
cache.serve_stale.on_error_max_sintegerNoSeconds after expiry during which a stale response is served if the origin fails (0 = never). Default 86400. From 0 to 2592000.
cache.max_object_mbintegerNoDefault 100. From 1 to 512.
cache.rulesarray of EdgeCacheRuleNoIn order; if several match, the last one wins for each setting. At most 25 items.
cache.rules[].idstringNoUnique; r1, r2… by default. Pattern ^[A-Za-z0-9_-]{1,64}$.
cache.rules[].hostsarray of stringNoNames of the zone it applies to (empty = all; not allowed in a name's own list).
cache.rules[].matchobjectNoEvery list present must match, and within a list any value; without lists it matches everything (GET and HEAD only).
cache.rules[].match.path_prefixarray of stringNoThe path starts with the value (canonical form). At most 32 items.
cache.rules[].match.path_exactarray of stringNoAt most 32 items.
cache.rules[].match.extensionsarray of stringNoWithout the dot, lowercase; "" = no extension. At most 32 items.
cache.rules[].match.cookie_presentarray of stringNoCookie name; a trailing * matches a prefix. At most 32 items.
cache.rules[].match.query_presentarray of stringNoThe query string has a parameter with that name (decoded); a trailing * matches a prefix. At most 32 items.
cache.rules[].actionstringYesbypass: never cache (no other parameters); cache: eligible even if the extension is not static. One of bypass, cache.
cache.rules[].edge_ttlobjectNo
cache.rules[].edge_ttl.modestringNooverride ignores the origin's Cache-Control, removes Set-Cookie and turns off the cache deception armor. One of respect_origin, bypass_by_default, override.
cache.rules[].edge_ttl.ttl_sintegerNoOnly with override (1..31536000). From 0 to 31536000.
cache.rules[].edge_ttl.statusarray of objectNoAt most 10 items.
cache.rules[].edge_ttl.status[].fromintegerNoFrom 100 to 599.
cache.rules[].edge_ttl.status[].tointegerNoFrom 100 to 599.
cache.rules[].edge_ttl.status[].ttl_sintegerNo-1 = do not store; 0 = store and always revalidate. From -1 to 31536000.
cache.rules[].browser_ttlobjectNo
cache.rules[].browser_ttl.modestringNoOne of respect_origin, override.
cache.rules[].browser_ttl.ttl_sintegerNoFrom 0 to 31536000.
cache.rules[].queryCacheQueryNo
cache.rules[].query.modestringYesall: the whole query string (Standard); ignore: no query string in the cache key (static extensions only); none: only requests without a query string use the cache; include/exclude: only, or all but, the params. One of all, ignore, none, include, exclude.
cache.rules[].query.sortbooleanNoDefault false.
cache.rules[].query.paramsarray of stringNoParameter names (include/exclude); a trailing * matches a prefix (utm_*). At most 32 items.
cache.rules[].serve_staleCacheServeStaleNo
cache.rules[].serve_stale.while_revalidatebooleanNoServe stale (UPDATING) while revalidating in the background. Default true.
cache.rules[].serve_stale.on_error_max_sintegerNoSeconds after expiry during which a stale response is served if the origin fails (0 = never). Default 86400. From 0 to 2592000.
cache.rules[].vary_bypass_if_presentarray of stringNoOnly with cache. Request headers (stored lowercase; not accept-encoding, accept or origin): a request carrying any of them is neither looked up nor stored (DYNAMIC); the origin's Vary may list them without causing BYPASS. Changing the list moves the name's cache to new keys. At most 32 items.
early_hintsEdgeEarlyHintsNo103 Early Hints, off by default. In a PATCH it is a JSON merge patch: fields are merged, extra_origins is replaced and "early_hints": null restores the defaults.
early_hints.enabledbooleanNoAnswer 103 to HTML navigations that go to the origin. Default false.
early_hints.modestringNoWhere links are learned from: the origin's Link headers, the first 32 KiB of the HTML, or both. One of origin_links, html_head, both. Default both.
early_hints.extra_originsarray of stringNoOrigins besides the site's own whose resources can be announced: https://host[:port], without a path. They are normalized (spaces, lowercase, a trailing / and :443 removed); duplicates or non-https values answer 422. At most 10 items.
ai_agentsZoneEdgeAIAgentsNo
ai_agents.enabledbooleanNoDefault false.
ai_agents.modestringNolog: only counts what it would do (enforced=false). One of log, enforce. Default log.
ai_agents.spoofed_challengestringNoenforce: only verified crawlers skip the proof-of-work challenge. One of log, enforce. Default log.
ai_agents.templatestringNoOne of search_ok_block_training, verified_only, block_unverified_automation.
ai_agents.policyobjectNo
ai_agents.policy.ai_trainingstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.ai_searchstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.ai_user_agentstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.search_enginestringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.unverified_automationstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.spoofedstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.unverified_botstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.trap_hitstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.secret_probestringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.robots_violationstringNoOne of allow, log, challenge, block, tarpit.
ai_agents.policy.agent_burststringNoOne of allow, log, challenge, block, tarpit.
ai_agents.bot_overridesarray of objectNoAt most 100 items.
ai_agents.bot_overrides[].bot_idstringYes
ai_agents.bot_overrides[].actionstringYesOne of allow, log, challenge, block, tarpit.
ai_agents.trapobjectNoTrap link; the zone's HMAC key is generated when published and never leaves the API.
ai_agents.trap.enabledbooleanNo
ai_agents.tarpitobjectNo
ai_agents.tarpit.enabledbooleanNo
ai_agents.robotsobjectNo
ai_agents.robots.enabledbooleanNo
ai_agents.robots.content_signalsobjectNo
ai_agents.robots.content_signals.searchstringNoOne of yes, no, "".
ai_agents.robots.content_signals.ai_inputstringNoOne of yes, no, "".
ai_agents.robots.content_signals.ai_trainstringNoOne of yes, no, "".
ai_agents.markdownobjectNo
ai_agents.markdown.enabledbooleanNo
ai_agents.block_responseobjectNo
ai_agents.block_response.statusintegerNoOne of 401, 402, 403, 404, 410, 429, 451, 503. Default 403.
ai_agents.block_response.messagestringNoAt most 1024 characters.
ai_agents.endpointsarray of objectNoAt most 20 items.
ai_agents.endpoints[].path_prefixstringNoAt most 256 characters. Pattern ^/.
ai_agents.endpoints[].methodsarray of stringNoPOST, PUT, PATCH, GET; with kind mcp, POST, GET and DELETE (with POST; empty = the three).
ai_agents.endpoints[].max_body_bytesintegerNo1-1048576; 0 with kind mcp. From 0 to 1048576.
ai_agents.endpoints[].rpm_per_ipintegerNoFrom 0 to 100000.
ai_agents.endpoints[].rpm_per_sessionintegerNoFrom 0 to 100000.
ai_agents.endpoints[].session_headerstringNo
ai_agents.endpoints[].session_cookiestringNo
ai_agents.endpoints[].injection_actionstringNoEmpty with kind mcp. One of log, block, "".
ai_agents.endpoints[].limit_actionstringNoEmpty with kind mcp. One of log, block, "".
ai_agents.endpoints[].kindstringNoAbsent = AI endpoint; mcp = MCP server protected by MCP Shield (the AI endpoint fields at 0 or empty). One of mcp.
ai_agents.endpoints[].mcpAiMcpPolicyNo
ai_agents.endpoints[].mcp.methods_allowedarray of stringNoExact JSON-RPC methods or x/* prefixes; by default initialize, ping, notifications/*, tools/list, tools/call, resources/list, resources/read, resources/templates/list, prompts/list, prompts/get, completion/complete, logging/setLevel. 1 to 64 items. Items match ^[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)*(/\*)?$.
ai_agents.endpoints[].mcp.tools_allowedarray of stringNo[] = any tool that is not denied. At most 200 items. Items match ^[A-Za-z0-9_.:/-]{1,128}$.
ai_agents.endpoints[].mcp.tools_deniedarray of stringNoAt most 200 items. Items match ^[A-Za-z0-9_.:/-]{1,128}$.
ai_agents.endpoints[].mcp.max_request_kbintegerNoDefault 256. From 1 to 1024.
ai_agents.endpoints[].mcp.inspect_requestsstringNoOne of off, log, block. Default log.
ai_agents.endpoints[].mcp.inspect_responsesstringNoOne of off, log, block. Default log.
ai_agents.endpoints[].mcp.rate_per_tokenintegerNoRequests per minute per token (Authorization); 0 = no limit. Default 0. From 0 to 100000.
rumZoneEdgeRUMNoReal user measurement of Core Web Vitals, off by default. In a PATCH it is a JSON merge patch: the given fields replace the current ones (exclude_paths as a whole), a field set to null returns to its default and "rum": null restores the default object. It is validated even when off.
rum.enabledbooleanNoThe edge injects /__waf/rum.js in the site's HTML pages and receives its beacons at /__waf/rum. Default false.
rum.sample_ratenumberNoFraction of page views that get the script, (0, 1]. Default 1. Maximum 1.
rum.exclude_pathsarray of stringNoPath prefixes that never get the script (spaces are trimmed; empty entries are dropped). Default []. At most 50 items. Items match ^/[^?#]*$.
rate_rulesarray of EdgeRateRuleNoPer-path rate limits, in evaluation order; none by default. In a PATCH the whole list is replaced ([] removes them all). Each name can have its own list in hosts.<name>.rate_rules. At most 25 items.
rate_rules[].idstringNoUnique in the list; empty = derived from the name (login, login-2…). Events carry it as rule_name rate_rule:<id>. Pattern ^[a-z0-9][a-z0-9-]{0,39}$.
rate_rules[].namestringNoName. At most 100 characters.
rate_rules[].enabledbooleanNoDefault true.
rate_rules[].hostsarray of stringNoNames of the zone it applies to; [] = all (always [] in a name's own list).
rate_rules[].path_prefixstringNoPaths starting with it at a segment boundary; / = all. Stored lowercase, without a trailing /. At most 512 characters.
rate_rules[].path_exactstringNoOnly this path (a trailing / does not count). Stored lowercase. At most 512 characters.
rate_rules[].methodsarray of stringNoMethods; [] = any. Default []. At most 16 items.
rate_rules[].header_presentstringNoOnly if the request has this header. At most 64 characters.
rate_rules[].query_presentstringNoOnly if the request has this query parameter. At most 64 characters.
rate_rules[].keystringNoWhat is counted: IP (IPv6 per /64), header, cookie or JSON body field (counted per IP when the value is missing). One of ip, header, cookie, body_field. Default ip.
rate_rules[].key_namestringNoHeader, cookie or path of the JSON field (a.b, up to 4 levels); empty with ip. At most 64 characters.
rate_rules[].requestsintegerYesRequests. From 1 to 1000000.
rate_rules[].periodintegerYesSeconds. From 1 to 86400.
rate_rules[].algorithmstringNoOne of sliding_window, gcra. Default sliding_window.
rate_rules[].actionstringNoOne of block, challenge, log. Default block.
rate_rules[].mitigation_timeoutintegerNoSeconds the action keeps applying to the key after it exceeds the limit; 0 = only while it exceeds it. Default 0. From 0 to 86400.
rate_rules[].per_node_divisorbooleanNoDivide requests among the edge entry points that serve the site, so the limit applies to the total. Default true.
updated_atstring (date-time)NoLast change.

Response

  • 200: Settings saved (with X-Config-Version and ETag) or, with dry_run, the plan (Applied). Returns ZoneEdgeSettings or Applied.
FieldTypeDescription
zone_idstring (uuid)Zone id.
modestringOne of active, log, off. Default active.
waf_levelstringOne of off, low, medium, high. Default medium.
rate_limit_rpmintegerBasic limit per IP and minute; 0 = off. Default 0. Minimum 0.
timeout_msintegerDefault 0. Minimum 0.
enable_feedbooleanDefault true.
stackstringOne of generic, wordpress, nextjs, static. Default generic.
block_page_modestringOne of nginx, branded, apache, generic, custom. Default branded.
fake_server_headerstringDefault "".
block_page_htmlstringAt most 262144 characters.
access_gateobject
access_gate.enabledbooleanDefault false.
access_gate.pathstringDefault /.
access_gate.ttl_hoursintegerDefault 0. Minimum 0.
access_gate.emailsarray of stringEmail addresses allowed through the access gate.
max_body_mbintegerDefault 0. Minimum 0.
redirect_allow_hostsarray of string
cors_allow_originsarray of string
hstsobject
hsts.max_ageintegerDefault 0. From 0 to 63072000.
hsts.include_subdomainsboolean
hsts.preloadboolean
compressionbooleanDefault false.
originobjectThe site's upstream URL = scheme://<record content>[:port] (IPv6 in brackets).
origin.schemestringOne of http, https. Default https.
origin.portinteger0 = the scheme's default. Default 0. From 0 to 65535.
origin.tls_verifystringVerification of an https origin's certificate: full encrypts without verifying; full_strict verifies the chain (public roots + OpenWAF Origin CA), dates, name and revocation (failure = 526). New zones: full_strict; zones created before the feature: full. Only affects https origins. One of full, full_strict.
origin.server_namestringSNI and verification name; empty = the origin host (or the site's domain if the origin is an IP). At most 253 characters.
origin.client_certbooleanThe edge presents its client certificate to the origin (mTLS). Default false.
hostsHostSettingsMapOwn settings of some names of the zone: each name's site uses the zone's settings merged with its own field by field. {} when there are none (always present in answers). In a PATCH it is a JSON merge patch (RFC 7396) per name.
redirectsarray of objectRedirect rules: the edge answers status with Location = target (+ the rest of the path after path_prefix if preserve_path, + the query string if preserve_query) without reaching the origin. The longest prefix of the name wins. [] when there are none (always present in answers). In a PATCH the list is replaced. The name needs a proxied record. At most 50 items.
redirects[].hoststringFull name in the zone (the zone or below it, no wildcard); lowercased.
redirects[].path_prefixstringStarts with /; no ?, #, spaces or control characters. Stored in canonical form (non-ASCII and reserved characters as uppercase %XX: /año → /a%C3%B1o). /blog matches /blog and /blog/x, not /blogging. Default /. At most 1024 characters.
redirects[].targetstringAbsolute http(s) URL without credentials, fragment or spaces; may have a query string. Stored with a lowercase scheme and non-ASCII path and query characters as %XX; the host in ASCII (punycode). It cannot point to a path that the rule itself captures. At most 2048 characters.
redirects[].preserve_pathbooleanDefault true.
redirects[].preserve_querybooleanDefault true.
redirects[].statusintegerOne of 301, 302, 307, 308. Default 301.
cacheEdgeCacheResponse cache at the edge, off by default. In a PATCH it is a JSON merge patch: objects are merged, lists (rules, query.params) are replaced, "dev_mode_until": null turns development mode off and "cache": null restores the defaults.
cache.enabledbooleanWithout rules only static extensions are eligible (never HTML or JSON); the origin's Cache-Control is respected. The WAF always runs first. Default false.
cache.dev_mode_untilstring (date-time) or nullDevelopment mode: the cache is not used until then (nothing is deleted); null = off.
cache.queryCacheQuery
cache.browser_ttlintegerMinimum browser TTL in seconds (a longer max-age from the origin wins); 0 = respect the origin. Default 0. From 0 to 31536000.
cache.deception_armorbooleanDo not store responses whose Content-Type does not match the extension. Default true.
cache.serve_staleCacheServeStale
cache.max_object_mbintegerDefault 100. From 1 to 512.
cache.rulesarray of EdgeCacheRuleIn order; if several match, the last one wins for each setting. At most 25 items.
early_hintsEdgeEarlyHints103 Early Hints, off by default. In a PATCH it is a JSON merge patch: fields are merged, extra_origins is replaced and "early_hints": null restores the defaults.
early_hints.enabledbooleanAnswer 103 to HTML navigations that go to the origin. Default false.
early_hints.modestringWhere links are learned from: the origin's Link headers, the first 32 KiB of the HTML, or both. One of origin_links, html_head, both. Default both.
early_hints.extra_originsarray of stringOrigins besides the site's own whose resources can be announced: https://host[:port], without a path. They are normalized (spaces, lowercase, a trailing / and :443 removed); duplicates or non-https values answer 422. At most 10 items.
ai_agentsZoneEdgeAIAgents
rumZoneEdgeRUMReal user measurement of Core Web Vitals, off by default. In a PATCH it is a JSON merge patch: the given fields replace the current ones (exclude_paths as a whole), a field set to null returns to its default and "rum": null restores the default object. It is validated even when off.
rum.enabledbooleanThe edge injects /__waf/rum.js in the site's HTML pages and receives its beacons at /__waf/rum. Default false.
rum.sample_ratenumberFraction of page views that get the script, (0, 1]. Default 1. Maximum 1.
rum.exclude_pathsarray of stringPath prefixes that never get the script (spaces are trimmed; empty entries are dropped). Default []. At most 50 items. Items match ^/[^?#]*$.
rate_rulesarray of EdgeRateRulePer-path rate limits, in evaluation order; none by default. In a PATCH the whole list is replaced ([] removes them all). Each name can have its own list in hosts.<name>.rate_rules. At most 25 items.
updated_atstring (date-time)Last change.

Response headers: ETag, X-Config-Version.

Errors

StatusDescription
400Malformed request (bad_request).
409zone_merged: the zone is merged into another one.
412version_conflict: If-Match does not match the current version.
422Validation error (invalid) or missing or invalid reason (reason_required).

Example

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
    }
  }'
200
{
  "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"
}

Get effective configuration of a name

GET /v1/orgs/{org}/zones/{zone}/hosts/{host}/effective

Shows the configuration that one name of the zone gets at the edge, exactly as the edge nodes receive it, the zone's settings merged with the name's own, the rules that apply to it and its redirects. The ETag header carries the zone's version.

Required role: readonly or higher.

Parameters

NameInTypeRequiredDescription
orgpathstring (uuid)YesOrganization id. Every route checks that it is the token's organization (otherwise 404).
zonepathstring (uuid)YesZone id (see List zones).
hostpathstringYesFull name (the zone or below it).

Response

FieldTypeDescription
zone_idstring (uuid)Zone id.
hoststring
proxiedbooleanfalse: the name has no proxied record and site is a preview without upstream_url.
itemsarray of object
items[].siteEdgeSite or any or null

Response headers: ETag.

Errors

StatusDescription
404Unknown zone, or host_not_in_zone: the name is neither the zone nor below it.
422Validation error (invalid).

Example

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"
200
{
  "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": []
      }
    }
  ]
}

Last updated:

↑↓ to navigate↵ to openesc to close