Shield (WAF, DDoS & Bots)
Per-site web application firewall, DDoS mitigation, and bot detection, backed by Bunny Shield.
Plan-gated. Every Shield endpoint returns 403 shield_not_in_plan
when the site's product does not include Shield. Premium-only writes (bot
detection update, custom WAF rule create) return 403
shield_premium_required on a non-premium plan. Reads that need a
provisioned shield zone return 409 shield_not_active. OAuth scopes:
reads sites:read, writes sites:write (deletes need can_destroy).
Upstream Bunny errors return 502.
Shield Zone
Get Shield Config
GET /api/sites/:site_id/shield
Returns 409 shield_not_active if the shield zone isn't provisioned.
Returned Params
- active: Boolean
- plan: String | basic, advanced, business, enterprise
- waf: Object | WAF settings
- ddos: Object | DDoS settings
- whitelabel_response_pages: Boolean
Activate Shield
POST /api/sites/:site_id/shield
Creates the shield zone. Returns 201. Returns 409 cdn_not_active if
there is no pull zone to attach to.
Update Shield
PATCH /api/sites/:site_id/shield
Params (all optional)
- plan_type: Integer | 0=basic, 1=advanced, 2=business, 3=enterprise
- premium: Boolean | back-compat alias for plan_type (true=1, false=0)
- learning_mode: Boolean
- waf_enabled: Boolean
- waf_execution_mode: Integer
- waf_disabled_rules:
Array<String>| ruleId strings - waf_log_only_rules:
Array<String>| ruleId strings - ddos_sensitivity: Integer
- ddos_execution_mode: Integer
- ddos_challenge_window: Integer
- whitelabel_response_pages: Boolean
Deactivate Shield
DELETE /api/sites/:site_id/shield
Soft deactivate — disables WAF and DDoS.
WAF
Get WAF Config
GET /api/sites/:site_id/shield/waf
Update WAF Config
PATCH /api/sites/:site_id/shield/waf
Params (all optional)
- waf_enabled: Boolean
- waf_execution_mode: Integer | 0=Log, 1=Block
- waf_disabled_rules:
Array<String>| ruleId strings - waf_log_only_rules:
Array<String>| ruleId strings
List Managed WAF Rules
GET /api/sites/:site_id/shield/waf/rules
Returns a bare array of managed WAF rule groups.
Custom WAF Rules
List
GET /api/sites/:site_id/shield/waf_custom_rules
Create
POST /api/sites/:site_id/shield/waf_custom_rules
Premium-only. Returns 201.
Params
- rule_name: String (required)
- rule_description: String (optional)
- rule_configuration: Object
- action_type: Integer | 1=Block, 2=Log, 3=Challenge, 4=Allow, 5=Bypass
- variable_type: String | e.g. REQUEST_HEADERS
- variable_subselector: String | e.g. "User-Agent"
- operator_type: Integer
- severity_type: Integer | 0=NOTICE, 1=WARNING, 2=CRITICAL
- value: String | the match value
Update
PATCH /api/sites/:site_id/shield/waf_custom_rules/:id
Not premium-gated.
Delete
DELETE /api/sites/:site_id/shield/waf_custom_rules/:id
Returns 204. Requires the can_destroy role.
Bot Detection
Get Config
GET /api/sites/:site_id/shield/bot_detection
Update Config
PATCH /api/sites/:site_id/shield/bot_detection
Premium-only (403 shield_premium_required).
Params (all optional)
- execution_mode: Integer
- request_integrity_sensitivity: Integer
- ip_address_sensitivity: Integer
- browser_fingerprint_sensitivity: Integer
- browser_fingerprint_aggression: Integer
- browser_fingerprint_complex_enabled: Boolean
Rate Limits
List
GET /api/sites/:site_id/shield/rate_limits
Create
POST /api/sites/:site_id/shield/rate_limits
Returns 201.
Params
- rule_name: String | letters, numbers, and spaces only (see below)
- rule_description: String | same character set as
rule_name; may be empty - rule_configuration: Object | forwarded verbatim to Bunny's rate-limit rule schema
Name character set
rule_name and rule_description may contain only ASCII letters, numbers,
and spaces — Bunny rejects hyphens, underscores, dots, and non-ASCII. An
invalid value is caught pre-flight and returns 422
{"error":"Rule name can only contain letters, numbers, and spaces."} (or
"Rule description ..."), not a 502 from Bunny.
Update
PATCH /api/sites/:site_id/shield/rate_limits/:id
Same params and name validation as Create.
Delete
DELETE /api/sites/:site_id/shield/rate_limits/:id
Returns 204. Requires the can_destroy role.
Access Lists
List
GET /api/sites/:site_id/shield/access_lists
List Enums
GET /api/sites/:site_id/shield/access_lists/enums
Available access-list type enum values.
View
GET /api/sites/:site_id/shield/access_lists/:id
Create
POST /api/sites/:site_id/shield/access_lists
Returns 201.
Params
- name: String
- description: String
- type: Integer
- content: String | newline-delimited entries
- checksum: String
Update
PATCH /api/sites/:site_id/shield/access_lists/:id
Delete
DELETE /api/sites/:site_id/shield/access_lists/:id
Returns 204. Requires the can_destroy role.
Events
GET /api/sites/:site_id/shield/events
Shield WAF/DDoS event log for a given date.
Params
- date: String |
MM-DD-YYYY(defaults to today) - continue: String | continuation token for pagination (optional)
Returned Params
- logs: Array
- hasMoreData: Boolean
- continuationToken: String
- startToken: String
Shield Metrics
These metric endpoints are not plan-gated, but still return 409
shield_not_active when there is no shield zone or the upstream stats
payload comes back empty. Scope: sites:read.
Individual Stats
GET /api/sites/:site_id/metrics/shield
Individual DDoS, bot, and WAF stats for the past 28 days.
Returned Params
- ddos: Array of series | logged, verified, blocked, challenged
- bots: Array of series | logged, challenged
- waf: Array of series | triggered events
Each series: { name: String, data: [ { x: "2026-05-01", y: 0 } ] }.
Overview Stats
GET /api/sites/:site_id/metrics/shield/overview
DDoS attacks + WAF triggers for the past 28 days. Returns a bare array of
series: [ { name: "DDoS Attacks", data: [...] }, { name: "WAF Triggers", data: [...] } ].