Overview
The base URL is https://compliance.dazr.eu/api/compliance-public. All endpoints are GET, take an action query parameter, and return JSON. Authenticate with your API key as a Bearer token. Bodies are never required.
# Quick check curl "https://compliance.dazr.eu/api/compliance-public?action=me" \ -H "Authorization: Bearer dzc_YOUR_KEY"
Authentication
API access is included in the Enterprise plan. An owner or admin generates the key in the portal under Settings → API & webhooks → Generate key (once a key exists, the button becomes Rotate). Keys begin with dzc_ followed by 43 characters of url-safe base64. Treat them like passwords: anyone holding a key has the same read access an admin would have.
Send on every request:
Authorization: Bearer dzc_...
Rotate the key the moment it leaks. Rotation is atomic; the previous key stops working immediately and the new key starts working as soon as the rotation response returns. There is currently a single active key per workspace; we don't support multiple concurrent keys.
Errors
Failures return a non-2xx status with a JSON body of the form:
{
"error": "machine-readable-code",
"detail": "human-readable explanation"
}
| Status | Code | When |
|---|---|---|
| 400 | bad_request | Missing action or required query parameter. |
| 401 | unauthorised | Missing, malformed, rotated, or invalid Bearer token. |
| 402 | tier_locked | Endpoint requires Enterprise. |
| 404 | not_found | Resource does not exist or belongs to another org. |
| 423 | org_paused | Workspace is paused by support; reads still work, writes don't. |
| 429 | rate_limited | Per-IP burst, per-key burst, or daily quota exceeded. |
| 500 | server_error | Unhandled server failure. Treat as transient and retry with backoff. |
Rate limits
- Per IP: 30 requests per minute (coarse abuse cap; shared across keys).
- Per API key burst: 240 requests per minute.
- Per API key daily: 60,000 requests per day (rolling 24-hour window).
When you hit a limit you get 429. Back off, wait a minute, retry. The minute-bucket resets sixty seconds after first hit; the daily bucket resets twenty-four hours after first hit.
Versioning
The API is currently at v1. Additive changes (new fields, new endpoints) keep v=1. Breaking changes get a new version number; the old version stays available for at least 12 months alongside.
/me
?action=meSelf-description for the authenticated workspace. Useful for connection checks.
{
"orgId": "a3f2e1c0...",
"name": "Acme",
"tier": "enterprise",
"frameworks": ["iso27001", "gdpr", "nis2"],
"memberCount": 12,
"apiVersion": 1
}
/readiness
?action=readinessPer-framework completion summary. Drives a "compliance health" tile in your dashboard. Recomputed on every call from the live task list.
{
"frameworks": [
{ "framework": "iso27001", "total": 93, "done": 68, "open": 22, "overdue": 3, "percentDone": 73 },
{ "framework": "gdpr", "total": 42, "done": 42, "open": 0, "overdue": 0, "percentDone": 100 }
],
"generatedAt": 1714694400000
}
/list-tasks
?action=list-tasksEvery control task on the workspace. Apply query filters to narrow.
| Param | Type | Effect |
|---|---|---|
framework | string | Filter to a single framework id (e.g. iso27001). |
status | string | open, overdue, or done. |
assignee | Tasks owned by a specific email. | |
updatedSince | ISO date | Only tasks whose history was touched at or after this timestamp. Useful for incremental sync. |
# Open or overdue ISO 27001 tasks updated this month curl "https://compliance.dazr.eu/api/compliance-public?action=list-tasks&framework=iso27001&status=overdue&updatedSince=2026-05-01" \ -H "Authorization: Bearer dzc_..."
/get-task
?action=get-task&id=...A single task with its full history, comments, and evidence record. Framework tasks also carry links: the risks, policies, processes, assets, vendors and processing activities linked to the task's control, each as { type, id, label }.
/list-risks
?action=list-risksRisk register entries with score (likelihood × impact).
| Param | Type | Effect |
|---|---|---|
status | string | e.g. open, mitigated, accepted. |
minScore | integer | Only risks with score ≥ minScore. Use 17 for critical. |
/get-risk
?action=get-risk&id=...A single risk with its mitigation plan and history, plus links: the mitigating controls (with framework and live status) and any linked policies, processes, assets and vendors.
/list-incidents
?action=list-incidentsInformation-security and data-protection incidents with regulator-notification fields.
| Param | Type | Effect |
|---|---|---|
status | string | investigating, contained, resolved, closed. |
severity | string | low, medium, high, critical. |
reportedOnly | bool | true = incidents reported to a regulator. |
/get-incident
?action=get-incident&id=...A single incident with the full timeline and history.
/list-vendors
?action=list-vendorsThe vendor / sub-processor register, including the auto-managed Dazr platform self-disclosure (it carries "system": true).
/list-assets
?action=list-assetsAsset inventory.
/list-activity
?action=list-activity&limit=100Append-only activity log. Metadata-only: each event is { at, kind, by }. Use this to ship the audit trail to your SIEM.
| Param | Type | Effect |
|---|---|---|
limit | integer | 1–500. Default 100. |
/list-links
?action=list-linksHow controls, risks, policies, processes, assets, vendors and processing activities are connected. Each link is { a, b, at, by }, where a and b are { type, id, label }. A control's id is its control code (for example A.5.15) and it also carries framework and status (done, open, scheduled, overdue, expired).
| Param | Type | Effect |
|---|---|---|
type | string | Only links that touch this type: control, risk, policy, process, asset, vendor, activity. |
id | string | With type: only the links of that one object. |
/list-processes
?action=list-processesThe business process register: name, owner, description and criticality. Use /list-links?type=process for what each process is linked to.
Polling vs. webhooks
The pull pattern works for most pipelines. Use updatedSince on list-tasks for incremental sync, plus a periodic full pull as a reconciliation pass. Webhooks (below) tell you something changed right away, but delivery is best-effort, so keep a periodic pull as the source of truth.
Webhooks
Configure up to 10 endpoints under Settings → API & webhooks (Enterprise, admins only). Each endpoint must be a public https:// URL on port 443 and subscribe to at least one event. When a subscribed event happens we send one POST with a JSON body.
Delivery: best-effort, at most once. 5-second timeout, no retries, redirects are not followed and the response body is ignored. Any 2xx counts as delivered. The portal shows the last status per webhook and has a Send test event button (event type test.ping, "test": true).
Events
| Type | When |
|---|---|
task.created | A custom task is created. |
task.assigned | A task gets a (new) assignee. |
task.completed | A task is marked done. |
risk.created | A risk is added to the register. |
risk.updated | A risk is edited (includes from/to on a status change). |
incident.created | An incident is logged. |
incident.status_changed | An incident moves between investigating / contained / resolved / closed. |
intake.submitted | Someone submits the public reporting form. |
vendor.created | A vendor is added to the register. |
link.changed | A link between two objects is added or removed (op is added or removed; a and b are { type, id }). |
Headers
| Header | Value |
|---|---|
X-Dazr-Event | Event type, e.g. risk.created. |
X-Dazr-Delivery | Unique delivery id (evt_...); use it to de-duplicate. |
X-Dazr-Timestamp | Unix time in seconds when the delivery was signed. |
X-Dazr-Signature | sha256=<hex>: HMAC-SHA256 of <X-Dazr-Timestamp>.<raw body>, keyed with the webhook's signing secret. |
Every webhook has its own signing secret (whsec_...), shown next to it in the portal. It is not your API key, and rotating the API key does not change it. To get a new secret, choose New secret on save on that webhook and save.
Payload
{
"id": "evt_5aabe9db80eaf886166be953",
"type": "risk.created",
"createdAt": "2026-10-01T09:55:38.561Z",
"orgId": "39w9XJ95bro",
"test": false,
"data": { "by": "owner@acme.eu", "riskId": "qa6rM9fEF4Q", "title": "Laptop theft", "score": 16 }
}
data carries the same fields as the matching activity-log entry (who, which record, its title or name).
Verifying the signature (Node.js)
// Use the raw request body, before JSON parsing. const crypto = require('crypto'); function verify(rawBody, headers, secret) { const ts = headers['x-dazr-timestamp']; if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // replay window const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(ts + '.' + rawBody).digest('hex'); const got = String(headers['x-dazr-signature'] || ''); return got.length === expected.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected)); }
Examples
Daily SIEM ingestion
# Cron at 06:00 - fetch the last 24h of activity SINCE=$(date -u -d '24 hours ago' +%FT%TZ) curl -sf "https://compliance.dazr.eu/api/compliance-public?action=list-activity&limit=500" \ -H "Authorization: Bearer ${DAZR_KEY}" \ | jq '.events[] | select(.at >= ('${SINCE}' | fromdate * 1000))' \ > /var/log/dazr/$(date -u +%F).jsonl
Slack ping when a critical risk gets logged
# Cron at */15 minutes PREV=$(cat .last-risk-pull 2>/dev/null || echo 0) NOW=$(date +%s%3N) curl -sf "https://compliance.dazr.eu/api/compliance-public?action=list-risks&minScore=17" \ -H "Authorization: Bearer ${DAZR_KEY}" \ | jq -c ".risks[] | select(.createdAt > ${PREV})" \ | while read r; do curl -sf -X POST "${SLACK_WEBHOOK}" -d "{\"text\": \"New critical risk: $(echo \$r | jq .title)\"}" done echo $NOW > .last-risk-pull
Incremental task sync to a data warehouse
# Pull tasks updated since the last successful run LAST=$(cat .last-task-sync 2>/dev/null || echo "2020-01-01") curl -sf "https://compliance.dazr.eu/api/compliance-public?action=list-tasks&updatedSince=${LAST}" \ -H "Authorization: Bearer ${DAZR_KEY}" \ | jq -c '.tasks[]' \ | psql -c "COPY raw_dazr_tasks (payload) FROM STDIN" date -u +%FT%TZ > .last-task-sync
Support
Questions or a feature request? Email api@dazr.eu. The published DPA and sub-processor list apply to all API access.