Sucuri API v2 — Audit Trails

API v2 - Audit Trails (audit_trails)

Retrieves the latest audit log entries caught by Sucuri. Returns blocked events for the date specified (or current day if omitted). Used for integrating Sucuri data into our own dashboards.

Note (from Sucuri): date, query, offset and limit are optional and not fully implemented — report issues to Sucuri dev team.

sh curl 'https://waf.sucuri.net/api?v2' \ --data 'k=API_KEY' \ --data 's=API_SECRET' \ --data 'a=audit_trails' \ --data 'date=yyyy-mm-dd' \ --data 'query=Lorem+ipsum+dolor' \ --data 'format=(txt or json or csv)' \ --data 'offset=0' \ --data 'limit=50'

Time zone: Eastern time

The date=yyyy-mm-dd parameter is interpreted in US Eastern time, not UTC. We store and query in UTC, so converting between the two requires care — see sucuri-time-zones.

Hard cap: 10,000 records per day

Sucuri returns at most 10,000 audit log records per calendar day for a site. Once that ceiling is hit, additional events that day are silently dropped from the feed — the API will keep returning the first 10,000 entries but nothing beyond.

Implication: on high-volume / actively-attacked days, our blocked-request counts (which derive entirely from this feed — see waf-metrics-blocked-only) under-report reality. There is no “passed traffic” denominator either, so the apparent flatline at 10k is the ceiling, not the truth.

Our quirk: format=bad

app/services/sucuri.rb deliberately sends format: 'bad' instead of one of the documented values. The documented formats (txt, json, csv) return a raw array with no record count, so pagination is impossible.

format=bad is an unsupported value that trips Sucuri’s error envelope, which accidentally wraps the data as:

json { "status": ..., "output": { "total_lines": N, "access_logs": [...] } }

We depend on total_lines to drive pagination. Do not “fix” this — passing the documented format breaks pagination.

See waf-metrics-blocked-only for why this audit feed is the only traffic data we ever see.