Webhooks User Guide

Last updated on Apr 03, 2026

Overview

Webhooks let you notify external systems in real-time when compliance events occur in Humadroid. When a policy is published or acknowledged, Humadroid sends an HTTP POST request to a URL you configure with a JSON payload describing the event.

Use Cases

  • Trust Center sync - Automatically update a self-hosted trust center when policies are published

  • Email distribution - Trigger notifications to specific distribution lists on policy changes

  • Audit trail - Feed compliance events into an external SIEM or logging system

  • Workflow automation - Kick off downstream processes in tools like Zapier, Make, or custom systems

Supported Events

  • compliance.document_published — fires when a policy or document is finalized (published)

  • compliance.document_acknowledged — fires when a user accepts, rejects, or reads an assigned policy


Setting Up a Webhook

Prerequisites

  • Admin access to Humadroid

  • At least one compliance project

  • An HTTPS endpoint that can receive POST requests

Step 1: Navigate to Webhooks

  1. Go to Account Settings

  2. Click Webhooks in the settings navigation

Step 2: Create a Webhook

  1. Click New webhook

  2. Fill in the form:

    • URL - The HTTPS endpoint that will receive events (e.g., https://yourapp.com/webhooks/humadroid)

    • Compliance project - Only events for documents in this project will trigger the webhook

    • Events - Select which events to subscribe to

    • Active - Toggle to enable/disable the webhook

  3. Click Create webhook

A signing secret is automatically generated. You'll need this to verify incoming requests.

Step 3: Copy the Signing Secret

  1. Open the webhook detail page

  2. Find the Signing secret section

  3. Copy the secret and store it securely in your application's configuration


Payload Format

Every webhook request is an HTTP POST with a JSON body. The payload has a standard envelope:

{
  "event": "compliance.document_published",
  "timestamp": "2026-04-03T12:00:00Z",
  "webhook_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": { ... }
}

Policy Published (compliance.document_published)

Fired when a document transitions to the "Published" state.

{
  "event": "compliance.document_published",
  "timestamp": "2026-04-03T12:00:00Z",
  "webhook_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "document_id": "a1b2c3d4-...",
    "title": "Information Security Policy",
    "version": "2.0",
    "document_type": "policy",
    "published_at": "2026-04-03T12:00:00Z",
    "project_ids": ["p1q2r3s4-..."],
    "author": {
      "id": "u1v2w3x4-...",
      "name": "Jane Smith",
      "email": "jane@example.com"
    }
  }
}

Policy Acknowledged (compliance.document_acknowledged)

Fired when a user responds to an assigned policy.

{
  "event": "compliance.document_acknowledged",
  "timestamp": "2026-04-03T14:30:00Z",
  "webhook_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "document_id": "a1b2c3d4-...",
    "title": "Information Security Policy",
    "assignment_id": "x9y8z7w6-...",
    "user_id": "u1v2w3x4-...",
    "status": "accepted",
    "responded_at": "2026-04-03T14:30:00Z"
  }
}

The status field is one of: accepted, rejected, or read.


Verifying Webhook Signatures

Every request includes two headers for verification:

  • X-Humadroid-Signature — HMAC-SHA256 signature of the raw request body, prefixed with sha256=

  • X-Humadroid-Timestamp — Unix timestamp of when the request was signed

Verification Steps

  1. Read the raw request body (before any JSON parsing)

  2. Compute HMAC-SHA256(signing_secret, raw_body)

  3. Compare with the signature in the header (use constant-time comparison)

  4. Optionally check the timestamp to prevent replay attacks (reject if older than 5 minutes)

Example: Ruby

def verify_webhook(request, signing_secret)
  body = request.body.read
  expected = "sha256=" + OpenSSL::HMAC.hexdigest("SHA256", signing_secret, body)
  signature = request.headers["X-Humadroid-Signature"]
​
  ActiveSupport::SecurityUtils.secure_compare(expected, signature)
end

Example: Node.js

const crypto = require('crypto');
​
function verifyWebhook(body, signature, signingSecret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', signingSecret)
    .update(body, 'utf8')
    .digest('hex');
​
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Example: Python

import hmac
import hashlib
​
def verify_webhook(body: bytes, signature: str, signing_secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        signing_secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Retry Behavior

If your endpoint returns a non-2xx status code or is unreachable, Humadroid retries with exponential backoff:

  • Attempt 1 — immediate

  • Attempt 2 — ~2 minutes

  • Attempt 3 — ~4 minutes

  • Attempt 4 — ~8 minutes

  • Attempt 5 — ~16 minutes

  • Attempt 6 — ~32 minutes

  • Attempt 7 — ~1 hour

  • Attempt 8 — ~2 hours

  • Attempt 9 — ~4 hours

  • Attempt 10 — ~8 hours

After 10 consecutive failures, the webhook is automatically disabled. You can re-enable it from the webhook detail page once the issue is resolved.


Monitoring Deliveries

Delivery Log

Each webhook has a delivery log showing all events sent:

  1. Open the webhook detail page

  2. See Recent deliveries at the bottom

  3. Click View all deliveries for the full paginated log

Delivery Details

Click on any delivery to see:

  • Overall status - Delivered, Failed, or Pending

  • Attempt history - Each retry attempt with full request/response details:

    • Request URL, headers, and body

    • Response status code, headers, and body

    • Timestamp of each attempt

This is useful for debugging integration issues — you can see exactly what was sent and what your endpoint returned.


Managing Webhooks

Editing a Webhook

  1. Go to Account Settings > Webhooks

  2. Click the pencil icon on the webhook row, or open the detail page and use the menu

  3. Update the URL, project, events, or active status

  4. Click Update webhook

Regenerating the Signing Secret

If your signing secret is compromised:

  1. Open the webhook detail page

  2. In the Signing secret section, click Regenerate

  3. Confirm the action

  4. Update your application with the new secret

Note: The old secret is immediately invalidated. Update your receiving application before regenerating, or expect failed deliveries until the new secret is configured.

Disabling a Webhook

You can temporarily disable a webhook without deleting it:

  • From the index: click the pause icon

  • From the detail page: use the menu and select Disable

A disabled webhook does not receive any events. Re-enable it the same way.

Deleting a Webhook

  1. From the index: click the trash icon

  2. Or from the detail page: use the menu and select Delete

  3. Confirm the deletion

Deleting a webhook also removes all its delivery history.


Best Practices

  1. Always verify signatures - Never trust a webhook payload without checking the X-Humadroid-Signature header

  2. Respond quickly - Return a 2xx response within 10 seconds; do heavy processing asynchronously

  3. Handle duplicates - In rare cases (e.g., network issues), you may receive the same event twice; deduplicate using webhook_id + timestamp + the event-specific entity ID (document_id for published events, assignment_id for acknowledged events)

  4. Monitor your endpoint - Check the delivery log periodically to catch failures early

  5. Use HTTPS - Webhook URLs must use HTTPS to protect payload data in transit