Skip to content

Logs, metrics and health

What the edge saw, read-only: the request log per vService, its traffic metrics, the same metrics summed over all your vServices, and their health. They have the lower request limit, see API access.

Endpoints

Method Path Key Purpose
GET /metrics read Traffic summed over all vServices you can see
GET /services/{fqdn}/logs read Request log: one aggregate or raw lines
GET /services/{fqdn}/logs/export read Export the request log (streamed)
GET /services/{fqdn}/logs/l4 read All aggregates of the L3/4 forensics view
GET /services/{fqdn}/logs/l4/raw read Newest raw L3/4 lines
GET /services/{fqdn}/logs/overview read All aggregates of the forensics view
GET /services/{fqdn}/logs/timeseries read Requests over time by a field
GET /services/{fqdn}/metrics read Traffic metrics of a vService

GET /metrics

Parameter In Meaning
metric query Chart; traffic_by_service is the current bytes/s per vService; one of traffic, response_codes, protection, pre_http_filter, l4_packets, l4_flows, traffic_by_service; default "traffic"
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 7d; default "1h"
delegation query Narrow to one delegation you can see

Returns: 200, MetricChart or TrafficByService

Answer 200: traffic
{
  "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
  }
}
Answer 200: traffic_by_service
{
  "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
  }
}

GET /services/{fqdn}/logs

Parameter In Meaning
type query An aggregate, or raw for the newest lines; one of 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"
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
limit query Rows; 1–500; default 10
view query allowed: what reached your origin; blocked: what the edge turned away; all: both; one of allowed, blocked, all; default "allowed"
from query Start of the window, RFC 3339, at most 96 h back; with only from, range sets the length; type=raw only
to query 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
client_ip query Lines whose client address contains this; type=raw only
status_code query Lines whose status code contains this: 403, or 40 for 400 to 409; type=raw only
uri query Lines whose path and query string contain this; type=raw only
ja4 query Lines whose TLS fingerprint contains this; type=raw only

Returns: 200, LogTop or LogRaw

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

GET /services/{fqdn}/logs/export

Parameter In Meaning
format query csv: one column per field; logfmt: key=value per line; one of csv, logfmt; default "csv"
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
from query Start of the window, RFC 3339, at most 96 h back; with only from, range sets the length
to query End of the window, RFC 3339, not included; with only to, range sets the length. Page back by passing the oldest timestamp you received
client_ip query Lines whose client address contains this
status_code query Lines whose status code contains this: 403, or 40 for 400 to 409
uri query Lines whose path and query string contain this
ja4 query Lines whose TLS fingerprint contains this

Returns: 200, a file (text/csv, text/plain)

Answer 200 (text/csv)
{
  "code": "not_found",
  "error": "Service not found: a.example.com"

GET /services/{fqdn}/logs/l4

Parameter In Meaning
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
view query allowed: UDP flows and TCP connections; dropped: sources the edge dropped; one of allowed, dropped; default "allowed"
limit query Rows per aggregate; 1–500; default 50

Returns: 200, L4Overview

Answer 200: allowed
{
  "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
}

GET /services/{fqdn}/logs/l4/raw

Parameter In Meaning
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
view query allowed: UDP flows and TCP connections; dropped: sources the edge dropped; one of allowed, dropped; default "allowed"
limit query Lines; 1–500; default 200
ip query Client or source address, prefix match

Returns: 200, L4Raw

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

GET /services/{fqdn}/logs/overview

Parameter In Meaning
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
limit query Rows per aggregate; 1–500; default 50
view query allowed: what reached your origin; blocked: what the edge turned away; all: both; one of allowed, blocked, all; default "allowed"
types query 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

Returns: 200, LogOverview

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

GET /services/{fqdn}/logs/timeseries

Parameter In Meaning
field query One line per value; one of geoip_country_code, http_method, http_version, status_code, user_agent, zp_cache; default "status_code"
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 96h; default "1h"
limit query Lines, the busiest values; 1–50; default 10

Returns: 200, LogTimeseries

Answer 200
{
  "type": "timeseries",
  "field": "status_code",
  "range": "1h",
  "step": 60,
  "series": [
    {
      "label": "200",
      "values": [
        [
          1792750344,
          3
        ],
        [
          1792750404,
          4
        ]
      ]
    }
  ]
}

GET /services/{fqdn}/metrics

Parameter In Meaning
metric query summary: live values; origin_status: health check per origin; the others: a chart; one of 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"
range query Time window; one of 5m, 15m, 1h, 6h, 24h, 7d; default "1h"

Returns: 200, MetricChart or MetricSummary or OriginStatus

Answer 200: summary
{
  "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
  }
}
Answer 200: traffic
{
  "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"
    }
  ]
}
Answer 200: origin_status
{
  "metric": "origin_status",
  "data": [
    {
      "name": "origin-1",
      "up_edges": 2,
      "edges": 2
    }
  ]
}
Method Path Key Purpose
GET /services/health read Health of all your vServices

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
      }
    }
  }
}

