Gareth Wilson Gareth Wilson

Guide to Drata Webhooks: Features and Best Practices

Published


Drata automates compliance work for frameworks such as SOC 2 and ISO 27001. Its workflows react to changes in your compliance programme, such as a control becoming not ready, a mapped test failing, evidence nearing renewal or an employee falling out of compliance. A Send webhook step in a workflow pushes those changes to your own systems, so you can open tickets or start remediation without checking Drata by hand.

This guide covers how Drata workflows send webhooks, the triggers and payload properties available, how to secure deliveries with a custom header, and what to plan for given what Drata doesn't document.

What are Drata webhooks?

Drata doesn't have a standalone webhook subscription. Webhooks are one of the step types in a workflow. A workflow has three parts:

  • Start: the object type (Control, Risk, Evidence or Personnel) and which items it covers, such as all controls or selected ones.
  • Trigger: the single event that runs the workflow, such as "Mapped test failing".
  • Steps: what happens next, such as creating a task, sending an email, Slack or Teams message, or sending a webhook.

Steps run in parallel. If one fails, the others still run, and Drata retries the failed step up to three times.

When a Send webhook step runs, Drata sends a POST to your URL with the properties you chose. Drata says it uses Svix to send webhooks, but it doesn't document a signing secret, so treat deliveries as unsigned. You can add authentication as custom headers on the step, and that header is what your endpoint should check.

Drata webhook features

FeatureDetails
ConfigurationSettings > Workflows > Create Workflow, then a Send webhook step
Who can configureAdmin or Workspace Manager
MethodPOST
AuthenticationCustom headers you add to the step
SignatureNone documented
Event fieldevent_type in the body
PayloadBase properties, plus the scope and trigger properties you select
RetriesA failed step is retried up to three times
Example payloads, timeout, delivery ID, source IPsNot documented

Common events

Each workflow targets one object type and one trigger:

ObjectTriggers
ControlDetails updated, readiness changed to Ready or Not ready, evidence linked or unlinked, policy linked or unlinked, test mapped or unmapped, mapped test passing or failing, requirement mapped or unmapped, owner updated, marked in scope or out of scope
RiskInherent score changed, residual score changed, treatment option changed
EvidenceUpcoming renewal, renewal past due, new artifact uploaded, linked to or unlinked from a control
PersonnelOut of compliance, status changed

Every payload includes four base properties:

  • event_type, the trigger that fired
  • timestamp, when it happened
  • organization_id
  • workspace, an object describing the workspace

You then choose which scope properties to include, such as control_name, control_code, control_readiness and control_owners for controls, or risk_name, risk_scores and risk_owners for risks. Each trigger adds its own properties. CONTROL_OWNER_UPDATED adds new_control_owner, old_control_owner and updated_by, and INHERENT_SCORE_UPDATED adds the old and new score values and the threshold.

Drata's docs list these trigger-specific properties under names such as CONTROL_TEST_CHANGED_TO_FAIL, TREATMENT_OPTION_UPDATED, NEW_ARTIFACT_UPLOADED and STATUS_CHANGED, which suggests the values event_type carries. Drata doesn't publish a complete example payload, so log event_type from your first deliveries before you route on exact strings.

Data formats are consistent: dates are ISO strings, object arrays such as owners are JSON arrays, booleans are true or false, and custom fields are arrays of {"key": ..., "value": ...}.

Setting up Drata webhooks

  1. Generate a long random secret to authenticate deliveries, and store it, for example as DRATA_WEBHOOK_SECRET.
  2. In Drata, go to Settings > Workflows and select Create Workflow. Enter a name and choose the target object type. For Control or Evidence, also choose the workspace.
  3. Choose the scope (for example, all controls or selected controls) and the trigger.
  4. Add a Send webhook step. Enter your URL, then add an authentication header, such as X-Drata-Secret, with your secret as its value.
  5. Select the properties you want in the payload.
  6. Publish the workflow, or save it as a draft. Then cause the trigger, for example by linking evidence to a control, and check that your endpoint receives the request.

Securing Drata webhooks

Compare your custom header with the stored secret in constant time:

const crypto = require('crypto');
const express = require('express');

const HEADER_NAME = (process.env.DRATA_WEBHOOK_HEADER || 'x-drata-secret').toLowerCase();

