40. Webhooks and custom sources
When no typed integration fits, webhooks are the universal adapter — POST JSON in, get events on the timeline.
When none of Daalu’s typed integrations fit, webhooks connect anything else. CI pipelines, homegrown alerters, internal scripts, IoT — all can write to Daalu’s timeline by POSTing JSON to the ingest endpoint. The reverse direction works too: Daalu can POST to your URL when an alert or proposal fires.
At a glance
| What it connects | Anything that can POST JSON — CI, scripts, IoT, custom alerters; and outbound to your own receivers |
| Auth model | Inbound: a per-tenant ingest key in the X-Daalu-Key header. Outbound: Daalu signs each delivery so you can verify it. |
| Where to set it up | Managed Infra → Webhooks |
Inbound: send events to Daalu
You hold a per-tenant ingest key; anything that can make an HTTPS POST sends events to a single endpoint with that key in a header. Daalu records each event on the timeline, and if an alert rule matches, an alert fires.
The endpoint
POST https://ops.daalu.io/api/v1/events
X-Daalu-Key: <your ingest key>
Content-Type: application/jsonFind or rotate the ingest key under Managed Infra → Webhooks → Ingest key. Daalu stores only a hash of it — treat it like a password.
Request body
The body is an event envelope:
{
"type": "deploy.failed",
"module": "ci",
"source": "github-actions",
"summary": "prod deploy of api failed at step build",
"severity": "warning",
"payload": {
"service": "api",
"env": "prod",
"commit": "a1b2c3d",
"url": "https://github.com/acme/api/actions/runs/123"
}
}| Field | Meaning |
|---|---|
type | Freeform, but follow a <system>.<verb> shape (deploy.failed, backup.completed) so it’s queryable. |
module | A routing category for the event (ci, security, custom, …). |
source | Stable identifier for the sender. |
summary | One human-readable line; this is what shows on the timeline. |
severity | One of info, warning, critical. Defaults to info. |
payload | Any JSON you want carried along and surfaced in the UI. |
Note: The tenant is resolved from your ingest key, never from the body. Daalu drops any
tenant_idyou try to set — a key can only write into its own tenant.
A worked example
INGEST_KEY="<your ingest key>"
curl -X POST https://ops.daalu.io/api/v1/events \
-H "X-Daalu-Key: $INGEST_KEY" \
-H 'Content-Type: application/json' \
-d '{
"type": "check.failed",
"module": "custom",
"source": "nightly-cron",
"summary": "disk usage on backup host exceeded 90%",
"severity": "warning",
"payload": {"host": "backup-1", "pct": 93}
}'A successful ingest returns 202 Accepted. Requests with a missing or
wrong key are rejected with 401.
Outbound: Daalu posts to you
The reverse path: Daalu POSTs to a URL you provide when configured triggers fire.
Setup
- Managed Infra → Webhooks → Add outbound webhook.
- Pick the trigger — which events fire it (alerts of severity X, proposals of kind Y, and so on).
- Provide your receiving URL.
- Daalu shows a signing secret. It signs every delivery with it so you can verify the POST really came from Daalu.
Verifying deliveries
Each outbound POST carries an HMAC-SHA256 signature of the body in the
X-Daalu-Signature header. Recompute the HMAC with your signing secret
and compare:
# pseudo-receiver
SIG_HEADER="$X_Daalu_Signature"
EXPECTED=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')
[ "$SIG_HEADER" = "$EXPECTED" ] || rejectRetries
If your receiver returns a non-2xx, Daalu retries with exponential backoff for up to an hour. After that the delivery is marked failed and surfaces on the webhook detail page.
Use cases
- Pipe Daalu events into your warehouse.
- Trigger your own automation from a Daalu alert.
- Mirror change proposals into your ticket system.
Webhook detail page
For each webhook (in or out):
- Endpoint / URL.
- Secret or ingest key — masked, with a Reveal button.
- Last delivery — timestamp, status, and the request/response pair.
- Recent history — the 100 latest deliveries with timings.
- Rotate secret — issues a new one; the old one keeps working for 24 hours so you can roll it out without downtime.
Limits
- Body size: 1 MiB per POST.
- Rate: 10 POSTs/second per ingest key (inbound); 50/second outbound to your URL.
- Retention: 30 days of delivery history.
Need more? Email support.
Patterns from the field
”Deploy started” event from CI
A GitHub Action POSTs type=deploy.started when each prod deploy
begins. The alert-explainer agent uses these to correlate — “the
latency spike at 14:32 coincided with the deploy at 14:30.”
Dead-man’s-switch heartbeat
A cron in your environment POSTs type=heartbeat every minute. A Daalu
rule fires an alert if those stop arriving. Cheap, reliable liveness
checking.
Mirroring to a warehouse
An outbound webhook on every event fires to your Snowflake/BigQuery ingest URL, giving you a long-term record of every Daalu event for your own analysis.
Cross-tool plumbing
When a Daalu change proposal is approved, an outbound webhook opens a Jira ticket so your existing ticketing workflow stays in sync.