API Reference

Pull DMARC data into your own tools. Build alerts, dashboards, and automations that fit your workflow.

The DMARCTrust dashboard shows you what is happening with your email authentication. The API lets you act on it. Pull your DMARC data into Slack, your SIEM, a cron job, or a custom dashboard, whatever your team already uses.

What people build with this API

Slack/Teams alerts when a new sender starts using your domain or authentication failures spike
SIEM integration to feed DMARC source data into Splunk, Datadog, or Grafana
Automated domain onboarding for MSPs managing hundreds of client domains
Scheduled CSV exports of daily stats and source data for compliance reporting
DNS health checks in CI/CD pipelines to catch misconfigurations before they go live

Prerequisites

  • An active DMARCTrust subscription (Starter or Pro plan)
  • At least one domain configured in your account

Getting started

Generate an API key

Go to Settings in your dashboard and scroll to the API keys section. Click Create API key, give it a name that describes its purpose (e.g., "Slack bot" or "Nightly export"), and copy the key. It is only shown once.

dt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Store this key in an environment variable or secrets manager. Do not commit it to source control.

Make your first request

Test your key by fetching your account info:

curl -H "Authorization: Bearer YOUR_API_KEY" \ https://www.dmarctrust.com/api/v1/account

Response:

{ "data": { "id": "usr_123", "email": "[email protected]", "reporting_address": "[email protected]", "subscription": { "plan": "pro", "status": "active", "included_domains": 5, "extra_domains": 1, "total_allowed_domains": 6, "active_domains": 4, "retention_days": 180, "current_period_end": "2026-04-15T00:00:00Z" }, "usage": { "reports_30d": 156, "messages_30d": 12847 } }, "meta": { "request_id": "abc123-def456-..." } }

Authentication

Every request requires a Bearer token in the Authorization header:

Authorization: Bearer dt_live_your_api_key_here

Missing or invalid keys return 401. Expired subscriptions return 403.

Rate limits

Client type Limit
Authenticated (with API key) 30 requests/minute
Unauthenticated 2 requests/minute per IP

When rate limited, you get a 429 response with a retry_after field (seconds) and rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Endpoints

Base URL: https://www.dmarctrust.com/api/v1

Account

GET /account

Returns your account details, subscription status, and 30-day usage statistics.

Domains

List all domains

GET /domains

Returns all domains in your account with their DNS status and activation state.

{ "data": [ { "id": "ud_19", "domain": "example.com", "active": true, "dns_status": "valid", "dns_status_message": "DNS Verified", "activated_at": "2025-10-13T08:58:52Z", "created_at": "2025-10-13T08:58:48Z", "reporting_address": "[email protected]" } ], "meta": { "total_count": 4, "has_more": false, "next_cursor": null } }

Get a single domain

GET /domains/:id

Returns full details for one domain, including 30-day statistics.

Add a domain

POST /domains

Body: {"domain": "newdomain.com"}

Creates the domain in a deactivated state. A DNS check is triggered automatically. Activate it once DNS is verified.

Domain actions

  • POST /domains/:id/activate — start receiving reports for this domain
  • POST /domains/:id/deactivate — stop report processing
  • POST /domains/:id/refresh_dns — trigger an immediate DNS check

Domain DNS records

GET /domains/:id/dns

Returns the current DMARC, SPF, and BIMI DNS records for a domain.

{ "data": { "domain": "example.com", "last_checked_at": "2025-01-17T16:20:01Z", "dmarc": { "status": "valid", "record": "v=DMARC1; p=quarantine; rua=mailto:...", "policy": "quarantine", "dmarctrust_configured": true }, "spf": { "status": "valid", "record": "v=spf1 include:_spf.google.com -all", "all_mechanism": "-all" }, "bimi": { "status": "valid", "record": "v=BIMI1; l=https://example.com/logo.svg" } } }

Domain statistics

GET /domains/:id/stats
Parameter Default Description
start_date 30 days ago Start date (YYYY-MM-DD)
end_date today End date (YYYY-MM-DD)

