API Documentation

Integrate Sender Audit programmatically. Create scans, retrieve results, and monitor your email deliverability from your own tools.

BASE URL https://senderaudit.com/api/v1

Authentication

All API requests require an API key passed in the Authorization header.

API keys are created from your dashboard. Each key is tied to your account and shares its scan quota.

Authorization: Bearer sa_live_your_api_key_here

Security: Keep your API key secret. Do not expose it in client-side code, public repositories, or logs. If compromised, delete it immediately from your dashboard and create a new one.

Rate limits

Scan creation 5 requests / minute + daily plan quota
Other endpoints 30 requests / minute

When a limit is exceeded, the API returns 429 Too Many Requests.

Errors

Errors return a JSON body with a detail field:

{ "detail": "Invalid API key" }
CodeMeaning
400Bad request (missing or invalid parameters)
401Invalid or missing API key
404Resource not found
429Rate limit or daily quota exceeded
500Internal server error

Scans

POST

/scans

Create a new email scan. Returns a unique email address to send your test email to.

The request body can be empty ({}).

Example

curl -X POST https://senderaudit.com/api/v1/scans \
  -H "Authorization: Bearer sa_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response 201 Created

{
  "local_part": "s1a2b3c4",
  "email_address": "s1a2b3c4@senderaudit.com",
  "status": "pending",
  "created_at": "2026-03-25T14:32:00",
  "view_count": 0
}

Next step: Send an email to the returned email_address. The scan starts automatically upon reception. Use local_part to check status and fetch results.

GET

/scans/{local_part}

Check the status of a scan. Poll this endpoint until status is completed or failed.

Path parameters

ParamDescription
local_partThe local part of the scan email address (e.g. s1a2b3c4)

Example

curl https://senderaudit.com/api/v1/scans/s1a2b3c4 \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "local_part": "s1a2b3c4",
  "email_address": "s1a2b3c4@senderaudit.com",
  "status": "completed",
  "created_at": "2026-03-25T14:32:00",
  "received_at": "2026-03-25T14:32:12",
  "processed_at": "2026-03-25T14:32:45",
  "processing_time_ms": 33000,
  "view_count": 0
}

Status values

pendingWaiting for the email to arrive
processingEmail received, analysis in progress
completedAnalysis finished, results ready
failedAnalysis failed
GET

/scans/{local_part}/results

Retrieve the full analysis results for a completed scan.

Example

curl https://senderaudit.com/api/v1/scans/s1a2b3c4/results \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

Returns 202 Accepted if analysis is still in progress.

Top-level fields
scan_idstringLocal part identifier
statusstring"completed"
scoresobjectOverall score (0-100), spam score, breakdown
emailobjectSender, subject, size
serverobjectSending server IP, hostname, protocol
authenticationobjectSPF, DKIM, DMARC, BIMI, DNSSEC, MX, PGP
securityobjectTLS encryption, tracking domains
reputationobjectRBL listings, AbuseIPDB score
contentobjectSpamAssassin, Rspamd, links, images analysis
scores object
overallintegerComposite deliverability score (0-100)
spamfloat|nullSpamAssassin score (lower is better)
breakdownarrayPer-category score details
authentication object
spfobjectresult, record, domain, dns_lookups
dkimobjectresult, signatures[], selector, domain
dmarcobjectresult, policy, record, alignment
bimiobject|nullBIMI record, logo URL, VMC certificate
dnssecobject|nullenabled, domain
mxobject|nullMX records for sender domain
reputation.rbl object
listed_countintegerNumber of blocklists listing this IP
total_checkedintegerTotal blocklists checked
listingsarrayDetails of each listing

Tip: The response is extensive. For a quick integration, focus on scores.overall (0-100 deliverability score), authentication.spf.result, authentication.dkim.result, and authentication.dmarc.result.

GET

/scans/{local_part}/optimized-images

Download a ZIP archive containing WebP-optimized versions of all images found in the email. Available only for a limited time after analysis.

Path parameters

ParamDescription
local_partThe local part of the scan email address (e.g. s1a2b3c4)

Example

curl -OJ https://senderaudit.com/api/v1/scans/s1a2b3c4/optimized-images \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

Returns a binary application/zip file containing optimized images in WebP format.

The Content-Disposition header provides the suggested filename: senderaudit-{local_part}-optimized.zip

Note: Optimized images are cached temporarily after analysis. If the bundle has expired, this endpoint returns 404.

Account

GET

/auth/me

Retrieve the authenticated user's profile.

Example