function verifyDrataHeader(headerValue, secret) {
  if (!headerValue || !secret) return false;
  const received = Buffer.from(headerValue, 'utf8');
  const expected = Buffer.from(secret, 'utf8');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

const app = express();

app.post('/webhooks/drata', express.raw({ type: '*/*' }), (req, res) => {
  const secret = process.env.DRATA_WEBHOOK_SECRET;
  if (!secret) return res.sendStatus(500); // fail closed

  if (!verifyDrataHeader(req.get(HEADER_NAME), secret)) return res.sendStatus(401);

  const event = JSON.parse(req.body.toString('utf8'));
  // Route on event.event_type, then process async.
  res.sendStatus(200);
});

The same check in Python:

import hmac
import os

HEADER_NAME = os.environ.get("DRATA_WEBHOOK_HEADER", "X-Drata-Secret")


def verify_drata_header(header_value, secret: str) -> bool:
    if not header_value or not secret:
        return False
    return hmac.compare_digest(header_value.encode("utf-8"), secret.encode("utf-8"))


# In FastAPI:
# verify_drata_header(request.headers.get(HEADER_NAME), os.environ["DRATA_WEBHOOK_SECRET"])

Make Drata webhooks production-ready. Hookdeck Event Gateway checks your secret header, records every compliance event Drata sends, and retries delivery to your tools long after Drata's three step retries are used up.

In Hookdeck, create a Drata source and enter the header name and value you added to the workflow step. Hookdeck compares them on each request. The header is optional in Drata, so leave verification off if you didn't add one, though you should for anything beyond testing.

Drata webhook limitations and pain points

No signature

The Problem: Anyone who learns your webhook URL can send fake compliance events.

Why It Happens: Drata doesn't document a signing secret for webhook steps. The only protection is a header you add yourself.

Workarounds:

  • Always add a secret header, and use a different one per workflow if different teams own them.
  • Use HTTPS only, and don't log the header.

How Hookdeck Can Help: Hookdeck checks the header value and stops requests that fail before they reach your service, and only Hookdeck needs to know the secret.

Limited retries

The Problem: An event sent while your endpoint is down may be lost.

Why It Happens: Drata retries a failed step up to three times. It doesn't document the timeout, the interval between retries, or what counts as a failure for a webhook step.

Workarounds:

  • Return 2xx quickly and process asynchronously.
  • Reconcile important state, such as control readiness, through Drata's API.

How Hookdeck Can Help: Hookdeck stores each event when it arrives and retries delivery to your service on a schedule you choose, so an outage doesn't use up Drata's three attempts.

Payloads you design yourself

The Problem: A handler expects a field that a workflow doesn't send.

Why It Happens: Apart from the four base properties, each workflow sends only the properties selected in its webhook step, so two workflows with the same trigger can send different payloads.

Workarounds:

  • Treat everything except the base properties as optional.
  • Include ID properties, such as control_id or risk_id, so you can fetch full details from the API.

How Hookdeck Can Help: Hookdeck keeps every payload it receives, so you can see exactly what each workflow sends and replay events after updating a handler.

No delivery ID

The Problem: Retries can produce duplicates you can't easily spot.

Why It Happens: Drata documents no event or delivery ID in the payload.

Workarounds:

  • Build a key from event_type, timestamp and the object's ID.
  • Make handlers idempotent.

How Hookdeck Can Help: Hookdeck's deduplication rules can match on those body fields and drop repeats within a window you set.

Best practices

One workflow per consumer

Workflows are cheap to duplicate. Give each downstream tool its own workflow, URL and secret so you can change one without affecting the others.

Scope workflows narrowly

Workflows can cover all current and future controls. If a consumer only cares about some, use Selected controls to keep volume down.

Include identifiers in every payload

Always select the object's ID and name properties, so receivers can look up full details and humans can read the logs.

Process asynchronously

Return 2xx as soon as the event is stored. See why to process webhooks asynchronously.

Conclusion

Drata sends webhooks as a step in compliance workflows, with a payload you design and no signature. Add a secret header to every webhook step, compare it in constant time, treat non-base properties as optional, and confirm the event_type values from real deliveries.

Hookdeck Event Gateway records every event and retries delivery well beyond Drata's three attempts.

Get started with Hookdeck for free and handle Drata webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.