Domains API
Programmatically manage the domains in your organization: add them, verify ownership, check what their live DNS actually says, and rotate report mailbox tokens.
Conventions on this page
https://api.ddmarc.com — every path below already includes the /api/v1 prefix.{domain_id} is an integer. The API never emits prefixed string ids.data or meta wrapper.write scope or higher. See Authentication.Endpoints
/api/v1/domainsList all domains/api/v1/domainsAdd a new domain/api/v1/domains/{domain_id}Get domain details/api/v1/domains/{domain_id}Remove a domain/api/v1/domains/{domain_id}/dns-checkCheck the domain's live DNS records/api/v1/domains/{domain_id}/verifyVerify domain ownership/api/v1/domains/{domain_id}/rotate-tokenRotate the domain's RUA/RUF tokens/api/v1/domains/{domain_id}/recommendationsGet configuration recommendationsList all domains
Returns every domain in your organization, newest first, each with its ingestion counters.
curl -X GET "https://api.ddmarc.com/api/v1/domains?limit=100&offset=0" \ -H "X-API-Key: $DDMARC_API_KEY"
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Maximum rows to return. Hard ceiling of 500. |
offset | integer | 0 | Rows to skip. Pagination is offset-based, not page-based. |
[
{
"id": 42,
"domain": "example.com",
"rua_token": "a1b2c3d4e5",
"ruf_token": "f6g7h8i9j0",
"verification_token": "ddmarc-verify-9f3c1a",
"is_verified": true,
"verified_at": "2026-01-15T11:00:00Z",
"dmarc_verified": true,
"spf_verified": true,
"dkim_verified": false,
"admin_email": null,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-01T08:12:44Z",
"reports_count": 1250,
"last_report_at": "2026-02-01T06:00:00Z"
}
]Add a domain
Adds a domain for monitoring. How many domains you may hold depends on your plan; exceeding the limit returns 403.
curl -X POST "https://api.ddmarc.com/api/v1/domains" \
-H "X-API-Key: $DDMARC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com"
}'| Field | Type | Required | Description |
|---|---|---|---|
domain | string | Required | Domain name. Trimmed, lowercased and format-validated; an invalid value returns 422. |
admin_email | string | Optional | Contact address, used by MSPs so the end customer can sign in to the domain. |
{
"id": 43,
"domain": "example.com",
"rua_token": "k1l2m3n4o5",
"ruf_token": "p6q7r8s9t0",
"verification_token": "ddmarc-verify-71ae4c",
"is_verified": false,
"verified_at": null,
"dmarc_verified": null,
"spf_verified": null,
"dkim_verified": null,
"admin_email": null,
"created_at": "2026-07-19T15:00:00Z",
"updated_at": "2026-07-19T15:00:00Z"
}rua=mailto:{rua_token}@rua.ddmarc.com in your DMARC record. There is no shared reporting address, and a generic one will not route.Get domain details
Returns a single domain in the same shape as the list endpoint, including reports_count and last_report_at. A domain belonging to another organization returns 404, not 403.
curl -X GET "https://api.ddmarc.com/api/v1/domains/42" \ -H "X-API-Key: $DDMARC_API_KEY"
Verify domain ownership
Looks up the domain's TXT records and checks whether any contains the verification_token. This is a live DNS lookup, so it reflects what is published right now.
{
"verified": true,
"message": "Domain ownership verified successfully",
"txt_records_found": [
"ddmarc-verify-9f3c1a",
"v=spf1 include:_spf.google.com ~all"
]
}verified boolean, not on the status code. A missing token returns 200 with verified: false and a message naming the value to publish.Check live DNS records
Resolves and validates the domain's email-authentication records as published today. This returns check results, not a list of records for you to create. Results are cached; pass refresh=true to force a fresh lookup.
{
"domain": "example.com",
"spf": {
"exists": true,
"valid": true,
"record": "v=spf1 include:_spf.google.com ~all",
"errors": [],
"warnings": []
},
"dkim": {
"exists": true,
"valid": true,
"record": "v=DKIM1; k=rsa; p=MIIBIjANBgkqh...",
"errors": [],
"warnings": [],
"dkim_alignment_note": null
},
"dmarc": {
"exists": true,
"valid": true,
"record": "v=DMARC1; p=none; rua=mailto:a1b2c3d4e5@rua.ddmarc.com",
"errors": [],
"warnings": ["Policy is p=none; no enforcement yet"]
},
"tls_rpt": null,
"mta_sts": null,
"bimi": null,
"overall_status": "warning"
}overall_status is one of pass, warning or fail. The tls_rpt, mta_sts and bimi blocks are only populated on plans that include advanced DNS checks, and each carries extra fields — policy mode, max age, logo URL — on top of the common check shape.
Rotate report mailbox tokens
Issues fresh RUA and/or RUF mailbox tokens. Use ?type=rua, ruf or both (default). Limited to five rotations per hour.
{
"domain_id": 42,
"domain": "example.com",
"rua_token": "u1v2w3x4y5",
"ruf_token": "z6a7b8c9d0",
"rotated": ["rua", "ruf"],
"dmarc_txt_record": "v=DMARC1; p=none; rua=mailto:u1v2w3x4y5@rua.ddmarc.com; ruf=mailto:z6a7b8c9d0@ruf.ddmarc.com; fo=1"
}dmarc_txt_record before the next reporting window. Reports already in flight to the old address are dropped.Delete a domain
Removes a domain from your organization. Returns 204 No Content with an empty body on success.
GET /api/v1/reports/export/csv.The domain object
| Field | Type | Description |
|---|---|---|
id | integer | Domain identifier, used as {domain_id} in paths |
domain | string | The domain name, lowercased on write |
rua_token | string | Mailbox token for aggregate reports |
ruf_token | string | Mailbox token for forensic reports |
verification_token | string | Value to publish in a TXT record to prove ownership |
is_verified | boolean | Whether ownership has been verified |
verified_at | string | null | ISO 8601 timestamp of verification |
dmarc_verified | boolean | null | Last DNS sweep saw a valid DMARC record |
spf_verified | boolean | null | Last DNS sweep saw a valid SPF record |
dkim_verified | boolean | null | Last DNS sweep saw a valid DKIM record |
admin_email | string | null | Optional contact used for MSP customer login |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last-modified timestamp |
reports_count | integer | List endpoints only: total reports ingested |
last_report_at | string | null | List endpoints only: most recent ingestion |
/dns-check when you need the current state. There is no status, dmarc_policy or pass_rate field on a domain — pass rates come from /api/v1/reports/stats/summary.