Home › API reference

API reference

Read-only REST access to your Dazr Compliance workspace. Bearer-authenticated, JSON over HTTPS, no SDK required. Available on the Enterprise plan.

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"
}
StatusCodeWhen
400bad_requestMissing action or required query parameter.
401unauthorisedMissing, malformed, rotated, or invalid Bearer token.
402tier_lockedEndpoint requires Enterprise.
404not_foundResource does not exist or belongs to another org.
423org_pausedWorkspace is paused by support; reads still work, writes don't.
429rate_limitedPer-IP burst, per-key burst, or daily quota exceeded.
500server_errorUnhandled 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

GET?action=me

Self-description for the authenticated workspace. Useful for connection checks.

{
  "orgId": "a3f2e1c0...",
  "name": "Acme",
  "tier": "enterprise",
  "frameworks": ["iso27001", "gdpr", "nis2"],
  "memberCount": 12,
  "apiVersion": 1
}

/readiness

GET?action=readiness

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

GET?action=list-tasks

Every control task on the workspace. Apply query filters to narrow.

ParamTypeEffect
frameworkstringFilter to a single framework id (e.g. iso27001).
statusstringopen, overdue, or done.
assigneeemailTasks owned by a specific email.
updatedSinceISO dateOnly 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

GET?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

GET?action=list-risks

Risk register entries with score (likelihood × impact).

ParamTypeEffect
statusstringe.g. open, mitigated, accepted.
minScoreintegerOnly risks with score ≥ minScore. Use 17 for critical.

/get-risk

GET?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

GET?action=list-incidents

Information-security and data-protection incidents with regulator-notification fields.

ParamTypeEffect
statusstringinvestigating, contained, resolved, closed.
severitystringlow, medium, high, critical.
reportedOnlybooltrue = incidents reported to a regulator.

/get-incident

GET?action=get-incident&id=...

A single incident with the full timeline and history.

/list-vendors

GET?action=list-vendors

The vendor / sub-processor register, including the auto-managed Dazr platform self-disclosure (it carries "system": true).

/list-assets

GET?action=list-assets

Asset inventory.

/list-activity

GET?action=list-activity&limit=100

Append-only activity log. Metadata-only: each event is { at, kind, by }. Use this to ship the audit trail to your SIEM.

ParamTypeEffect
limitinteger1–500. Default 100.
GET?action=list-links

How 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).

ParamTypeEffect
typestringOnly links that touch this type: control, risk, policy, process, asset, vendor, activity.
idstringWith type: only the links of that one object.

/list-processes

GET?action=list-processes

The 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

TypeWhen
task.createdA custom task is created.
task.assignedA task gets a (new) assignee.
task.completedA task is marked done.
risk.createdA risk is added to the register.
risk.updatedA risk is edited (includes from/to on a status change).
incident.createdAn incident is logged.
incident.status_changedAn incident moves between investigating / contained / resolved / closed.
intake.submittedSomeone submits the public reporting form.
vendor.createdA vendor is added to the register.
link.changedA link between two objects is added or removed (op is added or removed; a and b are { type, id }).

Headers

HeaderValue
X-Dazr-EventEvent type, e.g. risk.created.
X-Dazr-DeliveryUnique delivery id (evt_...); use it to de-duplicate.
X-Dazr-TimestampUnix time in seconds when the delivery was signed.
X-Dazr-Signaturesha256=<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.