{"openapi": "3.0.3", "info": {"title": "ZERO-PROTECT API", "version": "2.2.122", "description": "Programmatic access to ZERO-PROTECT. Create a key in the portal (Protect, API keys); it works only from the IPv4/IPv6 addresses bound to it. Send it as `Authorization: Bearer zsk_...`. Read access covers GET; everything else needs write.\n\nKeys are created, rotated and revoked in the portal only, bound to at most 16 single addresses (/32, /128) and valid for at most 365 days. That is deliberate: a stolen key is useless from anywhere else, and no key can mint its successor.\n\nLimits: per key a token bucket, a smaller one for heavy reads (lists, health, metrics, logs), and at most 4 concurrent requests; X-RateLimit-* report the bucket on every answer, 429 means your limit. 503 means the platform is busy, not you.\n\nTimes are RFC 3339; only the points of charts are [unix seconds, value]. Errors carry a stable code next to the message. /v1 stays compatible: new fields and codes may be added, a breaking change gets a new version.", "contact": {"name": "Zero Services GmbH", "email": "info@zeroservices.eu", "url": "https://docs.zeroservices.eu/zero-protect/"}}, "servers": [{"url": "https://api.zeroservices.eu/v1/protect"}], "security": [{"apiKey": []}], "tags": [{"name": "Keys", "description": "The API key you call with. Keys are created in the portal and work only from the addresses bound to them", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/#keys"}}, {"name": "Services", "description": "Your vServices: settings, health, attacks, DNS check and history. Creating and deleting is for dedicated and BYOIP accounts", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/services/"}}, {"name": "Origins", "description": "The servers the edge forwards clean traffic to", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/origins/"}}, {"name": "IP pools", "description": "Addresses of your own IP pools and the operations on them: assign, release, move, swap, rotate, block, announce", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/pools/"}}, {"name": "Cache", "description": "Purge the edge cache and read its hit ratio", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/cache/"}}, {"name": "TLS", "description": "Certificates of a vService and its aliases: issued and renewed via ACME, or uploaded", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/tls/"}}, {"name": "Metrics and logs", "description": "Traffic charts, request log aggregates, raw lines and export, and the layer 3/4 view", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/logs/"}}, {"name": "Account", "description": "Your tenant, accounts and branding, and the edges that serve your vServices", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/account/"}}, {"name": "Reference", "description": "Values other settings accept: country codes and groups, AS numbers, crawler names and health check options", "externalDocs": {"url": "https://docs.zeroservices.eu/zero-protect/api/reference-data/"}}], "paths": {"/accounts": {"get": {"tags": ["Account"], "summary": "Your accounts", "operationId": "listAccounts", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountList"}, "examples": {"default": {"value": [{"account_id": "acc-a", "tenant": "tenant-a", "name": null, "plan": "dedicated", "services": ["a.example.com", "deleg.example.com", "tcp.example.com"], "created": null}]}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/accounts/{account_id}": {"get": {"tags": ["Account"], "summary": "One account", "operationId": "getAccount", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Account id, as in GET /accounts"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Account"}, "examples": {"default": {"value": {"account_id": "acc-a", "tenant": "tenant-a", "plan": "dedicated", "created_by": "", "branding": {}, "services": ["a.example.com", "deleg.example.com", "tcp.example.com"]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "put": {"tags": ["Account"], "summary": "Change an account's name and branding", "operationId": "updateAccount", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Account id, as in GET /accounts"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Account"}, "examples": {"default": {"value": {"account_id": "acc-a", "tenant": "tenant-a", "name": "Shop", "plan": "dedicated", "acme_email": null, "branding": {"primary_color": "#009FE3", "background_color": "#f5f5f5", "logo_file": null, "support_email": null, "support_url": null, "pow_text": null, "block_text": null, "error_titles": {}, "error_messages": {}}, "created": "", "created_by": "", "services": ["a.example.com", "deleg.example.com", "tcp.example.com"]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountUpdate"}, "examples": {"default": {"value": {"name": "Shop", "branding": {"primary_color": "#009FE3"}}}}}}}}}, "/accounts/{account_id}/logo": {"post": {"tags": ["Account"], "summary": "Upload a logo", "operationId": "uploadAccountLogo", "description": "Checked by content, not by the declared type; replaces the logo of the account's branding. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Account id, as in GET /accounts"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LogoStored"}, "examples": {"default": {"value": {"filename": "logo.png", "path": "accounts/acc-a/assets/logo.png"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "413": {"$ref": "#/components/responses/TooLarge"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/LogoUpload"}}}}}}, "/attacks": {"get": {"tags": ["Services"], "summary": "Attacks running now on your vServices", "operationId": "listAttacks", "description": "Poll this for your own monitoring: an empty list means no attack. An attack ends when the light of the vService leaves under_attack or blackholed. Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AttackList"}, "examples": {"default": {"value": {"attacks": [{"fqdn": "a.example.com", "state": "under_attack", "start": "2026-10-04T08:00:00+00:00", "end": null, "ended_as": null, "reason": "protection_stack_stopping_traffic", "techniques": ["l7"], "signals": {"requests_per_sec": 80.0, "blocked_per_sec": 50.0, "rejected_conn_per_sec": 2.0}, "escalations": []}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/attacks/{month}": {"get": {"tags": ["Services"], "summary": "Attacks of one month on your vServices", "operationId": "listAttacksOfMonth", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "month", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Month as YYYY-MM, UTC"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AttackArchive"}, "examples": {"default": {"value": {"month": "2026-10", "attacks": [{"fqdn": "a.example.com", "state": "under_attack", "start": "2026-10-04T08:00:00+00:00", "end": null, "ended_as": null, "reason": "protection_stack_stopping_traffic", "techniques": ["l7"], "signals": {"requests_per_sec": 80.0, "blocked_per_sec": 50.0, "rejected_conn_per_sec": 2.0}, "escalations": []}, {"fqdn": "tcp.example.com", "state": "under_attack", "start": "2026-10-03T10:00:00+00:00", "end": "2026-10-03T10:20:00+00:00", "ended_as": "normal", "reason": "l4_dropping_at_edge", "techniques": ["xdp"], "signals": {"l4_dropped_pps": 90000.0}, "escalations": [{"action": "rtbh", "site": "FRA2", "vip": "203.0.113.5", "start": "2026-10-03T10:02:00+00:00", "end": "2026-10-03T10:12:00+00:00"}]}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/edges": {"get": {"tags": ["Account"], "summary": "Edges that serve your vServices", "operationId": "listEdges", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeList"}, "examples": {"default": {"value": [{"name": "shared-1", "display_name": "Frankfurt 1", "site": "fra", "location": "Frankfurt", "status": "healthy", "last_seen": "2026-10-22T14:00:00.500000+00:00", "config_sha": "abc", "puller_version": "2.2.38", "edgemon_version": "2.1.18", "scrubd_version": "0.1.57", "flowd_version": "0.1.11", "tenant": null, "dedicated": false}]}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/edges/{name}": {"get": {"tags": ["Account"], "summary": "One edge", "operationId": "getEdge", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Edge name, as in GET /edges; case-insensitive"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Edge"}, "examples": {"default": {"value": {"name": "shared-1", "display_name": "Frankfurt 1", "site": "fra", "location": "Frankfurt", "status": "healthy", "last_seen": "2026-10-22T14:00:00.500000+00:00", "config_sha": "abc", "puller_version": "2.2.38", "edgemon_version": "2.1.18", "scrubd_version": "0.1.57", "flowd_version": "0.1.11", "tenant": null, "dedicated": false}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/keys/me": {"get": {"tags": ["Keys"], "summary": "The calling key", "operationId": "getCurrentKey", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Key"}, "examples": {"default": {"value": {"id": "TGloIsNcCavQ", "tenant": "tenant-a", "owner": {"kind": "account"}, "label": "ci", "scopes": ["protect:read", "protect:write"], "allowed_ips": ["1.2.3.4", "2a00:1450:4001::1"], "expires_at": "2026-11-22T00:00:00Z", "created_by": "owner@tenant-a.example", "created_at": "2026-10-23T10:13:25Z", "revoked_at": null, "revoked_by": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/metrics": {"get": {"tags": ["Metrics and logs"], "summary": "Traffic summed over all vServices you can see", "operationId": "getMetrics", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "metric", "in": "query", "required": false, "schema": {"type": "string", "enum": ["traffic", "response_codes", "protection", "pre_http_filter", "l4_packets", "l4_flows", "traffic_by_service"], "default": "traffic"}, "description": "Chart; traffic_by_service is the current bytes/s per vService"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "default": "1h"}, "description": "Time window"}, {"name": "delegation", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Narrow to one delegation you can see"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/MetricChart"}, {"$ref": "#/components/schemas/TrafficByService"}], "discriminator": {"propertyName": "metric", "mapping": {"l4_flows": "#/components/schemas/MetricChart", "l4_packets": "#/components/schemas/MetricChart", "pre_http_filter": "#/components/schemas/MetricChart", "protection": "#/components/schemas/MetricChart", "response_codes": "#/components/schemas/MetricChart", "traffic": "#/components/schemas/MetricChart", "traffic_by_service": "#/components/schemas/TrafficByService"}}}, "examples": {"traffic": {"value": {"metric": "traffic", "range": "1h", "step": "15s", "series": [{"label": "at_site", "values": [[1792750389, 1.5], [1792750404, 2.0]], "dashed": true, "direction": "in"}, {"label": "inbound", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}, {"label": "passed_frontend", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}], "scope": {"delegation": null, "services": 3, "has_http": true, "has_l4": true}}}, "traffic_by_service": {"value": {"metric": "traffic_by_service", "window": "5m", "unit": "bytes/s", "data": [{"fqdn": "a.example.com", "inbound": 2.0, "outbound": 2.0}, {"fqdn": "deleg.example.com", "inbound": 0.0, "outbound": 0.0}, {"fqdn": "tcp.example.com", "inbound": 0.0, "outbound": 0.0}], "scope": {"delegation": null, "services": 3, "has_http": true, "has_l4": true}}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/pools": {"get": {"tags": ["IP pools"], "summary": "List your IP pools", "operationId": "listPools", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/PoolSummary"}}, "examples": {"default": {"value": [{"scope": "P-A", "name": "a dedicated", "ipv4_range": "203.0.113.0/28", "ipv6_range": "2001:db8:a::/64", "customer_announce": false, "announced": true, "announce_changed_at": null, "next_change_at": null, "total": 16, "assigned": 2, "blocked": 0, "reserved": 0, "free": 14}]}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/pools/{scope}": {"get": {"tags": ["IP pools"], "summary": "One IP pool, address by address", "operationId": "getPool", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "scope", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Pool id, as in GET /pools; case-insensitive"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Pool"}, "examples": {"default": {"value": {"scope": "P-A", "name": "a dedicated", "ipv4_range": "203.0.113.0/28", "ipv6_range": "2001:db8:a::/64", "customer_announce": false, "announced": true, "announce_changed_at": null, "next_change_at": null, "total": 16, "assigned": 2, "blocked": 0, "reserved": 0, "free": 14, "addresses": [{"address": "203.0.113.0", "ipv6": "2001:db8:a::", "state": "free", "service": null, "blocked": false, "released_at": null}, {"address": "203.0.113.1", "ipv6": "2001:db8:a::1", "state": "assigned", "service": "a.example.com", "blocked": false, "released_at": null}, {"address": "203.0.113.2", "ipv6": "2001:db8:a::2", "state": "assigned", "service": "tcp.example.com", "blocked": false, "released_at": null}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/pools/{scope}/metrics": {"get": {"tags": ["IP pools"], "summary": "Traffic summed over one of your IP pools", "operationId": "getPoolMetrics", "description": "Only a pool bound to your account. Summed are your vServices with every VIP in the pool; scope.partial_services names those with only some, they are not summed. Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "scope", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Pool id, as in GET /pools; case-insensitive"}, {"name": "metric", "in": "query", "required": false, "schema": {"type": "string", "enum": ["traffic", "response_codes", "protection", "pre_http_filter", "l4_packets", "l4_flows", "traffic_by_service"], "default": "traffic"}, "description": "Chart"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "default": "1h"}, "description": "Time window"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/MetricChart"}, {"$ref": "#/components/schemas/TrafficByService"}], "discriminator": {"propertyName": "metric", "mapping": {"l4_flows": "#/components/schemas/MetricChart", "l4_packets": "#/components/schemas/MetricChart", "pre_http_filter": "#/components/schemas/MetricChart", "protection": "#/components/schemas/MetricChart", "response_codes": "#/components/schemas/MetricChart", "traffic": "#/components/schemas/MetricChart", "traffic_by_service": "#/components/schemas/TrafficByService"}}}, "examples": {"traffic": {"value": {"metric": "traffic", "range": "1h", "step": "15s", "series": [{"label": "at_site", "values": [[1792750389, 1.5], [1792750404, 2.0]], "dashed": true, "direction": "in"}, {"label": "inbound", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}, {"label": "passed_frontend", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}], "scope": {"pool": "P-A", "services": 2, "has_http": true, "has_l4": true, "partial_services": []}}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/reference/asns": {"get": {"tags": ["Reference"], "summary": "Autonomous systems for rules and allowlists", "operationId": "listAsns", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Asns"}, "examples": {"default": {"value": {"asns": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/reference/countries": {"get": {"tags": ["Reference"], "summary": "Country codes", "operationId": "listCountries", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Countries"}, "examples": {"default": {"value": {"countries": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/reference/crawlers": {"get": {"tags": ["Reference"], "summary": "Known crawlers for allowlists", "operationId": "listCrawlers", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Crawlers"}, "examples": {"default": {"value": {"crawlers": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/reference/geo-groups": {"get": {"tags": ["Reference"], "summary": "Country groups", "operationId": "listGeoGroups", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GeoGroups"}, "examples": {"default": {"value": {"geo_groups": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/reference/health-check-options": {"get": {"tags": ["Reference"], "summary": "Allowed health check settings", "operationId": "getHealthCheckOptions", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthCheckOptions"}, "examples": {"default": {"value": {"paths": ["/", "/health", "/healthz"], "intervals": ["5s", "10s", "15s"], "expects": ["status 200", "status 2xx", "status 301"]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services": {"get": {"tags": ["Services"], "summary": "List your vServices", "operationId": "listServices", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/ServiceSummary"}}, "examples": {"default": {"value": [{"fqdn": "a.example.com", "tenant": "tenant-a", "account_id": "acc-a", "enabled": true, "mode": "https", "ports": [443], "udp_ports": [], "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}], "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "waf": {}, "maintenance_mode": false, "aliases": [{"fqdn": "www.a.example.com"}], "edges": [], "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null, "delegations": [], "origin_count": 1, "redirect_count": 0}, {"fqdn": "deleg.example.com", "tenant": "tenant-a", "account_id": "acc-a", "enabled": true, "mode": "https", "ports": [443], "udp_ports": [], "network": {"vips": []}, "waf": {}, "maintenance_mode": false, "aliases": [], "edges": [], "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null, "delegations": ["EFFORTA"], "origin_count": 0, "redirect_count": 0}, {"fqdn": "tcp.example.com", "tenant": "tenant-a", "account_id": "acc-a", "enabled": true, "mode": "tcp", "ports": [5000], "udp_ports": [5000], "network": {"vips": [{"anycast_ipv4": "203.0.113.2", "anycast_ipv6": null}]}, "waf": {}, "maintenance_mode": false, "aliases": [], "edges": [], "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null, "delegations": [], "origin_count": 1, "redirect_count": 0}]}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "post": {"tags": ["Services"], "summary": "Create a vService from one of your IP pools", "operationId": "createService", "description": "Only for dedicated and BYOIP accounts. Dedicated: on your dedicated edges, from your pools announced at their site, at most 100 vServices per account. BYOIP: from one of your own pools, on our edges at every site that announces it, as many as your pools hold. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Service"}, "examples": {"default": {"value": {"fqdn": "shop.example.com", "tenant": "tenant-a", "account_id": "acc-a", "enabled": true, "ports": [443], "created": "2026-10-01T00:00:00+00:00", "created_by": "", "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}], "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "origins": [{"name": "origin-1", "address": "192.0.2.10", "port": 443}], "aliases": [], "cache": {"enabled": true}, "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServiceCreate"}, "examples": {"default": {"value": {"account_id": "acc-a", "fqdn": "shop.example.com", "pool": "P-A", "origins": [{"address": "192.0.2.10", "port": 443}]}}}}}}}}, "/services/health": {"get": {"tags": ["Services"], "summary": "Health of all your vServices", "operationId": "listServiceHealth", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthOverview"}, "examples": {"default": {"value": {"summary": {"total": 3, "worst": "unknown", "counts": {"blackholed": 0, "origin_down": 0, "misconfigured": 0, "errors": 0, "origin_slow": 0, "under_attack": 0, "normal": 0, "maintenance": 0, "disabled": 0, "unknown": 3}}, "services": {"a.example.com": {"status": "unknown", "fault": "none", "reason": "warming_up", "signals": {"requests_per_sec": 2.0, "errors_per_sec": 2.0, "error_ratio": 1.0, "origin_response_seconds": null, "origins_up": null, "origins_total": null}}, "deleg.example.com": {"status": "unknown", "fault": "none", "reason": "warming_up", "signals": {"requests_per_sec": 0.0, "errors_per_sec": 0.0, "error_ratio": 0.0, "origin_response_seconds": null, "origins_up": null, "origins_total": null}}, "tcp.example.com": {"status": "unknown", "fault": "none", "reason": "dns_not_measured", "signals": {"requests_per_sec": 0.0, "errors_per_sec": 0.0, "error_ratio": 0.0, "origin_response_seconds": null, "origins_up": null, "origins_total": null}}}}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}": {"delete": {"tags": ["Services"], "summary": "Delete a vService of a dedicated or BYOIP account", "operationId": "deleteService", "description": "Removes its certificates and DNS records too. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"204": {"description": "No content", "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "get": {"tags": ["Services"], "summary": "Get a vService", "operationId": "getService", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Service"}, "examples": {"default": {"value": {"fqdn": "a.example.com", "tenant": "tenant-a", "account_id": "acc-a", "enabled": true, "ports": [443], "created": "2026-10-01T00:00:00+00:00", "created_by": "", "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}], "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "origins": [{"name": "origin-1", "address": "192.0.2.10", "port": 443}], "aliases": [{"fqdn": "www.a.example.com"}], "cache": {"enabled": true}, "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "patch": {"tags": ["Services"], "summary": "Change a vService", "operationId": "updateService", "description": "Send only the fields to change; the others keep their value. An object merges into the stored one (waf: {enabled: true} leaves the other waf fields alone); a list, or an object inside an object, replaces the stored one; null removes a setting, back to its default. A top-level field outside the body schema is rejected (422); a read-only field inside an object, set by support, is ignored. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Service"}, "examples": {"waf_and_limit": {"value": {"fqdn": "a.example.com", "tenant": "tenant-a", "enabled": true, "mode": "https", "ports": [443], "udp_ports": [], "created": "2026-10-01T00:00:00+00:00", "created_by": "", "account_id": "acc-a", "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}], "pool": null, "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "network_protection": {"enabled": true}, "backend": {"algorithm": "roundrobin", "health_check": {}}, "origins": [{"name": "origin-1", "address": "192.0.2.10", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}], "waf": {"enabled": true, "fail_open": true, "mode": "On", "paranoia_level": 1, "inbound_threshold": 5, "disabled_rules": []}, "rate_limiting": {"challenge_req_per_10s": 200, "req_per_10s": 800, "conn_per_10s": 50, "conn_drop_per_10s": 500, "path_default": 1000, "path_aggregate_per_10s": 5000, "geo_tcp_reject_sess_rate": 200, "ja4_enabled": false, "ja4_req_per_10s": 100, "ja4_action": "challenge"}, "pow": {"enabled": true, "difficulty": 18, "cookie_ttl": 86400, "always_challenge": false, "exempt_crawlers": true, "bind_ip": true, "botcheck_per_10s": 1000}, "admission": {"enabled": false, "credit_required": 5, "credit_window": "60s", "known_ttl": "24h", "unknown_conn_rate": 1500, "table_size": "1m"}, "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}, "aliases": [{"fqdn": "www.a.example.com", "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}}], "cache": {"enabled": true}, "slow_http": {"enabled": true, "timeout_http_request": "5s", "timeout_client_fin": "5s"}, "tcp_timeout": {"client": "30s", "server": "30s", "tunnel": "30s"}, "udp_timeout": {"idle": "300s", "unreplied": "30s", "unreplied_pkts": 32, "src_pps": 0}, "sni_policy": "allowlist", "proxy_protocol": false, "tls_termination": false, "priority": {"enabled": true, "session_signal": []}, "response_headers": {"hsts": {}, "cors": {}, "x_frame_options": null, "x_content_type_options": false, "referrer_policy": null}, "content_negotiation": {"enabled": false, "encodings": ["zstd", "gzip"], "file_types": ["css", "js", "html"]}, "logging": {"enabled": false}, "threat_intel": {"mode": "log", "abuse": "log", "tor": "log"}, "redirects": [], "origin_host": null, "origin_sni": null, "maintenance_mode": false, "auto_mitigation": false, "defense_posture": null, "protection_allowlist": null, "edges": [], "protection_rules": [], "append_trailing_slash": false, "exceed_no_rtbh": false, "exceed_no_flowspec": false, "origin_kind": "dynamic", "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null}}, "replace_origins": {"value": {"fqdn": "a.example.com", "tenant": "tenant-a", "enabled": true, "mode": "https", "ports": [443], "udp_ports": [], "created": "2026-10-01T00:00:00+00:00", "created_by": "", "account_id": "acc-a", "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}], "pool": null, "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "network_protection": {"enabled": true}, "backend": {"algorithm": "roundrobin", "health_check": {"method": "GET", "path": "/", "host": null, "interval": "10s", "rise": 2, "fall": 3, "expect": null}}, "origins": [{"name": "origin-1", "address": "192.0.2.10", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}], "waf": {"enabled": true, "fail_open": true, "mode": "On", "paranoia_level": 1, "inbound_threshold": 5, "disabled_rules": []}, "rate_limiting": {"challenge_req_per_10s": 200, "req_per_10s": 800, "conn_per_10s": 50, "conn_drop_per_10s": 500, "path_default": 1000, "path_aggregate_per_10s": 5000, "geo_tcp_reject_sess_rate": 200, "ja4_enabled": false, "ja4_req_per_10s": 100, "ja4_action": "challenge"}, "pow": {"enabled": true, "difficulty": 18, "cookie_ttl": 86400, "always_challenge": false, "exempt_crawlers": true, "bind_ip": true, "botcheck_per_10s": 1000}, "admission": {"enabled": false, "credit_required": 5, "credit_window": "60s", "known_ttl": "24h", "unknown_conn_rate": 1500, "table_size": "1m"}, "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}, "aliases": [{"fqdn": "www.a.example.com", "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}}], "cache": {"enabled": true}, "slow_http": {"enabled": true, "timeout_http_request": "5s", "timeout_client_fin": "5s"}, "tcp_timeout": {"client": "30s", "server": "30s", "tunnel": "30s"}, "udp_timeout": {"idle": "300s", "unreplied": "30s", "unreplied_pkts": 32, "src_pps": 0}, "sni_policy": "allowlist", "proxy_protocol": false, "tls_termination": false, "priority": {"enabled": true, "session_signal": []}, "response_headers": {"hsts": {"enabled": false, "max_age": 31536000, "include_subdomains": false, "preload": false}, "cors": {"enabled": false, "rules": []}, "x_frame_options": null, "x_content_type_options": false, "referrer_policy": null}, "content_negotiation": {"enabled": false, "encodings": ["zstd", "gzip"], "file_types": ["css", "js", "html"]}, "logging": {"enabled": false}, "threat_intel": {"mode": "log", "abuse": "log", "tor": "log"}, "redirects": [], "origin_host": null, "origin_sni": null, "maintenance_mode": false, "auto_mitigation": false, "defense_posture": null, "protection_allowlist": null, "edges": [], "protection_rules": [], "append_trailing_slash": false, "exceed_no_rtbh": false, "exceed_no_flowspec": false, "origin_kind": "dynamic", "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServicePatch"}, "examples": {"waf_and_limit": {"value": {"waf": {"enabled": true}, "rate_limiting": {"req_per_10s": 800}}}, "replace_origins": {"value": {"origins": [{"name": "origin-1", "address": "192.0.2.10", "port": 443}]}}}}}}}}, "/services/{fqdn}/aliases/{alias_fqdn}/ssl": {"get": {"tags": ["TLS"], "summary": "Certificate of an alias", "operationId": "getAliasCertificate", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "alias_fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "An alias of the vService"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateStatus"}, "examples": {"default": {"value": {"fqdn": "www.a.example.com", "mode": "acme", "has_custom_cert": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null, "detail": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "post": {"tags": ["TLS"], "summary": "Upload a certificate for an alias (ECDSA)", "operationId": "uploadAliasCertificate", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "alias_fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "An alias of the vService"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateStored"}, "examples": {"default": {"value": {"fqdn": "www.a.example.com", "mode": "custom", "cert": {"subject": "CN=a.example.com", "issuer": "CN=Example CA", "not_before": "2026-10-01T00:00:00+00:00", "not_after": "2026-12-30T00:00:00+00:00", "dns_names": ["a.example.com", "www.a.example.com"], "serial_number": "4f2a", "chain_length": 2, "key_type": "EC", "key_bits": 256, "curve": "secp256r1"}}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateUpload"}, "examples": {"default": {"value": {"fullchain_pem": "-----BEGIN CERTIFICATE-----\nMIIBszCCAVmgAwIBAgIU...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBuDCCAV6gAwIBAgIU...\n-----END CERTIFICATE-----\n", "privkey_pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEG...\n-----END PRIVATE KEY-----\n"}}}}}}}}, "/services/{fqdn}/aliases/{alias_fqdn}/ssl/issue": {"post": {"tags": ["TLS"], "summary": "Issue an alias certificate via ACME", "operationId": "issueAliasCertificate", "description": "No request body. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "alias_fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "An alias of the vService"}], "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AcmeStarted"}, "examples": {"default": {"value": {"status": "started", "fqdn": "www.a.example.com"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/aliases/{alias_fqdn}/ssl/renew": {"post": {"tags": ["TLS"], "summary": "Renew an alias certificate", "operationId": "renewAliasCertificate", "description": "No request body. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "alias_fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "An alias of the vService"}], "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AcmeStarted"}, "examples": {"default": {"value": {"status": "started", "fqdn": "www.a.example.com"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/cache/purge": {"get": {"tags": ["Cache"], "summary": "Recent purges", "operationId": "listPurges", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Purges"}, "examples": {"default": {"value": {"generation": 1, "all": [{"generation": 1, "at": "2026-10-23T10:13:25.538807+00:00", "by": "API key ci"}], "urls": [{"id": "58dc70c951364ae1b5577905bb6980af", "host": "a.example.com", "url": "/img/logo.png?v=2", "at": "2026-10-23T10:13:25.418554+00:00", "by": "API key ci"}], "prefixes": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "post": {"tags": ["Cache"], "summary": "Purge the cache", "operationId": "purgeCache", "description": "409 with code cache_disabled when the cache is off, or when a limit is reached: purge_all_interval (purge all once per interval, details.retry_after_seconds), url_purge_rate (30 URLs a minute), prefix_purge_limit (50 prefixes until the next purge all). Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PurgeResult"}, "examples": {"url": {"value": {"type": "url", "id": "58dc70c951364ae1b5577905bb6980af", "host": "a.example.com", "url": "/img/logo.png?v=2", "at": "2026-10-23T10:13:25.418554+00:00", "by": "key:TGloIsNcCavQ"}}, "prefix": {"value": {"type": "prefix", "id": "9e37874cfe68", "prefix": "/img/", "at": "2026-10-23T10:13:25.468399+00:00", "by": "key:TGloIsNcCavQ"}}, "all": {"value": {"type": "all", "generation": 1, "at": "2026-10-23T10:13:25.538807+00:00", "by": "key:TGloIsNcCavQ"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CachePurge"}, "examples": {"url": {"value": {"url": "/img/logo.png?v=2"}}, "prefix": {"value": {"prefix": "/img/"}}, "all": {"value": {"all": true}}}}}}}}, "/services/{fqdn}/cache/stats": {"get": {"tags": ["Cache"], "summary": "Cache hit ratio and volume", "operationId": "getCacheStats", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["1h", "6h", "24h"], "default": "24h"}, "description": "Time window"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CacheStats"}, "examples": {"default": {"value": {"range": "24h", "requests": {"HIT": 7}, "bytes": {"HIT": 7}, "hit_ratio": 1.0, "byte_share": 1.0, "token_denied": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/dns": {"get": {"tags": ["Services"], "summary": "DNS records the vService expects", "operationId": "getServiceDns", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "refresh", "in": "query", "required": false, "schema": {"type": "boolean", "default": false}, "description": "Look the records up again instead of the last minute's answer"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsStatus"}, "examples": {"default": {"value": {"fqdn": "a.example.com", "edge_hostname": "a-example-com.edge.protect.zeroservices.eu", "anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1", "status": "ok_cname", "ok": true, "hostnames": [{"fqdn": "a.example.com", "status": "ok_cname", "detail": null, "is_apex": false, "zone_apex": "example.com", "expected_cname": "a-example-com.edge.protect.zeroservices.eu", "expected_ipv4": "203.0.113.1", "expected_ipv6": "2001:db8:a::1", "cname_target": "a-example-com.edge.protect.zeroservices.eu", "cname_chain": ["a-example-com.edge.protect.zeroservices.eu"], "resolved_ipv4": ["203.0.113.1"], "resolved_ipv6": ["2001:db8:a::1"], "ttl": 60, "public_ipv4": ["203.0.113.1"], "public_ipv6": ["2001:db8:a::1"], "public_cname_target": null, "propagating": false, "caa": {"status": "none", "owner": null, "records": [], "issuer": "sectigo.com"}, "checked_at": "2026-10-23T10:13:25.197620+00:00", "role": "primary"}, {"fqdn": "www.a.example.com", "status": "ok_cname", "detail": null, "is_apex": false, "zone_apex": "example.com", "expected_cname": "a-example-com.edge.protect.zeroservices.eu", "expected_ipv4": "203.0.113.1", "expected_ipv6": "2001:db8:a::1", "cname_target": "a-example-com.edge.protect.zeroservices.eu", "cname_chain": ["a-example-com.edge.protect.zeroservices.eu"], "resolved_ipv4": ["203.0.113.1"], "resolved_ipv6": ["2001:db8:a::1"], "ttl": 60, "public_ipv4": ["203.0.113.1"], "public_ipv6": ["2001:db8:a::1"], "public_cname_target": null, "propagating": false, "caa": {"status": "none", "owner": null, "records": [], "issuer": "sectigo.com"}, "checked_at": "2026-10-23T10:13:25.197641+00:00", "role": "alias", "cert_status": null}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/history": {"get": {"tags": ["Services"], "summary": "Change history of a vService", "operationId": "getServiceHistory", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "default": "24h"}, "description": "Time window"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/History"}, "examples": {"default": {"value": {"fqdn": "a.example.com", "range": "24h", "entries": [{"kind": "config_change", "category": "config", "at": "2026-10-23T10:13:25+00:00", "sha": "7454e1cb177219e234491676fc66582d0d37342f", "short_sha": "7454e1cb", "action": "Patch service a.example.com", "user": "API key ci", "by_zero_services": false}, {"kind": "config_change", "category": "config", "at": "2026-10-23T10:13:25+00:00", "sha": "e89a055a4305b33b66f5d08f9659f89b11a79dd3", "short_sha": "e89a055a", "action": "Patch service a.example.com", "user": "API key ci", "by_zero_services": false}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs": {"get": {"tags": ["Metrics and logs"], "summary": "Request log: one aggregate or raw lines", "operationId": "getServiceLogs", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "type", "in": "query", "required": false, "schema": {"type": "string", "enum": ["raw", "status_codes", "threat_intel", "top_asns", "top_combination", "top_countries", "top_deny_rules", "top_host_headers", "top_http_methods", "top_http_versions", "top_ips", "top_ja4", "top_path_class", "top_rules", "top_uris", "top_user_agents"], "default": "top_ips"}, "description": "An aggregate, or raw for the newest lines"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 10}, "description": "Rows"}, {"name": "view", "in": "query", "required": false, "schema": {"type": "string", "enum": ["allowed", "blocked", "all"], "default": "allowed"}, "description": "allowed: what reached your origin; blocked: what the edge turned away; all: both"}, {"name": "from", "in": "query", "required": false, "schema": {"type": "string", "format": "date-time"}, "description": "Start of the window, RFC 3339, at most 96 h back; with only from, range sets the length; type=raw only"}, {"name": "to", "in": "query", "required": false, "schema": {"type": "string", "format": "date-time"}, "description": "End of the window, RFC 3339, not included; with only to, range sets the length. Page back by passing the oldest timestamp you received; type=raw only"}, {"name": "client_ip", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose client address contains this; type=raw only"}, {"name": "status_code", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose status code contains this: 403, or 40 for 400 to 409; type=raw only"}, {"name": "uri", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose path and query string contain this; type=raw only"}, {"name": "ja4", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose TLS fingerprint contains this; type=raw only"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/LogTop"}, {"$ref": "#/components/schemas/LogRaw"}], "discriminator": {"propertyName": "type", "mapping": {"raw": "#/components/schemas/LogRaw", "status_codes": "#/components/schemas/LogTop", "threat_intel": "#/components/schemas/LogTop", "top_asns": "#/components/schemas/LogTop", "top_combination": "#/components/schemas/LogTop", "top_countries": "#/components/schemas/LogTop", "top_deny_rules": "#/components/schemas/LogTop", "top_host_headers": "#/components/schemas/LogTop", "top_http_methods": "#/components/schemas/LogTop", "top_http_versions": "#/components/schemas/LogTop", "top_ips": "#/components/schemas/LogTop", "top_ja4": "#/components/schemas/LogTop", "top_path_class": "#/components/schemas/LogTop", "top_rules": "#/components/schemas/LogTop", "top_uris": "#/components/schemas/LogTop", "top_user_agents": "#/components/schemas/LogTop"}}}, "examples": {"top_ips": {"value": {"type": "top_ips", "range": "1h", "field": "client_ip", "window_seconds": 3600, "service_total": 7, "service_total_rps_avg": 0.0019444444444444444, "data": [{"value": "192.0.2.7", "count": 7, "rps_avg": 0.0019444444444444444, "share": 1.0}]}}, "raw": {"value": {"type": "raw", "range": "1h", "count": 1, "data": [{"timestamp": "2026-10-23T10:13:24.000000000Z", "line": "client_ip=192.0.2.7 client_port=40000 frontend_name=ft_a_example_com backend_name=bk_a_example_com server_name=origin-1 tq=0 tw=0 tc=1 tr=5 ta=6 status_code=200 bytes_read=512 termination_state=-- zp_cache=MISS feconn=3 beconn=2 srv_conn=1 retries=0 srv_queue=0 backend_queue=0 http_method=GET http_request_uri=/a"}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs/export": {"get": {"tags": ["Metrics and logs"], "summary": "Export the request log (streamed)", "operationId": "exportServiceLogs", "description": "A file download. A failure after the first page ends the file with a line starting # ERROR. Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "format", "in": "query", "required": false, "schema": {"type": "string", "enum": ["csv", "logfmt"], "default": "csv"}, "description": "csv: one column per field; logfmt: key=value per line"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "from", "in": "query", "required": false, "schema": {"type": "string", "format": "date-time"}, "description": "Start of the window, RFC 3339, at most 96 h back; with only from, range sets the length"}, {"name": "to", "in": "query", "required": false, "schema": {"type": "string", "format": "date-time"}, "description": "End of the window, RFC 3339, not included; with only to, range sets the length. Page back by passing the oldest timestamp you received"}, {"name": "client_ip", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose client address contains this"}, {"name": "status_code", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose status code contains this: 403, or 40 for 400 to 409"}, {"name": "uri", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose path and query string contain this"}, {"name": "ja4", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Lines whose TLS fingerprint contains this"}], "responses": {"200": {"description": "The log as a file (Content-Disposition: attachment)", "content": {"text/csv": {"schema": {"type": "string", "format": "binary"}, "example": "{\n  \"code\": \"not_found\",\n  \"error\": \"Service not found: a.example.com\"\n"}, "text/plain": {"schema": {"type": "string", "format": "binary"}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs/l4": {"get": {"tags": ["Metrics and logs"], "summary": "All aggregates of the L3/4 forensics view", "operationId": "getServiceL4Logs", "description": "For vServices with TCP or UDP ports outside HTTP; others get a 422. Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "view", "in": "query", "required": false, "schema": {"type": "string", "enum": ["allowed", "dropped"], "default": "allowed"}, "description": "allowed: UDP flows and TCP connections; dropped: sources the edge dropped"}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 50}, "description": "Rows per aggregate"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4Overview"}, "examples": {"allowed": {"value": {"range": "1h", "view": "allowed", "window_seconds": 3600, "since": "2026-10-23T09:13:25+00:00", "protocols": ["tcp", "udp"], "panels": {"top_countries": {"field": "geoip_country_code", "data": [{"value": "DE", "count": 14, "label": "DTAG"}]}, "top_clients": {"field": "client_ip", "data": [{"value": "192.0.2.7", "count": 14, "bytes": 14, "label": "DTAG"}]}, "top_asns": {"field": "geoip_asn", "data": [{"value": "3320", "count": 14, "label": "DTAG"}]}, "termination": {"field": "termination_state", "data": [{"value": "--", "count": 14}]}, "top_origins": {"field": "server_name", "data": [{"value": "origin-1", "count": 14, "bytes": 14, "label": "DTAG"}]}, "summary": {"udp_flows": 7, "udp_clients": 7, "tcp_connections": 7, "tcp_clients": 7, "bytes_to_client": 14, "bytes_to_origin": 14}, "top_ports": {"field": "vip_port", "data": [{"value": "5000", "count": 7, "label": "DTAG"}]}, "packet_shape": {"available": true, "samples": {"5m": 2}, "windows": {"5m": {"dport": [{"value": "443", "share": 2.0, "service_port": true}]}}}}, "errors": {}, "took_ms": 0}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs/l4/raw": {"get": {"tags": ["Metrics and logs"], "summary": "Newest raw L3/4 lines", "operationId": "getServiceL4RawLogs", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "view", "in": "query", "required": false, "schema": {"type": "string", "enum": ["allowed", "dropped"], "default": "allowed"}, "description": "allowed: UDP flows and TCP connections; dropped: sources the edge dropped"}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 200}, "description": "Lines"}, {"name": "ip", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Client or source address, prefix match"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4Raw"}, "examples": {"allowed": {"value": {"range": "1h", "view": "allowed", "since": "2026-10-23T09:13:25+00:00", "count": 1, "data": [{"timestamp": "2026-10-23T10:13:24.000000000Z", "fields": {"proto": "tcp", "client_ip": "192.0.2.7", "client_port": "40000", "server_name": "origin-1", "termination_state": "--", "duration_s": "3", "bytes_read": "10", "bytes_uploaded": "20"}}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs/overview": {"get": {"tags": ["Metrics and logs"], "summary": "All aggregates of the forensics view", "operationId": "getServiceLogOverview", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 50}, "description": "Rows per aggregate"}, {"name": "view", "in": "query", "required": false, "schema": {"type": "string", "enum": ["allowed", "blocked", "all"], "default": "allowed"}, "description": "allowed: what reached your origin; blocked: what the edge turned away; all: both"}, {"name": "types", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Comma-separated subset of top_countries, top_ips, top_asns, top_host_headers, top_uris, top_user_agents, top_http_methods, top_http_versions, status_codes, top_ja4, top_path_class, top_rules, top_deny_rules, threat_intel, top_combination; default all"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LogOverview"}, "examples": {"default": {"value": {"range": "1h", "view": "allowed", "window_seconds": 3600, "service_total": 7, "service_total_rps_avg": 0.0019444444444444444, "types": ["top_ips", "top_countries"], "panels": {"top_ips": {"type": "top_ips", "range": "1h", "field": "client_ip", "window_seconds": 3600, "service_total": 7, "service_total_rps_avg": 0.0019444444444444444, "data": [{"value": "192.0.2.7", "count": 7, "rps_avg": 0.0019444444444444444, "share": 1.0}]}, "top_countries": {"type": "top_countries", "range": "1h", "field": "geoip_country_code", "window_seconds": 3600, "service_total": 7, "service_total_rps_avg": 0.0019444444444444444, "data": [{"value": "DE", "count": 7, "rps_avg": 0.0019444444444444444, "share": 1.0}]}}, "errors": {}, "took_ms": 0}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/logs/timeseries": {"get": {"tags": ["Metrics and logs"], "summary": "Requests over time by a field", "operationId": "getServiceLogTimeseries", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "field", "in": "query", "required": false, "schema": {"type": "string", "enum": ["geoip_country_code", "http_method", "http_version", "status_code", "user_agent", "zp_cache"], "default": "status_code"}, "description": "One line per value"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "default": "1h"}, "description": "Time window"}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 10}, "description": "Lines, the busiest values"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LogTimeseries"}, "examples": {"default": {"value": {"type": "timeseries", "field": "status_code", "range": "1h", "step": 60, "series": [{"label": "200", "values": [[1792750344, 3], [1792750404, 4]]}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/metrics": {"get": {"tags": ["Metrics and logs"], "summary": "Traffic metrics of a vService", "operationId": "getServiceMetrics", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "metric", "in": "query", "required": false, "schema": {"type": "string", "enum": ["backend_connections", "backend_request_rate", "backend_response_codes", "backend_traffic", "blocked", "l4_flows", "l4_packets", "origin_status", "pre_http_filter", "protection", "request_rate", "request_rate_blocked", "response_codes", "response_time", "summary", "traffic", "upstream"], "default": "summary"}, "description": "summary: live values; origin_status: health check per origin; the others: a chart"}, {"name": "range", "in": "query", "required": false, "schema": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "default": "1h"}, "description": "Time window"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/MetricChart"}, {"$ref": "#/components/schemas/MetricSummary"}, {"$ref": "#/components/schemas/OriginStatus"}], "discriminator": {"propertyName": "metric", "mapping": {"backend_connections": "#/components/schemas/MetricChart", "backend_request_rate": "#/components/schemas/MetricChart", "backend_response_codes": "#/components/schemas/MetricChart", "backend_traffic": "#/components/schemas/MetricChart", "blocked": "#/components/schemas/MetricChart", "l4_flows": "#/components/schemas/MetricChart", "l4_packets": "#/components/schemas/MetricChart", "origin_status": "#/components/schemas/OriginStatus", "pre_http_filter": "#/components/schemas/MetricChart", "protection": "#/components/schemas/MetricChart", "request_rate": "#/components/schemas/MetricChart", "request_rate_blocked": "#/components/schemas/MetricChart", "response_codes": "#/components/schemas/MetricChart", "response_time": "#/components/schemas/MetricChart", "summary": "#/components/schemas/MetricSummary", "traffic": "#/components/schemas/MetricChart", "upstream": "#/components/schemas/MetricChart"}}}, "examples": {"summary": {"value": {"metric": "summary", "data": {"requests_per_sec": 2.0, "packets_per_sec": 2.0, "bits_per_sec": 2.0, "bits_out_per_sec": 2.0, "active_sessions": 4, "active_sessions_tcp": 2, "active_flows_udp": 2, "healthy_backends": 2, "connections_rejected_per_sec": 2.0, "edge_bytes": 2, "origin_bytes": 2}}}, "traffic": {"value": {"metric": "traffic", "range": "1h", "step": "15s", "series": [{"label": "at_site", "values": [[1792750389, 1.5], [1792750404, 2.0]], "dashed": true, "direction": "in"}, {"label": "inbound", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}, {"label": "passed_frontend", "values": [[1792750389, 1.5], [1792750404, 2.0]], "direction": "in"}]}}, "origin_status": {"value": {"metric": "origin_status", "data": [{"name": "origin-1", "up_edges": 2, "edges": 2}]}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/origins": {"get": {"tags": ["Origins"], "summary": "List the origins of a vService", "operationId": "listOrigins", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/Origin"}}, "examples": {"default": {"value": [{"name": "origin-1", "address": "192.0.2.10", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}]}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "post": {"tags": ["Origins"], "summary": "Add an origin", "operationId": "createOrigin", "description": "Send an Idempotency-Key so that a retry after a network error does not add the origin twice; the key holds for 24 h, the same key with another body is a 409. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "maxLength": 128}, "description": "Makes a retry return the first result"}], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Origin"}, "examples": {"default": {"value": {"name": "origin-2", "address": "192.0.2.13", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "200": {"description": "A retry with the same Idempotency-Key: the origin the first request added, with the header Idempotent-Replayed: true", "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Origin"}, "examples": {"default": {"value": {"name": "origin-2", "address": "192.0.2.13", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Origin"}, "examples": {"default": {"value": {"address": "192.0.2.13", "port": 443}}}}}}}}, "/services/{fqdn}/origins/{origin_name}": {"delete": {"tags": ["Origins"], "summary": "Remove an origin", "operationId": "deleteOrigin", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "origin_name", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Origin name, as in GET /services/{fqdn}/origins"}], "responses": {"204": {"description": "No content", "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "put": {"tags": ["Origins"], "summary": "Replace an origin", "operationId": "replaceOrigin", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}, {"name": "origin_name", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Origin name, as in GET /services/{fqdn}/origins"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Origin"}, "examples": {"default": {"value": {"name": "origin-1", "address": "192.0.2.14", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Origin"}, "examples": {"default": {"value": {"name": "origin-1", "address": "192.0.2.14", "port": 443}}}}}}}}, "/services/{fqdn}/rename": {"post": {"tags": ["Services"], "summary": "Make an alias the primary name", "operationId": "renameService", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Service"}, "examples": {"default": {"value": {"fqdn": "www.a.example.com", "tenant": "tenant-a", "enabled": true, "mode": "https", "ports": [443], "udp_ports": [], "created": "2026-10-01T00:00:00+00:00", "created_by": "", "account_id": "acc-a", "network": {"vips": [{"anycast_ipv4": "203.0.113.1", "anycast_ipv6": "2001:db8:a::1"}, {"anycast_ipv4": "203.0.113.0", "anycast_ipv6": "2001:db8:a::"}], "pool": "P-A", "edge_hostname": "a-example-com.edge.protect.zeroservices.eu"}, "network_protection": {"enabled": true}, "backend": {"algorithm": "roundrobin", "health_check": {"method": "GET", "path": "/", "host": null, "interval": "10s", "rise": 2, "fall": 3, "expect": null}}, "origins": [{"name": "origin-1", "address": "192.0.2.14", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}, {"name": "origin-2", "address": "192.0.2.13", "port": 443, "tls": true, "ssl_verify": true, "weight": 100, "maxconn": 100}], "waf": {"enabled": true, "fail_open": true, "mode": "On", "paranoia_level": 1, "inbound_threshold": 5, "disabled_rules": []}, "rate_limiting": {"challenge_req_per_10s": 200, "req_per_10s": 800, "conn_per_10s": 50, "conn_drop_per_10s": 500, "path_default": 1000, "path_aggregate_per_10s": 5000, "geo_tcp_reject_sess_rate": 200, "ja4_enabled": false, "ja4_req_per_10s": 100, "ja4_action": "challenge"}, "pow": {"enabled": true, "difficulty": 18, "cookie_ttl": 86400, "always_challenge": false, "exempt_crawlers": true, "bind_ip": true, "botcheck_per_10s": 1000}, "admission": {"enabled": false, "credit_required": 5, "credit_window": "60s", "known_ttl": "24h", "unknown_conn_rate": 1500, "table_size": "1m"}, "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}, "aliases": [{"fqdn": "a.example.com", "ssl": {"mode": "acme", "acme_provider": "zerossl", "acme_email": null, "https_redirect": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null}}], "cache": {"enabled": true}, "slow_http": {"enabled": true, "timeout_http_request": "5s", "timeout_client_fin": "5s"}, "tcp_timeout": {"client": "30s", "server": "30s", "tunnel": "30s"}, "udp_timeout": {"idle": "300s", "unreplied": "30s", "unreplied_pkts": 32, "src_pps": 0}, "sni_policy": "allowlist", "proxy_protocol": false, "tls_termination": false, "priority": {"enabled": true, "session_signal": []}, "response_headers": {"hsts": {"enabled": false, "max_age": 31536000, "include_subdomains": false, "preload": false}, "cors": {"enabled": false, "rules": []}, "x_frame_options": null, "x_content_type_options": false, "referrer_policy": null}, "content_negotiation": {"enabled": false, "encodings": ["zstd", "gzip"], "file_types": ["css", "js", "html"]}, "logging": {"enabled": false}, "threat_intel": {"mode": "log", "abuse": "log", "tor": "log"}, "redirects": [], "origin_host": "a.example.com", "origin_sni": "a.example.com", "maintenance_mode": false, "auto_mitigation": false, "defense_posture": null, "protection_allowlist": null, "edges": [], "protection_rules": [], "append_trailing_slash": false, "exceed_no_rtbh": false, "exceed_no_flowspec": false, "origin_kind": "dynamic", "alias_limit": 20, "serving_edges": ["shared-1"], "posture_drift": [], "baseline": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Rename"}, "examples": {"default": {"value": {"to": "www.a.example.com"}}}}}}}}, "/services/{fqdn}/ssl": {"get": {"tags": ["TLS"], "summary": "Certificate of a vService", "operationId": "getCertificate", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateStatus"}, "examples": {"default": {"value": {"fqdn": "a.example.com", "mode": "acme", "has_custom_cert": false, "cert_status": "none", "cert_issued": null, "cert_expires": null, "cert_last_renewal": null, "days_remaining": null, "detail": null}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "post": {"tags": ["TLS"], "summary": "Upload a certificate (ECDSA)", "operationId": "uploadCertificate", "description": "Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateStored"}, "examples": {"default": {"value": {"fqdn": "a.example.com", "mode": "custom", "cert": {"subject": "CN=a.example.com", "issuer": "CN=Example CA", "not_before": "2026-10-01T00:00:00+00:00", "not_after": "2026-12-30T00:00:00+00:00", "dns_names": ["a.example.com", "www.a.example.com"], "serial_number": "4f2a", "chain_length": 2, "key_type": "EC", "key_bits": 256, "curve": "secp256r1"}}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CertificateUpload"}, "examples": {"default": {"value": {"fullchain_pem": "-----BEGIN CERTIFICATE-----\nMIIBszCCAVmgAwIBAgIU...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBuDCCAV6gAwIBAgIU...\n-----END CERTIFICATE-----\n", "privkey_pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEG...\n-----END PRIVATE KEY-----\n"}}}}}}}}, "/services/{fqdn}/ssl/issue": {"post": {"tags": ["TLS"], "summary": "Issue a certificate via ACME", "operationId": "issueCertificate", "description": "No request body. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AcmeStarted"}, "examples": {"default": {"value": {"status": "started", "fqdn": "a.example.com"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/services/{fqdn}/ssl/renew": {"post": {"tags": ["TLS"], "summary": "Renew the ACME certificate", "operationId": "renewCertificate", "description": "No request body. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "fqdn", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Primary FQDN of the vService; an alias is not accepted here"}], "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AcmeStarted"}, "examples": {"default": {"value": {"status": "started", "fqdn": "a.example.com"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}, "/tenant": {"get": {"tags": ["Account"], "summary": "Your tenant", "operationId": "getTenant", "description": "Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Tenant"}, "examples": {"default": {"value": {"tenant": "tenant-a", "company_name": "A", "portal_name": null, "portal_domain": null, "default_posture": "standard", "dedicated_edges": [], "ip_pools": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}, "patch": {"tags": ["Account"], "summary": "Set the default posture for new vServices", "operationId": "updateTenant", "description": "Primary account only. Existing vServices keep their posture. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TenantPosture"}, "examples": {"default": {"value": {"default_posture": "standard"}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TenantPatch"}, "examples": {"default": {"value": {"default_posture": "standard"}}}}}}}}, "/vip-operations": {"post": {"tags": ["IP pools"], "summary": "Run VIP operations as one change", "operationId": "runVipOperations", "description": "All operations of a request are applied together or not at all. With an Idempotency-Key, a retry returns the first result (200, replayed: true); the same key with other operations is a 409. Scope: `protect:write`.", "x-scope": "protect:write", "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "maxLength": 128}, "description": "Makes a retry return the first result"}], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VipOperationRecord"}, "examples": {"assign": {"value": {"id": "f69c6909151c", "idempotency_key": null, "at": "2026-10-23T10:13:25.336158+00:00", "by": "key:TGloIsNcCavQ", "services": ["a.example.com"], "pools": [], "results": [{"op": "assign", "service": "a.example.com", "addresses": ["203.0.113.0"]}], "commit": "f3b4fa1574c766a5567fb442fee9989f5729792a", "replayed": false}}, "block": {"value": {"id": "85b0a4fd6a65", "idempotency_key": null, "at": "2026-10-23T10:13:25.393986+00:00", "by": "key:TGloIsNcCavQ", "services": [], "pools": [], "results": [{"op": "block", "blocked": ["203.0.113.9"]}], "commit": "bbe37eb5bfcf90d2369090b89e5c6ebb0e7c3a13", "replayed": false}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "200": {"description": "A retry with the same Idempotency-Key: the first result, replayed: true", "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VipOperationRecord"}, "examples": {"assign": {"value": {"id": "f69c6909151c", "idempotency_key": null, "at": "2026-10-23T10:13:25.336158+00:00", "by": "key:TGloIsNcCavQ", "services": ["a.example.com"], "pools": [], "results": [{"op": "assign", "service": "a.example.com", "addresses": ["203.0.113.0"]}], "commit": "f3b4fa1574c766a5567fb442fee9989f5729792a", "replayed": false}}, "block": {"value": {"id": "85b0a4fd6a65", "idempotency_key": null, "at": "2026-10-23T10:13:25.393986+00:00", "by": "key:TGloIsNcCavQ", "services": [], "pools": [], "results": [{"op": "block", "blocked": ["203.0.113.9"]}], "commit": "bbe37eb5bfcf90d2369090b89e5c6ebb0e7c3a13", "replayed": false}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Unprocessable"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VipOperations"}, "examples": {"assign": {"value": {"operations": [{"op": "assign", "service": "a.example.com", "pool": "P-A", "count": 1}]}}, "block": {"value": {"operations": [{"op": "block", "addresses": ["203.0.113.9"]}]}}}}}}}}, "/vip-operations/{op_id}": {"get": {"tags": ["IP pools"], "summary": "Where an operation stands", "operationId": "getVipOperation", "description": "state is live once every edge that serves the operation's vServices or pools runs it. Scope: `protect:read`.", "x-scope": "protect:read", "parameters": [{"name": "op_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Operation id returned by POST /vip-operations"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VipOperationStatus"}, "examples": {"default": {"value": {"id": "f69c6909151c", "idempotency_key": null, "at": "2026-10-23T10:13:25.336158+00:00", "by": "key:TGloIsNcCavQ", "services": ["a.example.com"], "pools": [], "results": [{"op": "assign", "service": "a.example.com", "addresses": ["203.0.113.0"]}], "commit": "f3b4fa1574c766a5567fb442fee9989f5729792a", "state": "pending", "edges": []}}}}}, "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/X-RateLimit-Limit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/X-RateLimit-Remaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/X-RateLimit-Reset"}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"$ref": "#/components/responses/Unavailable"}}}}}, "components": {"securitySchemes": {"apiKey": {"type": "http", "scheme": "bearer", "bearerFormat": "zsk", "description": "zsk_<id>_<secret>, bound to your addresses"}}, "responses": {"BadRequest": {"description": "Malformed request, or more than one X-Forwarded-For value (code bad_request)", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Unauthorized": {"description": "code invalid_key: missing, malformed, unknown, expired or revoked key, the address is not bound to the key, or API access is not enabled for your account. One answer for all of these on purpose: it tells nobody holding a key whether it is valid.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Forbidden": {"description": "code insufficient_scope: the key lacks protect:write; code not_available_with_key: the route is for the portal only", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "NotFound": {"description": "Unknown path or not one of your resources (code not_found)", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Conflict": {"description": "Conflicts with the current state; code says which (e.g. service_exists, origin_exists, acme_in_progress, idempotency_key_reused, cache_disabled)", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "TooLarge": {"description": "The upload is too large (code too_large)", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Unprocessable": {"description": "Validation failed; details name the field (code validation_failed)", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "TooManyRequests": {"description": "Your key's limit (code rate_limited or too_many_concurrent): retry after Retry-After. X-RateLimit-* show the budget before you hit it", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Unavailable": {"description": "The platform is busy or briefly unavailable, not your limit (code busy or unavailable): retry after Retry-After", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests the key may burst: the size of its bucket. Heavy reads (lists, health, metrics, logs) have their own, smaller bucket", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in the bucket now", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the bucket is full again", "schema": {"type": "integer"}}}, "schemas": {"Account": {"type": "object", "properties": {"account_id": {"type": "string", "description": "Account id"}, "tenant": {"type": "string", "description": "Your tenant id"}, "name": {"type": "string", "nullable": true, "description": "Display name; null when none is set"}, "plan": {"type": "string", "enum": ["shared", "dedicated", "byoip"], "description": "dedicated and byoip create vServices themselves; null = shared", "nullable": true}, "acme_email": {"type": "string", "nullable": true, "description": "Contact for the certificate authority"}, "branding": {"$ref": "#/components/schemas/Branding", "description": "Branding of the error and maintenance pages of the account's vServices"}, "created": {"type": "string", "format": "date-time", "nullable": true, "description": "When the account was created; null when not recorded"}, "created_by": {"type": "string", "description": "Your e-mail or key label; empty = Zero Services"}, "services": {"type": "array", "items": {"type": "string"}, "description": "FQDNs of the account's vServices"}}, "required": ["account_id", "services", "tenant"], "description": "One of your accounts: a booked plan with its vServices and the branding of their pages"}, "AccountList": {"type": "array", "items": {"$ref": "#/components/schemas/AccountSummary"}, "description": "Your accounts"}, "AccountSummary": {"type": "object", "properties": {"account_id": {"type": "string", "description": "Account id"}, "tenant": {"type": "string", "description": "Your tenant id"}, "name": {"type": "string", "nullable": true, "description": "Display name; null when none is set"}, "plan": {"type": "string", "enum": ["shared", "dedicated", "byoip"], "description": "shared, dedicated or byoip; dedicated and byoip accounts create vServices themselves"}, "services": {"type": "array", "items": {"type": "string"}, "description": "FQDNs of the account's vServices"}, "created": {"type": "string", "format": "date-time", "nullable": true, "description": "When the account was created; null when not recorded"}}, "required": ["account_id", "plan", "services", "tenant"], "description": "An account in the list: GET /accounts/{account_id} has every field"}, "AccountUpdate": {"type": "object", "properties": {"name": {"type": "string", "nullable": true, "maxLength": 100, "description": "Display name; null or empty clears it"}, "branding": {"$ref": "#/components/schemas/Branding", "description": "Merged into the stored branding: send only what changes"}}, "description": "Only the display name and the branding; everything else stays."}, "AcmeStarted": {"type": "object", "properties": {"status": {"type": "string", "enum": ["started"], "description": "Always started"}, "fqdn": {"type": "string", "description": "The name the certificate is for: the vService or the alias"}}, "required": ["fqdn", "status"], "description": "Runs in the background; GET .../ssl shows the result"}, "Admission": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Sources that earned credit with successful answers over time pass. While the edge is under strain, new connections from all other sources share one budget and are refused above it, before the TLS handshake"}, "credit_required": {"type": "integer", "minimum": 1, "maximum": 1000, "default": 5, "readOnly": true, "description": "Set by support on request"}, "credit_window": {"type": "string", "pattern": "^[1-9][0-9]{0,5}(ms|s|m|h)$", "default": "60s", "readOnly": true, "description": "Set by support on request"}, "known_ttl": {"type": "string", "pattern": "^[1-9][0-9]{0,5}(ms|s|m|h)$", "default": "24h", "readOnly": true, "description": "Set by support on request"}, "unknown_conn_rate": {"type": "integer", "minimum": 1, "maximum": 10000000, "default": 1500, "readOnly": true, "description": "Set by support on request"}, "table_size": {"type": "string", "pattern": "^[1-9][0-9]{0,5}[kmg]?$", "default": "1m", "readOnly": true, "description": "Set by support on request"}}, "description": "Returning-visitor admission for HTTPS vServices. You switch enabled; Zero Services sets the thresholds"}, "AdmissionPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "Sources that earned credit with successful answers over time pass. While the edge is under strain, new connections from all other sources share one budget and are refused above it, before the TLS handshake"}}, "description": "Merged into the stored admission: send only the fields to change."}, "Alias": {"type": "object", "properties": {"fqdn": {"type": "string", "minLength": 1, "maxLength": 253, "description": "The alias hostname"}, "ssl": {"allOf": [{"$ref": "#/components/schemas/Ssl"}], "description": "Certificate settings of the alias"}}, "required": ["fqdn"], "description": "A further hostname of the vService. It shares the addresses, origins and settings and has its own certificate"}, "Asns": {"type": "object", "properties": {"asns": {"type": "array", "items": {"type": "integer"}, "description": "Autonomous systems usable in rules and allowlists"}}, "required": ["asns"], "description": "Autonomous system numbers for asn matches and the allowlist"}, "Attack": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService"}, "state": {"type": "string", "enum": ["under_attack", "blackholed"], "description": "under_attack: the edge stops it; blackholed: your addresses are dark upstream"}, "start": {"type": "string", "format": "date-time", "description": "Started"}, "end": {"type": "string", "format": "date-time", "nullable": true, "description": "Ended; null while it runs"}, "ended_as": {"type": "string", "enum": ["blackholed", "origin_down", "misconfigured", "errors", "origin_slow", "under_attack", "normal", "maintenance", "disabled"], "description": "State of the vService after the attack; null while it runs", "nullable": true}, "reason": {"type": "string", "nullable": true, "description": "Machine-readable, as reason of the health light"}, "techniques": {"type": "array", "items": {"type": "string", "enum": ["admission", "l7", "xdp", "upstream"]}, "description": "Every technique that stopped traffic during the attack"}, "signals": {"$ref": "#/components/schemas/HealthSignals", "description": "Measured at the start; empty while it runs and not yet known"}, "escalations": {"type": "array", "items": {"$ref": "#/components/schemas/AttackEscalation"}, "description": "What we did beyond the edge; empty when the edge handled it alone"}}, "required": ["end", "ended_as", "escalations", "fqdn", "reason", "signals", "start", "state", "techniques"], "description": "An attack on one of your vServices and what we did against it"}, "AttackArchive": {"type": "object", "properties": {"month": {"type": "string", "description": "YYYY-MM"}, "attacks": {"type": "array", "items": {"$ref": "#/components/schemas/Attack"}, "description": "Newest first"}}, "required": ["attacks", "month"], "description": "Attacks of one month"}, "AttackEscalation": {"type": "object", "properties": {"action": {"type": "string", "enum": ["flowspec", "divert", "site_shed", "rtbh", "signature"], "description": "rtbh: the address dark upstream; flowspec and signature: filtered at the upstream routers; site_shed and divert: the traffic of the whole IP pool moved"}, "site": {"type": "string", "description": "Site it ran at"}, "vip": {"type": "string", "nullable": true, "description": "Your address it was for; null when it covered the IP pool"}, "start": {"type": "string", "format": "date-time", "description": "Started"}, "end": {"type": "string", "format": "date-time", "nullable": true, "description": "Ended; null while in force"}}, "required": ["action", "end", "site", "start", "vip"], "description": "A measure beyond the edge, taken during the attack"}, "AttackList": {"type": "object", "properties": {"attacks": {"type": "array", "items": {"$ref": "#/components/schemas/Attack"}, "description": "Newest first"}}, "required": ["attacks"], "description": "Attacks running now"}, "Backend": {"type": "object", "properties": {"algorithm": {"type": "string", "enum": ["roundrobin", "leastconn", "source", "uri"], "default": "roundrobin", "description": "roundrobin: in turn, by weight. leastconn: the origin with the fewest open connections. source: by client address, so a client stays on one origin. uri: by request path, so a path stays on one origin"}, "health_check": {"allOf": [{"$ref": "#/components/schemas/HealthCheck"}], "description": "Health check of the origins"}}, "description": "How the edge spreads requests across your origins and checks their health"}, "BackendPatch": {"type": "object", "properties": {"algorithm": {"type": "string", "enum": ["roundrobin", "leastconn", "source", "uri"], "description": "roundrobin: in turn, by weight. leastconn: the origin with the fewest open connections. source: by client address, so a client stays on one origin. uri: by request path, so a path stays on one origin"}, "health_check": {"allOf": [{"$ref": "#/components/schemas/HealthCheck"}], "description": "Health check of the origins"}}, "description": "Merged into the stored backend: send only the fields to change."}, "Branding": {"type": "object", "properties": {"primary_color": {"type": "string", "default": "#0055AA", "pattern": "^#[0-9A-Fa-f]{6}$", "description": "Accent color of the error and maintenance pages, #RRGGBB"}, "background_color": {"type": "string", "default": "#f5f5f5", "pattern": "^#[0-9A-Fa-f]{6}$", "description": "Page background of the error and maintenance pages, #RRGGBB"}, "logo_file": {"type": "string", "nullable": true, "readOnly": true, "description": "Set by POST /accounts/{account_id}/logo"}, "support_email": {"type": "string", "format": "email", "nullable": true, "description": "Support address shown on the error, challenge and maintenance pages"}, "support_url": {"type": "string", "nullable": true, "description": "Support link shown on the error, challenge and maintenance pages"}, "pow_text": {"type": "string", "maxLength": 500, "nullable": true, "description": "Headline of the challenge page, up to 500 characters. Empty: \"Checking your connection to\" and the host"}, "block_text": {"type": "string", "maxLength": 500, "nullable": true, "description": "What the block page (403) says happened, up to 500 characters; error_messages 403 wins. Empty: the page's own text"}, "error_titles": {"type": "object", "additionalProperties": {"type": "string"}, "default": {}, "description": "Headline per status code (403, 429, 502, 503), up to 200 characters each; a vService's own error page text wins"}, "error_messages": {"type": "object", "additionalProperties": {"type": "string"}, "default": {}, "description": "Message per status code (403, 429, 502, 503), up to 500 characters each; a vService's own error page text wins"}}, "description": "Look of the error and maintenance pages the edges serve for the account's vServices"}, "Cache": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": true, "description": "Edge cache for GET and HEAD requests. Off: every request goes to your origin"}, "engine": {"type": "string", "enum": ["haproxy", "ats"], "description": "Cache engine at the edge. Set by support on request; ignored when you send it", "readOnly": true}, "stale_if_error": {"type": "integer", "minimum": 0, "maximum": 86400, "description": "Seconds an expired object may still be served while your origin fails, 0 to 86400. Default 86400; 0: never"}, "stale_while_revalidate": {"type": "integer", "minimum": 0, "maximum": 300, "description": "Seconds an expired object is still served while the edge fetches a fresh copy, 0 to 300. Default 30; 0: off"}, "min_hits": {"type": "integer", "minimum": 2, "maximum": 10, "nullable": true, "description": "Store an object only from its Nth request on, 2 to 10, to keep one-off requests out. Null: from the first request"}, "purge_all_interval": {"type": "integer", "minimum": 60, "maximum": 86400, "nullable": true, "readOnly": true, "description": "Set by support on request; ignored when you send it"}, "negative_ttl": {"type": "integer", "minimum": 1, "maximum": 3600, "nullable": true, "description": "Seconds a 404 or 410 from your origin is served from the cache, 1 to 3600. Null: never"}, "large_files": {"type": "boolean", "nullable": true, "description": "Cache video, audio, archives, installers, disk images and PDFs (by file extension) in 4 MB blocks; your origin must answer Range requests"}, "key": {"allOf": [{"$ref": "#/components/schemas/CacheKey"}], "description": "What the cache key holds besides hostname, path and scheme"}, "rules": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/CacheRule"}]}, "maxItems": 25, "description": "Up to 25 rules on the request path, the first match wins; a path no rule matches follows your origin's headers"}, "token_gate": {"allOf": [{"$ref": "#/components/schemas/CacheTokenGate"}], "readOnly": true, "description": "Set by support on request; ignored when you send it"}}, "description": "Edge cache for GET and HEAD requests of HTTPS vServices. Without a rule your origin's Cache-Control and Expires decide; a response with only Last-Modified is kept 1 hour"}, "CacheKey": {"type": "object", "properties": {"params": {"type": "string", "enum": ["all", "include", "none"], "description": "all (the default): every query parameter except ignore_params. include: only include_params. none: no parameter, so ?x=1 is no cache miss"}, "ignore_params": {"type": "array", "items": {"type": "string"}, "maxItems": 20, "description": "Query parameters left out of the key, such as per-viewer tokens; a name ending in * matches a prefix (utm_*). Up to 20"}, "include_params": {"type": "array", "items": {"type": "string"}, "maxItems": 20, "description": "With params include: the only query parameters in the key; a name ending in * matches a prefix. Up to 20"}, "sort_params": {"type": "boolean", "description": "Sort the query parameters first, so ?a=1&b=2 and ?b=2&a=1 are one object"}}, "description": "Which query parameters make two requests different objects. Hostname, path and scheme are always part of the key; your origin always gets the full query string"}, "CachePatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "Edge cache for GET and HEAD requests. Off: every request goes to your origin"}, "stale_if_error": {"type": "integer", "minimum": 0, "maximum": 86400, "description": "Seconds an expired object may still be served while your origin fails, 0 to 86400. Default 86400; 0: never"}, "stale_while_revalidate": {"type": "integer", "minimum": 0, "maximum": 300, "description": "Seconds an expired object is still served while the edge fetches a fresh copy, 0 to 300. Default 30; 0: off"}, "min_hits": {"type": "integer", "minimum": 2, "maximum": 10, "nullable": true, "description": "Store an object only from its Nth request on, 2 to 10, to keep one-off requests out. Null: from the first request"}, "negative_ttl": {"type": "integer", "minimum": 1, "maximum": 3600, "nullable": true, "description": "Seconds a 404 or 410 from your origin is served from the cache, 1 to 3600. Null: never"}, "large_files": {"type": "boolean", "nullable": true, "description": "Cache video, audio, archives, installers, disk images and PDFs (by file extension) in 4 MB blocks; your origin must answer Range requests"}, "key": {"allOf": [{"$ref": "#/components/schemas/CacheKey"}], "description": "What the cache key holds besides hostname, path and scheme"}, "rules": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/CacheRule"}]}, "maxItems": 25, "description": "Up to 25 rules on the request path, the first match wins; a path no rule matches follows your origin's headers"}}, "description": "Merged into the stored cache: send only the fields to change."}, "CachePurge": {"type": "object", "description": "One of: url (with an optional alias host), prefix, or all.", "properties": {"url": {"type": "string", "example": "/img/logo.png?v=2", "description": "Path and query string of one object, starting with /"}, "host": {"type": "string", "description": "Alias the URL belongs to; default the vService"}, "prefix": {"type": "string", "example": "/img/", "description": "Purge every object whose path starts with this, any query string, on the vService and its aliases. Starts with /, not / alone"}, "all": {"type": "boolean", "description": "true: purge every cached object of the vService and its aliases"}}}, "CacheRule": {"type": "object", "properties": {"path": {"type": "string", "description": "Glob on the request path, starting with / or *; * matches any characters, / included"}, "action": {"type": "string", "enum": ["cache", "bypass"], "description": "cache: cache matching responses, for ttl when set. bypass: matching requests go to your origin without the cache"}, "ttl": {"type": "integer", "minimum": 1, "maximum": 31536000, "nullable": true, "description": "Seconds the edge keeps a matching response, 1 to 31536000, whatever max-age or Expires your origin sends, also when it sends none. Null: your origin decides. cache rules only"}, "cookie": {"type": "string", "nullable": true, "description": "bypass rules only: apply only when the request carries this cookie; a name ending in * matches a prefix (wordpress_logged_in_*)"}, "header": {"type": "string", "nullable": true, "description": "bypass rules only: apply only when the request carries this header"}, "browser_ttl": {"type": "integer", "minimum": 0, "maximum": 31536000, "nullable": true, "description": "Cache-Control max-age in seconds sent to browsers on matching 200 responses, 0 to 31536000; never on private, no-store or Set-Cookie responses. cache rules only"}}, "required": ["action", "path"], "description": "A cache rule on the request path; the first matching rule wins"}, "CacheStats": {"type": "object", "properties": {"range": {"type": "string", "enum": ["1h", "6h", "24h"], "description": "Time window"}, "requests": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "GET/HEAD by cache state (HIT, MISS, EXPIRED, NONE, ...)"}, "bytes": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Response bytes by cache state"}, "hit_ratio": {"type": "number", "nullable": true, "description": "HIT among HIT, EXPIRED and MISS"}, "byte_share": {"type": "number", "nullable": true, "description": "Part of the bytes served from the cache"}, "token_denied": {"type": "integer", "nullable": true, "description": "429s of the token gate; null when off"}}, "required": ["bytes", "range", "requests"], "description": "Edge cache figures of GET and HEAD requests in the range, read from the access log"}, "CacheTokenGate": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Only requests with a token your origin confirmed get cached objects; all others go to your origin uncached"}, "params": {"type": "array", "items": {"type": "string"}, "maxItems": 5, "description": "Query parameters carrying the viewer token, up to 5; their URL-decoded values together are the token"}, "ttl": {"type": "integer", "minimum": 10, "maximum": 86400, "default": 60, "description": "Seconds a token stays confirmed after your origin last answered it with 2xx, 10 to 86400; a 401 or 403 from your origin ends it at once"}, "unknown_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 500, "description": "GET and HEAD requests per 10 s a source may send without a confirmed token; above it the edge answers 429"}, "outage_grace": {"type": "integer", "minimum": 0, "maximum": 86400, "default": 1800, "description": "Seconds a confirmation outlives ttl while every origin fails its health check, 0 to 86400. Default 1800"}}, "description": "Cache hits only for viewer tokens your origin accepted recently, for streams with tokens in the URL. Set by support"}, "CertificateDetails": {"type": "object", "properties": {"subject": {"type": "string", "description": "Subject distinguished name (RFC 4514)"}, "issuer": {"type": "string", "description": "Issuer distinguished name (RFC 4514)"}, "not_before": {"type": "string", "format": "date-time", "description": "Start of validity"}, "not_after": {"type": "string", "format": "date-time", "description": "End of validity"}, "dns_names": {"type": "array", "items": {"type": "string"}, "description": "DNS names in the certificate's subject alternative names"}, "serial_number": {"type": "string", "description": "Serial number, decimal"}, "chain_length": {"type": "integer", "description": "Certificates in the stored chain, leaf included"}, "key_type": {"type": "string", "enum": ["EC", "RSA", "Ed25519", "Ed448"], "description": "Public key type"}, "key_bits": {"type": "integer", "description": "Key size in bits"}, "curve": {"type": "string", "nullable": true, "description": "Elliptic curve, such as secp256r1; null for RSA"}}, "description": "The stored certificate, as read from the certificate itself"}, "CertificateStatus": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService or alias"}, "mode": {"type": "string", "enum": ["acme", "custom"], "description": "acme: issued and renewed by ZERO-PROTECT. custom: uploaded by you"}, "has_custom_cert": {"type": "boolean", "description": "A certificate is stored and served"}, "cert_status": {"type": "string", "enum": ["issued", "expiring", "expired", "error", "pending", "none"], "description": "Derived from the certificate the edges serve; expiring = renewal not done yet, the certificate is still valid"}, "cert_issued": {"type": "string", "format": "date-time", "nullable": true, "description": "When ZERO-PROTECT last obtained the certificate via ACME; null without ACME issuance"}, "cert_expires": {"type": "string", "format": "date-time", "nullable": true, "description": "Expiry of the certificate last obtained via ACME; cert.not_after is read from the stored certificate itself"}, "cert_last_renewal": {"type": "string", "format": "date-time", "nullable": true, "description": "When ZERO-PROTECT last renewed the certificate via ACME; null without ACME issuance"}, "cert": {"$ref": "#/components/schemas/CertificateDetails", "description": "The stored certificate; absent when none is stored or it cannot be read"}, "days_remaining": {"type": "integer", "nullable": true, "description": "Days until the certificate expires, rounded up; 0 or less once expired; null when unknown"}, "detail": {"type": "string", "nullable": true, "description": "What the state means for you"}}, "required": ["cert_status", "fqdn", "mode"], "description": "Certificate of the vService or of one alias"}, "CertificateStored": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService or alias"}, "mode": {"type": "string", "enum": ["custom"], "description": "Always custom after an upload"}, "cert": {"$ref": "#/components/schemas/CertificateDetails", "description": "The stored certificate"}}, "required": ["cert", "fqdn", "mode"], "description": "The uploaded certificate, as stored"}, "CertificateUpload": {"type": "object", "properties": {"fullchain_pem": {"type": "string", "description": "Leaf certificate first, then the intermediates, PEM"}, "privkey_pem": {"type": "string", "description": "Unencrypted private key, PEM"}}, "required": ["fullchain_pem", "privkey_pem"], "description": "ECDSA P-256 or P-384 only. The certificate must be valid now and name the vService (or the alias) in its SAN; the key must match. Stored encrypted; mode becomes custom."}, "ContentNegotiation": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "For the listed file types, request the compressed copy the client accepts (app.css.zst, app.css.gz, app.css.br) and set Content-Encoding. Your origin must hold every copy: the edge does not fall back to the original"}, "encodings": {"type": "array", "items": {"type": "string", "enum": ["gzip", "zstd", "br"]}, "minItems": 1, "maxItems": 3, "description": "Encodings in order of preference: zstd (.zst), gzip (.gz), br (.br); the first the client's Accept-Encoding names wins"}, "file_types": {"type": "array", "items": {"type": "string", "enum": ["css", "js", "html", "json", "svg", "xml", "txt", "wasm"]}, "minItems": 1, "maxItems": 8, "description": "File extensions served pre-compressed"}}, "description": "Serves pre-compressed copies of static files that your origin holds next to the originals"}, "ContentNegotiationPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "For the listed file types, request the compressed copy the client accepts (app.css.zst, app.css.gz, app.css.br) and set Content-Encoding. Your origin must hold every copy: the edge does not fall back to the original"}, "encodings": {"type": "array", "items": {"type": "string", "enum": ["gzip", "zstd", "br"]}, "minItems": 1, "maxItems": 3, "description": "Encodings in order of preference: zstd (.zst), gzip (.gz), br (.br); the first the client's Accept-Encoding names wins"}, "file_types": {"type": "array", "items": {"type": "string", "enum": ["css", "js", "html", "json", "svg", "xml", "txt", "wasm"]}, "minItems": 1, "maxItems": 8, "description": "File extensions served pre-compressed"}}, "description": "Merged into the stored content_negotiation: send only the fields to change."}, "Cors": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Answer CORS at the edge with the rules"}, "rules": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/CorsRule"}]}, "maxItems": 10, "description": "Up to 10 rules; the first whose origin and method match applies. The edge answers its preflight with 204; a request no rule matches passes to your origin unchanged, and CORS headers your origin sets win"}}, "description": "CORS answered at the edge"}, "CorsRule": {"type": "object", "properties": {"allowed_origins": {"type": "array", "items": {"type": "string", "maxLength": 253}, "minItems": 1, "maxItems": 20, "description": "Origins the rule covers, case-insensitive: * for any, or http(s)://host[:port], where * in the host stands for any letters, digits, dots and dashes. The edge echoes the request's Origin, or answers * when the list holds *"}, "allowed_methods": {"type": "array", "items": {"type": "string", "enum": ["GET", "HEAD", "PUT", "POST", "DELETE"]}, "minItems": 1, "maxItems": 5, "description": "Methods the rule covers, also its Access-Control-Allow-Methods"}, "allowed_headers": {"type": "array", "items": {"type": "string", "enum": ["*", "Authorization", "Content-Type", "Content-MD5", "Content-Disposition", "Content-Encoding", "Content-Length", "Cache-Control", "Accept", "Origin", "Range", "If-Match", "If-None-Match", "If-Modified-Since"]}, "maxItems": 20, "description": "Access-Control-Allow-Headers of the preflight answer; * repeats the headers the browser asked for"}, "expose_headers": {"type": "array", "items": {"type": "string", "enum": ["ETag", "Content-Range", "Content-Disposition", "Content-Encoding"]}, "maxItems": 20, "description": "Access-Control-Expose-Headers on responses"}, "max_age_seconds": {"type": "integer", "minimum": 0, "maximum": 86400, "default": 3600, "description": "Access-Control-Max-Age of the preflight answer in seconds, 0 to 86400; 0 leaves it out"}}, "required": ["allowed_methods", "allowed_origins"], "description": "One CORS rule: the origins and methods it covers and the headers the edge sends"}, "Countries": {"type": "object", "properties": {"countries": {"type": "array", "items": {"type": "string", "description": "ISO 3166-1 alpha-2"}, "description": "Country codes for geo matches and the allowlist"}}, "required": ["countries"], "description": "Country codes for geo matches and the allowlist"}, "Crawlers": {"type": "object", "properties": {"crawlers": {"type": "array", "items": {"type": "string"}, "description": "Crawler names; the edge recognises each crawler by its published source networks"}}, "required": ["crawlers"], "description": "Crawler names for crawler matches"}, "DnsHostname": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The hostname checked"}, "role": {"type": "string", "enum": ["primary", "alias"], "description": "primary: the vService's name. alias: one of its aliases"}, "status": {"type": "string", "enum": ["error", "not_found", "wrong_target", "apex_cname", "partial", "ok_cname_foreign", "ok_a", "ok_cname"], "description": "ok_cname, ok_a and ok_cname_foreign point at us"}, "detail": {"type": "string", "nullable": true, "description": "What to change"}, "is_apex": {"type": "boolean", "description": "The name is the apex of its DNS zone, where a CNAME is not allowed: use A and AAAA"}, "zone_apex": {"type": "string", "nullable": true, "description": "Apex of the DNS zone the name lies in; null when the lookup failed"}, "expected_cname": {"type": "string", "nullable": true, "description": "Edge hostname a CNAME should point at"}, "expected_ipv4": {"type": "string", "nullable": true, "description": "IPv4 address an A record should hold: the primary VIP"}, "expected_ipv6": {"type": "string", "nullable": true, "description": "IPv6 address an AAAA record should hold: the primary VIP; null without IPv6"}, "cname_target": {"type": "string", "nullable": true, "description": "First CNAME target, as the authoritative nameservers answer; null without CNAME"}, "cname_chain": {"type": "array", "items": {"type": "string"}, "description": "CNAME targets in order, as the authoritative nameservers answer"}, "resolved_ipv4": {"type": "array", "items": {"type": "string"}, "description": "IPv4 addresses the authoritative answer resolves to"}, "resolved_ipv6": {"type": "array", "items": {"type": "string"}, "description": "IPv6 addresses the authoritative answer resolves to"}, "ttl": {"type": "integer", "nullable": true, "description": "TTL in seconds of your first record, the CNAME or the A/AAAA; null when unknown"}, "public_ipv4": {"type": "array", "items": {"type": "string"}, "description": "IPv4 addresses a public resolver answers"}, "public_ipv6": {"type": "array", "items": {"type": "string"}, "description": "IPv6 addresses a public resolver answers"}, "public_cname_target": {"type": "string", "nullable": true, "description": "First CNAME target as a public resolver answers"}, "propagating": {"type": "boolean", "description": "Authoritative servers are right, public resolvers not yet"}, "caa": {"type": "object", "properties": {"status": {"type": "string", "enum": ["ok", "none", "unknown", "blocks_issuance"], "description": "ok: issuance allowed. none: no CAA records, any CA may issue. blocks_issuance: the records forbid your CA; add it or ACME fails. unknown: lookup failed, or no CA is known for the provider"}, "owner": {"type": "string", "nullable": true, "description": "Name the CAA records were found at: the hostname or a parent domain"}, "records": {"type": "array", "items": {"type": "string"}, "description": "The CAA records as text"}, "issuer": {"type": "string", "nullable": true, "description": "CA the records must allow for the acme_provider: letsencrypt.org, sectigo.com (ZeroSSL), buypass.com or pki.goog"}}, "description": "CAA records of the name and whether they let your certificate authority issue"}, "checked_at": {"type": "string", "format": "date-time", "description": "When the check ran; answers are reused for 60 s unless you send refresh=true"}, "cert_status": {"type": "string", "nullable": true, "description": "Alias only: state of its certificate"}}, "required": ["fqdn", "role", "status"], "description": "DNS check of one hostname of the vService"}, "DnsStatus": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService"}, "edge_hostname": {"type": "string", "nullable": true, "description": "CNAME target for your records"}, "anycast_ipv4": {"type": "string", "nullable": true, "description": "Primary IPv4 VIP of the vService"}, "anycast_ipv6": {"type": "string", "nullable": true, "description": "Primary IPv6 VIP of the vService"}, "status": {"type": "string", "enum": ["error", "not_found", "wrong_target", "apex_cname", "partial", "ok_cname_foreign", "ok_a", "ok_cname"], "description": "The worst of all names"}, "ok": {"type": "boolean", "description": "Every name points at us"}, "hostnames": {"type": "array", "items": {"$ref": "#/components/schemas/DnsHostname"}, "description": "The vService's name first, then every alias"}}, "required": ["fqdn", "hostnames", "ok", "status"], "description": "DNS check of the vService: what your records must say and what they say now"}, "Edge": {"type": "object", "properties": {"name": {"type": "string", "description": "Hostname of the edge"}, "display_name": {"type": "string", "description": "Readable name of the edge"}, "site": {"type": "string", "description": "Site the edge belongs to"}, "location": {"type": "string", "description": "Location code from the edge's hostname, such as fra"}, "status": {"type": "string", "enum": ["healthy", "degraded", "config_outdated", "maintenance", "error", "unknown"], "description": "healthy: every check passes. config_outdated: runs an older configuration, for less than a minute. degraded: monitoring silent, configuration behind for longer, last reload failed, or WAF or BGP down. maintenance: taken out by Zero Services. error: no report for 5 minutes, or HAProxy down. unknown: never reported"}, "last_seen": {"type": "string", "format": "date-time", "nullable": true, "description": "Time of the edge's last report"}, "config_sha": {"type": "string", "nullable": true, "description": "Config revision the edge runs"}, "puller_version": {"type": "string", "nullable": true, "description": "Installed version of the puller, which applies the configuration; null when not installed"}, "edgemon_version": {"type": "string", "nullable": true, "description": "Installed version of edgemon, the edge's monitoring agent; null when not installed"}, "scrubd_version": {"type": "string", "nullable": true, "description": "Installed version of scrubd, the layer 3/4 packet filter; null when not installed"}, "flowd_version": {"type": "string", "nullable": true, "description": "Installed version of flowd, the flow statistics at the site boundary; null when not installed"}, "tenant": {"type": "string", "nullable": true, "description": "Your tenant on an edge dedicated to you, null on a shared edge"}, "dedicated": {"type": "boolean", "description": "The edge is dedicated to you"}}, "required": ["name", "status"], "description": "An edge server that serves your vServices"}, "EdgeList": {"type": "array", "items": {"$ref": "#/components/schemas/Edge"}, "description": "Edges that serve at least one of your vServices"}, "Error": {"type": "object", "required": ["error"], "description": "Every error is JSON. Errors of the API and its gateway carry code; an error page of the edge (the API unreachable, 502 to 504) carries status and ray instead.", "properties": {"error": {"type": "string", "description": "What went wrong, for people; may change"}, "code": {"type": "string", "description": "What went wrong, for programs; stable. Generic: bad_request, invalid_key, forbidden, insufficient_scope, not_available_with_key, not_found, method_not_allowed, conflict, too_large, validation_failed, rate_limited, too_many_concurrent, busy, unavailable, upstream_unavailable, internal_error. Specific (409): service_exists, origin_exists, acme_in_progress, idempotency_key_reused, cache_disabled, purge_all_interval, url_purge_rate, prefix_purge_limit. New codes may come; treat an unknown one by its HTTP status"}, "details": {"type": "object", "additionalProperties": true, "description": "validation_failed: field name to a list of messages; purge_all_interval: retry_after_seconds"}, "status": {"type": "integer", "description": "Edge error pages only: the HTTP status"}, "ray": {"type": "string", "description": "Edge error pages only: request id for support"}}}, "GeoGroups": {"type": "object", "properties": {"geo_groups": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string", "description": "Use it where a country code goes"}, "label": {"type": "string", "description": "Readable name"}, "type": {"type": "string", "enum": ["continent", "countries"], "description": "continent: one continent. countries: a list of member countries"}, "source": {"type": "string", "description": "type continent: the continent code"}, "members": {"type": "array", "items": {"type": "string"}, "description": "type countries: the member countries"}, "note": {"type": "string", "description": "What to know before choosing it"}}, "required": ["id", "label", "type"]}, "description": "The groups"}}, "required": ["geo_groups"], "description": "Named country groups, usable where a country code goes"}, "HealthCheck": {"type": "object", "properties": {"method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"], "default": "GET", "description": "HTTP method of the check"}, "path": {"type": "string", "default": "/", "description": "Path the check requests, one of GET /reference/health-check-options"}, "host": {"type": "string", "nullable": true, "description": "Host header of the check. Default: origin_host, else the FQDN"}, "interval": {"type": "string", "default": "10s", "pattern": "^[1-9][0-9]{0,5}(ms|s|m|h)$", "description": "One of the intervals of GET /reference/health-check-options"}, "rise": {"type": "integer", "minimum": 1, "maximum": 10, "default": 2, "description": "Passed checks in a row that bring an origin back, 1 to 10"}, "fall": {"type": "integer", "minimum": 1, "maximum": 10, "default": 3, "description": "Failed checks in a row that take an origin out of rotation, 1 to 10"}, "expect": {"type": "string", "pattern": "^(status|rstatus) [a-zA-Z0-9x]{1,10}$", "nullable": true, "description": "Expected answer, one of GET /reference/health-check-options, such as status 200 or status 2xx. Null: any 2xx or 3xx passes"}}, "description": "Health check the edge sends to each origin"}, "HealthCheckOptions": {"type": "object", "properties": {"paths": {"type": "array", "items": {"type": "string"}, "description": "Allowed values of backend.health_check.path"}, "intervals": {"type": "array", "items": {"type": "string"}, "description": "Allowed values of backend.health_check.interval"}, "expects": {"type": "array", "items": {"type": "string"}, "description": "Allowed values of backend.health_check.expect"}}, "required": ["expects", "intervals", "paths"], "description": "The values backend.health_check accepts"}, "HealthOverview": {"type": "object", "properties": {"summary": {"type": "object", "properties": {"total": {"type": "integer", "description": "Number of vServices"}, "worst": {"type": "string", "enum": ["blackholed", "origin_down", "misconfigured", "errors", "origin_slow", "under_attack", "unknown", "normal", "maintenance", "disabled"], "description": "The most severe state of any vService, in this order: blackholed, origin_down, misconfigured, errors, origin_slow, under_attack, unknown, normal, maintenance, disabled"}, "counts": {"type": "object", "properties": {"blackholed": {"type": "integer", "description": "vServices in state blackholed"}, "origin_down": {"type": "integer", "description": "vServices in state origin_down"}, "misconfigured": {"type": "integer", "description": "vServices in state misconfigured"}, "errors": {"type": "integer", "description": "vServices in state errors"}, "origin_slow": {"type": "integer", "description": "vServices in state origin_slow"}, "under_attack": {"type": "integer", "description": "vServices in state under_attack"}, "normal": {"type": "integer", "description": "vServices in state normal"}, "maintenance": {"type": "integer", "description": "vServices in state maintenance"}, "disabled": {"type": "integer", "description": "vServices in state disabled"}, "unknown": {"type": "integer", "description": "vServices in state unknown"}}, "description": "vServices per state"}}, "required": ["counts", "total", "worst"], "description": "Summary over all vServices"}, "services": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/ServiceHealth"}, "description": "By FQDN"}}, "required": ["services", "summary"], "description": "Health of every vService you can see, with a summary"}, "HealthSignals": {"type": "object", "properties": {"requests_per_sec": {"type": "number", "description": "HTTP requests per second at the edge"}, "errors_per_sec": {"type": "number", "description": "5xx per second"}, "error_ratio": {"type": "number", "description": "Share of the answers that are 5xx, 0 to 1"}, "origin_response_seconds": {"type": "number", "nullable": true, "description": "Mean response time of your origins in seconds; null without data"}, "origins_up": {"type": "integer", "nullable": true, "description": "Origins passing their health check; null when not measured"}, "origins_total": {"type": "integer", "nullable": true, "description": "Origins the edges check; null when not measured"}, "hostnames_total": {"type": "integer", "description": "Hostnames of the vService; only when some point elsewhere"}, "hostnames_elsewhere": {"type": "integer", "description": "Hostnames whose DNS does not point at us; unprotected"}, "until": {"type": "string", "format": "date-time", "description": "blackholed only: when your addresses are announced again at the latest"}, "blocked_per_sec": {"type": "number", "description": "under_attack: requests and connections the protection stops per second"}, "rejected_conn_per_sec": {"type": "number", "description": "under_attack: of those, connections refused before HTTP"}, "l4_dropped_pps": {"type": "number", "description": "under_attack: packets per second the edge drops in XDP"}, "site_gap_bps": {"type": "integer", "description": "under_attack: bits per second that reach the site but not the edge, filtered on the way"}, "techniques": {"type": "array", "items": {"type": "string", "enum": ["admission", "l7", "xdp", "upstream"]}, "description": "under_attack: every technique stopping traffic now"}}, "description": "Last 5 minutes; empty when the metrics are unavailable"}, "History": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService"}, "range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "description": "Time window"}, "entries": {"type": "array", "items": {"$ref": "#/components/schemas/HistoryEntry"}, "description": "Newest first"}}, "required": ["entries", "fqdn", "range"], "description": "Configuration and health changes of a vService, newest first"}, "HistoryEntry": {"type": "object", "properties": {"kind": {"type": "string", "enum": ["config_change", "health_change"], "description": "config_change: the vService's configuration or certificate changed. health_change: its health state changed"}, "at": {"type": "string", "format": "date-time", "description": "When it happened"}, "category": {"type": "string", "enum": ["config", "certificate"], "description": "config_change only"}, "sha": {"type": "string", "description": "config_change: id of the configuration revision"}, "short_sha": {"type": "string", "description": "config_change: the revision id, shortened"}, "action": {"type": "string", "description": "config_change: what changed"}, "user": {"type": "string", "description": "config_change: your e-mail or key label; empty = Zero Services"}, "by_zero_services": {"type": "boolean", "description": "config_change: true when Zero Services made the change, false when you did, in the portal or with an API key"}, "from": {"type": "string", "enum": ["blackholed", "origin_down", "misconfigured", "errors", "origin_slow", "under_attack", "normal", "maintenance", "disabled", "unknown"], "description": "health_change only", "nullable": true}, "to": {"type": "string", "enum": ["blackholed", "origin_down", "misconfigured", "errors", "origin_slow", "under_attack", "normal", "maintenance", "disabled", "unknown"], "description": "health_change only", "nullable": true}, "fault": {"type": "string", "enum": ["zp", "customer", "none"], "description": "health_change: who has to act on the new state, as in ServiceHealth"}, "reason": {"type": "string", "description": "health_change: machine-readable reason of the new state, as in ServiceHealth"}, "signals": {"$ref": "#/components/schemas/HealthSignals", "description": "health_change: the measurements when the state changed"}, "techniques": {"type": "array", "items": {"type": "string"}, "description": "Attack techniques seen, on a change to or from under_attack"}}, "required": ["at", "kind"], "description": "One event in the history"}, "Hsts": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Set Strict-Transport-Security on the responses the edge passes on, replacing your origin's"}, "max_age": {"type": "integer", "minimum": 0, "maximum": 63072000, "default": 31536000, "description": "Seconds browsers remember to use HTTPS only, 0 to 63072000"}, "include_subdomains": {"type": "boolean", "default": false, "description": "Add includeSubDomains: browsers use HTTPS for every subdomain as well"}, "preload": {"type": "boolean", "default": false, "description": "Add preload, the condition for the browsers' preload lists"}}, "description": "Strict-Transport-Security header the edge sets on the responses it passes on"}, "Key": {"type": "object", "properties": {"id": {"type": "string", "description": "Key id: the 12 characters after zsk_"}, "tenant": {"type": "string", "description": "Your tenant id"}, "label": {"type": "string", "description": "Name given to the key at creation"}, "owner": {"type": "object", "properties": {"kind": {"type": "string", "enum": ["account", "delegation"], "description": "account: the whole account. delegation: only the vServices of one delegation"}, "delegation": {"type": "string", "description": "kind delegation: the delegation"}}, "description": "Who the key belongs to"}, "scopes": {"type": "array", "items": {"type": "string", "enum": ["protect:read", "protect:write"]}, "description": "protect:read allows GET; protect:write allows everything else"}, "allowed_ips": {"type": "array", "items": {"type": "string"}, "description": "The only client addresses the key works from: single IPv4 or IPv6 addresses"}, "expires_at": {"type": "string", "format": "date-time", "description": "When the key stops working"}, "created_by": {"type": "string", "description": "E-mail of the person who created the key"}, "created_at": {"type": "string", "format": "date-time", "description": "When the key was created"}, "revoked_at": {"type": "string", "format": "date-time", "nullable": true, "description": "When the key was revoked; null while it is not"}, "revoked_by": {"type": "string", "nullable": true, "description": "Who revoked the key; null while it is not revoked"}}, "description": "An API key, without its secret"}, "L4Overview": {"type": "object", "properties": {"range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "view": {"type": "string", "enum": ["allowed", "dropped"], "description": "allowed: forwarded flows and connections. dropped: what the edge dropped"}, "window_seconds": {"type": "integer", "description": "Seconds covered: the range, less when the vService is younger, at least 60"}, "since": {"type": "string", "format": "date-time", "description": "Start of the window; never before the vService was created"}, "protocols": {"type": "array", "items": {"type": "string", "enum": ["tcp", "udp"]}, "description": "tcp when the vService has TCP ports outside HTTP (mode tcp or anyconnect); udp when it has UDP ports"}, "panels": {"type": "object", "properties": {"summary": {"type": "object", "properties": {"udp_flows": {"type": "integer", "description": "view allowed: UDP flows the edge forwarded"}, "udp_clients": {"type": "integer", "description": "view allowed: distinct client addresses of UDP flows"}, "tcp_connections": {"type": "integer", "description": "view allowed: TCP connections that ended in the window"}, "tcp_clients": {"type": "integer", "description": "view allowed: distinct client addresses of TCP connections"}, "bytes_to_client": {"type": "integer", "description": "view allowed: bytes from your origins to clients"}, "bytes_to_origin": {"type": "integer", "description": "view allowed: bytes from clients to your origins"}, "events": {"type": "integer", "description": "view=dropped: one event per dropped source and period, not per packet"}, "sources": {"type": "integer", "description": "view=dropped: distinct dropped sources"}}, "description": "Totals over the window"}, "top_clients": {"$ref": "#/components/schemas/L4Panel", "description": "Client addresses, by bytes"}, "top_countries": {"$ref": "#/components/schemas/L4Panel", "description": "Source countries"}, "top_asns": {"$ref": "#/components/schemas/L4Panel", "description": "Source networks; label is the AS name"}, "top_origins": {"$ref": "#/components/schemas/L4Panel", "description": "Origins, by bytes"}, "termination": {"$ref": "#/components/schemas/L4Panel", "description": "How connections and flows ended: the HAProxy termination state for TCP; idle, unreplied or service_gone for UDP"}, "top_ports": {"$ref": "#/components/schemas/L4Panel", "description": "Ports of your vService the UDP flows came in on"}, "top_sources": {"$ref": "#/components/schemas/L4Panel", "description": "Dropped source addresses"}, "top_reasons": {"$ref": "#/components/schemas/L4Panel", "description": "Why the edge dropped traffic"}, "top_dports": {"$ref": "#/components/schemas/L4Panel", "description": "Destination ports of dropped traffic"}, "top_protocols": {"$ref": "#/components/schemas/L4Panel", "description": "IP protocols of dropped traffic"}, "packet_shape": {"$ref": "#/components/schemas/PacketShape", "description": "Packet shape at the site boundary"}}, "description": "allowed: top_clients, top_origins, termination, top_ports (UDP); dropped: top_sources, top_reasons, top_dports, top_protocols; both: summary, top_countries, top_asns, packet_shape"}, "errors": {"type": "object", "additionalProperties": {"type": "string"}, "description": "Panels that failed; the others are still there"}, "took_ms": {"type": "integer", "description": "Server time for all panels in milliseconds"}}, "required": ["errors", "panels", "range", "view"], "description": "Layer 3/4 aggregates of a vService with TCP or UDP ports outside HTTP"}, "L4Panel": {"type": "object", "properties": {"field": {"type": "string", "description": "The log field ranked"}, "data": {"type": "array", "items": {"type": "object", "properties": {"value": {"type": "string", "description": "The field's value"}, "count": {"type": "integer", "description": "Flows, connections or drop events"}, "bytes": {"type": "integer", "description": "Only on top_clients and top_origins"}, "label": {"type": "string", "description": "AS name next to its number"}}, "required": ["count", "value"]}, "description": "Rows, busiest first"}}, "required": ["data", "field"], "description": "A ranking: the busiest values of one field"}, "L4Raw": {"type": "object", "properties": {"range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "view": {"type": "string", "enum": ["allowed", "dropped"], "description": "allowed: UDP flows and TCP connections. dropped: drop events and sampled dropped packets"}, "since": {"type": "string", "format": "date-time", "description": "Start of the window"}, "count": {"type": "integer", "description": "Lines returned"}, "data": {"type": "array", "items": {"type": "object", "properties": {"timestamp": {"type": "string", "format": "date-time", "description": "RFC 3339 with nanoseconds"}, "fields": {"type": "object", "properties": {"proto": {"type": "string", "description": "Protocol: tcp or udp on allowed lines; on dropped lines the IP protocol by name (tcp, udp, icmp) or number"}, "phase": {"type": "string", "description": "allowed, UDP: interim (the flow still runs) or end"}, "client_ip": {"type": "string", "description": "allowed: client address"}, "client_port": {"type": "string", "description": "allowed: client port"}, "vip": {"type": "string", "description": "allowed, UDP: your address the flow came in on"}, "vip_port": {"type": "string", "description": "allowed, UDP: your port the flow came in on"}, "server_name": {"type": "string", "description": "allowed: name of the origin"}, "origin": {"type": "string", "description": "allowed, UDP: address of the origin the flow went to"}, "termination_state": {"type": "string", "description": "allowed: how it ended. TCP: HAProxy termination state, \"--\" when normal. UDP: idle, unreplied or service_gone; - on interim lines"}, "duration_s": {"type": "string", "description": "allowed, UDP: duration of the flow in seconds"}, "ta": {"type": "string", "description": "allowed, TCP: duration of the connection in milliseconds"}, "bytes_read": {"type": "string", "description": "allowed: bytes from your origin to the client"}, "bytes_uploaded": {"type": "string", "description": "allowed: bytes from the client to your origin"}, "pkts_to_client": {"type": "string", "description": "allowed, UDP: packets from your origin to the client"}, "pkts_to_origin": {"type": "string", "description": "allowed, UDP: packets from the client to your origin"}, "geoip_country_code": {"type": "string", "description": "Country of the source"}, "geoip_asn": {"type": "string", "description": "AS number of the source"}, "geoip_asn_org": {"type": "string", "description": "AS name of the source"}, "event": {"type": "string", "description": "dropped: l4 (one line per dropped source and period) or l4_sample (one sampled dropped packet)"}, "action": {"type": "string", "description": "dropped: what the edge did: drop, pass, or tx (answered at the edge, such as with a SYN cookie)"}, "reason": {"type": "string", "description": "dropped: why, such as synrate, blocklist, malformed, garbage or autoblock"}, "af": {"type": "string", "description": "dropped: IP version, 4 or 6"}, "src": {"type": "string", "description": "dropped: source address"}, "sport": {"type": "string", "description": "dropped: source port"}, "dst": {"type": "string", "description": "dropped: destination address, one of your VIPs"}, "dport": {"type": "string", "description": "dropped: destination port"}, "len": {"type": "string", "description": "dropped sample: length of the packet in bytes as received"}, "ttl": {"type": "string", "description": "dropped, IPv4 sample: time to live"}, "tos": {"type": "string", "description": "dropped, IPv4 sample: type of service byte"}, "ip_len": {"type": "string", "description": "dropped sample: IP total length (IPv6: payload length)"}, "ip_id": {"type": "string", "description": "dropped, IPv4 sample: identification field"}, "df": {"type": "string", "description": "dropped, IPv4 sample: don't-fragment flag, 0 or 1"}, "mf": {"type": "string", "description": "dropped, IPv4 sample: more-fragments flag, 0 or 1"}, "frag_off": {"type": "string", "description": "dropped, IPv4 sample: fragment offset in bytes"}, "tcp_flags": {"type": "string", "description": "dropped, TCP sample: flags as letters (F S R P A U E C), . for none"}, "seq": {"type": "string", "description": "dropped, TCP sample: sequence number"}, "ack": {"type": "string", "description": "dropped, TCP sample: acknowledgement number"}, "win": {"type": "string", "description": "dropped, TCP sample: window size"}, "tcp_opts": {"type": "string", "description": "dropped, TCP sample: TCP options, hex"}, "payload": {"type": "string", "description": "dropped sample: start of the payload, hex, up to 64 bytes"}}, "description": "allowed: a UDP flow or TCP connection; dropped: a dropped source or packet sample"}}}, "description": "Lines, newest first"}}, "required": ["count", "data", "range", "view"], "description": "Newest layer 3/4 log lines of a vService"}, "LogOverview": {"type": "object", "properties": {"range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "view": {"type": "string", "enum": ["allowed", "blocked", "all"], "description": "The view asked for"}, "window_seconds": {"type": "integer", "description": "Length of the range in seconds"}, "service_total": {"type": "integer", "nullable": true, "description": "Requests of the vService in the window and view"}, "service_total_rps_avg": {"type": "number", "description": "service_total per second of the window"}, "types": {"type": "array", "items": {"type": "string"}, "description": "The aggregates asked for"}, "panels": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/LogTop"}, "description": "By log type"}, "errors": {"type": "object", "additionalProperties": {"type": "string"}, "description": "Log types that failed; the others are still there"}, "took_ms": {"type": "integer", "description": "Server time for all panels in milliseconds"}}, "required": ["errors", "panels", "range", "view"], "description": "All request log aggregates of a vService in one answer"}, "LogRaw": {"type": "object", "properties": {"type": {"type": "string", "enum": ["raw"], "description": "Always raw"}, "range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "count": {"type": "integer", "description": "Lines returned"}, "data": {"type": "array", "items": {"type": "object", "properties": {"timestamp": {"type": "string", "format": "date-time", "description": "RFC 3339 with nanoseconds; pass the oldest as to= to read the lines before it"}, "line": {"type": "string", "description": "The access log line, logfmt (key=value)"}}}, "description": "Lines, newest first"}}, "required": ["count", "data", "range", "type"], "description": "Newest access log lines"}, "LogRow": {"type": "object", "properties": {"value": {"type": "string", "description": "The field's value; Unknown when the line carries none"}, "label": {"type": "string", "description": "Application of a JA4 fingerprint, name of a threat-intel set"}, "fields": {"type": "object", "additionalProperties": {"type": "string"}, "description": "top_combination only: the six fields of the combination"}, "count": {"type": "integer", "description": "Requests in the window"}, "rps_avg": {"type": "number", "description": "count / window_seconds"}, "share": {"type": "number", "nullable": true, "description": "Part of the vService's requests in the chosen view, 0 to 1"}}, "required": ["count", "rps_avg"], "description": "One row of a ranking"}, "LogTimeseries": {"type": "object", "properties": {"type": {"type": "string", "enum": ["timeseries"], "description": "Always timeseries"}, "field": {"type": "string", "description": "The log field"}, "range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "step": {"type": "integer", "description": "Seconds per point"}, "series": {"type": "array", "items": {"type": "object", "properties": {"label": {"type": "string", "description": "The field's value; Unknown when the line carries none"}, "values": {"type": "array", "items": {"type": "array", "items": {"type": "integer"}, "minItems": 2, "maxItems": 2}, "description": "[unix seconds, requests in the step] pairs"}}}, "description": "One line per value, the busiest first"}}, "required": ["field", "range", "series", "step", "type"], "description": "Requests over time, one line per value of a log field"}, "LogTop": {"type": "object", "properties": {"type": {"type": "string", "description": "The aggregate asked for"}, "range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "96h"], "description": "Time window"}, "field": {"type": "string", "description": "The log field ranked"}, "fields": {"type": "array", "items": {"type": "string"}, "description": "top_combination only: the fields of a combination"}, "window_seconds": {"type": "integer", "description": "Length of the range in seconds"}, "service_total": {"type": "integer", "nullable": true, "description": "Requests of the vService in the window, in the chosen view"}, "service_total_rps_avg": {"type": "number", "description": "service_total divided by window_seconds"}, "total": {"type": "integer", "description": "threat_intel only: requests from listed sources"}, "total_rps_avg": {"type": "number", "description": "threat_intel only"}, "total_share": {"type": "number", "nullable": true, "description": "threat_intel only"}, "data": {"type": "array", "items": {"$ref": "#/components/schemas/LogRow"}, "description": "Rows, busiest first"}}, "required": ["data", "range", "type", "window_seconds"], "description": "A ranking: the busiest values of one log field in the range"}, "Logging": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Write one structured access log line per request or connection; logs, forensics and the log export read them"}}, "description": "Access log of the vService. Set by support"}, "LogoStored": {"type": "object", "properties": {"filename": {"type": "string", "description": "Stored file name, cleaned of unsafe characters; it replaces the previous logo"}, "path": {"type": "string", "description": "Where the file is stored in the configuration"}}, "required": ["filename"], "description": "Where the uploaded logo is stored"}, "LogoUpload": {"type": "object", "properties": {"file": {"type": "string", "format": "binary", "description": "PNG, JPEG or WebP, at most 24 KB (the edges inline it into their pages); SVG is not accepted"}}, "required": ["file"], "description": "The logo, sent as multipart/form-data"}, "MatchNode": {"type": "object", "properties": {"geo": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "nullable": true, "description": "Countries of the source address: ISO 3166-1 alpha-2 codes such as DE, or group ids from GET /reference/geo-groups"}, "asn": {"type": "array", "items": {"type": "integer"}, "maxItems": 500, "nullable": true, "description": "AS numbers of the source address"}, "ip": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "nullable": true, "description": "Source addresses or CIDR ranges, IPv4 or IPv6"}, "path": {"type": "array", "items": {"type": "string"}, "maxItems": 100, "nullable": true, "description": "Request paths without query string, after the edge normalised them, case-sensitive: exact, or a prefix when the entry ends in *. # is refused"}, "path_class": {"type": "string", "enum": ["auth", "admin"], "nullable": true, "description": "Built-in path group: auth (login paths such as /wp-login.php or /login) or admin (admin areas such as /wp-admin/)"}, "crawler": {"type": "array", "items": {"type": "string"}, "maxItems": 100, "nullable": true, "description": "Crawler names from GET /reference/crawlers, recognised by the crawler's published source networks, not by its User-Agent"}, "fingerprint": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "nullable": true, "description": "JA4 TLS fingerprints of the client, exact"}, "user_agent": {"type": "array", "items": {"type": "string", "minLength": 1, "maxLength": 256}, "maxItems": 100, "nullable": true, "description": "Text anywhere in the User-Agent header, case-insensitive; backslashes and double quotes are dropped"}, "referer_host": {"type": "array", "items": {"type": "string"}, "maxItems": 100, "nullable": true, "description": "Host of the Referer header, case-insensitive: a hostname, *.example.com for its subdomains (not example.com itself), or none for a request without Referer"}, "method": {"type": "array", "items": {"type": "string", "enum": ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]}, "minItems": 1, "maxItems": 7, "nullable": true, "description": "HTTP methods. HTTPS only"}, "content_type": {"type": "array", "items": {"type": "string", "minLength": 3, "maxLength": 127}, "minItems": 1, "maxItems": 20, "nullable": true, "description": "Media types the Content-Type header starts with, case-insensitive: lower-case type/subtype without parameters, such as multipart/form-data. HTTPS only"}, "any_of": {"type": "array", "items": {"$ref": "#/components/schemas/MatchNode"}, "minItems": 1, "maxItems": 20, "nullable": true, "description": "Group: matches when at least one child node matches. 1 to 20 children, groups at most 2 levels deep; besides not the node holds nothing else"}, "all_of": {"type": "array", "items": {"$ref": "#/components/schemas/MatchNode"}, "minItems": 1, "maxItems": 20, "nullable": true, "description": "Group: matches when every child node matches. 1 to 20 children, groups at most 2 levels deep; besides not the node holds nothing else"}, "not": {"type": "boolean", "nullable": true, "description": "Inverts this node. Only in a match with any_of or all_of; a flat match uses the rule's negate"}}, "description": "Which requests a rule matches. The values of one key combine with OR; the keys of a node combine with AND (a flat rule uses its match_mode). any_of and all_of group child nodes, not inverts one. tcp and anyconnect vServices take only geo, asn and ip, and only what a flat match can express"}, "MetricChart": {"type": "object", "properties": {"metric": {"type": "string", "description": "The chart asked for"}, "range": {"type": "string", "enum": ["5m", "15m", "1h", "6h", "24h", "7d"], "description": "Time window"}, "step": {"type": "string", "description": "Distance between two points"}, "series": {"type": "array", "items": {"$ref": "#/components/schemas/MetricSeries"}, "description": "One series per line"}, "meta": {"type": "object", "properties": {"sampled": {"type": "boolean", "description": "Estimated from sampled flows"}, "sampling_floor_bytes_per_sec": {"type": "number", "description": "Smallest rate in bytes per second the sampling can show; below it reads 0"}, "per_vip": {"type": "boolean", "description": "Counted per address: hostnames sharing an address share the number"}, "available": {"type": "boolean", "description": "Flow is measured for this vService"}}, "description": "metric=upstream only: flow at the site boundary is sampled"}, "scope": {"$ref": "#/components/schemas/MetricScope", "description": "GET /metrics and pool metrics only: what was summed"}}, "required": ["metric", "range", "series", "step"], "description": "A chart: one series per line. Rates are per second over the step; traffic in bytes/s, positive in both directions (each series names its direction). From 6h on each point is the highest 1-minute value within its step, so a short attack stays visible."}, "MetricScope": {"type": "object", "properties": {"delegation": {"type": "string", "nullable": true, "description": "The delegation asked for, null for all you can see"}, "pool": {"type": "string", "description": "Pool metrics only: the pool summed"}, "services": {"type": "integer", "description": "vServices summed"}, "has_http": {"type": "boolean", "description": "The http charts apply"}, "has_l4": {"type": "boolean", "description": "The L3/4 charts apply"}, "partial_services": {"type": "array", "items": {"type": "string"}, "description": "Pool metrics: vServices with only some VIPs in the pool, not summed"}}, "description": "What was summed"}, "MetricSeries": {"type": "object", "properties": {"label": {"type": "string", "description": "Name of the line, such as inbound, outbound or 2xx"}, "values": {"type": "array", "items": {"type": "array", "items": {"type": "number"}, "minItems": 2, "maxItems": 2}, "description": "[unix seconds, value] pairs; never negative"}, "dashed": {"type": "boolean", "description": "Drawn dashed: a sampled estimate or a limit, not a measured total"}, "direction": {"type": "string", "enum": ["in", "out"], "description": "Traffic towards your vService (in) or back to the clients (out); absent when the series has no direction"}}, "required": ["label", "values"], "description": "One line of a chart"}, "MetricSummary": {"type": "object", "properties": {"metric": {"type": "string", "enum": ["summary"], "description": "Always summary"}, "data": {"type": "object", "properties": {"requests_per_sec": {"type": "number", "description": "HTTP requests per second at the edge"}, "packets_per_sec": {"type": "number", "description": "Packets per second arriving at the edge, dropped ones included"}, "bits_per_sec": {"type": "number", "description": "Inbound at the edge"}, "bits_out_per_sec": {"type": "number", "description": "Bits per second from the edge to clients, forwarded UDP included"}, "active_sessions": {"type": "integer", "description": "TCP sessions and UDP flows open now"}, "active_sessions_tcp": {"type": "integer", "description": "Client sessions open at the edge now"}, "active_flows_udp": {"type": "integer", "description": "Forwarded UDP flows open now"}, "healthy_backends": {"type": "integer", "description": "Origins passing the health check"}, "connections_rejected_per_sec": {"type": "number", "description": "Connections per second refused before the request, such as by admission or the geofence"}, "edge_bytes": {"type": "integer", "description": "Bytes that arrived at the edge in the range, dropped ones included"}, "origin_bytes": {"type": "integer", "description": "Request bytes delivered to your origins in the range"}}, "description": "The values"}}, "required": ["data", "metric"], "description": "Live values; edge_bytes and origin_bytes over the range"}, "Network": {"type": "object", "properties": {"vips": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Vip"}]}, "maxItems": 16, "readOnly": true, "description": "Change addresses with POST /vip-operations"}, "pool": {"type": "string", "nullable": true, "readOnly": true, "description": "Change addresses with POST /vip-operations"}, "edge_hostname": {"type": "string", "nullable": true, "readOnly": true, "description": "Change addresses with POST /vip-operations"}}, "description": "Addresses of the vService"}, "NetworkProtection": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": true, "description": "Filter the vService's addresses at the edge before HAProxy: only its ports pass, SYN floods per source are limited and blocklisted sources dropped. Off: traffic to the addresses passes unfiltered"}}, "description": "Layer 3/4 filter of the vService's addresses at the edge. Set by support"}, "Operation": {"oneOf": [{"$ref": "#/components/schemas/OperationAssign"}, {"$ref": "#/components/schemas/OperationRelease"}, {"$ref": "#/components/schemas/OperationMove"}, {"$ref": "#/components/schemas/OperationSwap"}, {"$ref": "#/components/schemas/OperationRotatePrefix"}, {"$ref": "#/components/schemas/OperationBlock"}, {"$ref": "#/components/schemas/OperationAnnounce"}], "discriminator": {"propertyName": "op", "mapping": {"announce": "#/components/schemas/OperationAnnounce", "assign": "#/components/schemas/OperationAssign", "block": "#/components/schemas/OperationBlock", "move": "#/components/schemas/OperationMove", "release": "#/components/schemas/OperationRelease", "rotate_prefix": "#/components/schemas/OperationRotatePrefix", "swap": "#/components/schemas/OperationSwap", "unblock": "#/components/schemas/OperationBlock", "withdraw": "#/components/schemas/OperationAnnounce"}}, "description": "One VIP operation; op selects its kind and the fields it takes"}, "OperationAnnounce": {"type": "object", "description": "Switch the announcement of a pool you switch yourself, at most once per 15 min; withdraw only without VIPs of your vServices in the pool", "properties": {"op": {"type": "string", "enum": ["announce", "withdraw"], "description": "announce: the edges start announcing the pool. withdraw: they stop"}, "pool": {"type": "string", "description": "The pool; only one you switch yourself"}}, "required": ["op", "pool"]}, "OperationAssign": {"type": "object", "description": "Give a vService addresses: count free ones from pool, or exactly address; send one of the two", "properties": {"op": {"type": "string", "enum": ["assign"], "description": "Always assign"}, "service": {"type": "string", "description": "The vService that gets the addresses"}, "pool": {"type": "string", "description": "Pool to take free addresses from; needed unless address is set"}, "address": {"type": "string", "description": "Exactly this free address of your pools; its IPv6 partner follows"}, "count": {"type": "integer", "minimum": 1, "maximum": 16, "default": 1, "description": "How many free addresses to take from pool, 1 to 16; the one unused longest comes first"}}, "required": ["op", "service"]}, "OperationBlock": {"type": "object", "description": "Block or unblock addresses: a blocked address is not handed out again; blocking does not take it off a vService that holds it. Send address or addresses", "properties": {"op": {"type": "string", "enum": ["block", "unblock"], "description": "block: never hand the addresses out again; an address already assigned stays. unblock: hand them out again"}, "address": {"type": "string", "description": "One address of your pools"}, "addresses": {"type": "array", "items": {"type": "string"}, "maxItems": 4096, "description": "Several addresses of your pools, up to 4096"}}, "required": ["op"]}, "OperationMove": {"type": "object", "description": "Move an address to another of your vServices", "properties": {"op": {"type": "string", "enum": ["move"], "description": "Always move"}, "address": {"type": "string", "description": "An address of one of your vServices; its IPv6 partner moves along"}, "to": {"type": "string", "description": "The vService that gets it"}}, "required": ["op", "address", "to"]}, "OperationRelease": {"type": "object", "description": "Take an address off its vService", "properties": {"op": {"type": "string", "enum": ["release"], "description": "Always release"}, "address": {"type": "string", "description": "An address of one of your vServices, not its last one"}, "service": {"type": "string", "description": "The vService that holds it, as a check"}}, "required": ["op", "address"]}, "OperationRotatePrefix": {"type": "object", "description": "Move every IPv4 address of your vServices from one pool to another", "properties": {"op": {"type": "string", "enum": ["rotate_prefix"], "description": "Always rotate_prefix"}, "from_pool": {"type": "string", "description": "The pool whose addresses move"}, "to_pool": {"type": "string", "description": "The pool they move to; it must be announced"}, "keep_host": {"type": "boolean", "default": true, "description": "Keep the host part when both pools have the same prefix length and the address is free"}}, "required": ["op", "from_pool", "to_pool"]}, "OperationSwap": {"type": "object", "description": "Replace an address of a vService: by new_address, or by a free one from pool (default the pool of the old address)", "properties": {"op": {"type": "string", "enum": ["swap"], "description": "Always swap"}, "address": {"type": "string", "description": "The address to replace, on one of your vServices"}, "new_address": {"type": "string", "description": "Exactly this free address instead. Default: a free address of pool, the one unused longest first"}, "pool": {"type": "string", "description": "Pool of the new address; default the pool of the old one"}, "block_old": {"type": "boolean", "default": true, "description": "Block the old address so that no vService gets it again until you unblock it"}}, "required": ["op", "address"]}, "Origin": {"type": "object", "properties": {"name": {"type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?$", "nullable": true, "description": "Omit it and the server names the origin origin-1, origin-2, ...; the name is in the response and is what PUT and DELETE take"}, "address": {"type": "string", "description": "IPv4 address, IPv6 address or hostname. Private and reserved addresses are refused, also when a hostname resolves to one"}, "port": {"type": "integer", "minimum": 1, "maximum": 65535, "default": 443, "description": "Port on the origin. Requests to an extra HTTP port go to the same port number instead"}, "tls": {"type": "boolean", "default": true, "description": "Connect to the origin with TLS"}, "ssl_verify": {"type": "boolean", "default": true, "description": "Verify the origin's certificate against the public certificate authorities; with tls only"}, "sni": {"type": "string", "maxLength": 253, "nullable": true, "description": "TLS server name for this origin, also the name its certificate is checked against. Default: origin_sni, else origin_host, else the FQDN"}, "weight": {"type": "integer", "minimum": 0, "maximum": 256, "default": 100, "description": "Share of requests relative to the other origins, 0 to 256; 0 sends none. Also the share of new UDP flows"}, "maxconn": {"type": "integer", "minimum": 1, "maximum": 65535, "default": 100, "description": "Connections each edge opens to this origin at most. Further requests queue, up to 4 times this per origin and for at most 2 s; beyond either they get 503. With a sensitivity set, a learned value replaces it once measured"}}, "required": ["address"], "description": "A server of yours the edge forwards requests to"}, "OriginStatus": {"type": "object", "properties": {"metric": {"type": "string", "enum": ["origin_status"], "description": "Always origin_status"}, "data": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string", "description": "Origin name"}, "up_edges": {"type": "integer", "description": "Edges whose health check passes"}, "edges": {"type": "integer", "description": "Edges checking this origin"}}}, "description": "One row per origin"}}, "required": ["data", "metric"], "description": "Health check result per origin"}, "PacketShape": {"type": "object", "properties": {"available": {"type": "boolean", "description": "The site boundary measures this vService"}, "samples": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Sampled packets per window"}, "windows": {"type": "object", "additionalProperties": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "object", "properties": {"value": {"type": "string", "description": "The value: a port, a length in bytes, a TTL class, a TCP window, TCP options or the first 4 payload bytes in hex"}, "share": {"type": "number", "description": "Share of the inbound packets to the address that carry this value, 0 to 1, estimated from samples"}, "service_port": {"type": "boolean", "description": "Packets with this value went to one of your vService's ports"}}}}, "description": "Top values per packet feature"}, "description": "Per window"}}, "description": "Packet shape at the site boundary (sampled): top values of ports, length, TTL, flags"}, "Pool": {"allOf": [{"$ref": "#/components/schemas/PoolSummary"}, {"type": "object", "properties": {"addresses": {"type": "array", "items": {"type": "object", "properties": {"address": {"type": "string", "description": "IPv4 address"}, "ipv6": {"type": "string", "nullable": true, "description": "IPv6 partner at the same position in the IPv6 range; null without one"}, "state": {"type": "string", "enum": ["free", "assigned", "blocked", "reserved"], "description": "assigned: on one of your vServices. reserved: withheld by Zero Services or in use elsewhere. blocked: on your block list. free: can be assigned"}, "service": {"type": "string", "nullable": true, "description": "vService that holds the address; null otherwise"}, "blocked": {"type": "boolean", "description": "On your block list; an assigned address can be blocked too"}, "released_at": {"type": "string", "format": "date-time", "nullable": true, "description": "When the address was last released; the free address unused longest is handed out first"}}}, "description": "Every IPv4 address of the pool"}}}], "description": "An IP pool with every address and its state"}, "PoolSummary": {"type": "object", "properties": {"scope": {"type": "string", "description": "Pool id, used in paths and operations"}, "name": {"type": "string", "description": "Display name"}, "ipv4_range": {"type": "string", "description": "IPv4 range of the pool"}, "ipv6_range": {"type": "string", "description": "IPv6 range of the pool"}, "total": {"type": "integer", "description": "IPv4 addresses in the range, first and last included"}, "assigned": {"type": "integer", "description": "Addresses on your vServices"}, "blocked": {"type": "integer", "description": "Addresses on your block list"}, "reserved": {"type": "integer", "description": "Addresses withheld by Zero Services"}, "free": {"type": "integer", "description": "Addresses neither assigned, reserved nor blocked"}, "customer_announce": {"type": "boolean", "description": "You switch the announcement"}, "announced": {"type": "boolean", "description": "The edges announce the prefixes now"}, "announce_changed_at": {"type": "string", "format": "date-time", "nullable": true, "description": "When you last switched the announcement; null if never"}, "next_change_at": {"type": "string", "format": "date-time", "nullable": true, "description": "Earliest time of the next announce or withdraw; null when possible now or not yours to switch"}}, "description": "One of your IP pools and its use"}, "Pow": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": true, "description": "Proof-of-work challenge. While your origins are under load (80 % of maxconn in use, or a queue), unknown visitors asking for HTML get it too. Off: no challenge of any kind happens"}, "difficulty": {"type": "integer", "minimum": 16, "maximum": 20, "default": 18, "description": "Difficulty of the puzzle, 16 to 20: each step doubles the work, 18 is about a thousand hashes in the browser. A solution counts only on this vService and at this difficulty"}, "cookie_ttl": {"type": "integer", "minimum": 60, "maximum": 604800, "default": 86400, "description": "Seconds a solved challenge lets the visitor through, 60 to 604800; the puzzle itself must be solved within the same time"}, "always_challenge": {"type": "boolean", "default": false, "description": "Challenge every request without a solved puzzle, except static files, crawlers while exempt_crawlers is on, and sources an allow or skip rule exempts. Lockdown"}, "exempt_crawlers": {"type": "boolean", "default": true, "description": "Never challenge known crawlers (GET /reference/crawlers), recognised by their published source networks"}, "bind_ip": {"type": "boolean", "default": true, "description": "A solved puzzle holds only for the solver's IPv4 /24 or IPv6 /64"}, "botcheck_per_10s": {"type": "integer", "minimum": 100, "maximum": 100000, "default": 1000, "readOnly": true, "description": "Set by support on request"}}, "description": "Proof-of-work challenge: the visitor's browser computes an Argon2 puzzle before the request passes. Every challenge needs it"}, "PowPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "Proof-of-work challenge. While your origins are under load (80 % of maxconn in use, or a queue), unknown visitors asking for HTML get it too. Off: no challenge of any kind happens"}, "difficulty": {"type": "integer", "minimum": 16, "maximum": 20, "description": "Difficulty of the puzzle, 16 to 20: each step doubles the work, 18 is about a thousand hashes in the browser. A solution counts only on this vService and at this difficulty"}, "cookie_ttl": {"type": "integer", "minimum": 60, "maximum": 604800, "description": "Seconds a solved challenge lets the visitor through, 60 to 604800; the puzzle itself must be solved within the same time"}, "always_challenge": {"type": "boolean", "description": "Challenge every request without a solved puzzle, except static files, crawlers while exempt_crawlers is on, and sources an allow or skip rule exempts. Lockdown"}, "exempt_crawlers": {"type": "boolean", "description": "Never challenge known crawlers (GET /reference/crawlers), recognised by their published source networks"}, "bind_ip": {"type": "boolean", "description": "A solved puzzle holds only for the solver's IPv4 /24 or IPv6 /64"}}, "description": "Merged into the stored pow: send only the fields to change."}, "Priority": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": true, "description": "While requests queue at your origins (maxconn reached), serve them in this order: sources an allow rule matches, then clients that solved a challenge or earned returning-visitor credit, then requests with a session signal, then the rest. A full queue refuses only the last two"}, "session_signal": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/SessionSignal"}]}, "description": "Up to 8 places a session shows itself; any one counts. Empty: any cookie counts. It can be forged: priority, not access control"}}, "description": "Order of waiting requests while your origins are at their connection limit"}, "PriorityPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "While requests queue at your origins (maxconn reached), serve them in this order: sources an allow rule matches, then clients that solved a challenge or earned returning-visitor credit, then requests with a session signal, then the rest. A full queue refuses only the last two"}, "session_signal": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/SessionSignal"}]}, "description": "Up to 8 places a session shows itself; any one counts. Empty: any cookie counts. It can be forged: priority, not access control"}}, "description": "Merged into the stored priority: send only the fields to change."}, "ProtectionAllowlist": {"type": "object", "properties": {"countries": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "description": "Countries of the source, ISO 3166-1 alpha-2"}, "asns": {"type": "array", "items": {"type": "integer"}, "maxItems": 500, "description": "AS numbers of the source"}, "ips": {"type": "array", "items": {"type": "string"}, "description": "Addresses or ranges, up to 128, none broader than /16 (IPv4) or /32 (IPv6). They are also exempt from the layer 3/4 limits at the edge"}, "paths": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "description": "Request paths: exact, or a prefix when the entry ends in *"}}, "description": "Sources and paths mitigation must never stop. Each entry becomes an allow rule at the top of protection_rules, and automatic mitigation never acts against an entry. Up to 200 entries"}, "ProtectionAllowlistPatch": {"type": "object", "properties": {"countries": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "description": "Countries of the source, ISO 3166-1 alpha-2"}, "asns": {"type": "array", "items": {"type": "integer"}, "maxItems": 500, "description": "AS numbers of the source"}, "ips": {"type": "array", "items": {"type": "string"}, "description": "Addresses or ranges, up to 128, none broader than /16 (IPv4) or /32 (IPv6). They are also exempt from the layer 3/4 limits at the edge"}, "paths": {"type": "array", "items": {"type": "string"}, "maxItems": 500, "description": "Request paths: exact, or a prefix when the entry ends in *"}}, "description": "Merged into the stored protection_allowlist: send only the fields to change."}, "ProtectionRule": {"type": "object", "properties": {"name": {"type": "string", "nullable": true, "description": "Letters, digits, dot, dash and underscore, up to 40 characters, unique in the vService; logged as pr_hit=<name>-<action>. Omit it and the server names the rule rule<position>. The prefixes rate-, posture-, ti- and allowlist- are reserved"}, "match_mode": {"type": "string", "enum": ["and", "or"], "default": "and", "description": "Flat match only: and (every key must match) or or (one key is enough). The server stores the conditions as a group (any_of or all_of) and returns and here"}, "negate": {"type": "boolean", "default": false, "description": "Flat match only: the rule matches every request the match does not; rate is not inverted. The server stores it as not on the group and returns false here"}, "match": {"allOf": [{"$ref": "#/components/schemas/MatchNode"}], "description": "Which requests the rule matches"}, "rate": {"allOf": [{"$ref": "#/components/schemas/RuleRate"}], "nullable": true, "type": "object", "description": "Extra condition: the source's request rate"}, "action": {"type": "string", "enum": ["allow", "skip", "deny", "challenge", "block", "drop"], "description": "allow: exempt from the rules below, the blocklists, threat intelligence, the rate limits and proof-of-work; the WAF still inspects. skip: the same, for the stages in skip only. deny: 403. block: 429. drop: close the connection without an answer. challenge: proof-of-work unless solved, only with pow.enabled; the checks after the rules still run first. On tcp and anyconnect vServices deny and block refuse the connection; skip and challenge do not exist there"}, "skip": {"type": "array", "items": {"type": "string", "enum": ["rules", "rate_limits", "blocklists", "threat_intel", "pow"]}, "nullable": true, "description": "skip rules only: the stages to skip. Omit it to skip all five, like allow"}, "enabled": {"type": "boolean", "default": true, "description": "false keeps the rule without applying it"}, "bind_to": {"type": "string", "nullable": true, "description": "Apply the rule only to requests for this hostname: the FQDN or one of its aliases. Null: every hostname. HTTPS only"}, "_meta": {"type": "object", "additionalProperties": {}, "nullable": true, "description": "Set by ZERO-PROTECT on rules it adds itself: source (posture, allowlist or emergency) and for time-limited rules expires_at, after which the edges stop applying the rule. Send it back unchanged"}}, "required": ["action"], "description": "A protection rule. Rules run in list order; deny, block and drop end the request at once, so an allow or skip rule exempts only from the rules below it"}, "PurgeResult": {"type": "object", "properties": {"type": {"type": "string", "enum": ["all", "url", "prefix"], "description": "What was purged"}, "generation": {"type": "integer", "description": "type all"}, "id": {"type": "string", "description": "type url and prefix"}, "host": {"type": "string", "description": "type url: the hostname"}, "url": {"type": "string", "description": "type url: path and query string"}, "prefix": {"type": "string", "description": "type prefix: the path prefix"}, "at": {"type": "string", "format": "date-time", "description": "When the purge was recorded"}, "by": {"type": "string", "description": "Who purged: your e-mail, or key:<key id> for an API key"}}, "required": ["at", "by", "type"], "description": "The purge just recorded"}, "Purges": {"type": "object", "properties": {"generation": {"type": "integer", "description": "Rises with each purge of everything"}, "all": {"type": "array", "items": {"type": "object", "properties": {"generation": {"type": "integer", "description": "Generation this purge started"}, "at": {"type": "string", "format": "date-time", "description": "When"}, "by": {"type": "string", "description": "Your e-mail, \"API key <label>\", or support"}}}, "description": "The last 10 purges of everything, oldest first"}, "urls": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string", "description": "Purge id"}, "host": {"type": "string", "description": "The hostname"}, "url": {"type": "string", "description": "Path and query string"}, "at": {"type": "string", "format": "date-time", "description": "When"}, "by": {"type": "string", "description": "Your e-mail, \"API key <label>\", or support"}}}, "description": "The last 50 URL purges, oldest first"}, "prefixes": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string", "description": "Purge id"}, "prefix": {"type": "string", "description": "The path prefix"}, "at": {"type": "string", "format": "date-time", "description": "When"}, "by": {"type": "string", "description": "Your e-mail, \"API key <label>\", or support"}}}, "description": "Prefix purges since the last purge of everything, up to 50, oldest first"}}, "required": ["all", "generation", "prefixes", "urls"], "description": "Recent purges of the vService"}, "RateLimiting": {"type": "object", "properties": {"challenge_req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 200, "description": "HTTP requests per 10 s a source may send before the edge asks it for proof-of-work; static files and crawlers excepted. Only with pow.enabled"}, "req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 500, "description": "HTTP requests per 10 s a source may send; above it the edge answers 429"}, "conn_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 50, "description": "New connections per 10 s a source may open; above it its HTTP requests get 429, on tcp and anyconnect vServices the connection is refused. Also the new forwarded UDP flows per 10 s a source may open"}, "conn_drop_per_10s": {"type": "integer", "minimum": 1, "maximum": 1000000, "default": 500, "description": "New connections per 10 s from one source above which the edge drops its further connections silently, before TLS; no rule exempts from it. Must be above conn_per_10s. Also sets the layer 3/4 SYN limit per source, at one fifth of this per second"}, "path_default": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 1000, "description": "HTTP requests per 10 s a source may send to the vService, all paths together, before a further request gets 429. It is compared with the source's total rate, not with its requests to one path"}, "path_aggregate_per_10s": {"type": "integer", "minimum": 0, "maximum": 10000000, "default": 5000, "description": "Responses not served from the cache per 10 s for one hostname and path (without query string), all sources together. Above it, and only while your origins are under load (80 % of maxconn in use, or a queue), requests get proof-of-work, or 429 for static files, crawlers and without pow.enabled; solved clients and sources with returning-visitor credit pass. 0: off"}, "geo_tcp_reject_sess_rate": {"type": "integer", "minimum": 0, "maximum": 1000000, "default": 200, "description": "Only with a geofence rule (a negated deny rule on geo, without rate): while the vService takes more new sessions per second than this on an edge, sources the geofence does not allow are refused at connection setup instead of getting a 403. 0: always answer 403"}, "ja4_enabled": {"type": "boolean", "default": false, "description": "Limit requests per JA4 TLS fingerprint"}, "ja4_req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "default": 100, "description": "HTTP requests per 10 s per JA4 fingerprint, all sources together. A fingerprint is shared by everyone running the same software"}, "ja4_action": {"type": "string", "enum": ["challenge", "deny"], "default": "challenge", "description": "Above ja4_req_per_10s: challenge (proof-of-work, only with pow.enabled) or deny (429)"}}, "description": "Limits per source and per vService. A source is one IPv4 address or one IPv6 /64"}, "RateLimitingPatch": {"type": "object", "properties": {"challenge_req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "description": "HTTP requests per 10 s a source may send before the edge asks it for proof-of-work; static files and crawlers excepted. Only with pow.enabled"}, "req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "description": "HTTP requests per 10 s a source may send; above it the edge answers 429"}, "conn_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "description": "New connections per 10 s a source may open; above it its HTTP requests get 429, on tcp and anyconnect vServices the connection is refused. Also the new forwarded UDP flows per 10 s a source may open"}, "conn_drop_per_10s": {"type": "integer", "minimum": 1, "maximum": 1000000, "description": "New connections per 10 s from one source above which the edge drops its further connections silently, before TLS; no rule exempts from it. Must be above conn_per_10s. Also sets the layer 3/4 SYN limit per source, at one fifth of this per second"}, "path_default": {"type": "integer", "minimum": 1, "maximum": 100000, "description": "HTTP requests per 10 s a source may send to the vService, all paths together, before a further request gets 429. It is compared with the source's total rate, not with its requests to one path"}, "path_aggregate_per_10s": {"type": "integer", "minimum": 0, "maximum": 10000000, "description": "Responses not served from the cache per 10 s for one hostname and path (without query string), all sources together. Above it, and only while your origins are under load (80 % of maxconn in use, or a queue), requests get proof-of-work, or 429 for static files, crawlers and without pow.enabled; solved clients and sources with returning-visitor credit pass. 0: off"}, "geo_tcp_reject_sess_rate": {"type": "integer", "minimum": 0, "maximum": 1000000, "description": "Only with a geofence rule (a negated deny rule on geo, without rate): while the vService takes more new sessions per second than this on an edge, sources the geofence does not allow are refused at connection setup instead of getting a 403. 0: always answer 403"}, "ja4_enabled": {"type": "boolean", "description": "Limit requests per JA4 TLS fingerprint"}, "ja4_req_per_10s": {"type": "integer", "minimum": 1, "maximum": 100000, "description": "HTTP requests per 10 s per JA4 fingerprint, all sources together. A fingerprint is shared by everyone running the same software"}, "ja4_action": {"type": "string", "enum": ["challenge", "deny"], "description": "Above ja4_req_per_10s: challenge (proof-of-work, only with pow.enabled) or deny (429)"}}, "description": "Merged into the stored rate_limiting: send only the fields to change."}, "Redirect": {"type": "object", "properties": {"path": {"type": "string", "description": "Request path to match"}, "target": {"type": "string", "description": "Relative path or https:// URL"}, "code": {"type": "integer", "enum": [301, 302, 307, 308], "default": 301, "description": "HTTP status of the redirect"}, "match_type": {"type": "string", "enum": ["exact", "prefix"], "default": "exact", "description": "exact: the request path equals path. prefix: the request path starts with path"}, "condition": {"allOf": [{"$ref": "#/components/schemas/RedirectCondition"}], "nullable": true, "type": "object", "description": "Optional condition on a request header"}, "redirect_type": {"type": "string", "enum": ["location", "prefix"], "default": "location", "description": "location: send to target as written. prefix: target followed by the request's path and query string; a trailing slash of target is removed"}, "bind_to": {"type": "string", "nullable": true, "description": "Only for requests to this hostname: the FQDN or one of its aliases. Null: every hostname"}}, "required": ["path", "target"], "description": "A redirect the edge answers itself, without contacting your origin"}, "RedirectCondition": {"type": "object", "properties": {"header": {"type": "string", "enum": ["accept-language"], "description": "Request header to test; only accept-language"}, "value": {"type": "string", "pattern": "^[a-z]{2,3}$", "description": "Language code, 2 or 3 lower-case letters; matches when one of the languages in the header starts with it (de matches de-AT)"}}, "required": ["header", "value"], "description": "Extra condition of a redirect on a request header"}, "Rename": {"type": "object", "properties": {"to": {"type": "string", "description": "An alias of the vService; it becomes the primary name"}}, "required": ["to"], "description": "The old name becomes an alias and keeps answering until you remove it. VIPs, edge hostname, rules and certificates stay; nothing is re-issued."}, "ResponseHeaders": {"type": "object", "properties": {"hsts": {"allOf": [{"$ref": "#/components/schemas/Hsts"}], "description": "Strict-Transport-Security"}, "cors": {"allOf": [{"$ref": "#/components/schemas/Cors"}], "description": "CORS"}, "x_frame_options": {"type": "string", "enum": ["DENY", "SAMEORIGIN"], "nullable": true, "description": "X-Frame-Options on the responses the edge passes on, replacing your origin's; null: the edge sets none"}, "x_content_type_options": {"type": "boolean", "default": false, "description": "Set X-Content-Type-Options: nosniff on the responses the edge passes on"}, "referrer_policy": {"type": "string", "enum": ["no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"], "nullable": true, "description": "Referrer-Policy on the responses the edge passes on, replacing your origin's; null: the edge sets none"}}, "description": "Headers the edge sets on responses"}, "ResponseHeadersPatch": {"type": "object", "properties": {"hsts": {"allOf": [{"$ref": "#/components/schemas/Hsts"}], "description": "Strict-Transport-Security"}, "cors": {"allOf": [{"$ref": "#/components/schemas/Cors"}], "description": "CORS"}, "x_frame_options": {"type": "string", "enum": ["DENY", "SAMEORIGIN"], "nullable": true, "description": "X-Frame-Options on the responses the edge passes on, replacing your origin's; null: the edge sets none"}, "x_content_type_options": {"type": "boolean", "description": "Set X-Content-Type-Options: nosniff on the responses the edge passes on"}, "referrer_policy": {"type": "string", "enum": ["no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"], "nullable": true, "description": "Referrer-Policy on the responses the edge passes on, replacing your origin's; null: the edge sets none"}}, "description": "Merged into the stored response_headers: send only the fields to change."}, "RuleRate": {"type": "object", "properties": {"threshold": {"type": "integer", "minimum": 1, "description": "Requests of the source to the vService within window, all paths together, above which the rule fires"}, "window": {"type": "string", "enum": ["10s", "30s", "1m", "100s", "5m", "10m"], "description": "Length of the counting window"}}, "required": ["threshold", "window"], "description": "Rate condition of a rule; HTTPS only"}, "Service": {"type": "object", "properties": {"fqdn": {"type": "string", "readOnly": true, "description": "Rename with POST /services/{fqdn}/rename"}, "tenant": {"type": "string", "minLength": 1, "maxLength": 64, "readOnly": true, "description": "Set by the server"}, "enabled": {"type": "boolean", "default": true, "description": "false switches the vService off: the edges stop serving it and its health reads disabled. The configuration stays"}, "mode": {"type": "string", "enum": ["https", "tcp", "anyconnect"], "default": "https", "readOnly": true, "description": "Set when the vService is created"}, "ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "TCP ports the edge accepts, up to 8 entries. https: 443 and 80 by default, any further port is plain HTTP to the same port on your origins. tcp: also ranges (\"40000-40009\") and mappings (\"40000-40009=50000\": edge range to origin start)"}, "udp_ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "UDP ports of a tcp or anyconnect vService, up to 8 entries: forwarded to your origins, to the same port unless mapped (ranges and mappings tcp only). Not for https (no UDP listener). Empty: all UDP to the vService's addresses is dropped"}, "created": {"type": "string", "nullable": true, "format": "date-time", "readOnly": true, "description": "Set by the server"}, "created_by": {"type": "string", "nullable": true, "readOnly": true, "description": "Your e-mail or key label; empty = Zero Services"}, "account_id": {"type": "string", "nullable": true, "readOnly": true, "description": "Set when the vService is created"}, "network": {"allOf": [{"$ref": "#/components/schemas/Network"}], "readOnly": true, "description": "Change addresses with POST /vip-operations"}, "network_protection": {"allOf": [{"$ref": "#/components/schemas/NetworkProtection"}], "readOnly": true, "description": "Set by support on request"}, "backend": {"allOf": [{"$ref": "#/components/schemas/Backend"}], "description": "Load balancing and health checks of the origins"}, "origins": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Origin"}]}, "maxItems": 50, "default": [], "description": "Your origin servers, up to 50"}, "waf": {"allOf": [{"$ref": "#/components/schemas/Waf"}], "description": "Web application firewall"}, "rate_limiting": {"allOf": [{"$ref": "#/components/schemas/RateLimiting"}], "description": "Rate limits"}, "pow": {"allOf": [{"$ref": "#/components/schemas/Pow"}], "description": "Proof-of-work challenge"}, "admission": {"allOf": [{"$ref": "#/components/schemas/Admission"}], "description": "Returning-visitor admission"}, "ssl": {"allOf": [{"$ref": "#/components/schemas/Ssl"}], "description": "Certificate settings of the FQDN"}, "aliases": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Alias"}]}, "default": [], "description": "Further hostnames of the vService"}, "cache": {"allOf": [{"$ref": "#/components/schemas/Cache"}], "description": "Edge cache"}, "slow_http": {"allOf": [{"$ref": "#/components/schemas/SlowHttp"}], "description": "Timeouts against slow requests"}, "tcp_timeout": {"allOf": [{"$ref": "#/components/schemas/TcpTimeout"}], "readOnly": true, "description": "Set by support on request"}, "udp_timeout": {"allOf": [{"$ref": "#/components/schemas/UdpTimeout"}], "readOnly": true, "description": "Set by support on request"}, "sni_policy": {"type": "string", "enum": ["allowlist", "off"], "default": "allowlist", "readOnly": true, "description": "Set by support on request"}, "proxy_protocol": {"type": "boolean", "default": false, "description": "tcp and anyconnect: send a PROXY protocol v2 header with the client address to your origins, before each TCP connection and each forwarded UDP datagram. Your origin must expect it"}, "tls_termination": {"type": "boolean", "default": false, "description": "tcp only: the edge terminates TLS with the vService's certificate and opens its own connection to each origin as its tls and ssl_verify say. Until a certificate exists, TLS passes through"}, "priority": {"allOf": [{"$ref": "#/components/schemas/Priority"}], "description": "Origin queue priority"}, "response_headers": {"allOf": [{"$ref": "#/components/schemas/ResponseHeaders"}], "description": "Response headers set at the edge"}, "content_negotiation": {"allOf": [{"$ref": "#/components/schemas/ContentNegotiation"}], "description": "Pre-compressed static files"}, "logging": {"allOf": [{"$ref": "#/components/schemas/Logging"}], "readOnly": true, "description": "Set by support on request"}, "threat_intel": {"allOf": [{"$ref": "#/components/schemas/ThreatIntel"}], "description": "Reputation lists"}, "redirects": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Redirect"}]}, "maxItems": 200, "default": [], "description": "Redirects and response_headers.cors.rules together: at most 200 per vService"}, "origin_host": {"type": "string", "maxLength": 253, "nullable": true, "description": "Host header sent to your origins for requests to the FQDN; aliases keep their own. Also the Host of the health check and the default TLS server name. Default: the FQDN"}, "origin_sni": {"type": "string", "maxLength": 253, "nullable": true, "description": "TLS server name sent to TLS origins without their own sni. Default: origin_host, else the FQDN"}, "maintenance_mode": {"type": "boolean", "default": false, "description": "true: the edges answer every request with a 503 maintenance page (JSON for service_profile api) and do not contact your origins. HTTPS only"}, "auto_mitigation": {"type": "boolean", "default": false, "description": "true: automatic attack response may add time-limited protection rules to the vService itself, never against your allowlist. false: it only suggests them"}, "defense_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "nullable": true, "description": "Protection bundle for the service type. off: loose limits only, no challenge, WAF or threat intelligence. standard: denies the network reputation list and, for browser services, challenges busy login and admin paths. under_attack: strictest, challenges every request where the type allows proof-of-work. Setting it applies the bundle's values to rate_limiting, pow, slow_http, cache, waf, threat_intel, admission and priority and replaces the rules it added"}, "protection_allowlist": {"allOf": [{"$ref": "#/components/schemas/ProtectionAllowlist"}], "nullable": true, "type": "object", "description": "Sources and paths mitigation must never stop"}, "edges": {"type": "array", "items": {"type": "string", "maxLength": 253}, "maxItems": 50, "default": [], "readOnly": true, "description": "Set when the vService is created"}, "protection_rules": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/ProtectionRule"}]}, "maxItems": 300, "default": [], "description": "Your protection rules and those the posture and the allowlist add, in the order they run. Up to 100 of your own; the allowlist rules are rebuilt from protection_allowlist"}, "append_trailing_slash": {"type": "boolean", "default": false, "description": "Redirect /foo to /foo/ with 301 for GET and HEAD when the path has neither a trailing slash nor a file extension, for directory-style static origins. HTTPS only"}, "exceed_no_rtbh": {"type": "boolean", "default": false, "readOnly": true, "description": "Set by support on request"}, "exceed_no_flowspec": {"type": "boolean", "default": false, "readOnly": true, "description": "Set by support on request"}, "origin_kind": {"type": "string", "enum": ["dynamic", "static"], "default": "dynamic", "description": "static: your origin is a bucket or file server, and the edge replaces its 403 and 404 answers with the branded error pages. dynamic: its answers pass unchanged"}, "service_profile": {"type": "string", "enum": ["api", "web_dynamic", "web_static", "hls"], "nullable": true, "description": "What talks to the vService: web_dynamic (browsers), web_static (static files), api (apps and devices; the edge answers its own errors as JSON) or hls (video streaming). It picks the posture bundle, which applies when you next set defense_posture"}, "sensitivity": {"type": "string", "enum": ["low", "medium", "high"], "nullable": true, "description": "Learn the service-wide limits (path_aggregate_per_10s, geo_tcp_reject_sess_rate, challenge answers, origin maxconn) from your normal peak: low 3 times, medium 2 times, high 1.5 times, never below the floor. Null: the fixed values apply. HTTPS only"}, "size_tier": {"type": "string", "enum": ["S", "M", "L", "XL"], "nullable": true, "description": "S, M, L or XL: scales the floors of the learned limits by 0.5, 1, 2 or 4. Only with a sensitivity"}, "alias_limit": {"type": "integer", "nullable": true, "readOnly": true, "description": "Aliases you may add; null = no limit"}, "serving_edges": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Edges that serve the vService now"}, "posture_drift": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Sections that differ from the posture"}, "baseline": {"type": "object", "nullable": true, "properties": {"computed_at": {"type": "string", "format": "date-time", "nullable": true, "description": "When the learned limits were computed"}, "window_days": {"type": "integer", "nullable": true, "description": "Days of traffic measured"}, "sensitivity": {"type": "string", "nullable": true, "description": "Sensitivity the limits were computed with"}, "size_tier": {"type": "string", "nullable": true, "description": "Size tier the floors were scaled with"}, "factor": {"type": "number", "nullable": true, "description": "Multiplier on the measured baseline: 3 for low, 2 for medium, 1.5 for high"}, "measured": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "Measured baseline per limit: the busiest normal day of the window, attack days left out; maxconn per origin"}, "floors": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "Lowest value per limit: the posture's value for the service type, scaled by size_tier"}, "paused": {"type": "boolean", "nullable": true, "description": "Posture that suspends the learned limits (under_attack); null while they apply"}, "values": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "The learned limits: path_aggregate_per_10s, botcheck_per_10s, geo_tcp_reject_sess_rate and origin_maxconn per origin. The edges apply them only while sensitivity is set"}}, "readOnly": true, "description": "Learned limits, null before the first measurement"}, "delegations": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Delegations the vService is part of (GET /services only)"}}, "description": "A vService: one protected hostname with its aliases, origins and settings"}, "ServiceCreate": {"type": "object", "properties": {"account_id": {"type": "string", "minLength": 1, "maxLength": 64, "description": "Your dedicated or BYOIP account the vService is booked under"}, "defense_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "nullable": true, "description": "Protection bundle: off, standard or under_attack. Default: your tenant's default_posture, else standard"}, "edges": {"type": "array", "items": {"type": "string"}, "description": "Dedicated accounts: your dedicated edges, default all. BYOIP accounts: not allowed"}, "fqdn": {"type": "string", "description": "The hostname to protect; it becomes the vService's name"}, "mode": {"type": "string", "enum": ["https", "tcp", "anyconnect"], "default": "https", "description": "https (HTTP and TLS at the edge), tcp (TCP passed through, UDP forwarded) or anyconnect (a Cisco Secure Client VPN gateway). Fixed after creation"}, "origins": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Origin"}]}, "maxItems": 50, "default": [], "description": "May be empty: add origins later; the vService answers 503 until then"}, "pool": {"type": "string", "description": "One of your IP pools; default the first"}, "ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "TCP ports the edge accepts, up to 8 entries. https: 443 and 80 by default, any further port is plain HTTP to the same port on your origins. tcp: also ranges (\"40000-40009\") and mappings (\"40000-40009=50000\": edge range to origin start)"}, "service_profile": {"type": "string", "enum": ["api", "web_dynamic", "web_static", "hls"], "nullable": true, "description": "What talks to the vService: web_dynamic (browsers), web_static (static files), api (apps and devices; the edge answers its own errors as JSON) or hls (video streaming). It picks the posture bundle applied at creation"}, "size_tier": {"type": "string", "enum": ["S", "M", "L", "XL"], "nullable": true, "description": "S, M, L or XL: scales the floors of the learned limits by 0.5, 1, 2 or 4. Only with a sensitivity"}, "udp_ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "UDP ports of a tcp or anyconnect vService, up to 8 entries: forwarded to your origins, to the same port unless mapped (ranges and mappings tcp only). Not for https (no UDP listener). Empty: all UDP to the vService's addresses is dropped"}}, "required": ["account_id", "fqdn"], "description": "A new vService"}, "ServiceHealth": {"type": "object", "properties": {"status": {"type": "string", "enum": ["blackholed", "origin_down", "misconfigured", "errors", "origin_slow", "under_attack", "normal", "maintenance", "disabled", "unknown"], "description": "normal: nothing found. under_attack: the protection is stopping attack traffic; not a fault, nothing to do. errors: 5 % or more of the answers are 5xx, at least 1 per second; fault says whether the edge or your origin makes them. origin_slow: your origins take 1 s or more on average. origin_down: no origin passes its health check. misconfigured: a hostname's DNS does not point at ZERO-PROTECT (GET /services/{fqdn}/dns), or there is neither an origin nor a redirect. blackholed: Zero Services had the address blackholed upstream to protect the site's line from a flood; nothing arrives until that ends. maintenance: maintenance_mode is on. disabled: the vService is switched off. unknown: not measured right now, such as just after a restart; not an error"}, "fault": {"type": "string", "enum": ["zp", "customer", "none"], "description": "zp: our side; customer: origin, DNS or configuration"}, "reason": {"type": "string", "description": "Machine-readable, empty when normal"}, "signals": {"$ref": "#/components/schemas/HealthSignals", "description": "The measurements behind the state"}}, "required": ["fault", "reason", "signals", "status"], "description": "Health of a vService over the last 5 minutes"}, "ServicePatch": {"type": "object", "properties": {"admission": {"allOf": [{"$ref": "#/components/schemas/AdmissionPatch"}], "nullable": true, "type": "object", "description": "Returning-visitor admission"}, "aliases": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Alias"}]}, "nullable": true, "description": "Further hostnames of the vService"}, "append_trailing_slash": {"type": "boolean", "nullable": true, "description": "Redirect /foo to /foo/ with 301 for GET and HEAD when the path has neither a trailing slash nor a file extension, for directory-style static origins. HTTPS only"}, "auto_mitigation": {"type": "boolean", "nullable": true, "description": "true: automatic attack response may add time-limited protection rules to the vService itself, never against your allowlist. false: it only suggests them"}, "backend": {"allOf": [{"$ref": "#/components/schemas/BackendPatch"}], "nullable": true, "type": "object", "description": "Load balancing and health checks of the origins"}, "cache": {"allOf": [{"$ref": "#/components/schemas/CachePatch"}], "nullable": true, "type": "object", "description": "Edge cache"}, "content_negotiation": {"allOf": [{"$ref": "#/components/schemas/ContentNegotiationPatch"}], "nullable": true, "type": "object", "description": "Pre-compressed static files"}, "defense_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "nullable": true, "description": "Protection bundle for the service type. off: loose limits only, no challenge, WAF or threat intelligence. standard: denies the network reputation list and, for browser services, challenges busy login and admin paths. under_attack: strictest, challenges every request where the type allows proof-of-work. Setting it applies the bundle's values to rate_limiting, pow, slow_http, cache, waf, threat_intel, admission and priority and replaces the rules it added"}, "enabled": {"type": "boolean", "nullable": true, "description": "false switches the vService off: the edges stop serving it and its health reads disabled. The configuration stays"}, "maintenance_mode": {"type": "boolean", "nullable": true, "description": "true: the edges answer every request with a 503 maintenance page (JSON for service_profile api) and do not contact your origins. HTTPS only"}, "origin_host": {"type": "string", "maxLength": 253, "nullable": true, "description": "Host header sent to your origins for requests to the FQDN; aliases keep their own. Also the Host of the health check and the default TLS server name. Default: the FQDN"}, "origin_kind": {"type": "string", "enum": ["dynamic", "static"], "nullable": true, "description": "static: your origin is a bucket or file server, and the edge replaces its 403 and 404 answers with the branded error pages. dynamic: its answers pass unchanged"}, "origin_sni": {"type": "string", "maxLength": 253, "nullable": true, "description": "TLS server name sent to TLS origins without their own sni. Default: origin_host, else the FQDN"}, "origins": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Origin"}]}, "maxItems": 50, "nullable": true, "description": "Your origin servers, up to 50"}, "ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "TCP ports the edge accepts, up to 8 entries. https: 443 and 80 by default, any further port is plain HTTP to the same port on your origins. tcp: also ranges (\"40000-40009\") and mappings (\"40000-40009=50000\": edge range to origin start)"}, "pow": {"allOf": [{"$ref": "#/components/schemas/PowPatch"}], "nullable": true, "type": "object", "description": "Proof-of-work challenge"}, "priority": {"allOf": [{"$ref": "#/components/schemas/PriorityPatch"}], "nullable": true, "type": "object", "description": "Origin queue priority"}, "protection_allowlist": {"allOf": [{"$ref": "#/components/schemas/ProtectionAllowlistPatch"}], "nullable": true, "type": "object", "description": "Sources and paths mitigation must never stop"}, "protection_rules": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/ProtectionRule"}]}, "maxItems": 300, "nullable": true, "description": "Your protection rules and those the posture and the allowlist add, in the order they run. Up to 100 of your own; the allowlist rules are rebuilt from protection_allowlist"}, "proxy_protocol": {"type": "boolean", "nullable": true, "description": "tcp and anyconnect: send a PROXY protocol v2 header with the client address to your origins, before each TCP connection and each forwarded UDP datagram. Your origin must expect it"}, "rate_limiting": {"allOf": [{"$ref": "#/components/schemas/RateLimitingPatch"}], "nullable": true, "type": "object", "description": "Rate limits"}, "redirects": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Redirect"}]}, "maxItems": 200, "nullable": true, "description": "Redirects and response_headers.cors.rules together: at most 200 per vService"}, "response_headers": {"allOf": [{"$ref": "#/components/schemas/ResponseHeadersPatch"}], "nullable": true, "type": "object", "description": "Response headers set at the edge"}, "sensitivity": {"type": "string", "enum": ["low", "medium", "high"], "nullable": true, "description": "Learn the service-wide limits (path_aggregate_per_10s, geo_tcp_reject_sess_rate, challenge answers, origin maxconn) from your normal peak: low 3 times, medium 2 times, high 1.5 times, never below the floor. Null: the fixed values apply. HTTPS only"}, "service_profile": {"type": "string", "enum": ["api", "web_dynamic", "web_static", "hls"], "nullable": true, "description": "What talks to the vService: web_dynamic (browsers), web_static (static files), api (apps and devices; the edge answers its own errors as JSON) or hls (video streaming). It picks the posture bundle, which applies when you next set defense_posture"}, "size_tier": {"type": "string", "enum": ["S", "M", "L", "XL"], "nullable": true, "description": "S, M, L or XL: scales the floors of the learned limits by 0.5, 1, 2 or 4. Only with a sensitivity"}, "slow_http": {"allOf": [{"$ref": "#/components/schemas/SlowHttpPatch"}], "nullable": true, "type": "object", "description": "Timeouts against slow requests"}, "ssl": {"allOf": [{"$ref": "#/components/schemas/SslPatch"}], "nullable": true, "type": "object", "description": "Certificate settings of the FQDN"}, "threat_intel": {"allOf": [{"$ref": "#/components/schemas/ThreatIntelPatch"}], "nullable": true, "type": "object", "description": "Reputation lists"}, "tls_termination": {"type": "boolean", "nullable": true, "description": "tcp only: the edge terminates TLS with the vService's certificate and opens its own connection to each origin as its tls and ssl_verify say. Until a certificate exists, TLS passes through"}, "udp_ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "UDP ports of a tcp or anyconnect vService, up to 8 entries: forwarded to your origins, to the same port unless mapped (ranges and mappings tcp only). Not for https (no UDP listener). Empty: all UDP to the vService's addresses is dropped"}, "waf": {"allOf": [{"$ref": "#/components/schemas/WafPatch"}], "nullable": true, "type": "object", "description": "Web application firewall"}}, "description": "The fields of a vService you can change"}, "ServiceSummary": {"type": "object", "description": "A vService in the list: GET /services/{fqdn} has every field.", "properties": {"fqdn": {"type": "string", "readOnly": true, "description": "Rename with POST /services/{fqdn}/rename"}, "tenant": {"type": "string", "minLength": 1, "maxLength": 64, "readOnly": true, "description": "Set by the server"}, "account_id": {"type": "string", "nullable": true, "readOnly": true, "description": "Set when the vService is created"}, "enabled": {"type": "boolean", "default": true, "description": "false switches the vService off: the edges stop serving it and its health reads disabled. The configuration stays"}, "mode": {"type": "string", "enum": ["https", "tcp", "anyconnect"], "default": "https", "readOnly": true, "description": "Set when the vService is created"}, "ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "TCP ports the edge accepts, up to 8 entries. https: 443 and 80 by default, any further port is plain HTTP to the same port on your origins. tcp: also ranges (\"40000-40009\") and mappings (\"40000-40009=50000\": edge range to origin start)"}, "udp_ports": {"type": "array", "items": {"oneOf": [{"type": "integer"}, {"type": "string", "example": "40000-40009"}]}, "maxItems": 8, "nullable": true, "description": "UDP ports of a tcp or anyconnect vService, up to 8 entries: forwarded to your origins, to the same port unless mapped (ranges and mappings tcp only). Not for https (no UDP listener). Empty: all UDP to the vService's addresses is dropped"}, "network": {"allOf": [{"$ref": "#/components/schemas/Network"}], "readOnly": true, "description": "Change addresses with POST /vip-operations"}, "waf": {"allOf": [{"$ref": "#/components/schemas/Waf"}], "description": "Web application firewall"}, "maintenance_mode": {"type": "boolean", "default": false, "description": "true: the edges answer every request with a 503 maintenance page (JSON for service_profile api) and do not contact your origins. HTTPS only"}, "aliases": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Alias"}]}, "default": [], "description": "Further hostnames of the vService"}, "edges": {"type": "array", "items": {"type": "string", "maxLength": 253}, "maxItems": 50, "default": [], "readOnly": true, "description": "Set when the vService is created"}, "alias_limit": {"type": "integer", "nullable": true, "readOnly": true, "description": "Aliases you may add; null = no limit"}, "serving_edges": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Edges that serve the vService now"}, "posture_drift": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Sections that differ from the posture"}, "baseline": {"type": "object", "nullable": true, "properties": {"computed_at": {"type": "string", "format": "date-time", "nullable": true, "description": "When the learned limits were computed"}, "window_days": {"type": "integer", "nullable": true, "description": "Days of traffic measured"}, "sensitivity": {"type": "string", "nullable": true, "description": "Sensitivity the limits were computed with"}, "size_tier": {"type": "string", "nullable": true, "description": "Size tier the floors were scaled with"}, "factor": {"type": "number", "nullable": true, "description": "Multiplier on the measured baseline: 3 for low, 2 for medium, 1.5 for high"}, "measured": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "Measured baseline per limit: the busiest normal day of the window, attack days left out; maxconn per origin"}, "floors": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "Lowest value per limit: the posture's value for the service type, scaled by size_tier"}, "paused": {"type": "boolean", "nullable": true, "description": "Posture that suspends the learned limits (under_attack); null while they apply"}, "values": {"type": "object", "nullable": true, "additionalProperties": {}, "description": "The learned limits: path_aggregate_per_10s, botcheck_per_10s, geo_tcp_reject_sess_rate and origin_maxconn per origin. The edges apply them only while sensitivity is set"}}, "readOnly": true, "description": "Learned limits, null before the first measurement"}, "delegations": {"type": "array", "items": {"type": "string"}, "readOnly": true, "description": "Delegations the vService is part of (GET /services only)"}, "origin_count": {"type": "integer", "description": "Number of origins; the origins are in GET /services/{fqdn}"}, "redirect_count": {"type": "integer", "description": "Number of redirects"}}}, "SessionSignal": {"type": "object", "properties": {"kind": {"type": "string", "enum": ["cookie", "header", "query"], "description": "Where to look: cookie, header or query (a query parameter)"}, "name": {"type": "string", "description": "Name of the cookie, header or query parameter; the request counts as a session when it is present"}}, "required": ["kind", "name"], "description": "Where a request shows that it belongs to a session"}, "SlowHttp": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": true, "description": "Apply the timeouts below and wait for the complete request before passing it on. Off: the edge defaults apply, 10 s for the request and 5 s for client-fin"}, "timeout_http_request": {"type": "string", "nullable": true, "default": "5s", "description": "Time a client has to send the complete request, or it gets 408: a number with the unit us, ms, s, m, h or d, such as 5s. Null: 5s"}, "timeout_client_fin": {"type": "string", "nullable": true, "default": "5s", "description": "Time a client that half-closed its connection has to finish it: a number with the unit us, ms, s, m, h or d, such as 5s. Null: 5s"}}, "description": "Timeouts against clients that send their requests slowly (Slowloris)"}, "SlowHttpPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "Apply the timeouts below and wait for the complete request before passing it on. Off: the edge defaults apply, 10 s for the request and 5 s for client-fin"}, "timeout_http_request": {"type": "string", "nullable": true, "description": "Time a client has to send the complete request, or it gets 408: a number with the unit us, ms, s, m, h or d, such as 5s. Null: 5s"}, "timeout_client_fin": {"type": "string", "nullable": true, "description": "Time a client that half-closed its connection has to finish it: a number with the unit us, ms, s, m, h or d, such as 5s. Null: 5s"}}, "description": "Merged into the stored slow_http: send only the fields to change."}, "Ssl": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["acme", "custom"], "default": "acme", "description": "acme: ZERO-PROTECT issues and renews the certificate, validating through the edge, so DNS must point here first. custom: you upload it and renew it yourself"}, "acme_provider": {"type": "string", "enum": ["letsencrypt", "buypass", "zerossl", "google"], "default": "zerossl", "description": "Certificate authority for acme: letsencrypt, buypass, zerossl or google (Google Trust Services)"}, "acme_email": {"type": "string", "format": "email", "nullable": true, "description": "Contact address for the certificate authority. Empty: the account's acme_email, then your tenant's contact address"}, "https_redirect": {"type": "boolean", "default": false, "description": "Redirect HTTP to HTTPS with 301 for this hostname: the vService's own name, or the alias under aliases[]. ACME validation stays on HTTP. Needs a certificate for that name"}, "cert_status": {"type": "string", "enum": ["issued", "expiring", "expired", "error", "pending", "none"], "description": "Derived from the certificate the edges serve; expiring = renewal not done yet, the certificate is still valid. Set by the server", "readOnly": true}, "cert_issued": {"type": "string", "nullable": true, "format": "date-time", "readOnly": true, "description": "Set by the server"}, "cert_expires": {"type": "string", "nullable": true, "format": "date-time", "readOnly": true, "description": "Set by the server"}, "cert_last_renewal": {"type": "string", "nullable": true, "format": "date-time", "readOnly": true, "description": "Set by the server"}, "days_remaining": {"type": "integer", "nullable": true, "readOnly": true, "description": "Set by the server"}}, "description": "Certificate settings of the vService or of one alias"}, "SslPatch": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["acme", "custom"], "description": "acme: ZERO-PROTECT issues and renews the certificate, validating through the edge, so DNS must point here first. custom: you upload it and renew it yourself"}, "acme_provider": {"type": "string", "enum": ["letsencrypt", "buypass", "zerossl", "google"], "description": "Certificate authority for acme: letsencrypt, buypass, zerossl or google (Google Trust Services)"}, "acme_email": {"type": "string", "format": "email", "nullable": true, "description": "Contact address for the certificate authority. Empty: the account's acme_email, then your tenant's contact address"}, "https_redirect": {"type": "boolean", "description": "Redirect HTTP to HTTPS with 301 for this hostname: the vService's own name, or the alias under aliases[]. ACME validation stays on HTTP. Needs a certificate for that name"}}, "description": "Merged into the stored ssl: send only the fields to change."}, "TcpTimeout": {"type": "object", "properties": {"client": {"type": "string", "default": "30s", "description": "Time the edge waits for the client to send or acknowledge data: a number with the unit us, ms, s, m, h or d, such as 30s"}, "server": {"type": "string", "default": "30s", "description": "Time the edge waits for your origin to send or acknowledge data: a number with the unit us, ms, s, m, h or d, such as 30s"}, "tunnel": {"type": "string", "default": "30s", "description": "Inactivity timeout of tunnelled connections such as WebSocket, both directions: a number with the unit us, ms, s, m, h or d, such as 30s"}}, "description": "Inactivity timeouts of connections. Set by support"}, "Tenant": {"type": "object", "properties": {"tenant": {"type": "string", "description": "Your tenant id"}, "company_name": {"type": "string", "nullable": true, "description": "Your company name"}, "portal_name": {"type": "string", "nullable": true, "description": "Name of your white-label portal; null without one"}, "portal_domain": {"type": "string", "nullable": true, "description": "Domain of your white-label portal; null without one"}, "default_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "description": "Posture of vServices created from now on"}, "dedicated_edges": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string", "description": "Hostname of the edge"}, "site": {"type": "string", "nullable": true, "description": "Site of the edge"}}}, "description": "Edges dedicated to you, the choices for POST /services"}, "ip_pools": {"type": "array", "items": {"type": "object", "properties": {"scope": {"type": "string", "description": "Pool id, the value for pool in POST /services"}, "name": {"type": "string", "description": "Display name of the pool"}, "ipv4_available": {"type": "integer", "nullable": true, "description": "Free IPv4 addresses in the pool"}}}, "description": "Your pools, the choices for POST /services; empty without a dedicated or BYOIP account"}}, "required": ["default_posture", "tenant"], "description": "Your tenant: the company all your accounts and vServices belong to"}, "TenantPatch": {"type": "object", "properties": {"default_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "description": "Posture of vServices created from now on: off, standard or under_attack"}}, "required": ["default_posture"], "description": "The default posture for new vServices"}, "TenantPosture": {"type": "object", "properties": {"default_posture": {"type": "string", "enum": ["off", "standard", "under_attack"], "description": "Posture of vServices created from now on"}}, "required": ["default_posture"], "description": "The default posture now set"}, "ThreatIntel": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "default": "log", "description": "Hijacked and criminal netblocks and malware command servers (Spamhaus DROP, abuse.ch)"}, "abuse": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "default": "log", "description": "Sources reported for attacks in the last 48 hours (blocklist.de, CINS). These addresses rotate and sit behind NAT: prefer challenge over deny"}, "tor": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "default": "log", "description": "Tor exit nodes"}}, "description": "Reputation lists matched against the source address. Each is off, log (only record the hit as ti_hit), challenge (proof-of-work, only with pow.enabled) or deny (403)"}, "ThreatIntelPatch": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "description": "Hijacked and criminal netblocks and malware command servers (Spamhaus DROP, abuse.ch)"}, "abuse": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "description": "Sources reported for attacks in the last 48 hours (blocklist.de, CINS). These addresses rotate and sit behind NAT: prefer challenge over deny"}, "tor": {"type": "string", "enum": ["off", "log", "challenge", "deny"], "description": "Tor exit nodes"}}, "description": "Merged into the stored threat_intel: send only the fields to change."}, "TrafficByService": {"type": "object", "properties": {"metric": {"type": "string", "enum": ["traffic_by_service"], "description": "Always traffic_by_service"}, "window": {"type": "string", "description": "Averaging window of the rates"}, "unit": {"type": "string", "enum": ["bytes/s"], "description": "Unit of inbound and outbound"}, "data": {"type": "array", "items": {"type": "object", "properties": {"fqdn": {"type": "string", "description": "The vService"}, "inbound": {"type": "number", "description": "Bytes per second arriving at the edge, dropped traffic included"}, "outbound": {"type": "number", "description": "Bytes per second from the edge to clients"}}}, "description": "One row per vService"}, "scope": {"$ref": "#/components/schemas/MetricScope", "description": "What was summed"}}, "required": ["data", "metric"], "description": "Current rate per vService (5-minute average)"}, "UdpTimeout": {"type": "object", "properties": {"idle": {"type": "string", "default": "300s", "description": "A flow without packets in either direction for this long ends: a number with the unit us, ms, s, m, h or d, such as 300s; at least 1 s"}, "unreplied": {"type": "string", "default": "30s", "description": "A flow your origin has not answered within this long ends, so spoofed sources cannot hold flow entries: a number with the unit us, ms, s, m, h or d, such as 30s"}, "unreplied_pkts": {"type": "integer", "minimum": 0, "maximum": 65535, "default": 32, "description": "Packets a flow may send before your origin answers; 0: no cap, for one-way protocols"}, "src_pps": {"type": "integer", "minimum": 0, "maximum": 100000000, "default": 0, "description": "Forwarded packets per second per source over all its flows; 0: no limit"}}, "description": "Limits of forwarded UDP flows of tcp and anyconnect vServices. Set by support"}, "Vip": {"type": "object", "properties": {"anycast_ipv4": {"type": "string", "nullable": true, "readOnly": true, "description": "Change addresses with POST /vip-operations"}, "anycast_ipv6": {"type": "string", "nullable": true, "readOnly": true, "description": "Change addresses with POST /vip-operations"}}, "description": "One address pair of the vService"}, "VipOperationRecord": {"type": "object", "properties": {"id": {"type": "string", "description": "Operation id for GET /vip-operations/{op_id}"}, "idempotency_key": {"type": "string", "nullable": true, "description": "The Idempotency-Key sent; null without one"}, "at": {"type": "string", "format": "date-time", "description": "When the operations were applied"}, "by": {"type": "string", "description": "Who ran them; key:<key id> for an API key"}, "services": {"type": "array", "items": {"type": "string"}, "description": "vServices the operations changed"}, "pools": {"type": "array", "items": {"type": "string"}, "description": "Pools whose announcement changed"}, "results": {"type": "array", "items": {"type": "object"}, "description": "One result per operation, in order: the op and what it did"}, "commit": {"type": "string", "nullable": true, "description": "Configuration revision holding the change"}, "replayed": {"type": "boolean", "description": "true: a retry with the same Idempotency-Key, answered with the first result"}}, "description": "Result of a VIP operations request"}, "VipOperationStatus": {"allOf": [{"$ref": "#/components/schemas/VipOperationRecord"}, {"type": "object", "properties": {"state": {"type": "string", "enum": ["pending", "live", "unknown"], "description": "live: every reporting edge runs the change. pending: written, not yet live everywhere. unknown: the revision was not found"}, "edges": {"type": "array", "items": {"type": "object", "properties": {"edge": {"type": "string", "description": "Hostname of the edge"}, "reporting": {"type": "boolean", "description": "The edge reported within 5 minutes; edges not reporting are not waited for"}, "puller": {"type": "boolean", "description": "The edge's applied configuration contains the change"}, "scrubd": {"type": "boolean", "description": "Only for vServices with UDP ports: the edge's packet filter runs the change"}}}, "description": "Every edge that serves the changed vServices or announces the changed pools"}}}], "description": "Where a VIP operations request stands on the edges"}, "VipOperations": {"type": "object", "properties": {"operations": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/Operation"}]}, "minItems": 1, "maxItems": 500, "description": "Up to 500 operations, applied in order; all succeed or none is applied"}, "idempotency_key": {"type": "string", "minLength": 1, "maxLength": 128, "description": "Same as the Idempotency-Key header; when both are sent they must be equal"}}, "required": ["operations"], "description": "VIP operations, applied in order as one change"}, "Waf": {"type": "object", "properties": {"enabled": {"type": "boolean", "default": false, "description": "Inspect requests with the WAF: headers and the first 32,768 bytes of the body. Requests answered from the cache skip it; no rule exempts from it"}, "fail_open": {"type": "boolean", "default": true, "readOnly": true, "description": "Set by support on request"}, "mode": {"type": "string", "enum": ["On", "DetectionOnly"], "default": "On", "description": "On: block a request whose anomaly score reaches the threshold with 403. DetectionOnly: only log"}, "paranoia_level": {"type": "integer", "minimum": 1, "maximum": 4, "default": 1, "description": "Core Rule Set paranoia level, 1 to 4: each level adds stricter rules and more false positives; 1 suits most applications"}, "inbound_threshold": {"type": "integer", "minimum": 1, "maximum": 10, "default": 5, "description": "Anomaly score at which a request is blocked, 1 to 10; a critical rule adds 5, an error 4, a warning 3"}, "disabled_rules": {"type": "array", "items": {"type": "integer"}, "maxItems": 200, "default": [], "description": "Core Rule Set rule ids switched off for this vService, up to 200"}}, "description": "Web application firewall of HTTPS vServices: Coraza with the OWASP Core Rule Set"}, "WafPatch": {"type": "object", "properties": {"enabled": {"type": "boolean", "description": "Inspect requests with the WAF: headers and the first 32,768 bytes of the body. Requests answered from the cache skip it; no rule exempts from it"}, "mode": {"type": "string", "enum": ["On", "DetectionOnly"], "description": "On: block a request whose anomaly score reaches the threshold with 403. DetectionOnly: only log"}, "paranoia_level": {"type": "integer", "minimum": 1, "maximum": 4, "description": "Core Rule Set paranoia level, 1 to 4: each level adds stricter rules and more false positives; 1 suits most applications"}, "inbound_threshold": {"type": "integer", "minimum": 1, "maximum": 10, "description": "Anomaly score at which a request is blocked, 1 to 10; a critical rule adds 5, an error 4, a warning 3"}, "disabled_rules": {"type": "array", "items": {"type": "integer"}, "maxItems": 200, "description": "Core Rule Set rule ids switched off for this vService, up to 200"}}, "description": "Merged into the stored waf: send only the fields to change."}}}}
