---
title: "Domains · API v1"
description: "The domains you monitor and their health."
---
# Domains

The domains you monitor and their health.

## List domains

`GET /domains`

Every domain the organization monitors, added manually or discovered from reports, with its verification state per protocol.

- Permission: `domain:read`
- Key scope: `read`, `full`

### Query parameters

| Name | Type | Description |
| --- | --- | --- |
| `limit` | `integer` | Page size. Values above the maximum are clamped; zero, negative or non-numeric values are ignored and the default applies. Default 50. |
| `offset` | `integer` | Number of rows to skip; combine with limit to page. A negative or non-numeric value is treated as 0. Default 0. |

### Example request

```bash
curl "https://api.dmarcguard.io/api/v1/domains" \
  -H "Authorization: Bearer dg_your_key"
```

### Response

| Field | Type | Notes |
| --- | --- | --- |
| `domains` | `object[]` | The requested page. Never null; an empty page is []. |
| `domains[].id` | `string` (optional) | Identifier, Crockford Base32. Opaque; never parse it as a number. |
| `domains[].domain` | `string` | The monitored domain. |
| `domains[].verified` | `boolean` | Legacy boolean; prefer dmarc_state, which distinguishes no record from a record that reports elsewhere and from an inconclusive check. |
| `domains[].dmarc_state` | `string` | State of the domain's DMARC record: pending before the first check, verified when its own record reports to you, verified_inherited when the organizational parent's record does, not_published when the authoritative nameservers say there is none, published_not_ours when a record exists but reports elsewhere, multiple_records when the name serves more than one (receivers discard them all), and unconfirmed when the check could not reach authoritative DNS. unconfirmed is not a negative. One of "pending", "verified", "verified_inherited", "not_published", "published_not_ours", "unconfirmed", "multiple_records". |
| `domains[].tlsrpt_enabled` | `boolean` | Whether TLS reporting is switched on for this domain. |
| `domains[].tlsrpt_state` | `string` | State of the domain's TLS-RPT record, on the same scale as dmarc_state. One of "pending", "verified", "verified_inherited", "not_published", "published_not_ours", "unconfirmed", "multiple_records". |
| `domains[].forensic_enabled` | `boolean` | Whether failure (forensic) reporting is switched on for this domain. |
| `domains[].forensic_state` | `string` | State of the failure-report address in the domain's DMARC record, on the same scale as dmarc_state. One of "pending", "verified", "verified_inherited", "not_published", "published_not_ours", "unconfirmed", "multiple_records". |
| `domains[].source` | `string` | How the domain got here: manual if you added it, auto if a report introduced it, both when both are true. |
| `domains[].verified_source` | `string` (optional) | Why the domain counts as verified: self for its own record, inherited for the organizational parent's. Empty when it is not verified. |
| `domains[].inherited_from` | `string` (optional) | The organizational parent whose record covers this domain; present only when verified_source is inherited. |
| `domains[].report_count` | `integer` | Aggregate reports held for this domain. |
| `domains[].verified_at` | `string` (nullable, optional) | RFC 3339 UTC instant with whole seconds, e.g. 2026-09-15T16:03:43Z; null when absent. |
| `total` | `integer` | Domains the organization monitors, before paging. |
| `limit` | `integer` | The page size actually applied. |
| `offset` | `integer` | The offset actually applied. |

### Errors

| Status | When |
| --- | --- |
| `401` | Missing, malformed, revoked, expired or not-entitled API key. |
| `403` | The key's scope or its owner's role does not allow this operation. |
| `429` | Hourly quota or an abuse limit exceeded; the body's code says which. Honour Retry-After. |
| `500` | Unexpected server error; retry with backoff. |
| `503` | A transient failure resolving the organization or reading storage; retry after a short pause. |

Plus the errors every request can return: https://dmarcguard.io/docs/api/v1/#errors

## Domain health

`GET /domains/{domain}/health`

Score, grade, DNS record status, compliance, top senders, open action items and a trend sparkline for one domain. The figures may be up to an hour old.