Dates are clamped to your plan's retention period. A Starter plan with 90-day retention cannot query data older than 90 days.

Domain sources

GET /domains/:id/sources

Returns email sources grouped by sender domain, with message counts, disposition breakdown (accepted/quarantined/rejected), alignment percentages, and per-IP details.

Parameter Default Description
range 7d Time range: "48h", "7d", or "30d"
date Specific date (YYYY-MM-DD), overrides range

Reports

List reports

GET /reports

Returns DMARC aggregate reports received for your domains.

Parameter Description
domain_id Filter by domain ID (e.g., "ud_19")
domain Filter by domain name (partial match)
sender_org Filter by sender organization (partial match)
start_date Filter reports after this date (YYYY-MM-DD)
end_date Filter reports before this date (YYYY-MM-DD)
limit Results per page (default: 25, max: 100)
cursor Pagination cursor from previous response

Get report details

GET /reports/:id

Returns a single report with all record entries: source IPs, hostnames, and per-record SPF/DKIM/DMARC results.

Pagination

List endpoints use cursor-based pagination. The meta object tells you if there are more results:

{ "meta": { "total_count": 915, "has_more": true, "next_cursor": "eyJpZCI6OTE0LC..." } }

Pass the cursor to get the next page:

GET /reports?cursor=eyJpZCI6OTE0LC...

ID formats

Resources use prefixed IDs so you can tell them apart at a glance:

Resource Prefix Example
User usr_ usr_123
Domain ud_ ud_19
Report rpt_ rpt_915

Both prefixed and raw numeric IDs work: GET /domains/ud_19 and GET /domains/19 return the same result.

Error handling

All errors return a JSON object with a machine-readable code and a human-readable message:

{ "error": { "code": "not_found", "message": "The requested resource could not be found", "request_id": "abc123-..." } }
HTTP status Code Meaning
400 bad_request Malformed request or invalid parameters
401 invalid_api_key API key is missing or invalid
403 subscription_required No active subscription
403 retention_exceeded Data is outside your plan's retention window
404 not_found Resource does not exist or is not in your account
422 unprocessable_entity Validation failed (e.g., invalid domain format)
429 rate_limit_exceeded Too many requests. Check retry_after field.

Include the request_id when contacting support. It lets us find your exact request in our logs.

Integration examples

Slack alert for DMARC failures

This Python script checks for authentication failures in the last 48 hours and posts a summary to Slack. Run it as a daily cron job.

import requests, json, os API_KEY = os.environ["DMARCTRUST_API_KEY"] SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"] BASE = "https://www.dmarctrust.com/api/v1" headers = {"Authorization": f"Bearer {API_KEY}"} # Get all domains domains = requests.get(f"{BASE}/domains", headers=headers).json()["data"] alerts = [] for d in domains: resp = requests.get( f"{BASE}/domains/{d['id']}/sources", headers=headers, params={"range": "48h"} ).json()["data"] for src in resp["sources"]: rejected = src.get("rejected", 0) quarantined = src.get("quarantined", 0) if rejected + quarantined > 0: alerts.append( f"*{d['domain']}*: {src['sender_domain']} " f"({rejected} rejected, {quarantined} quarantined)" ) if alerts: requests.post(SLACK_WEBHOOK, json={ "text": f"DMARC failures (last 48h):\n" + "\n".join(alerts) })

Export daily stats to CSV

Pull 30 days of per-domain statistics and write them to a CSV file. Useful for compliance reports or feeding data into a spreadsheet.

