DMARC Engine
Home/Documentation/API reference
Documentation

API reference

Use the DMARC Engine API to automate everything the dashboard does. This reference covers creating and managing API keys in Settings, choosing read versus read-write permissions, regenerating and deleting keys, authenticating with the X-Api-Key header, the CSRF rule for browser sessions, and a full, example-driven tour of every endpoint group: domains, DNS records, analytics, reports, alerts, settings and utilities.

21 June 2026 · 15 min read

What the API is for

DMARC Engine has a full HTTP API behind the dashboard. Anything you can do by clicking, you can also do with a script: list your domains, read their DMARC, SPF, DKIM, MTA-STS and BIMI configuration, pull aggregate-report analytics, raise or resolve alerts, manage your team and read your billing history. The dashboard at https://app.dmarcengine.com calls exactly these endpoints, so there is no second-class "public" API; you reach the same surface the product itself uses.

This reference covers the two things you need to use it well: how to create and manage an API key from your account settings, and what each group of endpoints does, with copy-and-paste examples. It assumes you are already set up. If you have not added a domain yet, start with getting started and adding your first domain, then come back here to automate.

The API is for automation and integration: provisioning domains from your own onboarding flow, exporting compliance data into a warehouse or a dashboard of your own, wiring alerts into a system that does not speak one of the built-in channels, or scripting a bulk change across many domains. For one-off checks you do not need a key at all; the free DMARC checker, SPF checker, DKIM checker, MTA-STS checker and BIMI checker run read-only lookups in the browser.

The base URL for every endpoint is:

https://app.dmarcengine.com

Every path below is relative to that base. So GET /api/domains means GET https://app.dmarcengine.com/api/domains.

Creating an API key

API keys live in your account settings, on a dedicated tab. To get there, open the dashboard, click your account area and go to Settings. Settings is split into seven tabs across the top: Profile, Organization, Security, Notifications, API Keys, Team and Billing. Select API Keys.

The API Keys tab shows a table of every key on your organisation. The columns are:

  • Name: the human label you gave the key, so you can tell one from another.
  • Permissions: whether the key is read (it can fetch data but not change anything) or read-write (it can also create, update and delete).
  • Created: when the key was made.
  • Last used: when the key last authenticated a request, which is the quickest way to spot a key nothing is using any more.
  • Per-row actions to Regenerate or Delete the key.

To make a new one, click Create API Key. A modal opens with these fields:

  1. Key Name: a short, descriptive label, for example ci-deploy or analytics-export. Choose something that tells future-you what the key is for; you cannot see the secret again later, so the name is how you will recognise it.
  2. Permissions: a set of checkboxes that decide what the key may do. Grant the minimum the integration needs. If a script only reads analytics, give it read access and leave write off. A key that has to create domains or change DNS needs write.

