Datadog — Ingest Setup
This guide shows how to route Datadog alerts straight to Culprit using Datadog's built-in Webhooks integration.
Endpoint
POST https://ingest.theculprit.ai/ingest/<tenant_id>/<service_name>/datadog
Replace <tenant_id> and <service_name> with the values shown on your
service's settings page.
Authentication
Requests must carry an ingest token in the Authorization header:
Authorization: Bearer <ingest_token>
Getting your ingest token:
- Open the Culprit dashboard → Services → select the service.
- In the Ingest token section, click Issue.
- Copy the token shown — it is displayed once. After you navigate away, only the token prefix is shown.
To rotate a compromised token, click Rotate. The previous token remains valid for the grace period shown, giving you time to update Datadog without an interruption.
Setup in Datadog
Datadog webhook bodies are user-defined templates. You must paste the body template below so Culprit receives the fields it needs.
- Open Integrations → Webhooks → New Webhook.
- Set URL to your Culprit endpoint shown above.
- Under Custom Headers, add:
- Header:
Authorization - Value:
Bearer <ingest_token>
- Header:
- In the Payload field, replace the default content with this template:
{ "title": "$EVENT_TITLE", "body": "$EVENT_MSG", "alert_type": "$ALERT_TYPE", "priority": "$PRIORITY", "tags": "$TAGS", "id": "$ID", "date": "$DATE" }
- Save the webhook.
- In your Datadog monitors, add the webhook as a notification channel using
@webhook-<webhook_name>.
How Culprit maps Datadog alerts
Field mapping
| Datadog field | Culprit event field | Notes |
|---|---|---|
| body | message | Falls back to title if body is absent or unsubstituted |
| title | event_type suffix + message fallback | Used as message when body is absent |
| priority | severity | P1 → critical (overrides alert_type) |
| alert_type | severity | error → error; warning → warning; success / info → info |
| alert_type, priority, tags, id, date | context | All preserved for correlation and RCA |
Severity resolution (in priority order)
- P1 priority →
critical(overrides everything else) alert_type: error→erroralert_type: warning→warningalert_type: successoralert_type: info→info- No usable fields →
warning
Unsubstituted variables
If a field contains an unsubstituted Datadog variable (for example $EVENT_MSG
or $ALERT_TYPE) or is blank, Culprit treats it as absent. An event where both
body and title are absent or unsubstituted is rejected with 400 unrecognized_payload.
PII in any field (IP addresses, hostnames, email addresses, API keys) is detected and tokenized before any storage or notification. The original values are preserved encrypted and are visible only in the incident detail view after authentication.
Worked example
Datadog sends:
{
"title": "[Triggered] 5xx spike on checkout",
"body": "Error rate 12% on api-1.acme.internal",
"alert_type": "error",
"priority": "P1",
"tags": "env:prod,service:checkout",
"id": "1234567890",
"date": "1716926400000"
}
Culprit event (before tokenization):
{
"event_type": "datadog.error",
"severity": "critical",
"source": "datadog",
"message": "Error rate 12% on api-1.acme.internal",
"context": {
"alert_type": "error",
"priority": "P1",
"tags": "env:prod,service:checkout",
"id": "1234567890",
"date": "1716926400000"
}
}
This event flows through the standard pipeline: encrypted vault storage → PII tokenization → storm check → embedding → correlation → root-cause analysis.
Successful response
{ "accepted": true, "ids": ["<vault_id>"] }
Error responses
| Status | Body | Meaning |
|---|---|---|
| 401 | { "error": "missing_auth" } | No Authorization header |
| 401 | { "error": "invalid_ingest_token" } | Token is incorrect or has been rotated/revoked |
| 400 | { "error": "unrecognized_payload" } | Body is not valid JSON, both body and title are absent or unsubstituted, or the payload does not match the expected shape |
| 403 | { "error": "service_disabled" } | The service exists but monitoring is paused |
| 404 | { "error": "service_deleted_or_not_found" } | The service does not exist |
| 429 | { "error": "rate_limited" } | Storm protection active (sustained high volume) |