Endpoint reference
Six endpoints. Base URL https://api.deliversight.com.
| Endpoint | Returns | Auth |
|---|---|---|
POST /v1/tests | a new test address | key, scope tests:write |
GET /v1/tests | your tests | key, scope tests:read — or a dashboard session |
GET /v1/tests/{token} | one test’s deliverability report | key, scope tests:read — or a dashboard session |
GET /v1/shared/{token} | an anonymous test’s report | the token itself |
GET /v1/shared/{token}/message | an anonymous test’s received message | the token itself |
GET /v1/whoami | the key’s account and scopes | key, no scope |
GET /v1/domains | your domains, with their ids | key, scope domains:read |
GET /v1/domains/{id}/dmarc/summary | DMARC volume and pass rates | key, scope dmarc:read |
GET /v1/domains/{id}/dmarc/reports | the aggregate reports received | key, scope dmarc:read |
GET /v1/domains/{id}/dmarc/sources | who is sending as you, and results | key, 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
status—pendinguntil the message arrives, thenscored(orfailedif it could not be analysed).score/max_score— the score counts down frommax_score. Fractional values occur.gated—truewhen the full report is withheld pending an upgrade;scoreis still present.created_at/received_at— when the test was allocated, and when the message arrived.received_atis 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.statusispassed,failed,neutralorerror;scoreis that check’s contribution (0when it passed, negative when it cost you);detailis 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"]
}