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 across the access request lifecycle, policy changes, API key activity, support tickets, and SCIM provisioning. 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
api_key.createdAn API key is created
api_key.revokedAn API key is revoked
api_key.expiredAn API key reaches its expiration date
api_key.ip_rejectedAn API key request is rejected by its IP allowlist
support_ticket.createdA support ticket is opened
support_ticket.commentedA comment is added to a support ticket
scim.user_createdA user is provisioned via SCIM
scim.user_deactivatedA user is deactivated via SCIM
scim.group_createdA group is created via SCIM
scim.group_member_addedA member is added to a group via SCIM
scim.group_member_removedA member is removed from a group via SCIM

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",
    "origin": "mcp",
    "proposed_unmasked_count": 2
  }
}

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 the retries are exhausted, the delivery is permanently marked as failed.

Each delivery is attempted up to 3 times with exponential backoff: the first retry runs ~1 minute after the initial failure and the second ~2 minutes after that. A delivery that is still pending after max_retry_age (72 hours by default) is bulk-failed regardless of attempt count. Treat a delivery as permanently lost once it reaches the failed state.

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.