Answers

ServiceHealth

Field Type Notes
status (required) string one of blackholed, origin_down, misconfigured, errors, origin_slow, under_attack, normal, maintenance, disabled, unknown; 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 (required) string one of zp, customer, none; zp: our side; customer: origin, DNS or configuration
reason (required) string Machine-readable, empty when normal
signals (required) HealthSignals The measurements behind the state

MetricChart

Field Type Notes
metric (required) string The chart asked for
range (required) string one of 5m, 15m, 1h, 6h, 24h, 7d; Time window
step (required) string Distance between two points
series (required) list of MetricSeries One series per line
meta object metric=upstream only: flow at the site boundary is sampled
scope MetricScope GET /metrics and pool metrics only: what was summed

MetricSummary

Field Type Notes
metric (required) string one of summary; Always summary
data (required) object The values

LogTop

Field Type Notes
type (required) string The aggregate asked for
range (required) string one of 5m, 15m, 1h, 6h, 24h, 96h; Time window
field string The log field ranked
fields list of string top_combination only: the fields of a combination
window_seconds (required) integer Length of the range in seconds
service_total integer may be null; Requests of the vService in the window, in the chosen view
service_total_rps_avg number service_total divided by window_seconds
total integer threat_intel only: requests from listed sources
total_rps_avg number threat_intel only
total_share number may be null; threat_intel only
data (required) list of LogRow Rows, busiest first

LogRow

Field Type Notes
value string The field's value; Unknown when the line carries none
label string Application of a JA4 fingerprint, name of a threat-intel set
fields map of string top_combination only: the six fields of the combination
count (required) integer Requests in the window
rps_avg (required) number count / window_seconds
share number may be null; Part of the vService's requests in the chosen view, 0 to 1

LogRaw

Field Type Notes
type (required) string one of raw; Always raw
range (required) string one of 5m, 15m, 1h, 6h, 24h, 96h; Time window
count (required) integer Lines returned
data (required) list of object Lines, newest first

Example

Top blocked addresses in the last hour, then the raw log of that hour as CSV:

curl -s -H "Authorization: Bearer $ZP_KEY" \
  "$API/services/www.example.com/logs?view=blocked&type=top_ips&range=1h&limit=20"
curl -s -H "Authorization: Bearer $ZP_KEY" -o log.csv \
  "$API/services/www.example.com/logs/export?format=csv&range=1h"

Raw lines of a past hour, then the hour before it: to takes the oldest timestamp of the previous page.

curl -s -H "Authorization: Bearer $ZP_KEY" \
  "$API/services/www.example.com/logs?type=raw&limit=500&from=2026-10-23T05:00:00Z&to=2026-10-23T06:00:00Z"
curl -s -H "Authorization: Bearer $ZP_KEY" \
  "$API/services/www.example.com/logs?type=raw&limit=500&to=2026-10-23T05:41:07.120834512Z"

Behaviour

  • view: allowed (default) is what reached your application, blocked what mitigation stopped, all both. A drop in allowed means your users are affected; a spike in blocked alone is the protection working.
  • Logs reach back 96 hours, metrics 7 days. Request-level data is kept 4 days: export what you need longer.
  • from and to (RFC 3339) choose a window for raw lines and the export, within the last 96 hours; to is not included. With only one of them, range gives the length.
  • Each aggregate row has its rate in requests per second and its share of all traffic to the service in the range, not of the list.
  • Request paths fold runs of digits into # (/live/c#/seg_hd_#.ts).
  • Connections stopped before HTTP (most of a flood) are not in the log; the metrics count them as connections, not requests. Never add the two.
  • The edge request total is your request rate; origin figures are always lower, since cached, challenged and blocked requests never reach it.
  • Origin connections are shown for the busiest edge, against your maxconn, which applies per edge (origins).
  • Dedicated sites with flow export also get traffic at the site boundary, per address and attack class, including what was already dropped. It is sampled (right in the Gbit/s range) and is never comparable with the edge figures, see sites.

