API Reference

Ship MailSift with predictable endpoints.

Everything you need to integrate single checks and bulk jobs into your stack. Authenticate with a single header, ship in minutes.

Base URL
PRODUCTION API
https://mailsift.dev/api/v1
All requests start here · v1 stable

API Key Auth

Send your key in the X-API-Key header for server-to-server verification requests. Generate a key from your dashboard.

Header:X-API-Key: msk_…
Quickstart

Copy, call, ship.

Start with a single verify call, then move into keys, jobs, and parsed result rows as soon as you need scale. The examples below match the current route surface.

Check Your Balance
curl "https://mailsift.dev/api/v1/account" \
  -H "X-API-Key: msk_your_api_key_here"
Single Verify
curl "https://mailsift.dev/api/v1/[email protected]" \
  -H "X-API-Key: msk_your_api_key_here"
Batch Verify (up to 100)
curl -X POST "https://mailsift.dev/api/v1/verify/batch" \
  -H "X-API-Key: msk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"emails":["[email protected]","[email protected]","[email protected]"]}'
Create Bulk Job
curl -X POST "https://mailsift.dev/api/v1/verify/bulk" \
  -H "X-API-Key: msk_your_api_key_here" \
  -F "[email protected]"
Poll Job Status
curl "https://mailsift.dev/api/v1/jobs/{job_id}" \
  -H "X-API-Key: msk_your_api_key_here"
Verify a Webhook Signature (Node.js)
// req.body — raw body string, signature — X-MailSift-Signature header
const crypto = require('crypto');
const expected = crypto
  .createHmac('sha256', webhookSecret)  // from GET /account
  .update(req.body)
  .digest('hex');
const valid = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(signature)
);
Endpoints

Full route map

Verification

2 endpoints
GET
/api/v1/verify?email={email}
Single email verification with API key or session.
POST
/api/v1/verify/batch
Verify up to 100 emails synchronously in one call.

Account

1 endpoint
GET
/api/v1/account
Credits balance, usage this month, webhook secret.

Bulk Jobs

7 endpoints
POST
/api/v1/verify/bulk
Upload CSV and create a bulk job.
GET
/api/v1/jobs
List your jobs.
GET
/api/v1/jobs/{id}
Job summary and counts.
GET
/api/v1/jobs/{id}/stream
Server-sent events progress stream.
GET
/api/v1/jobs/{id}/results
Paginated parsed result rows.
GET
/api/v1/jobs/{id}/download
Download final CSV.
DELETE
/api/v1/jobs/{id}
Cancel or delete a job.
Response shape

Single verify JSON

Single verify returns the classification, numeric score, boolean checks, and enrichment fields used by the dashboard.

{
  "email": "[email protected]",
  "status": "valid",
  "score": 92,
  "checks": {
    "syntax": true,
    "free": true,
    "disposable": false,
    "mx": true,
    "relay": false,
    "spf": true,
    "dmarc": true,
    "role": false,
    "catch_all": false
  },
  "domain": "gmail.com",
  "mx_records": [
    "gmail-smtp-in.l.google.com",
    "alt1.gmail-smtp-in.l.google.com"
  ],
  "normalized_email": "[email protected]",
  "mx_provider": "Google",
  "is_catch_all": false,
  "domain_age_days": 11188,
  "response_time_ms": 46,
  "checked_at": "2026-04-01T17:32:18Z"
}
Bulk results

Parsed job rows

Use the parsed result endpoint to drive in-app filtering and dashboards without downloading the whole CSV first.

{
  "results": [
    {
      "email": "[email protected]",
      "verification_status": "risky",
      "verification_score": 82,
      "is_disposable": false,
      "has_mx": true,
      "is_role_based": false,
      "is_free_provider": true,
      "is_relay": false,
      "is_blacklisted": false,
      "has_spf": true,
      "has_dmarc": true,
      "is_catch_all": false,
      "domain_age_days": 11188,
      "mx_provider": "Google",
      "normalized_email": "[email protected]",
      "did_you_mean": ""
    }
  ],
  "total_rows": 16,
  "page": 1,
  "page_size": 50,
  "total_pages": 1
}
Bulk workflow

How bulk processing works

  1. 1Upload a CSV with an email column using multipart form data.
  2. 2Receive a job id immediately and poll /jobs/{id} or stream /jobs/{id}/stream.
  3. 3Read parsed rows from /jobs/{id}/results for in-app filtering.
  4. 4Download the final CSV from /jobs/{id}/download when the job reaches complete.
!CSV requirements
Include a header row. The parser will look for columns like email, email_address, or any header containing "email".
Status semantics

What the statuses mean

valid
Strong domain and mailbox-pattern signals. Good default pass case.
risky
Deliverable-looking domain but suspicious local part, role-based inbox, relay, or uncertain posture.
invalid
Domain does not exist, null MX, or other hard failure.
unknown
Reserved for inconclusive processing failures or transient edge cases.