- Permission: `domain:read`
- Key scope: `read`, `full`
- Budget: heavy route (https://dmarcguard.io/docs/rate-limits/#heavy-routes)

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `domain` (required) | `string` | A domain monitored by the organization. |

### Example request

```bash
curl "https://api.dmarcguard.io/api/v1/domains/example.com/health" \
  -H "Authorization: Bearer dg_your_key"
```

### Response

| Field | Type | Notes |
| --- | --- | --- |
| `domain` | `string` | The domain this report is about. |
| `overall_score` | `integer` | Composite health score for the domain, 0 to 100. |
| `grade` | `string` | Letter grade for overall_score: A+, A, A-, B+, B, B-, C+, C, C-, D or F, or N/A before the first report has been received. |
| `verdict` | `string` | A ready-to-show sentence summarising the domain's posture. Display it; its wording is not a value to branch on. |
| `last_report_date` | `string` (nullable) | Calendar day, YYYY-MM-DD (UTC); null when absent. |
| `total_messages` | `integer` | Messages reported for this domain in the scoring window. |
| `dns` | `object` | What a live DNS lookup found for each email-authentication record. |
| `dns.dmarc` | `object` | The domain's DMARC record. |
| `dns.dmarc.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.dmarc.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.dmarc.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.dmarc.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.dmarc.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.dmarc.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.spf` | `object` | The domain's SPF record. |
| `dns.spf.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.spf.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.spf.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.spf.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.spf.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.spf.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.dkim` | `object` | The domain's DKIM signing keys. |
| `dns.dkim.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.dkim.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.dkim.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.dkim.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.dkim.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.dkim.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.mta_sts` | `object` | The domain's MTA-STS policy. |
| `dns.mta_sts.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.mta_sts.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.mta_sts.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.mta_sts.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.mta_sts.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.mta_sts.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.tls_rpt` | `object` | The domain's TLS reporting record. |
| `dns.tls_rpt.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.tls_rpt.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.tls_rpt.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.tls_rpt.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.tls_rpt.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.tls_rpt.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.bimi` | `object` | The domain's BIMI record. |
| `dns.bimi.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.bimi.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.bimi.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.bimi.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.bimi.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.bimi.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `dns.dane` | `object` | DANE (TLSA) records for the domain's mail servers. |
| `dns.dane.status` | `string` | How the record stands: ok, warning when it exists but is not doing its job, error when it is missing or malformed, and unknown when nothing could be determined. |
| `dns.dane.details` | `string` | A ready-to-show sentence explaining the status. |
| `dns.dane.inherited_from` | `string` (optional) | The parent domain the record was found on, when this domain has none of its own. |
| `dns.dane.hosted_cta` | `object` (nullable, optional) | Link to host this protocol on DMARCguard, present when the record is missing or failing, or a hosted setup is still in progress. |
| `dns.dane.hosted_cta.label` | `string` | Short label for the link, ready to show. |
| `dns.dane.hosted_cta.url` | `string` | SPA path of the Hosted DNS page with this domain selected. |
| `compliance` | `object` | How this domain's mail authenticates. |
| `compliance.rate` | `number` | Percentage from 0 to 100 of this domain's messages that passed DMARC. |
| `compliance.spf_pass` | `number` | Percentage from 0 to 100 of this domain's messages with an aligned SPF pass. |
| `compliance.dkim_pass` | `number` | Percentage from 0 to 100 of this domain's messages with an aligned DKIM pass. |
| `compliance.policy` | `string` | The DMARC policy in force for the domain: none, quarantine or reject. |
| `top_senders` | `object[]` | The highest-volume senders for the domain, busiest first. |
| `top_senders[].ip` | `string` | The sending IP. |
| `top_senders[].count` | `integer` | Messages it sent as this domain. |
| `top_senders[].spf_result` | `string` | Whether SPF produced an aligned pass for its mail: pass or fail. |
| `top_senders[].dkim_result` | `string` | Whether DKIM produced an aligned pass for its mail: pass or fail. |
| `top_senders[].service_name` | `string` (optional) | The sending service the IP was identified as, when it is recognised. |
| `top_senders[].service_icon` | `string` (optional) | Icon slug for the identified service. |
| `top_senders[].service_slug` | `string` (optional) | Stable identifier of the identified service. |
| `alert_count` | `integer` | Open attention items for this domain. |
| `action_items` | `object[]` (nullable) | What to do next for this domain, most urgent first. It is a to-do list, not an inventory, so it is capped at a handful. |
| `action_items[].type` | `string` (optional) | What kind of problem this is. A gap the live DNS check found carries a dns_ prefix (dns_dmarc, dns_spf, dns_dkim, dns_mta_sts, dns_bimi); anything DMARCguard flagged carries the same type the events feed uses. |
| `action_items[].severity` | `string` | How urgent the item is: high, medium or low. |
| `action_items[].title` | `string` | One-line statement of the problem. |
| `action_items[].suggested_action` | `string` | What to do about it, ready to show. |
| `action_items[].cta_url` | `string` (optional) | Link to the screen where the item is resolved. |
| `action_items[].cta_label` | `string` (optional) | Label for that link. |
| `trend_sparkline` | `object[]` | One point per day for the trend line, oldest first. |
| `trend_sparkline[].date` | `string` (nullable) | Calendar day, YYYY-MM-DD (UTC); null when absent. |
| `trend_sparkline[].compliance_rate` | `number` | Percentage from 0 to 100 of the day's messages that passed DMARC. |
| `trend_sparkline[].total_messages` | `integer` | Messages reported for the day. |
| `empty_state` | `object` (nullable, optional) | What an empty action_items list means. Present only when the list is empty. |
| `empty_state.healthy` | `boolean` | True only when there is genuinely nothing wrong. False means the list is empty for some other reason, which the message gives. |
| `empty_state.message` | `string` | A ready-to-show sentence explaining why there is nothing to do. |
| `empty_state.cta_url` | `string` (optional) | Where to send the reader next, when there is somewhere useful. |
| `empty_state.cta_label` | `string` (optional) | Label for that link. |
| `computed_at` | `string` (nullable) | RFC 3339 UTC instant with whole seconds, e.g. 2026-09-15T16:03:43Z; null when absent. |

### Errors

| Status | When |
| --- | --- |
| `400` | The path segment is not a valid domain name. |
| `401` | Missing, malformed, revoked, expired or not-entitled API key. |
| `403` | The key's scope or its owner's role does not allow this operation. |
| `404` | The domain is not monitored by this organization. |
| `429` | Hourly quota or an abuse limit exceeded; the body's code says which. Honour Retry-After. |
| `500` | Unexpected server error; retry with backoff. |
| `503` | A transient failure resolving the organization or reading storage; retry after a short pause. |

Plus the errors every request can return: https://dmarcguard.io/docs/api/v1/#errors