Documentation

Learn how to integrate and use DDMARC.

Docs/API Reference
REST API v1

API Reference

Integrate DDMARC into your applications with our REST API. Manage domains, retrieve reports, and automate your email authentication workflow.

RESTful

JSON over HTTPS

API keys

X-API-Key or Bearer

Rate limited

Hourly, per plan

Scoped

read / write / admin

Base URL

https://api.ddmarc.com/api/v1

Every path on this page already includes the /api/v1 prefix, so a full URL looks like https://api.ddmarc.com/api/v1/domains. All requests must be made over HTTPS.

Authentication

Programmatic access uses an API key. Create and revoke keys in the dashboard under Settings → Organization → API Keys, or through the /api/v1/api-keys endpoints. Keys are shown once at creation and require the Protect plan or higher.

Preferred: X-API-Key header
X-API-Key: ddmarc_<64 hex characters>
Also accepted: Authorization header
Authorization: Bearer ddmarc_<64 hex characters>

The same Authorization: Bearer header also accepts a short-lived JWT access token from a dashboard sign-in. If both X-API-Key and Authorization are sent, the API key wins. See Authentication for key format, scopes and token lifetimes.

Keep your API key secure

Never expose your API key in client-side code or public repositories. Store it in a secrets manager and revoke keys you no longer use.

Example Request

cURL
curl -X GET "https://api.ddmarc.com/api/v1/domains?limit=100&offset=0" \
  -H "X-API-Key: $DDMARC_API_KEY"

Example Response

List endpoints return a bare JSON array — there is no data / meta envelope, and resource ids are integers.

200 OKapplication/json
[
  {
    "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"
  }
]

Endpoints

Path parameters shown in braces are integers, except {customer_public_id}, which is an opaque string.

Domains

MethodEndpointDescription
GET/api/v1/domainsList all domains
POST/api/v1/domainsAdd a new domain
GET/api/v1/domains/{domain_id}Get domain details
DELETE/api/v1/domains/{domain_id}Remove a domain
GET/api/v1/domains/{domain_id}/dns-checkCheck the domain's live DNS records
POST/api/v1/domains/{domain_id}/verifyVerify domain ownership
POST/api/v1/domains/{domain_id}/rotate-tokenRotate the domain's RUA/RUF tokens
GET/api/v1/domains/{domain_id}/recommendationsGet configuration recommendations

Full reference: Domains API.

Reports

MethodEndpointDescription
GET/api/v1/reportsList DMARC aggregate reports
GET/api/v1/reports/{report_id}Get report details
GET/api/v1/reports/stats/summaryGet aggregated report statistics
POST/api/v1/reports/uploadUpload a DMARC report file
GET/api/v1/reports/export/csvExport report records as CSV

Full reference: Reports API.

Dashboard analytics

MethodEndpointDescription
GET/api/v1/dashboard/statsGet summary statistics
GET/api/v1/dashboard/trendGet authentication trend over time
GET/api/v1/dashboard/geoGet geographic distribution
GET/api/v1/dashboard/heatmapGet volume heatmap data
GET/api/v1/dashboard/protocol-breakdownGet SPF/DKIM pass-rate breakdown
GET/api/v1/dashboard/top-sourcesGet the highest-volume sending sources
GET/api/v1/dashboard/policy-distributionGet policy distribution across domains
GET/api/v1/dashboard/compliance-scorecardGet the per-domain compliance scorecard

