Endpoint reference

Six endpoints. Base URL https://api.deliversight.com.

EndpointReturnsAuth
POST /v1/testsa new test addresskey, scope tests:write
GET /v1/testsyour testskey, scope tests:read — or a dashboard session
GET /v1/tests/{token}one test’s deliverability reportkey, scope tests:read — or a dashboard session
GET /v1/shared/{token}an anonymous test’s reportthe token itself
GET /v1/shared/{token}/messagean anonymous test’s received messagethe token itself
GET /v1/whoamithe key’s account and scopeskey, no scope
GET /v1/domainsyour domains, with their idskey, scope domains:read
GET /v1/domains/{id}/dmarc/summaryDMARC volume and pass rateskey, scope dmarc:read
GET /v1/domains/{id}/dmarc/reportsthe aggregate reports receivedkey, scope dmarc:read
GET /v1/domains/{id}/dmarc/sourceswho is sending as you, and resultskey, scope dmarc:read

The path says why these need no key: the token is the share link, so anyone holding it can read that one result. That is the same capability the website hands out when you share a result.

“Report” here always means a deliverability test report — the score and findings for one message you sent us. It does not mean a DMARC aggregate report. Those are a different thing entirely, and they are not part of this API today: DMARC data is available in the dashboard (and as CSV export) but has no key-authenticated endpoint yet. If you need it programmatically, tell us — it is the most likely next addition, and knowing who wants it decides the shape.


POST /v1/tests

Allocate a test address. Requires tests:write.

curl -s -X POST https://api.deliversight.com/v1/tests 
  -H "Authorization: Bearer $DELIVERSIGHT_API_KEY"
{
	"token": "ds-q6mdtt6rqbktzg74",
	"address": "[email protected]",
	"source": "api",
	"expires_at": "2026-08-03T05:46:54.406186979Z",
	"created_at": "2026-07-27T05:46:54.403576Z"
}

source is api for anything created this way. Read the result back with GET /v1/tests/{token}not GET /v1/shared/{token}, which does not serve key-created tests.

Counts against your monthly test allowance. Not idempotent — see retrying safely.


GET /v1/tests

Your account’s tests, newest first. Requires tests:read.

Query parameters: limit (default 50, max 200) and offset.

curl -s "https://api.deliversight.com/v1/tests?limit=2" 
  -H "Authorization: Bearer $DELIVERSIGHT_API_KEY"
{
	"tests": [
		{
			"token": "ds-wjhme5khuo3qgqiw",
			"source": "api",
			"status": "scored",
			"score": 9,
			"created_at": "2026-07-27T21:51:04Z",
			"received_at": "2026-07-27T21:51:22Z"
		},
		{
			"token": "ds-2slvat3l5k2dygky",
			"source": "dashboard",
			"status": "pending",
			"created_at": "2026-07-27T19:04:11Z"
		}
	]
}

source is where the test came from: api, dashboard or monitor. score and received_at are absent until the message arrives and is scored.


GET /v1/tests/{token}

The full report for a test your account owns, requiring tests:read. This is how you read the result of anything you created with a key — see the body documented under GET /v1/shared/{token} below, which is identical.


GET /v1/shared/{token}

The deliverability test report — not a DMARC report — for an anonymous test — one created on the website without an account. Authenticated by the token in the URL, so anyone holding it can read that report, which is what makes a website result shareable as a link.

It returns 404 for a test created with an API key, however valid the token. Those are readable only through GET /v1/tests/{token} with your key: an API-created address transits your own sending path and can leak from a bounce or a log, so the token alone must not unlock the result.