Click create, and the modal shows you the raw key once, and only once. This is the single most important thing to understand about the whole flow: the full secret is displayed a single time, at the moment of creation, and is never shown again. Only a SHA-256 hash of the key is stored, so even DMARC Engine cannot reveal it later. Copy it immediately and store it somewhere safe (a secrets manager, your CI provider's encrypted variables, a password manager). If you close the modal without copying it, the key is not recoverable; you will have to delete it and create another. The table afterwards shows only the name and metadata, never the secret.

Treat an API key like a password. Anyone holding it can act on your organisation with whatever permissions you granted. Do not commit keys to source control, paste them into chat, or email them. Keep separate keys for separate uses so you can revoke one without breaking the others.

Permissions: read versus read-write

The permission you pick maps directly onto the HTTP method an endpoint uses:

  • A read key can call GET endpoints. It can list domains, read a DMARC record, pull analytics and so on. It cannot change anything.
  • A read-write key can additionally call the mutating methods (POST, PUT, PATCH, DELETE). That is what you need to add a domain, edit an SPF record, create a DKIM selector or resolve an alert.

Some endpoints are admin-only regardless of the key's read or write setting, because they touch the organisation itself: changing organisation settings, managing team members and managing API keys. Those require a key (or session) belonging to an admin. See team and roles for how admin, editor and viewer differ.

Regenerating and deleting keys

Two actions sit on every row of the API Keys table.

  • Regenerate issues a fresh secret for the same key entry, keeping its name and permissions, and invalidates the old secret straight away. Use this when a key may have leaked, or on a routine schedule, without having to repoint everything to a new name. As with creation, the new secret is shown once; copy it and update wherever the key is stored, because the old value stops working the instant you regenerate.
  • Delete removes the key entirely and permanently. Any request still using it will start failing with an authentication error. Use this to retire an integration for good. The Last used column is your friend here: a key that has not been used in months is usually safe to delete.

There is no separate "disable" state; the model is deliberately simple. To rotate, regenerate. To retire, delete.

Authenticating your requests

There are two ways to authenticate, and which one you use depends on whether you are a browser or a script.

  • Session cookie. When you sign in to the dashboard, the server sets a session cookie that the browser sends on every request automatically. This is how the dashboard itself is authenticated. You will not use this from a script.
  • API key. For your own integrations, send the key in the x-api-key request header. This is the method to use everywhere outside the browser.

A minimal authenticated call looks like this:

curl https://app.dmarcengine.com/api/domains \
  -H "x-api-key: YOUR_API_KEY"

The CSRF rule (browser sessions only)

There is one extra rule that catches people out, so it is worth stating plainly. Mutating requests (POST, PUT, PATCH, DELETE) that authenticate with a session cookie must also send an X-CSRF-Token header whose value matches the csrf cookie set at login. This is a cross-site-request-forgery protection for the browser.

It does not apply to API-key requests. If you authenticate with x-api-key, you do not need a CSRF token at all, for any method. So for scripting, use an API key and ignore CSRF entirely; it is only relevant if you are driving the product through a logged-in browser session.

What unauthenticated requests get

Almost every endpoint requires authentication. The exceptions are the health checks and the authentication endpoints themselves (signup, login, password reset). Everything else returns an authentication error if the key is missing, wrong, deleted or regenerated out from under you.

Reading the endpoint list

The sections below group the endpoints by what they touch. Where an endpoint accepts a request body, it is JSON. Path parameters are written :id and mean a domain identifier you got back from a list call. Query parameters are listed where they apply.

A note on method notation: GET/PUT /api/domains/:id/dmarc means the same path answers both a GET (read the current value) and a PUT (replace it). Read keys can use the GET; only read-write keys can use the PUT.

Auth endpoints

These manage sessions and passwords. Scripts rarely need them, because an API key already authenticates you, but they are listed for completeness and for anyone building a sign-in flow on top of the platform.

  • POST /api/auth/signup creates a new organisation and its first admin user. Body: { "orgName": "Acme Inc", "name": "John", "email": "john@acme.com", "password": "..." }.
  • POST /api/auth/login signs a user in. Body: { "email": "john@acme.com", "password": "..." }. It returns the user and organisation, and sets the session and csrf cookies described above.
  • POST /api/auth/logout destroys the current session.
  • GET /api/auth/me returns the currently authenticated user. Handy as a quick "is this credential valid?" probe.
  • POST /api/auth/forgot-password starts a password reset. Body: { "email": "john@acme.com" }. It always returns { "sent": true }, on purpose, so that an outsider cannot use it to discover which emails have accounts. It is rate limited to three requests a minute.
  • POST /api/auth/reset-password completes the reset with the token from the email. Body: { "token": "...", "password": "newpassword" }.

Domain endpoints

This is the core of the API: the domains you protect and their lifecycle.

  • GET /api/domains lists every domain on your organisation. This is usually your first call, because the id of each domain is what the per-domain endpoints below need.
  • POST /api/domains adds a domain. Body: { "domain": "example.com", "group": "Production" }. The group is the optional domain group it belongs to, the same grouping you see in the dashboard. This is the scripted equivalent of the add-domain wizard in adding your first domain.
  • GET /api/domains/:id returns one domain in full, including the status of each of its five services. Use it to check, for example, whether DKIM is verified before you flip a policy.
  • DELETE /api/domains/:id removes a domain from your account.
  • POST /api/domains/:id/verify triggers verification of domain ownership via the DNS TXT record. Call it after you have published the verification token the platform gave you. Verification is covered in delegating your DNS.

Here is the create-then-verify pair in practice:

# Add a domain
curl https://app.dmarcengine.com/api/domains \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "example.com", "group": "Production" }'

# After publishing the TXT token, verify ownership
curl -X POST https://app.dmarcengine.com/api/domains/DOMAIN_ID/verify \
  -H "x-api-key: YOUR_API_KEY"

DNS record endpoints

These read and write the actual authentication records for a domain. Each maps to one of the five standards and to its dashboard page.

  • GET/PUT /api/domains/:id/dmarc reads or replaces the DMARC policy. The PUT body looks like { "policy": "reject", "subdomain_policy": "reject", "pct": 100, "rua": "mailto:dmarc@example.com" }, where policy is the main policy (none, quarantine or reject), subdomain_policy is the policy for subdomains, pct is the percentage of mail the policy applies to, and rua is where aggregate reports are sent. Treat changes here with care; moving policy to reject enforces. The background is in hosted DMARC and understanding your DMARC record, and the safe path is in the enforcement journey.
  • GET/PUT /api/domains/:id/spf reads or replaces the SPF mechanisms. The PUT body carries a mechanisms array, for example { "mechanisms": [{"type": "include", "value": "_spf.google.com", "qualifier": "+"}] }. The platform handles flattening and the ten-lookup limit for you; see hosted SPF and how SPF flattening works.
  • GET/POST/PATCH/DELETE /api/domains/:id/dkim lists, creates, updates and removes DKIM selectors. DKIM key pairs are generated in your browser (via WebCrypto): the private key is shown to you once and is never sent to or stored by DMARC Engine, so you install it in your own sending platform, which does the signing. DMARC Engine publishes only the public key through the CNAME delegation. Because of this, the POST body must include the public key you generated: { "selector": "google", "keyType": "rsa", "keySize": 2048, "publicKey": "..." }. The PATCH method toggles the RFC 6376 t=y testing flag on an existing selector, which lets you run a new selector in test mode before you rely on it. More on how this works in hosted DKIM.
  • GET/PUT /api/domains/:id/mtasts reads or replaces the MTA-STS policy. See hosted MTA-STS.
  • GET/PUT /api/domains/:id/bimi reads or replaces the BIMI record. BIMI only displays once DMARC is enforced; see hosted BIMI.

A read of one record is as simple as:

curl https://app.dmarcengine.com/api/domains/DOMAIN_ID/dmarc \
  -H "x-api-key: YOUR_API_KEY"

A full reference for the values these records can hold is in the DNS record reference, and if a tag is unfamiliar the glossary explains it.

Analytics endpoints

This is where you export the data behind the home screen and the analytics page.

  • GET /api/analytics/stats returns aggregate-report statistics. Query parameters: domainId to scope to one domain, startDate and endDate to set the window, and type which selects the shape of the data: daily for the day-by-day pass and fail trend, sources for a breakdown by sending source, and geo for a breakdown by geography.
  • POST /api/analytics/ingest ingests stats manually, for advanced cases where you are feeding data in yourself rather than relying on the receivers' reports.

To pull the last month of daily figures for one domain:

curl "https://app.dmarcengine.com/api/analytics/stats?domainId=DOMAIN_ID&type=daily&startDate=2026-05-23&endDate=2026-06-22" \
  -H "x-api-key: YOUR_API_KEY"

If you have a raw report you want to read rather than ingest programmatically, the browser-based DMARC report analyzer does it without a key.

Reports endpoints

  • GET/POST/DELETE /api/reports lists, schedules and removes scheduled reports, the same recurring summaries you can configure in the dashboard.
  • POST /api/reports/upload uploads a DMARC aggregate (RUA) report so the platform can parse it into your analytics. It accepts application/xml for a plain report or application/gzip for the compressed form that most receivers send.

Alerts endpoints

These drive the alerting you would otherwise manage in the dashboard. The full feature is documented in setting up alerts.

  • GET /api/alerts lists alerts. Query parameters: status (active, acknowledged or resolved), plus limit and offset for paging.
  • POST /api/alerts creates an alert.
  • PATCH /api/alerts updates an alert's status, for example { "alertId": "...", "status": "resolved" }. This is how you resolve an alert from a script once you have dealt with whatever it flagged.
  • GET/POST/PATCH /api/alerts/rules lists, creates and updates alert rules, the conditions that decide when an alert fires in the first place.

Settings endpoints

These mirror the Settings tabs. Several are admin-only for the mutating method, as noted.

  • GET/PATCH /api/settings/org reads or updates organisation settings, the same fields as the Organization tab (Organization Name, Organization Email, Timezone). The PATCH is admin-only.
  • GET/POST/DELETE /api/settings/team lists, invites and removes team members, mirroring the Team tab. The POST and DELETE are admin-only. Roles are covered in team and roles.
  • GET/POST/PATCH /api/settings/api-keys manages API keys, the programmatic version of the API Keys tab you used above. It supports limit and offset paging, and the POST and PATCH are admin-only. As in the UI, the secret is only returned at creation.
  • GET/POST /api/settings/channels lists and creates outbound notification channels of type email, slack, webhook or pagerduty, matching Create Notification Channel on the Notifications tab. These are the channels alerts are pushed to; there are no inbound webhooks, so for automation poll the REST endpoints above.
  • GET /api/settings/billing returns your billing history, the same read-only invoice records shown on the Billing tab. Signup is free and self-serve and your account is fully usable without payment; there is no in-product checkout or plan management, so to change or cancel a paid arrangement you contact the team.

The remaining Settings tabs, Profile (your Profile Name and read-only Email) and Security (two-factor authentication, sessions, password change and the login activity log), are managed in the dashboard rather than through these endpoints. For hardening your own access, see security and 2FA.

Other endpoints

A handful of utility endpoints round things out.

  • GET /api/threats lists threat events. Query parameters: severity, domainId, limit, offset. This is the data behind the Threat events detected figure and the threats view.
  • GET /api/audit returns the audit log of who did what. Query parameters: userId, action, limit, offset.
  • GET /api/lookup runs a live DNS lookup, the same read-back the dashboard's DNS Check uses. Query parameters: domain and type. The type values are case-sensitive and must be one of DMARC, SPF, DKIM, MTA-STS, BIMI, MX or TLS-RPT. This is read-only and a quick way to confirm what is actually published.
  • GET /api/health is a basic health check (database connectivity). It needs no authentication.
  • GET /api/health/ready is a fuller readiness check across all of the platform's bindings, also unauthenticated. Use either for uptime monitoring.

Handling errors and limits

A few habits will keep an integration healthy:

  • Check the status code, not just the body. A 2xx is success. A 401 or 403 means your key is missing, wrong, deleted, regenerated, or lacks the permission or admin rights the call needs; re-read the permissions section above. A 404 usually means a domain id that does not belong to your organisation. A 429 means you are being rate limited (the forgot-password endpoint, for instance, allows three a minute); back off and retry.
  • Send Content-Type: application/json on any request with a body, and send valid JSON. The upload endpoint is the exception, taking application/xml or application/gzip.
  • Page through lists. Endpoints that take limit and offset will not hand you everything at once on a large account; loop until you have read the lot.
  • Fail safe on writes. The DNS endpoints change live records that decide whether your mail is trusted. Read the current value first, change one thing, and verify the result, especially before moving DMARC towards reject.

Putting it together

A typical first integration reads like a short script: list your domains, pick one, read its DMARC, pull a month of daily analytics, and resolve any alert you have handled. Each of those is one of the calls above, authenticated with a single x-api-key header from a key you created on the API Keys tab with exactly the permissions it needs.

When you are ready to go further, the per-standard docs explain what good configuration looks like before you automate it: hosted DMARC, hosted SPF, hosted DKIM, hosted MTA-STS and hosted BIMI. For the product overview of what you are automating, see the products. And whenever you just need to check a domain by hand, the free tools are always there, no key required.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.