curl https://senderaudit.com/api/v1/auth/me \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "id": 1,
  "email": "user@example.com",
  "is_verified": true,
  "active_account_id": 1,
  "memberships": [
    { "account_id": 1, "role": "owner" }
  ],
  "created_at": "2026-01-15T10:00:00"
}
GET

/auth/me/scan-usage

Check your daily scan quota and current usage.

Example

curl https://senderaudit.com/api/v1/auth/me/scan-usage \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "scans_used_today": 3,
  "scans_limit": 20,
  "scans_remaining": 17
}
FieldTypeDescription
scans_used_todayintegerScans consumed today (UTC)
scans_limitintegerMaximum scans per day for your plan
scans_remainingintegerRemaining scans today (-1 = unlimited)
GET

/auth/me/scans

List all scans for your account with pagination and optional domain filtering.

Query parameters

ParamTypeDescription
limitintegerNumber of results (1-100, default 50)
offsetintegerPagination offset (default 0)
domainstringOptional. Filter scans by sender domain (e.g. example.com)
statusstringOptional. Filter by status: pending, processing, completed, failed, or all. Default: excludes pending.

Example

curl "https://senderaudit.com/api/v1/auth/me/scans?limit=10&offset=0" \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "scans": [
    {
      "email_address": "s1a2b3c4@senderaudit.com",
      "status": "completed",
      "overall_score": 87,
      "from_header": "noreply@example.com",
      "subject": "Welcome!",
      "spam_score": 1.2,
      "created_at": "2026-03-25T14:32:00",
      "processed_at": "2026-03-25T14:32:45"
    }
  ],
  "total": 42
}
FieldTypeDescription
scansarrayList of scan objects
totalintegerTotal number of matching scans (for pagination)
overall_scoreinteger | nullDeliverability score (0-100)
from_headerstring | nullSender address from email header
spam_scorenumber | nullSpamAssassin score

API keys

Manage API keys for your account. Maximum 5 keys per account.

POST

/auth/me/api-keys

Create a new API key. The raw key is returned only once.

Request body
{ "name": "My integration" }
Response 201
{
  "id": 1,
  "name": "My integration",
  "key": "sa_live_abc123...",
  "key_hint": "c123",
  "created_at": "2026-03-25T14:00:00"
}

Important: The key field is only returned at creation time. Store it securely.

GET

/auth/me/api-keys

List all API keys for your account. Full keys are never exposed.

Response 200
{
  "keys": [
    {
      "id": 1,
      "name": "My integration",
      "key_hint": "c123",
      "is_active": true,
      "created_at": "2026-03-25T14:00:00",
      "last_used_at": "2026-04-05T09:15:00"
    }
  ]
}
DELETE

/auth/me/api-keys/{key_id}

Permanently delete an API key. This action is irreversible.

Response 200
{ "deleted": true }

Seed addresses

Seed addresses are persistent scan addresses that can receive multiple test emails over time, making it easy to track improvements.

POST

/auth/me/seed-addresses

Create a new seed address.

Request body
{ "name": "Production newsletter" }
Response 201
{
  "id": 1,
  "name": "Production newsletter",
  "email": "seed-x7k9m2@senderaudit.com",
  "created_at": "2026-03-25T14:00:00"
}
GET

/auth/me/seed-addresses

List all seed addresses for your account.

Response 200
{
  "addresses": [
    {
      "id": 1,
      "name": "Production newsletter",
      "email": "seed-x7k9m2@senderaudit.com",
      "is_active": true,
      "created_at": "2026-03-25T14:00:00",
      "last_used_at": "2026-04-01T08:30:00"
    }
  ],
  "limit": 10
}
DELETE

/auth/me/seed-addresses/{addr_id}

Delete a seed address.

Response 200
{ "deleted": true }

Domains

GET

/domains

List all domains registered on your account.

Example

curl https://senderaudit.com/api/v1/domains \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

[
  {
    "id": "a1b2c3d4-...",
    "domain": "example.com",
    "verification_method": "dns",
    "is_verified": true,
    "verified_at": "2026-03-20T10:00:00",
    "created_at": "2026-03-20T09:50:00",
    "monitored_hosts_count": 3
  }
]
FieldTypeDescription
idstringPublic UUID identifier
domainstringDomain name
verification_methodstring"dns" or "email"
is_verifiedbooleanWhether domain ownership is confirmed
monitored_hosts_countintegerNumber of monitored hosts for this domain
POST

/domains/initiate

Start domain ownership verification. Choose between DNS (TXT record) or email-based verification.

Request body

FieldTypeDescription
domainstringDomain to verify (e.g. example.com)
methodstring"dns" or "email"
targetstring | nullRequired if method="email": "postmaster", "abuse", "contact", "support", or "admin"
langstringVerification email language: "en" (default), "fr"

