---
title: "DMARCguard API v1"
description: "Read your organization's DMARC data programmatically. Authenticate with an API key, page with limit and offset, and watch the rate-limit headers."
---
# DMARCguard API v1

Read your organization's DMARC data programmatically. Authenticate with an API key, page with limit and offset, and watch the rate-limit headers.

## Base URL and versioning

Every path in this reference is relative to `https://api.dmarcguard.io/api/v1`. The version segment is part of the contract: fields are only added within a version, never renamed or removed. A breaking change ships as a new version at a new base URL, and the old one keeps serving.

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

OpenAPI document: https://dmarcguard.io/docs/api/v1/openapi.json. API catalog for automated discovery: https://dmarcguard.io/.well-known/api-catalog

## Authentication

Send an API key as a bearer token. Keys start with `dg_`, are bound to one organization and carry a scope (`read` or `full`) that narrows what the owner's role allows. Each endpoint lists the permission it checks and the scopes that satisfy it. See the authentication guide: https://dmarcguard.io/docs/authentication/

## Conventions

- **IDs** are opaque strings (Crockford Base32). Never parse one as a number.
- **Timestamps** are RFC 3339 in UTC with whole seconds, e.g. `2026-09-15T16:03:43Z`, never another offset and never fractional seconds. A field naming a calendar day rather than a moment (a trend bucket, a snapshot date, a date-range bound, a last-report date) is an RFC 3339 full date: `2026-09-15`. An absent value is `null`, never `0` and never `""`. Two exceptions: the report object inside `GET /reports/{id}` keeps the reporter's own epoch seconds, since it is passed through exactly as sent, and `X-RateLimit-Reset` stays epoch seconds, the convention for that header everywhere.
- **Rates** such as `compliance_rate` are percentages from 0 to 100, not fractions.
- **Paging**: every list endpoint (reports, sources, events, domains and top sending IPs) returns an envelope holding the rows under their own key plus `total`, `limit` and `offset`. `total` counts everything matching the filter before paging, so it is what you page through, while `limit` and `offset` are the values the server actually applied, so a limit above 200 comes back clamped to 200. Reports and sources also carry `has_any`, which ignores the filter: use it to tell a page that matched nothing apart from an organization with no data yet.
- **Empty lists**: a list is always an array. An empty list is `[]`, never `null`.
- **Rate limits** are reported on every metered response on a plan with an hourly quota, in the X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, RateLimit-Policy, RateLimit headers, and `Retry-After` on a rejection. The rate limits guide explains the budgets: https://dmarcguard.io/docs/rate-limits/
- **Methods**: every documented operation is a GET; any other method returns 405 with an `Allow` header and no body.
- **Unknown paths**: a path that is not in this reference returns 404 with the error shape below.

## Errors

Every non-2xx response is JSON with this shape, except a 405, which has no body. The `error` text is for people; branch on `code` when one is present.

| Field | Type | Notes |
| --- | --- | --- |
| `error` | `string` | Human-readable, title-cased reason. |
| `code` | `string` (optional) | Optional machine-readable discriminator, e.g. quota_exceeded. |
| `required` | `string` (optional) | The permission the request lacked; present only on a permission denial. |

| 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. |

A `429` carries `code` `rate_limited` when an abuse control rejected the request (back off for `Retry-After`) and `quota_exceeded` when the hourly quota is spent (nothing helps before `X-RateLimit-Reset`).

## Endpoints

### Reports

Aggregate (RUA) reports as received, parsed and classified.

Markdown: https://dmarcguard.io/docs/api/v1/reports.md

- `GET` `/reports` List aggregate reports (https://dmarcguard.io/docs/api/v1/reports/#listReports)
- `GET` `/reports/date-range` Report date range (https://dmarcguard.io/docs/api/v1/reports/#getReportDateRange)
- `GET` `/reports/{id}` Get one aggregate report (https://dmarcguard.io/docs/api/v1/reports/#getReport)

### Analytics

Organization-wide and per-domain rollups computed by DMARCguard.

Markdown: https://dmarcguard.io/docs/api/v1/analytics.md

- `GET` `/dashboard/overview` Organization overview (https://dmarcguard.io/docs/api/v1/analytics/#getDashboardOverview)
- `GET` `/statistics` Message statistics (https://dmarcguard.io/docs/api/v1/analytics/#getStatistics)
- `GET` `/compliance-score` Compliance score (https://dmarcguard.io/docs/api/v1/analytics/#getComplianceScore)
- `GET` `/compliance-score/history` Compliance score history (https://dmarcguard.io/docs/api/v1/analytics/#getComplianceScoreHistory)
- `GET` `/trends` Daily message trends (https://dmarcguard.io/docs/api/v1/analytics/#getTrends)
- `GET` `/top-sources` Top sending IPs (https://dmarcguard.io/docs/api/v1/analytics/#listTopSources)

### Domains

The domains you monitor and their health.

Markdown: https://dmarcguard.io/docs/api/v1/domains.md

- `GET` `/domains` List domains (https://dmarcguard.io/docs/api/v1/domains/#listDomains)
- `GET` `/domains/{domain}/health` Domain health (https://dmarcguard.io/docs/api/v1/domains/#getDomainHealth)

### Sources

Who sends mail as your domains, and whether they should.

Markdown: https://dmarcguard.io/docs/api/v1/sources.md

- `GET` `/sources` List sending sources (https://dmarcguard.io/docs/api/v1/sources/#listSources)
- `GET` `/sources/{ip}` Get one sending source (https://dmarcguard.io/docs/api/v1/sources/#getSource)

### Events

Conditions that needed attention and whether they were acknowledged.

Markdown: https://dmarcguard.io/docs/api/v1/events.md

- `GET` `/events` List events (https://dmarcguard.io/docs/api/v1/events/#listEvents)

### API keys

How much of the hourly budget the organization's keys have used.

Markdown: https://dmarcguard.io/docs/api/v1/api-keys.md

- `GET` `/api-keys/usage` API usage (https://dmarcguard.io/docs/api/v1/api-keys/#getAPIKeyUsage)

### Vocabulary

The enumerations other responses use, keyed by category: verification states, severities, grades, policies and reputation.

Markdown: https://dmarcguard.io/docs/api/v1/vocabulary.md

- `GET` `/enums` List enumerations (https://dmarcguard.io/docs/api/v1/vocabulary/#listEnums)