API reference
Complete reference for the DMARCdrift read-only API: authentication, endpoints, response shapes, rate limits, and example requests.
The external API gives programmatic read-only access to your domains, DMARC reports, and alerts. All endpoints are under /v1/external/ and require an API key. The API is available on the Pro plan.
Base URL: https://api.dmarcdrift.com
Authentication
Pass your API key in the Authorization header:
Authorization: Bearer dd_live_<your-key>Missing or invalid keys return 401 Unauthorized:
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key"
}
}Rate limits
| Scope | Limit |
|---|---|
| Per API key | 60 requests / minute |
| Per IP address | 200 requests / minute |
When a limit is exceeded the response is 429 Too Many Requests with Retry-After: 60.
Pagination
All list endpoints accept limit and offset query parameters and return a consistent envelope:
{
"data": [ /* array of items */ ],
"total": 42
}| Parameter | Default | Range |
|---|---|---|
limit | 50 | 1–200 |
offset | 0 | ≥ 0 |
Endpoints
List domains
GET /v1/external/domainsReturns all active domains in your account.
Query parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Page size. Default 50, max 200. |
offset | integer | Number of items to skip. Default 0. |
Example request
GET /v1/external/domains?limit=10 HTTP/1.1
Authorization: Bearer dd_live_...Example response 200 OK
{
"data": [
{
"id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
"domain": "example.com",
"status": "active",
"last_report_at": "2026-05-01T04:00:00+00:00"
}
],
"total": 1
}Domain object fields
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Domain identifier. Used in other endpoint paths. |
domain | string | The domain name. |
status | string | active or paused. |
last_report_at | string (ISO 8601) | null | Timestamp of the most recent report received. |
List reports for a domain
GET /v1/external/domains/{domain_id}/reportsReturns DMARC aggregate reports received for a specific domain, newest first.
Returns 404 Not Found if the domain does not exist or does not belong to your account.
Path parameters
| Name | Description |
|---|---|
domain_id | UUID of the domain, from the list domains response. |
Query parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Page size. Default 50, max 200. |
offset | integer | Number of items to skip. Default 0. |
Example request
GET /v1/external/domains/dddddddd-dddd-dddd-dddd-dddddddddddd/reports HTTP/1.1
Authorization: Bearer dd_live_...Example response 200 OK
{
"data": [
{
"id": "rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr",
"reporter_org": "google.com",
"reporter_email": "noreply-dmarc-support@google.com",
"begin_date": "2026-05-01T00:00:00+00:00",
"end_date": "2026-05-02T00:00:00+00:00",
"record_count": 12,
"total_messages": 4820,
"aligned_messages": 4785
}
],
"total": 1
}Report object fields
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Report identifier. |
reporter_org | string | null | Organisation name from the report (e.g., google.com). |
reporter_email | string | null | Contact email from the report. |
begin_date | string (ISO 8601) | Start of the reporting window. |
end_date | string (ISO 8601) | End of the reporting window. |
record_count | integer | Number of policy evaluation records in the report. |
total_messages | integer | Total message count across all records. |
aligned_messages | integer | Messages that passed SPF or DKIM alignment. |
List alerts
GET /v1/external/alertsReturns alerts fired for your account, newest first. Use the optional domain_id filter to scope results to a single domain.
Query parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Page size. Default 50, max 200. |
offset | integer | Number of items to skip. Default 0. |
domain_id | string (UUID) | Optional. Filter to alerts for a specific domain. |
Example request
GET /v1/external/alerts?domain_id=dddddddd-dddd-dddd-dddd-dddddddddddd HTTP/1.1
Authorization: Bearer dd_live_...Example response 200 OK
{
"data": [
{
"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"domain_id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
"type": "alert.alignment_regression",
"fired_at": "2026-05-01T04:30:00+00:00",
"resolved_at": null,
"context": {
"drop_pct": 35.2,
"prev_pass_rate": 98.1,
"curr_pass_rate": 62.9
}
}
],
"total": 1
}Alert object fields
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Alert identifier. |
domain_id | string (UUID) | Domain this alert is associated with. |
type | string | Alert type. See the event types table. |
fired_at | string (ISO 8601) | When the alert was created. |
resolved_at | string (ISO 8601) | null | When the alert was resolved, or null if still active. |
context | object | Alert-type-specific data (metrics, DNS record changes, etc.). |
Error responses
All errors follow the same envelope:
{
"error": {
"code": "string",
"message": "string"
}
}| Status | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing, invalid, or disabled API key. |
404 | not_found | Resource does not exist or does not belong to your account. |
422 | validation_error | Invalid query parameter (e.g., limit out of range). |
429 | rate_limited | Per-key or per-IP rate limit exceeded. |
500 | internal_error | Unexpected server error. |
See also: API keys — creating and managing keys. Webhooks — receiving push notifications when alerts fire.
Webhooks
Configure webhooks to receive real-time HTTP callbacks whenever DMARCdrift fires an alignment regression, spoofing, or DNS change alert on your domain.
Troubleshooting DMARC alignment failures
Symptom-by-symptom diagnosis for SPF passes but DMARC fails, DKIM passes but DMARC fails, and related alignment problems.