Audit Log Webhooks
Configure webhooks to stream audit log events in real-time to your SIEM, log aggregator, or any webhook endpoint using CloudEvents v1.0 format.
Audit log webhooks deliver workspace audit events to your external systems via HTTPS. Events are formatted as CloudEvents v1.0, signed with HMAC-SHA256, and delivered in batches with automatic retries.
- 1Navigate to Workspace Settings in the sidebar
- 2Scroll to the Webhooks section
- 3Click Add Destination
- 4Enter your HTTPS webhook URL and an optional description
- 5Add any custom headers your endpoint requires (e.g., API keys, authorization tokens)
- 6Click Create Destination
- 7Copy the HMAC secret — it is shown only once. Store it securely.
- 8Click the Test button to send a test event and verify delivery
You can add multiple destinations per workspace. Each destination can be independently enabled, disabled, tested, or deleted.
Each destination has a Payload Format, selected in the Add/Edit Destination dialog:
- CloudEvents v1.0 (default) — a generic structured envelope that works with most consumers (Knative Eventing, Argo Events, custom HTTP receivers). Documented below.
- Datadog Logs — pre-formatted for Datadog's HTTP log intake, with top-level reserved attributes (
ddsource,service,hostname,status,message,ddtags,event_id,event_type) so events are searchable in Log Explorer without a remap pipeline. See the Datadog quickstart below.
With the default CloudEvents v1.0 format, every delivery is a JSON array of CloudEvents v1.0 envelopes:
[
{
"specversion": "1.0",
"id": "aud_abc123",
"source": "https://atmos-pro.com/workspaces/ws_xyz",
"type": "pro.atmos.workspace.created",
"time": "2025-01-15T10:30:00.000Z",
"subject": "ws_target1",
"datacontenttype": "application/json",
"data": {
"actor": { "id": "usr_actor1", "type": "user" },
"action": { "category": "workspace", "action": "created" },
"target": { "type": "workspace", "id": "ws_target1" },
"description": null,
"metadata": {}
}
}
]| Field | Description |
|---|---|
specversion | Always "1.0" |
id | Unique audit log entry ID |
source | Workspace URL that generated the event |
type | Event type in the format pro.atmos.{category}.{action} |
time | ISO 8601 timestamp |
subject | Target resource ID (if applicable) |
datacontenttype | Always "application/json" |
data | Event payload with actor, action, target, description, and metadata |
All event types follow the pattern
pro.atmos.{category}.{action}. See the Audit Log overview for the complete list of categories and actions.Every webhook delivery includes an
X-Webhook-Signature header:X-Webhook-Signature: sha256=5d7861...
The signature is an HMAC-SHA256 hex digest of the raw request body using the destination's secret key. Always verify this signature before processing events.
const crypto = require('crypto');
function verifySignature(body, secret, signatureHeader) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected)
);
}
// In your webhook handler:
const body = req.body; // raw string, not parsed JSON
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(body, process.env.WEBHOOK_SECRET, signature)) {
return res.status(401).send('Invalid signature');
}- Events are batched — up to 100 events are collected over a 30-second window before delivery
- Failed deliveries are retried up to 5 times with exponential backoff
- After all retries are exhausted, an alert email is sent to notify you of the failure
- Delivery status (success/failure) is visible in the webhook destinations list in workspace settings
- The
X-Webhook-Idheader identifies which destination received the delivery
Axiom offers a generous free tier (500 GB/month ingest, 30-day retention) and accepts CloudEvents JSON arrays directly.
- 1Create a dataset in Axiom (e.g.,
atmos-pro-audit) - 2Generate an API token scoped to that dataset with ingest permission
- 3Set the webhook URL to
https://api.axiom.co/v1/datasets/atmos-pro-audit/ingest - 4Add a custom header:
Authorization: Bearer <your-ingest-token> - 5Send a test event from Atmos Pro and confirm it appears in the dataset within ~30 seconds
Query examples using APL (Axiom Processing Language):
// All permission grants in the last 24 hours
['atmos-pro-audit']
| where _time > ago(24h)
| where ['data.action.action'] == 'assigned'
| where ['data.action.category'] == 'permission'
| project _time, ['data.actor.email'], ['data.target.id']// Failed actions by user
['atmos-pro-audit']
| where ['data.outcome'] == 'failure'
| summarize count() by ['data.actor.email']
| order by count_ descDelivery status shows "failed"
- Verify the destination URL is reachable and returns a 2xx status code
- Check that HTTPS is used (HTTP URLs are not allowed)
- Verify any custom headers (e.g., API keys) are correct and not expired
- Check your endpoint's firewall or IP allowlist
Events not appearing in your SIEM
- Confirm the destination is enabled in workspace settings
- Check the audit log viewer to verify events are being recorded
- Send a test event to confirm connectivity
Signature verification fails
- Verify against the raw request body (the exact bytes received), not a re-serialized version
- Use timing-safe comparison (e.g.,
crypto.timingSafeEqualin Node.js) - Ensure you are using the correct secret for the destination