Example

curl -X POST https://senderaudit.com/api/v1/domains/initiate \
  -H "Authorization: Bearer sa_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "example.com", "method": "dns" }'

Response 201 Created

{
  "id": "a1b2c3d4-...",
  "domain": "example.com",
  "verification_method": "dns",
  "verification_token": "senderaudit_verify:abc123def456",
  "is_verified": false,
  "created_at": "2026-03-25T14:00:00",
  "monitored_hosts_count": 0
}

DNS method: Add a TXT record with the verification_token value to your domain, then call POST /domains/{id}/verify.

POST

/domains/{domain_id}/verify

Attempt to verify domain ownership. For DNS verification, checks that the TXT record is present.

Path parameters

ParamDescription
domain_idThe public UUID of the domain

Example

curl -X POST https://senderaudit.com/api/v1/domains/a1b2c3d4-.../verify \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "status": "verified"
}
FieldTypeDescription
statusstring"verified" or "conflict"
existing_owner_emailstring | nullObfuscated email of existing owner (if conflict)
DELETE

/domains/{domain_id}

Remove a domain and all its associated monitoring data.

Example

curl -X DELETE https://senderaudit.com/api/v1/domains/a1b2c3d4-... \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 204 No Content

Empty response body.

GET

/domains/quota

Check your domain and monitored hosts quota.

Example

curl https://senderaudit.com/api/v1/domains/quota \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "plan": "pro",
  "monitored_hosts_used": 5,
  "monitored_hosts_total": 8,
  "monitored_hosts_limit": 20
}
FieldTypeDescription
planstringCurrent plan name
monitored_hosts_usedintegerActive monitored hosts
monitored_hosts_totalintegerTotal hosts (including inactive)
monitored_hosts_limitintegerMaximum hosts allowed by plan

Monitoring

GET

/domains/{domain_id}/monitoring

Retrieve current DNS records and change timeline for a verified domain.

Path parameters

ParamDescription
domain_idThe public UUID of the domain

Example

curl https://senderaudit.com/api/v1/domains/a1b2c3d4-.../monitoring \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "records": [
    {
      "id": 1,
      "record_type": "SPF",
      "record_key": "example.com",
      "record_value": "v=spf1 include:_spf.google.com ~all",
      "first_seen_at": "2026-03-20T10:00:00",
      "last_seen_at": "2026-04-05T06:00:00",
      "removed_at": null
    }
  ],
  "timeline": [
    {
      "record_type": "DMARC",
      "record_key": "_dmarc.example.com",
      "record_value": "v=DMARC1; p=reject;",
      "first_seen_at": "2026-03-22T10:00:00",
      "removed_at": "2026-04-01T06:00:00"
    }
  ],
  "building": false
}
GET

/domains/{domain_id}/monitored-items

List all monitored hosts (IPs, domains) discovered from scan results for this domain.

Example

curl https://senderaudit.com/api/v1/domains/a1b2c3d4-.../monitored-items \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "hosts": [
    {
      "id": 1,
      "host_value": "example.com",
      "is_active": true,
      "types": [
        { "host_type": "header_from", "discovered_by": "scan" }
      ],
      "created_at": "2026-03-20T10:00:00"
    },
    {
      "id": 2,
      "host_value": "198.51.100.25",
      "is_active": true,
      "types": [
        { "host_type": "sending_ip", "discovered_by": "scan" }
      ],
      "created_at": "2026-03-20T10:00:00"
    }
  ]
}
PATCH

/domains/{domain_id}/monitored-items/{item_id}

Toggle the active state of a monitored host. Deactivated hosts stop being monitored and free up quota.

Path parameters

ParamDescription
domain_idThe public UUID of the domain
item_idThe monitored host ID

Example

curl -X PATCH https://senderaudit.com/api/v1/domains/a1b2c3d4-.../monitored-items/2 \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "id": 2,
  "is_active": false
}

Note: The main domain host (header_from) cannot be deactivated. Reactivation is subject to your monitored hosts quota.

GET

/domains/{domain_id}/score-summary

Get the average deliverability score, percentile ranking, and certificate eligibility for a domain.

Example

curl https://senderaudit.com/api/v1/domains/a1b2c3d4-.../score-summary \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "avg_score": 92,
  "scan_count": 8,
  "percentile": 87,
  "eligible_certificate": true,
  "certificate": {
    "token": "cert_abc123",
    "avg_score": 92,
    "updated_at": "2026-04-05T06:00:00"
  }
}
FieldTypeDescription
avg_scoreinteger | nullAverage score across recent scans (null if <3 scans)
scan_countintegerNumber of recent scans used for scoring
percentileinteger | nullPercentage of domains scoring below yours
eligible_certificatebooleanTrue if score >= 80 and scan_count >= 3
certificateobject | nullCertificate details (token, avg_score, updated_at)

