Services¶
A vService is one protected hostname with its aliases, origins and settings. Every setting in this API section is a field of the service. Requests need a key, see API access.
Creating and deleting a vService over the API is for dedicated edges and own prefixes (BYOIP) only; a Shared vService is ordered in the customer portal and removed by cancelling the order. Both are configured the same way. Details: Shared and Dedicated.
Endpoints¶
| Method | Path | Key | Purpose |
|---|---|---|---|
GET |
/attacks |
read | Attacks running now on your vServices |
GET |
/attacks/{month} |
read | Attacks of one month on your vServices |
GET |
/services |
read | List your vServices |
POST |
/services |
write | Create a vService from one of your IP pools |
GET |
/services/health |
read | Health of all your vServices |
DELETE |
/services/{fqdn} |
write | Delete a vService of a dedicated or BYOIP account |
GET |
/services/{fqdn} |
read | Get a vService |
PATCH |
/services/{fqdn} |
write | Change a vService |
GET |
/services/{fqdn}/dns |
read | DNS records the vService expects |
GET |
/services/{fqdn}/history |
read | Change history of a vService |
POST |
/services/{fqdn}/rename |
write | Make an alias the primary name |
GET /attacks
Returns: 200, AttackList
Answer 200
{
"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": []
}
]
}
GET /attacks/{month}
Returns: 200, AttackArchive
Answer 200
{
"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"
}
]
}
]
}
GET /services
Returns: 200, list of ServiceSummary
Answer 200
[
{
"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
}
]
POST /services
Body: ServiceCreate
Returns: 201, Service
Request
{
"account_id": "acc-a",
"fqdn": "shop.example.com",
"pool": "P-A",
"origins": [
{
"address": "192.0.2.10",
"port": 443
}
]
}
Answer 201
{
"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
}
GET /services/health
Returns: 200, HealthOverview
Answer 200
{
"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
}
}
}
}
DELETE /services/{fqdn}
Returns: 204, no body
GET /services/{fqdn}
Returns: 200, Service
Answer 200
{
"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
}
PATCH /services/{fqdn}
Body: ServicePatch
Returns: 200, Service
Request: waf_and_limit
{
"waf": {
"enabled": true
},
"rate_limiting": {
"req_per_10s": 800
}
}
Request: replace_origins
{
"origins": [
{
"name": "origin-1",
"address": "192.0.2.10",
"port": 443
}
]
}
Answer 200: waf_and_limit
{
"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
}
Answer 200: replace_origins
{
"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
}
GET /services/{fqdn}/dns
| Parameter | In | Meaning |
|---|---|---|
refresh |
query | Look the records up again instead of the last minute's answer; default false |
Returns: 200, DnsStatus
Answer 200
{
"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
}
]
}
GET /services/{fqdn}/history
| Parameter | In | Meaning |
|---|---|---|
range |
query | Time window; one of 5m, 15m, 1h, 6h, 24h, 7d; default "24h" |
Returns: 200, History
Answer 200
{
"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
}
]
}
POST /services/{fqdn}/rename
Body: Rename
Returns: 200, Service
Request
{
"to": "www.a.example.com"
}
Answer 200
{
"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
}
Fields¶
Part of the service: send them with PATCH /services/{fqdn}; only the fields you send
change, on all edges in about 30 seconds. Origins, ports and certificates have their own pages: Origins,
Ports, TLS.
| Field | Type | Notes |
|---|---|---|
enabled |
boolean | may be null; false switches the vService off: the edges stop serving it and its health reads disabled. The configuration stays |
maintenance_mode |
boolean | may be null; true: the edges answer every request with a 503 maintenance page (JSON for service_profile api) and do not contact your origins. HTTPS only |
service_profile |
string | one of api, web_dynamic, web_static, hls; may be null; 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 |
defense_posture |
string | one of off, standard, under_attack; may be null; 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 |
sensitivity |
string | one of low, medium, high; may be null; 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 |
string | one of S, M, L, XL; may be null; S, M, L or XL: scales the floors of the learned limits by 0.5, 1, 2 or 4. Only with a sensitivity |
auto_mitigation |
boolean | may be null; true: automatic attack response may add time-limited protection rules to the vService itself, never against your allowlist. false: it only suggests them |
append_trailing_slash |
boolean | may be null; 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 |
aliases |
list of Alias |
may be null; Further hostnames of the vService |
redirects |
list of Redirect |
at most 200; may be null; Redirects and response_headers.cors.rules together: at most 200 per vService |
ServiceCreate¶
POST /services creates a vService on your dedicated edges, or from one of your own prefixes on our edges.
| Field | Type | Notes |
|---|---|---|
account_id (required) |
string | up to 64 characters; Your dedicated or BYOIP account the vService is booked under |
defense_posture |
string | one of off, standard, under_attack; may be null; Protection bundle: off, standard or under_attack. Default: your tenant's default_posture, else standard |
edges |
list of string | Dedicated accounts: your dedicated edges, default all. BYOIP accounts: not allowed |
fqdn (required) |
string | The hostname to protect; it becomes the vService's name |
mode |
string | one of https, tcp, anyconnect; default "https"; 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 |
list of Origin |
at most 50; May be empty: add origins later; the vService answers 503 until then |
pool |
string | One of your IP pools; default the first |
ports |
list of integer or string | at most 8; may be null; 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 |
string | one of api, web_dynamic, web_static, hls; may be null; 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 |
string | one of S, M, L, XL; may be null; 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 |
list of integer or string | at most 8; may be null; 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 |
Alias¶
| Field | Type | Notes |
|---|---|---|
fqdn (required) |
string | up to 253 characters; The alias hostname |
ssl |
Ssl |
Certificate settings of the alias |
Redirect¶
| Field | Type | Notes |
|---|---|---|
path (required) |
string | Request path to match |
target (required) |
string | Relative path or https:// URL |
code |
integer | one of 301, 302, 307, 308; default 301; HTTP status of the redirect |
match_type |
string | one of exact, prefix; default "exact"; exact: the request path equals path. prefix: the request path starts with path |
condition |
RedirectCondition |
may be null; Optional condition on a request header |
redirect_type |
string | one of location, prefix; default "location"; 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 |
string | may be null; Only for requests to this hostname: the FQDN or one of its aliases. Null: every hostname |
RedirectCondition¶
| Field | Type | Notes |
|---|---|---|
header (required) |
string | one of accept-language; Request header to test; only accept-language |
value (required) |
string | Language code, 2 or 3 lower-case letters; matches when one of the languages in the header starts with it (de matches de-AT) |
Read-only fields¶
Returned by GET /services/{fqdn}. A PATCH with a field that is not in ServicePatch
is rejected.
| Field | Type | Notes |
|---|---|---|
fqdn |
string | read-only; Rename with POST /services/{fqdn}/rename |
mode |
string | one of https, tcp, anyconnect; default "https"; read-only; Set when the vService is created |
network |
Network |
read-only; Change addresses with POST /vip-operations |
serving_edges |
list of string | read-only; Edges that serve the vService now |
posture_drift |
list of string | read-only; Sections that differ from the posture |
baseline |
object | may be null; read-only; Learned limits, null before the first measurement |
created |
string | may be null; read-only; Set by the server |
ServiceSummary¶
GET /services lists each vService in short; GET /services/{fqdn} has every field.
| Field | Type | Notes |
|---|---|---|
fqdn |
string | read-only; Rename with POST /services/{fqdn}/rename |
tenant |
string | up to 64 characters; read-only; Set by the server |
account_id |
string | may be null; read-only; Set when the vService is created |
enabled |
boolean | default true; false switches the vService off: the edges stop serving it and its health reads disabled. The configuration stays |
mode |
string | one of https, tcp, anyconnect; default "https"; read-only; Set when the vService is created |
ports |
list of integer or string | at most 8; may be null; 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 |
list of integer or string | at most 8; may be null; 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 |
Network |
read-only; Change addresses with POST /vip-operations |
waf |
Waf |
Web application firewall |
maintenance_mode |
boolean | default false; 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 |
list of Alias |
Further hostnames of the vService |
edges |
list of string | at most 50; read-only; Set when the vService is created |
alias_limit |
integer | may be null; read-only; Aliases you may add; null = no limit |
serving_edges |
list of string | read-only; Edges that serve the vService now |
posture_drift |
list of string | read-only; Sections that differ from the posture |
baseline |
object | may be null; read-only; Learned limits, null before the first measurement |
delegations |
list of string | read-only; Delegations the vService is part of (GET /services only) |
origin_count |
integer | Number of origins; the origins are in GET /services/{fqdn} |
redirect_count |
integer | Number of redirects |
DnsStatus¶
| Field | Type | Notes |
|---|---|---|
fqdn (required) |
string | The vService |
edge_hostname |
string | may be null; CNAME target for your records |
anycast_ipv4 |
string | may be null; Primary IPv4 VIP of the vService |
anycast_ipv6 |
string | may be null; Primary IPv6 VIP of the vService |
status (required) |
string | one of error, not_found, wrong_target, apex_cname, partial, ok_cname_foreign, ok_a, ok_cname; The worst of all names |
ok (required) |
boolean | Every name points at us |
hostnames (required) |
list of DnsHostname |
The vService's name first, then every alias |
DnsHostname¶
| Field | Type | Notes |
|---|---|---|
fqdn (required) |
string | The hostname checked |
role (required) |
string | one of primary, alias; primary: the vService's name. alias: one of its aliases |
status (required) |
string | one of error, not_found, wrong_target, apex_cname, partial, ok_cname_foreign, ok_a, ok_cname; ok_cname, ok_a and ok_cname_foreign point at us |
detail |
string | may be null; What to change |
is_apex |
boolean | The name is the apex of its DNS zone, where a CNAME is not allowed: use A and AAAA |
zone_apex |
string | may be null; Apex of the DNS zone the name lies in; null when the lookup failed |
expected_cname |
string | may be null; Edge hostname a CNAME should point at |
expected_ipv4 |
string | may be null; IPv4 address an A record should hold: the primary VIP |
expected_ipv6 |
string | may be null; IPv6 address an AAAA record should hold: the primary VIP; null without IPv6 |
cname_target |
string | may be null; First CNAME target, as the authoritative nameservers answer; null without CNAME |
cname_chain |
list of string | CNAME targets in order, as the authoritative nameservers answer |
resolved_ipv4 |
list of string | IPv4 addresses the authoritative answer resolves to |
resolved_ipv6 |
list of string | IPv6 addresses the authoritative answer resolves to |
ttl |
integer | may be null; TTL in seconds of your first record, the CNAME or the A/AAAA; null when unknown |
public_ipv4 |
list of string | IPv4 addresses a public resolver answers |
public_ipv6 |
list of string | IPv6 addresses a public resolver answers |
public_cname_target |
string | may be null; First CNAME target as a public resolver answers |
propagating |
boolean | Authoritative servers are right, public resolvers not yet |
caa |
object | CAA records of the name and whether they let your certificate authority issue |
checked_at |
string | When the check ran; answers are reused for 60 s unless you send refresh=true |
cert_status |
string | may be null; Alias only: state of its certificate |
HistoryEntry¶
| Field | Type | Notes |
|---|---|---|
kind (required) |
string | one of config_change, health_change; config_change: the vService's configuration or certificate changed. health_change: its health state changed |
at (required) |
string | When it happened |
category |
string | one of config, certificate; config_change only |
sha |
string | config_change: id of the configuration revision |
short_sha |
string | config_change: the revision id, shortened |
action |
string | config_change: what changed |
user |
string | config_change: your e-mail or key label; empty = Zero Services |
by_zero_services |
boolean | config_change: true when Zero Services made the change, false when you did, in the portal or with an API key |
from |
string | one of blackholed, origin_down, misconfigured, errors, origin_slow, under_attack, normal, maintenance, disabled, unknown; may be null; health_change only |
to |
string | one of blackholed, origin_down, misconfigured, errors, origin_slow, under_attack, normal, maintenance, disabled, unknown; may be null; health_change only |
fault |
string | one of zp, customer, none; health_change: who has to act on the new state, as in ServiceHealth |
reason |
string | health_change: machine-readable reason of the new state, as in ServiceHealth |
signals |
HealthSignals |
health_change: the measurements when the state changed |
techniques |
list of string | Attack techniques seen, on a change to or from under_attack |
Attack¶
GET /attacks lists the attacks running now (an empty list: none), GET /attacks/{month} those of one month.
Poll it from your own monitoring.
| Field | Type | Notes |
|---|---|---|
fqdn (required) |
string | The vService |
state (required) |
string | one of under_attack, blackholed; under_attack: the edge stops it; blackholed: your addresses are dark upstream |
start (required) |
string | Started |
end (required) |
string | may be null; Ended; null while it runs |
ended_as (required) |
string | one of blackholed, origin_down, misconfigured, errors, origin_slow, under_attack, normal, maintenance, disabled; may be null; State of the vService after the attack; null while it runs |
reason (required) |
string | may be null; Machine-readable, as reason of the health light |
techniques (required) |
list of string | Every technique that stopped traffic during the attack |
signals (required) |
HealthSignals |
Measured at the start; empty while it runs and not yet known |
escalations (required) |
list of AttackEscalation |
What we did beyond the edge; empty when the edge handled it alone |
Example¶
A device API: no browser challenges.
curl -s -X PATCH -H "Authorization: Bearer $ZP_KEY" -H 'Content-Type: application/json' \
$API/services/api.example.com -d '{"service_profile": "api", "defense_posture": "off"}'
Apex alias that redirects to www:
curl -s -X PATCH -H "Authorization: Bearer $ZP_KEY" -H 'Content-Type: application/json' \
$API/services/www.example.com -d '{
"aliases": [{"fqdn": "example.com"}],
"redirects": [{"path": "/", "target": "https://www.example.com", "match_type": "prefix",
"redirect_type": "prefix", "bind_to": "example.com"}]}'
Behaviour¶
modeis set at creation:https(ports 443 and 80),tcporanyconnect, see Ports.- Shared: 1 FQDN plus up to 20 aliases. Dedicated: up to 100 vServices per account, addresses from your own pools, see Limits.
service_profileis what talks to the service:web_dynamic(browsers),web_static(static, downloads),api(apps, set-top boxes, callbacks, no JavaScript; the edge answers its own errors as JSON,{"error", "status", "ray"}),hls(video streaming). After changing it, senddefense_postureagain so the type's settings take effect.defense_posture:standardfor browser services, it limits login and admin paths;offfor a device API or HLS, whose clients cannot solve a challenge;under_attackduring an attack.sensitivityderives service-wide limits from your own normal peak;size_tierscales the posture's floor and needs a sensitivity. Details: Rate limits.maintenance_modeserves a branded maintenance page instead of contacting the origin.auto_mitigation(beta) lets the platform apply time-limited challenges itself, see Under attack.- Redirects:
redirect_type: prefixkeeps the rest of the path, so writetargetwithout a trailing slash;bind_tolimits a redirect to one alias.append_trailing_slashadds/to directory-style paths. - Rename: add the new name as an alias, point its DNS at the service, wait for its certificate, then rename. The old name stays as an alias; statistics and cache start fresh.
In the portal: the service's Overview (type, posture, sensitivity) and Aliases (Make primary).