Outbound Webhooks
When DDMARC raises an alert, it can POST that alert to a URL you own. This page describes exactly what arrives, and is equally explicit about the delivery guarantees that do not exist.
How delivery works
There is no webhook resource to create. Each user has a single webhook URL on their notification preferences, and DDMARC fans an alert out to every enabled URL in the organization. A failed delivery is retried: three attempts in total, one second and then three seconds apart (or as long as a Retry-After header asks, up to ten seconds), after a timeout, a connection error, a 429 or a 5xx. Any other 4xx is not retried.
PATCH /api/v1/alerts/preferences with webhook_url and webhook_enabled: true. The URL must be HTTPS.webhook in its notification_channels.The payload
A generic endpoint receives four top-level fields. Everything about the alert itself is nested under alert.
{
"event_type": "alert.dns_record_changed",
"timestamp": "2026-07-19T04:31:07.918204+00:00Z",
"organization_public_id": "org_7f2c91ab",
"alert": {
"alert_id": 88213,
"alert_type": "dns_record_changed",
"title": "DMARC record changed on example.com",
"message": "The published policy moved from p=quarantine to p=none.",
"severity": "warning",
"domain": "example.com",
"domain_id": 42,
"organization_id": 17
}
}| Field | Type | Description |
|---|---|---|
event_type | string | Always alert.<alert_type>, for example alert.high_failure_rate |
timestamp | string | When the delivery was built, ISO 8601 |
organization_public_id | string | Your organization's opaque public id |
alert | object | The alert body: alert_id, alert_type, title, message, severity, domain, domain_id, organization_id |
Slack and Discord differ
The payload above is what a generic endpoint receives. DDMARC inspects the URL you saved and, if it recognizes a chat platform, sends that platform's native format instead of the JSON envelope.
| URL contains | Body sent |
|---|---|
hooks.slack.com | Slack Block Kit: a header block with a severity emoji, a section block with the message, and a context block showing type and severity. No action buttons. |
discord.com/api/webhooks | A Discord embed with a severity-colored stripe and Type and Severity fields. |
| anything else | The generic JSON payload shown above. |
Microsoft Teams, Telegram and Jira are separate channels with their own configuration fields, not URL sniffing. See the integrations overview.
Alert types
event_type is always the alert type prefixed with alert. These are the types that exist. Which of them you receive depends on your plan, your notification preferences and your alert rules.
Send a test delivery
Sends a synthetic alert so you can confirm your receiver works before waiting for a real one. Two variants exist: one for an ad-hoc URL, one for the URL already saved on your preferences.
curl -X POST "https://api.ddmarc.com/api/v1/alerts/webhook/test" \
-H "X-API-Key: $DDMARC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://hooks.example.com/ddmarc" }'{
"success": true,
"status_code": 200,
"error": null
}{
"success": false,
"status_code": null,
"error": "URL resolves to a private address"
}success. Use POST /api/v1/alerts/webhook/test-saved with no body to test the URL already stored on your preferences; that variant returns 400 if no URL is saved or webhooks are disabled.Delivery guarantees
GET /api/v1/alerts if you need a complete record.Not implemented
These are commonly expected of a webhooks product and are absent from DDMARC today. They are listed explicitly so you do not build against them.