IPs

GET

/ips

List all IPs registered on your account.

Example

curl https://senderaudit.com/api/v1/ips \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

[
  {
    "id": "a1b2c3d4-...",
    "ip_value": "51.178.83.230",
    "input_type": "single",
    "ip_count": 1,
    "root_domains": ["example.com"],
    "verification_method": "dns",
    "is_verified": true,
    "verified_at": "2026-04-05T10:00:00",
    "created_at": "2026-04-05T09:50:00"
  }
]
FieldTypeDescription
idstringPublic UUID identifier
ip_valuestringIP address, CIDR or range
input_typestring"single", "cidr" or "range"
ip_countintegerNumber of individual IPs in the group
root_domainsarray | nullRoot domains extracted from PTR records
verification_methodstring"dns" or "email"
is_verifiedbooleanWhether IP ownership is confirmed
verified_atstring | nullISO timestamp of verification
POST

/ips/preview

Resolve PTR records for an IP and return available verification targets. Use this before /ips/initiate to preview which hostnames and email addresses are available for verification.

Request body

FieldTypeDescription
ip_valuestringIP address, CIDR (max /24) or range (max 256)

Example

curl -X POST https://senderaudit.com/api/v1/ips/preview \
  -H "Authorization: Bearer sa_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ip_value": "51.178.83.230" }'

Response 200 OK

{
  "ip_value": "51.178.83.230",
  "input_type": "single",
  "ip_count": 1,
  "ptr_hostnames": ["mail.example.com"],
  "root_domains": ["example.com"],
  "ptr_map": { "51.178.83.230": "mail.example.com" },
  "is_multi": false,
  "dns_targets": {
    "ptr": ["mail.example.com"],
    "root": ["example.com"]
  },
  "email_targets": {
    "ptr": {
      "postmaster": ["postmaster@mail.example.com"],
      "abuse": ["abuse@mail.example.com"],
      "contact": ["contact@mail.example.com"],
      "support": ["support@mail.example.com"],
      "admin": ["admin@mail.example.com"]
    },
    "root": {
      "postmaster": ["postmaster@example.com"],
      "abuse": ["abuse@example.com"],
      "contact": ["contact@example.com"],
      "support": ["support@example.com"],
      "admin": ["admin@example.com"]
    }
  }
}
FieldTypeDescription
ptr_hostnamesarrayPTR hostnames resolved for the IP(s)
root_domainsarrayRoot domains extracted from PTR hostnames
ptr_mapobjectMapping of each IP to its PTR hostname
dns_targetsobjectDNS verification hostnames grouped by scope (ptr / root)
email_targetsobjectEmail verification addresses grouped by scope and target role
POST

/ips/initiate

Start IP ownership verification. Choose between DNS (TXT record on the PTR hostname) or email-based verification.

Request body

FieldTypeDescription
ip_valuestringIP address, CIDR (max /24) or range (max 256)
methodstring"dns" or "email"
targetstring | nullRequired for email: "postmaster", "abuse", "contact", "support", or "admin"
scopestring"ptr" (default) - verify on PTR hostname, or "root" - verify on root domain. Single IPs always use "ptr".
langstringVerification email language: "en" (default), "fr", "de", "es"

Example

curl -X POST https://senderaudit.com/api/v1/ips/initiate \
  -H "Authorization: Bearer sa_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ip_value": "51.178.83.230", "method": "dns", "scope": "ptr" }'

Response 201 Created

{
  "id": "a1b2c3d4-...",
  "ip_value": "51.178.83.230",
  "input_type": "single",
  "ip_count": 1,
  "root_domains": ["example.com"],
  "ptr_map": { "51.178.83.230": "mail.example.com" },
  "verification_method": "dns",
  "verification_token": "senderaudit_verify:abc123def456",
  "verification_hosts": ["mail.example.com"],
  "is_verified": false,
  "verified_at": null,
  "created_at": "2026-04-05T09:50:00"
}

DNS method: Add a TXT record with the verification_token value on each host listed in verification_hosts, then call POST /ips/{ip_id}/verify.

POST

/ips/{ip_id}/verify

Attempt to verify IP ownership via DNS TXT record. Checks that the TXT record is present on each verification host.

Path parameters

ParamDescription
ip_idThe public UUID of the IP

Example