import requests, csv, os API_KEY = os.environ["DMARCTRUST_API_KEY"] BASE = "https://www.dmarctrust.com/api/v1" headers = {"Authorization": f"Bearer {API_KEY}"} domains = requests.get(f"{BASE}/domains", headers=headers).json()["data"] with open("dmarc_stats.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["domain", "date", "total", "spf_pass", "spf_fail", "dkim_pass", "dkim_fail"]) for d in domains: stats = requests.get( f"{BASE}/domains/{d['id']}/stats", headers=headers ).json()["data"]["daily_stats"] for day in stats: writer.writerow([ d["domain"], day["date"], day["total_messages"], day["spf_pass"], day["spf_fail"], day["dkim_pass"], day["dkim_fail"] ])

DNS health check in a shell script

Check all domains and exit with a non-zero status if any DNS record is invalid. Plug this into a CI/CD pipeline or a monitoring cron.

#!/bin/bash set -e API_KEY="${DMARCTRUST_API_KEY}" BASE="https://www.dmarctrust.com/api/v1" ERRORS=0 DOMAINS=$(curl -s -H "Authorization: Bearer $API_KEY" "$BASE/domains" | jq -r '.data[] | .id') for ID in $DOMAINS; do DNS=$(curl -s -H "Authorization: Bearer $API_KEY" "$BASE/domains/$ID/dns") DOMAIN=$(echo "$DNS" | jq -r '.data.domain') DMARC_STATUS=$(echo "$DNS" | jq -r '.data.dmarc.status') SPF_STATUS=$(echo "$DNS" | jq -r '.data.spf.status') if [ "$DMARC_STATUS" != "valid" ] || [ "$SPF_STATUS" != "valid" ]; then echo "FAIL: $DOMAIN (DMARC=$DMARC_STATUS, SPF=$SPF_STATUS)" ERRORS=$((ERRORS + 1)) fi done if [ $ERRORS -gt 0 ]; then echo "$ERRORS domain(s) have DNS issues" exit 1 fi echo "All domains healthy"

Client libraries

There is no official SDK. The API uses standard REST conventions, so any HTTP client works. Here are starter examples in three languages.

Python

import requests, os API_KEY = os.environ["DMARCTRUST_API_KEY"] BASE_URL = "https://www.dmarctrust.com/api/v1" headers = {"Authorization": f"Bearer {API_KEY}"} # List domains domains = requests.get(f"{BASE_URL}/domains", headers=headers).json()["data"] for d in domains: print(f"{d['domain']}: {d['dns_status']}") # Get reports for a specific domain reports = requests.get( f"{BASE_URL}/reports", headers=headers, params={"domain_id": "ud_19", "limit": 50} ).json()["data"]

JavaScript (Node.js)

const API_KEY = process.env.DMARCTRUST_API_KEY; const BASE_URL = "https://www.dmarctrust.com/api/v1"; async function apiGet(path, params = {}) { const url = new URL(`${BASE_URL}${path}`); Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v)); const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } }); if (!res.ok) throw new Error(`API error: ${res.status}`); return res.json(); } // List domains const { data: domains } = await apiGet("/domains"); // Get sources for a domain (last 48 hours) const { data: sources } = await apiGet(`/domains/${domains[0].id}/sources`, { range: "48h" });

Ruby

require "net/http" require "json" API_KEY = ENV.fetch("DMARCTRUST_API_KEY") BASE_URL = "https://www.dmarctrust.com/api/v1" def api_get(endpoint, params = {}) uri = URI("#{BASE_URL}#{endpoint}") uri.query = URI.encode_www_form(params) if params.any? req = Net::HTTP::Get.new(uri) req["Authorization"] = "Bearer #{API_KEY}" res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) } JSON.parse(res.body) end # List domains domains = api_get("/domains") domains["data"].each { |d| puts "#{d['domain']}: #{d['dns_status']}" } # Get DNS records dns = api_get("/domains/ud_19/dns") puts "DMARC: #{dns.dig('data', 'dmarc', 'status')}"

Managing API keys

All your keys are listed in Settings > API keys. For each key you can see the name, the first 12 characters (so you can identify it), when it was created, and when it was last used.

To revoke a key, click the trash icon next to it. Revoked keys stop working immediately. Any application using that key will get 401 responses.

Security practices

  • Use one key per application so you can revoke them independently.
  • Store keys in environment variables, not in code. Never commit them to git.
  • Rotate keys periodically. Create the new key, update your application, then revoke the old one.
  • Check "last used" dates to find unused keys and clean them up.

Need help? Include the request_id from error responses when contacting support. It lets us find your exact request in our logs.

Was this page helpful? Send us feedback

Last updated: April 2026