Aggregated analytics live under /dashboard. Most accept an optional domain_id and a dayswindow (1–365, capped to your plan's retention).

Senders

MethodEndpointDescription
GET/api/v1/sendersList all senders
GET/api/v1/senders/{sender_id}Get sender details
PATCH/api/v1/senders/{sender_id}Update a sender's category, display name or notes
PATCH/api/v1/senders/bulkBulk-update senders
GET/api/v1/senders/isp-analyticsGet ISP/provider breakdown statistics
GET/api/v1/senders/ip-trendsGet sender IP behaviour trends
GET/api/v1/senders/{sender_id}/reputationGet sender reputation detail
GET/api/v1/senders/{sender_id}/remediationGet suggested remediation for a sender

A sender's state is changed by sending a category value to PATCH /api/v1/senders/{sender_id}. There are no separate approve or reject endpoints.

Failure analysis

MethodEndpointDescription
GET/api/v1/failure-analysis/summaryGet failure totals and split by mechanism
GET/api/v1/failure-analysis/root-causesGet classified root causes with fix suggestions
GET/api/v1/failure-analysis/root-causes/by-sourceGet root causes grouped by sending source
GET/api/v1/failure-analysis/sourcesList failing sources
GET/api/v1/failure-analysis/spoof-clustersGet suspected spoofing campaign clusters
GET/api/v1/failure-analysis/by-header-fromGet failures grouped by spoofed From identity
GET/api/v1/failure-analysis/trendGet failure trend over time
GET/api/v1/failure-analysis/resolution-statsGet time-to-resolution statistics

Every endpoint accepts days(1–365, default 30) and an optional domain_id.

Forensic reports

MethodEndpointDescription
GET/api/v1/forensic-reportsList forensic (RUF) reports
GET/api/v1/forensic-reports/{report_id}Get forensic report details
GET/api/v1/forensic-reports/statsGet forensic summary statistics
DELETE/api/v1/forensic-reports/{report_id}Delete a forensic report

Forensic (RUF) reports require the Protect plan or higher.

DNS monitoring

MethodEndpointDescription
GET/api/v1/dns-monitoring/overviewGet DNS monitoring overview for all domains
GET/api/v1/dns-monitoring/healthGet DNS health across all domains
GET/api/v1/dns-monitoring/domains/{domain_id}/historyGet a domain's DNS record history
GET/api/v1/dns-monitoring/domains/{domain_id}/trendsGet a domain's DNS health trend
POST/api/v1/dns-monitoring/domains/{domain_id}/check-nowTrigger an immediate DNS check
PUT/api/v1/dns-monitoring/domains/{domain_id}/settingsUpdate a domain's monitoring settings

Managed policy

MethodEndpointDescription
GET/api/v1/domains/{domain_id}/policyGet the managed DNS policy for a domain
POST/api/v1/domains/{domain_id}/policyCreate a managed policy
PATCH/api/v1/domains/{domain_id}/policyUpdate a managed policy
POST/api/v1/domains/{domain_id}/policy/publishPublish the policy to DNS
GET/api/v1/domains/{domain_id}/simulate-policySimulate the impact of a policy change

Policy rollouts

MethodEndpointDescription
GET/api/v1/rolloutsList policy rollouts across domains
GET/api/v1/domains/{domain_id}/rolloutGet a domain's rollout status
POST/api/v1/domains/{domain_id}/rolloutCreate a rollout for a domain
POST/api/v1/domains/{domain_id}/rollout/startStart the rollout
POST/api/v1/domains/{domain_id}/rollout/pausePause the rollout
POST/api/v1/domains/{domain_id}/rollout/resumeResume a paused rollout
POST/api/v1/domains/{domain_id}/rollout/skipSkip to the next stage
POST/api/v1/domains/{domain_id}/rollout/rollbackRoll back to the previous stage
GET/api/v1/domains/{domain_id}/rollout/historyGet rollout stage history

A rollout belongs to a domain, so every mutating route is nested under /domains/{domain_id}/rollout. The bare /rollouts collection is read-only.

Alerts and alert rules

MethodEndpointDescription
GET/api/v1/alertsList alerts
POST/api/v1/alerts/{alert_id}/readMark an alert as read
POST/api/v1/alerts/read-allMark all alerts as read
PATCH/api/v1/alerts/{alert_id}/snoozeSnooze an alert
GET/api/v1/alerts/rulesList custom alert rules
POST/api/v1/alerts/rulesCreate a custom alert rule
PATCH/api/v1/alerts/rules/{rule_id}Update a custom alert rule
DELETE/api/v1/alerts/rules/{rule_id}Delete a custom alert rule
GET/api/v1/alerts/preferencesGet notification preferences
PATCH/api/v1/alerts/preferencesUpdate notification preferences
POST/api/v1/alerts/webhook/testSend a test webhook

Alert rules are created under /alerts/rules, not on the bare /alerts collection, which is read-only.

TLS-RPT

MethodEndpointDescription
GET/api/v1/tls-rptList TLS-RPT reports
GET/api/v1/tls-rpt/{report_id}Get TLS-RPT report details
GET/api/v1/tls-rpt/stats/summaryGet TLS-RPT summary statistics
POST/api/v1/tls-rpt/uploadUpload a TLS-RPT report file

SMTP TLS reporting requires the Protect plan or higher.

ARC monitoring

MethodEndpointDescription
GET/api/v1/arc-monitoring/overviewGet ARC monitoring overview
GET/api/v1/arc-monitoring/domains/{domain_id}/chainsList ARC chains for a domain
GET/api/v1/arc-monitoring/chains/{chain_id}Get ARC chain details
GET/api/v1/arc-monitoring/forwardersList known forwarders
POST/api/v1/arc-monitoring/forwardersAdd a trusted forwarder

ARC chain monitoring requires the Growth plan or higher.

Lookalike domains

MethodEndpointDescription
GET/api/v1/domains/{domain_id}/lookalikesList detected lookalike domains
POST/api/v1/domains/{domain_id}/lookalikes/scanTrigger a lookalike domain scan

Typosquat detection requires the Professional plan or higher.

API keys

MethodEndpointDescription
GET/api/v1/api-keysList API keys
POST/api/v1/api-keysCreate an API key
DELETE/api/v1/api-keys/{key_id}Revoke an API key

Key management is admin-only. See Authentication for scopes and per-plan key caps.

Team

MethodEndpointDescription
GET/api/v1/teamList team members
POST/api/v1/team/inviteInvite a team member
PATCH/api/v1/team/members/{user_id}/roleChange a member's role
DELETE/api/v1/team/members/{user_id}Remove a team member
DELETE/api/v1/team/invite/{invitation_id}Revoke a pending invitation

Activity log

MethodEndpointDescription
GET/api/v1/activityList activity log entries
GET/api/v1/activity/actionsList available activity action types
GET/api/v1/activity/export/csvExport the activity log as CSV

MSP Management

Partner Plan
MethodEndpointDescription
GET/api/v1/msp/customersList MSP customers
POST/api/v1/msp/customersCreate a new customer
GET/api/v1/msp/customers/{customer_public_id}/detailGet customer details
DELETE/api/v1/msp/customers/{customer_public_id}Delete a customer
GET/api/v1/msp/billingGet MSP billing summary
GET/api/v1/msp/brandingGet MSP branding config
PATCH/api/v1/msp/brandingUpdate MSP branding

MSP customer routes take {customer_public_id}, the customer's opaque public identifier — not an integer id.

Outbound notifications

There is no webhook CRUD resource. Outbound delivery is configured per user in notification preferences (GET / PATCH /api/v1/alerts/preferences) and fires when an alert is raised. You can send a probe to any URL with POST /api/v1/alerts/webhook/test. See Webhooks for the payload shape and the delivery guarantees that do and do not exist today.

Rate Limiting

API-key requests are metered hourly and pooled across your whole organization, not per key. There is no per-minute limit and no daily cap.

PlanRequest limitAPI keys
MonitorNo API access
Protect1,000 requests / hour1 key
Growth5,000 requests / hour3 keys
Professional10,000 requests / hour10 keys
Partner Starter25,000 requests / hourUnlimited
Partner25,000 requests / hourUnlimited
EnterpriseCustomUnlimited

Exceeding the cap returns 429 with a Retry-After: 3600 header. The API does not emit X-RateLimit-*headers, so do not rely on them for client-side budgeting — track your own request count, or back off when you see a 429.

Errors

CodeStatusDescription
400Bad RequestInvalid request parameters
401UnauthorizedMissing, invalid or expired API key
403ForbiddenKey scope too low, or the feature is not on your plan
404Not FoundResource not found, or not owned by your organization
422Unprocessable EntityRequest body or query failed validation
429Too Many RequestsHourly rate limit exceeded; see Retry-After
500Internal ErrorServer error - quote the request_id to support
Error body
{
  "detail": "Invalid API key"
}
Unhandled 500
{
  "detail": "Internal server error",
  "request_id": "9f2b41c7-..."
}

Validation failures (422) use FastAPI's structured form, where detail is an array of field errors rather than a string.

Client libraries

DDMARC does not publish official SDKs. The API is plain JSON over HTTPS with a single authentication header, so any HTTP client works — curl, fetch, requests, or your language's equivalent. If you need a generated client, the running API serves its own OpenAPI schema.

Explore More