All your vServices

GET /metrics sums the same metrics over every vService the key can see: the whole account for an account key, only its delegation for a delegation key. delegation= narrows to one delegation you can see; any other name is 404.

curl -s -H "Authorization: Bearer $ZP_KEY" "$API/metrics?metric=traffic&range=24h"
curl -s -H "Authorization: Bearer $ZP_KEY" "$API/metrics?metric=traffic_by_service"
  • traffic has inbound, passed_frontend, scrubbed and outbound in bytes per second, all positive; each series says its direction (in or out). Draw out below the axis if you mirror the chart.
  • traffic_by_service is the current inbound and outbound of each vService, averaged over 5 minutes. One vService dropping to 0 while the others carry on is what the sum hides.
  • scope in the answer counts the vServices summed and says whether HTTP and layer 3/4 metrics apply.
  • From 6 hours up, each point is the peak of its interval, so a short burst stays visible.

In the portal: ZERO-PROTECT → Overview, charts Frontend (Edge) for all services, one delegation or one service.

Layer 3/4

For vServices with TCP or UDP ports outside HTTP, GET /services/{fqdn}/logs/l4 gives the same kind of aggregates below HTTP, and GET /services/{fqdn}/logs/l4/raw the newest lines.

  • view=allowed: the UDP flows the edge forwarded and the TCP connections, by client, country, AS, port and origin, and how they ended. A UDP flow appears when it ends, and every 30 minutes while it runs; its bytes are the flow's total.
  • view=dropped: the sources the edge dropped, by reason, destination port and protocol. One entry is one source per period, not one packet.
  • Packets per second by verdict and the open flows and sessions are the metrics l4_packets and l4_flows.
  • Mode tcp lists TCP connections only with access logging on; UDP flows and drops always.

In the portal: Forensics → Layer 3/4 and the Metrics tab.

Log fields

The export (csv or logfmt) and raw lines carry:

Field Meaning
client_ip, client_port the source
geoip_country_code, geoip_asn, geoip_asn_org where it is from
http_hostname, http_method, http_request_uri, http_version the request
status_code, bytes_read the answer
user_agent, ja4 claimed client, and its real TLS stack
tq, tw, tc, tr, ta timings: request, queue, connect, response, total
termination_state how the connection ended
feconn, retries connections on the frontend, origin retries
pow_passed, force_pow proof-of-work solved, and whether it was demanded
coraza_action, coraza_failed WAF verdict, and whether the WAF itself failed
ti_hit threat-intelligence list that matched
path_class auth, admin or unset
pr_hit the first rule that matched
pr_deny the rule that stopped the request; empty when nothing did

Why a request was blocked

Read pr_deny. pr_hit can differ: an earlier challenge rule keeps pr_hit while a later rule blocks.

pr_deny / pr_hit Cause
<name>-deny, -block, -drop, -challenge your protection rule <name> (rules)
rate-conn, rate-http, rate-path, rate-pathagg, rate-ja4, rate-soft a rate limit
rate-botcheck, rate-botcheck-agg the proof-of-work endpoint's own limit, per source or per service
host-mismatch 421: the Host header is not a hostname of this service
ti-deny, ti-abuse, ti-tor threat intelligence
geo-blocklist, asn-blocklist, ip-blocklist, ja4-blocklist platform-wide blocklist
origin-busy your origin's queue was full: 503 at once (origins)
token-unknown token gate: too many unconfirmed tokens from one source, 429 (cache)
empty, with coraza_action=deny the WAF, never a geo or rate decision

Health states

Health Meaning Who acts
Normal nothing stands out —
Under attack attack traffic is being stopped; not a fault nobody
Errors visitors get errors us if they start at our edge, you if your origin returns them
Origin down no origin passes its health check you
Origin slow your origin answers slowly you
Misconfigured a hostname's DNS does not point at us (see GET /services/{fqdn}/dns), or no origin and no redirect you
Maintenance maintenance mode is on —
Disabled the service is switched off —
Unknown no reliable measurement just now; not an error nobody

enabled means switched on, not healthy.

Reports

Support makes reports over a period you choose on request, normally on the next business day: name the period, one service or all, and the purpose. They reach back 90 days for aggregated metrics, 4 days for request-level detail.

In the portal: Forensics and Metrics per service, the Health column in the service list.