curl -s https://api.deliversight.com/v1/shared/ds-wjhme5khuo3qgqiw
{
	"token": "ds-wjhme5khuo3qgqiw",
	"address": "[email protected]",
	"status": "scored",
	"score": 9,
	"max_score": 10,
	"gated": false,
	"created_at": "2026-07-27T21:51:04Z",
	"received_at": "2026-07-27T21:51:22Z",
	"message_id": "018f3c2a-7b41-7e3d-9c02-5a1f6d8e4b77",
	"checks": [
		{
			"name": "blocklist",
			"status": "passed",
			"score": 0,
			"detail": {
				"checked_ip": "203.0.113.9",
				"checked_domain": "mail.example.com",
				"b.barracudacentral.org": "clean",
				"bl.mailspike.net": "clean"
			}
		},
		{
			"name": "content",
			"status": "failed",
			"score": -1,
			"detail": { "list_unsubscribe": "missing List-Unsubscribe header" }
		},
		{
			"name": "dkim",
			"status": "passed",
			"score": 0,
			"detail": { "valid_domains": "mail.example.com" }
		}
	]
}

Fields

  • statuspending until the message arrives, then scored (or failed if it could not be analysed).
  • score / max_score — the score counts down from max_score. Fractional values occur.
  • gatedtrue when the full report is withheld pending an upgrade; score is still present.
  • created_at / received_at — when the test was allocated, and when the message arrived. received_at is absent until it does.
  • message_id — the message this report describes. A test address can receive more than one message; pass it as ?m= to pin a report to a specific one instead of the latest.
  • checks[] — one entry per analyzer. status is passed, failed, neutral or error; score is that check’s contribution (0 when it passed, negative when it cost you); detail is a free-form string map whose keys vary by check.

Do not hardcode the set of check names or detail keys — new checks get added, and that is an additive change under v1.


GET /v1/shared/{token}/message

Metadata about the received message for an anonymous test: sender and date always, subject and body only when the message does not look like credential mail. Like the endpoint above, it returns 404 for key-created tests.

{
	"from": "Release Bot <[email protected]>",
	"date": "Sun, 27 Jul 2026 21:51:20 +0000",
	"subject": "Release 4.12 is out",
	"content": "...",
	"withheld": false
}

When the message looks like a verification code, a sign-in link or a password reset, the content is withheld and the reason given:

{
	"from": "Acme <[email protected]>",
	"date": "Sun, 27 Jul 2026 21:51:20 +0000",
	"withheld": true,
	"withheld_reason": "the message appears to contain a sign-in code or link"
}

That decision is made on the message, not on who is asking — test addresses would otherwise work as disposable inboxes for signing up to other services. Sender and date are always returned, so you can still confirm a message arrived.


GET /v1/domains

Your domains and their ids. Requires domains:read.

Every DMARC endpoint below is addressed by domain id, and this is the only public route that returns one — so an integration starts here.

{
	"domains": [
		{
			"id": "018f3c2a-7b41-7e3d-9c02-5a1f6d8e4b77",
			"domain": "example.com",
			"verified": true
		}
	]
}

A subdomain you have added is its own entry with its own id — mail.example.com is not reachable through example.com’s id.


GET /v1/domains/{id}/dmarc/summary

Volume and authentication rates for the domain over a window. Requires dmarc:read.

The fastest way to answer “is our mail authenticating?” without pulling every report.


GET /v1/domains/{id}/dmarc/reports

The aggregate reports received for the domain — DMARC reports, not the deliverability test reports at GET /v1/shared/{token}. Requires dmarc:read.

Reports arrive from mailbox providers on their own schedule, usually daily, so a window that has just closed may still be filling.


GET /v1/domains/{id}/dmarc/sources

Every source sending as the domain, with its DMARC results. Requires dmarc:read.

This is the one to watch: a source you do not recognise passing DMARC means someone is authorised who should not be, and a source you do recognise failing means your own mail is at risk.


Domain writes are not in the API

Adding, verifying and deleting domains are dashboard-only. Verification means owning the DNS records and the flow around them, which is not something to automate blind — and getting it wrong stops mail rather than misreporting it.


GET /v1/whoami

Confirm a key and see its scopes. No scope required.

{
	"account_id": "018f3c2a-7b41-7e3d-9c02-5a1f6d8e4b77",
	"scopes": ["tests:write", "tests:read"]
}