DAAM
Alpha

Notifications

DAAM delivers webhook notifications to external services when key events occur. Configure webhook channels, subscribe to event types, and verify signed payloads to build reliable integrations with your operational tooling.

Overview

The notification system pushes real-time event data to external HTTP endpoints when important events happen in your organization. Each notification is a signed JSON payload delivered via HTTP POST to your configured webhook URL.

  • Webhook-based — notifications are delivered as HTTP POST requests to URLs you configure.
  • Event-filtered — subscribe channels to specific event types or receive all events.
  • Signed payloads — optional signatures let you verify that payloads originated from DAAM.
  • Automatic retry — failed deliveries are retried with exponential backoff.
  • Non-blocking — notification delivery never blocks the operation that triggered the event.

Notification delivery is fire-and-forget from the perspective of the triggering operation. An access request approval succeeds even when all webhook deliveries fail. Failed deliveries are retried in the background.

Creating a Webhook Channel

Org admins can create notification channels from the console. Each channel targets a single webhook URL and can subscribe to specific event types.

  1. Navigate to Settings in the sidebar, then click Notifications.
  2. Click New Channel.
  3. Enter the channel Name (e.g. "Slack Alerts" or "PagerDuty").
  4. Enter the Webhook URL where DAAM should send HTTP POST requests.
  5. Optionally enter a Signing Secret to enable payload signatures.
  6. Select the Events you want to receive, or leave empty to receive all events.
  7. Click Create Channel.
FieldRequiredDescription
NameYesA descriptive label for the channel. Must be unique within the organization.
Webhook URLYesThe HTTP or HTTPS endpoint that receives POST requests. Must be publicly reachable.
Signing SecretNoA shared secret used to compute HMAC-SHA256 signatures. Stored encrypted at rest.
EventsNoEvent types to subscribe to. Empty means all events.
EnabledN/AChannels are enabled by default. Disable to pause delivery without deleting.

Webhook URLs are validated to ensure security. URLs pointing to private or internal networks are blocked.

Event Types

DAAM fires notifications for access request lifecycle events and policy changes. Subscribe to specific event types or leave the events list empty to receive all of them.

Event TypeTrigger
access_request_createdA new access request is submitted by a user
access_request_approvedAn admin approves an access request
access_request_deniedAn admin denies an access request
access_request_revokedAn approved or active access request is revoked
access_request_expiredAn active access request reaches its end time and expires automatically
policy_changedA policy is created, updated, deleted, or its user/group assignments change

When a channel subscribes to no specific events (empty events list), it receives all event types. This is useful for general-purpose integrations that want complete visibility.

Payload Format

Each webhook delivery sends an HTTP POST with a JSON body. The payload includes a unique delivery ID, the event type, your organization ID, a timestamp, and event-specific data.

Headers

HeaderValue
Content-Typeapplication/json
User-AgentDAAM-Webhook/1.0
X-DAAM-EventThe event type (e.g. access_request_created)
X-DAAM-Signature-256HMAC-SHA256 signature (only when signing secret is configured)

Example Payload

Below is an example payload for an access request creation event:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event_type": "access_request_created",
  "org_id": "f9e8d7c6-b5a4-3210-fedc-ba0987654321",
  "timestamp": "2026-01-31T10:05:00Z",
  "data": {
    "request_id": "11223344-5566-7788-99aa-bbccddeeff00",
    "requester_email": "[email protected]",
    "database_name": "prod-orders",
    "justification": "Debug customer issue #5678"
  }
}

The top-level fields are present on every delivery. The data object varies by event type and contains the event-specific details.

The delivery ID in the payload is unique per delivery attempt. Use it for idempotency checks in your webhook handler to avoid processing the same event twice during retries.

Signature Verification

When you configure a signing secret on a channel, every delivery includes an HMAC-SHA256 signature in the X-DAAM-Signature-256 header. Verify this signature to confirm that the webhook payload was sent by DAAM and has not been tampered with.

The signature format is:

X-DAAM-Signature-256: sha256=<hex-encoded HMAC-SHA256>

Verification Steps

  1. Read the raw request body (do not parse it first).
  2. Compute HMAC-SHA256(your_signing_secret, raw_body) and hex-encode the result.
  3. Extract the hex string after sha256= from the header value.
  4. Compare the two hex strings using a constant-time comparison to prevent timing attacks.
  5. Reject the request with HTTP 403 when the signatures do not match.

Python Example

import hmac, hashlib

def verify_signature(secret, body, header):
    expected = hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    received = header.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)

Node.js Example

const crypto = require("crypto");

function verifySignature(secret, body, header) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  const received = header.replace("sha256=", "");
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(received)
  );
}

Always use constant-time comparison (e.g. hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js) to prevent timing side-channel attacks. Standard string equality is vulnerable.

Retry Behavior

When a webhook delivery fails (non-2xx response or network error), DAAM retries automatically. A delivery is considered successful when the endpoint returns any HTTP 2xx status code.

  • Success — any HTTP 2xx response. The delivery is marked complete.
  • Failure — any non-2xx response, timeout, or connection error. Retried automatically.
  • Permanent failure — after all retry attempts are exhausted, the delivery is permanently marked as failed.

The channel detail page in the console shows recent deliveries with their status and HTTP response codes.

Delivery Status

Each delivery progresses through a simple state machine:

StatusDescription
pendingAwaiting delivery or scheduled for retry
successDelivered successfully (received HTTP 2xx)
failedPermanently failed after all retries exhausted or max age exceeded

The channel detail page also shows the last error message and timestamp for channels with recent failures. Use this to diagnose connectivity issues with your webhook endpoint.

Testing Webhooks

After creating a channel, use the Send Test button on the channel detail page to send a test notification. This fires a special test event to verify that your endpoint is reachable and can process DAAM webhooks.

  1. Navigate to Settings → Notifications and click the channel you want to test.
  2. Click the Send Test button.
  3. Check your endpoint for the incoming test payload.
  4. The delivery result appears in the delivery history table on the channel detail page.

The test event is not subscribable as a regular event type. It is sent only via the test button and does not appear in normal event delivery. Use it to verify your endpoint, signature verification, and response handling before relying on the channel for real events.

Managing Channels

The channel detail page provides full management of each notification channel:

  • Edit — update the name, webhook URL, signing secret, subscribed events, or enabled state.
  • Disable — toggle the channel off to pause delivery without deleting configuration.
  • Delete — permanently remove the channel and all associated delivery history.
  • Delivery history — view recent deliveries with status, HTTP response code, and timestamps.

Disabled channels are skipped during event matching. Re-enable a channel to resume delivery without recreating it. Signing secrets are stored encrypted and are never displayed after creation — set a new secret to rotate.