curl -X POST https://senderaudit.com/api/v1/ips/a1b2c3d4-.../verify \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "status": "verified"
}
FieldTypeDescription
statusstring"verified", "pending" or "failed"
messagestring | nullProgress details when status is "pending" (e.g. "1/2 host(s) verified")

Email method: For email-based verification, the user receives a link at GET /ips/confirm/{token}. No manual call to this endpoint is needed.

GET

/ips/{ip_id}/health-card

Retrieve the structured health card for a verified IP. Returns a 5-category score breakdown out of 100.

Path parameters

ParamDescription
ip_idThe public UUID of the IP

Example

curl https://senderaudit.com/api/v1/ips/a1b2c3d4-.../health-card \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 200 OK

{
  "overall": 85,
  "max": 100,
  "crisis": false,
  "categories": [
    {
      "key": "reputation",
      "label": "Reputation",
      "score": 30,
      "max": 30,
      "items": [
        {
          "key": "rbl",
          "label": "Blocklists (RBL)",
          "status": "pass",
          "score": 30,
          "max": 30,
          "value": "0 / 45 - Clean",
          "summary": "Not listed on any of 45 monitored blocklists",
          "details": { "listings": [...], "crisis": false }
        }
      ]
    },
    { "key": "identity", "label": "Identity", "score": 20, "max": 20, "items": [...] },
    { "key": "connectivity", "label": "Connectivity", "score": 15, "max": 20, "items": [...] },
    { "key": "senderscore", "label": "SenderScore", "score": 16, "max": 20, "items": [...] },
    { "key": "geoip", "label": "GeoIP", "score": 10, "max": 10, "items": [...] }
  ],
  "actions": [
    {
      "category": "connectivity",
      "item": "smtp_banner",
      "label": "SMTP Banner",
      "status": "fail",
      "gain": 10,
      "summary": "No SMTP banner"
    }
  ],
  "sparkline": [80, 82, 85, 85],
  "ip_value": "51.178.83.230",
  "input_type": "single",
  "ip_count": 1,
  "ptr_map": { "51.178.83.230": "mail.example.com" },
  "root_domains": ["example.com"]
}
Categories (max 100)
reputation30 ptsRBL blocklist presence (weighted by provider impact)
identity20 ptsPTR record (10) + Forward-Confirmed rDNS (10)
connectivity20 ptsPort 25 reachability (10) + SMTP banner (10)
senderscore20 ptsSenderScore reputation (0-100 mapped to 0-20). N/A if unavailable.
geoip10 ptsGeoIP and ASN data availability
Item status values
passCheck passed (score >= 90% of max)
warnPartial pass (score >= 50% of max)
failCheck failed (score < 50% of max)
naNot applicable (e.g. SenderScore unavailable)

Crisis mode: If the IP is listed on a critical blocklist (e.g. Spamhaus), crisis is true and overall is forced to 0.

SenderScore N/A: When SenderScore data is not available for an IP, the category max is set to 0 and the overall score is normalized to /80 instead of /100. It does not penalize the score.

DELETE

/ips/{ip_id}

Remove an IP and all its associated monitoring data (DNS records, health scores).

Example

curl -X DELETE https://senderaudit.com/api/v1/ips/a1b2c3d4-... \
  -H "Authorization: Bearer sa_live_YOUR_KEY"

Response 204 No Content

Empty response body.

Typical flow

1

Create a scan

POST /scans - get back the target email address.

2

Send your email

Send a test email to the returned address using your mail infrastructure.

3

Poll for completion

GET /scans/{local_part} - poll every 5 seconds until status is completed.

4

Fetch results

GET /scans/{local_part}/results - retrieve the full deliverability report.

Complete example (bash)

#!/bin/bash
API_KEY="sa_live_YOUR_KEY"
BASE="https://senderaudit.com/api/v1"

# 1. Create scan
RESPONSE=$(curl -s -X POST "$BASE/scans" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}')
LOCAL=$(echo "$RESPONSE" | jq -r '.local_part')
EMAIL=$(echo "$RESPONSE" | jq -r '.email_address')

echo "Send your email to: $EMAIL"
echo "Waiting for analysis..."

# 2. Send your email (via your SMTP server)
# echo "Test" | mail -s "Deliverability check" "$EMAIL"

# 3. Poll until completed
while true; do
  STATUS=$(curl -s "$BASE/scans/$LOCAL" \
    -H "Authorization: Bearer $API_KEY" | jq -r '.status')
  [ "$STATUS" = "completed" ] && break
  [ "$STATUS" = "failed" ] && echo "Scan failed" && exit 1
  sleep 5
done

# 4. Get results
curl -s "$BASE/scans/$LOCAL/results" \
  -H "Authorization: Bearer $API_KEY" | jq '.scores'