API Documentation

Everything you need to integrate Mailcaff email verification and finder into your application.

Authentication

All API requests require a Bearer token in the Authorization header. You can generate API keys from the API Keys page.

# Include this header in every request
Authorization: Bearer your-api-key-here

Requests without a valid API key will receive a 401 Unauthorized response.

Base URL

https://mailcaff.com/api/v1

Verify Email

Verify the deliverability of a single email address. Returns reachability status, quality score, and detailed checks.

POST /api/v1/verify

Request

curl -X POST https://mailcaff.com/api/v1/verify \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "mode": "power"
  }'

Request Fields

FieldTypeRequiredDescription
emailstringYesThe email address to verify
modestringNopower (default): full SMTP verification, 2–60s. quick: syntax + MX check only, sub-500ms. Quick mode does not contact the mail server.

Response

{
  "email": "user@example.com",
  "status": "valid",
  "quality_score": 100,
  "is_valid": true,
  "is_deliverable": true,
  "is_disposable": false,
  "is_role_account": false,
  "is_free_email": false,
  "can_connect_smtp": true,
  "mx_accepts_mail": true,
  "mode": "power",
  "response_ms": 1240
}

Response Fields

FieldTypeDescription
emailstringThe email address that was verified
statusstringReachability result: valid, invalid, risky, unknown, disposable, or error
quality_scoreintegerComposite quality score from 0–100 (higher is better)
is_validbooleanWhether the email is confirmed deliverable
is_deliverablebooleanSMTP server accepted the recipient
is_disposablebooleanTemporary/disposable email provider
is_role_accountbooleanRole-based address (e.g. info@, support@)
is_free_emailbooleanFree email provider (e.g. Gmail, Yahoo, Outlook)
can_connect_smtpbooleanSMTP connection was successful
mx_accepts_mailbooleanDomain has valid MX records
modestringVerification mode used: power or quick
is_spam_trapbooleanDetected as a known spam trap address (only present when true)
response_msintegerVerification time in milliseconds

Status Values

ValueQuality ScoreMeaning
valid90–100Email exists and is deliverable
risky40–85Delivery uncertain. The domain may accept all emails, or SMTP signals are mixed. Score reflects confidence: 75+ is likely deliverable, below 50 is likely undeliverable
unknown40–45Could not determine reachability (server timeout, etc.)
disposable0–10Temporary/throwaway email address
invalid5–10Email does not exist or is not deliverable

Bulk Verify

Submit up to 500 emails for background verification. Returns a job ID to poll for results.

POST /api/v1/verify/bulk

Request

curl -X POST https://mailcaff.com/api/v1/verify/bulk \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      "alice@example.com",
      "bob@company.org",
      "charlie@domain.net"
    ]
  }'

Response (202 Accepted)

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "total": 3,
  "status": "processing"
}

Check Job Status

GET /api/v1/verify/bulk/{job_id}
curl https://mailcaff.com/api/v1/verify/bulk/{job_id} \
  -H "Authorization: Bearer your-api-key"

Response (completed)

{
  "job_id": "550e8400-...",
  "status": "completed",
  "total": 3,
  "processed": 3,
  "valid_count": 2,
  "invalid_count": 1,
  "risky_count": 0,
  "results": [
    { "email": "alice@example.com", "status": "valid", "quality_score": 100, ... },
    { "email": "bob@company.org", "status": "valid", "quality_score": 95, ... },
    { "email": "charlie@domain.net", "status": "invalid", "quality_score": 5, ... }
  ]
}

Each object in results has the same fields as the single verify response.

Find Email

Find a person's email address given their name and company domain. Tests common patterns against the mail server.

POST /api/v1/find

Request

curl -X POST https://mailcaff.com/api/v1/find \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "John",
    "last_name": "Doe",
    "domain": "company.com"
  }'

Response (found)

{
  "found": true,
  "email": "john.doe@company.com",
  "confidence": "high",
  "pattern": "first.last",
  "source": "learned",
  "response_ms": 3200
}

Response (not found)

{
  "found": false,
  "email": null,
  "confidence": null,
  "pattern": null,
  "source": null,
  "reason": "no_mx_records",
  "response_ms": 45
}

Response Fields

FieldTypeDescription
foundbooleanWhether a valid email was discovered
emailstring|nullThe discovered email address
confidencestring|nullhigh (SMTP verified), medium (likely valid), or low (best guess on catch-all domain)
patternstring|nullPattern that matched (e.g. first.last, flast)
sourcestring|nullHow the email was found: learned (SMTP verified), cache (cached result), mx_intel (MX provider intelligence), gravatar (Gravatar match), pattern_db (known domain pattern), scraped (website scrape)
reasonstring|nullExplanation when not found: no_mx_records, disposable_domain, catchall_detected, no_pattern_matched
response_msintegerSearch time in milliseconds

Confidence Levels

ValueMeaning
highEmail confirmed deliverable via SMTP verification
mediumEmail likely valid based on domain pattern or catch-all with strong signals
lowBest statistical guess on a catch-all domain. The email format is likely correct but delivery cannot be verified

Bulk Find

Submit multiple leads for background email finding. Returns a job ID to poll for results.

POST /api/v1/find/bulk

Request

curl -X POST https://mailcaff.com/api/v1/find/bulk \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      { "first_name": "John", "last_name": "Doe", "domain": "company.com" },
      { "first_name": "Jane", "last_name": "Smith", "domain": "acme.org" }
    ]
  }'

Response (202 Accepted)

{
  "job_id": "660f9500-...",
  "total": 2,
  "status": "processing"
}

Check Job Status

GET /api/v1/find/bulk/{job_id}
curl https://mailcaff.com/api/v1/find/bulk/{job_id} \
  -H "Authorization: Bearer your-api-key"

Response (completed)

{
  "job_id": "660f9500-...",
  "status": "completed",
  "total": 2,
  "processed": 2,
  "found_count": 1,
  "results": [
    { "first_name": "John", "last_name": "Doe", "domain": "company.com", "found": true, "email": "john.doe@company.com" },
    { "first_name": "Jane", "last_name": "Smith", "domain": "acme.org", "found": false, "email": null }
  ]
}

Domain Finder

Find the company domain from just a company name. Returns the domain with MX validation so you know it handles email. Pair with the Email Finder to go from company name to email address.

POST /api/v1/find-domain

Request

curl -X POST https://mailcaff.com/api/v1/find-domain \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "Coolblue"
  }'

Response

{
  "company_name": "Coolblue",
  "domain": "coolblue.nl",
  "has_mx": true,
  "has_website": true,
  "confidence": "high",
  "candidates_checked": 4,
  "status": "found",
  "response_ms": 620
}

Response Fields

FieldTypeDescription
company_namestringThe company name that was searched
domainstring|nullBest matching domain found (null if none found)
has_mxbooleanWhether the domain has MX records (accepts email)
has_websitebooleanWhether the domain has a live website
confidencestring"high" (website + MX), "medium" (MX only), or "low" (website only)
candidates_checkedintegerNumber of domain candidates tested
statusstring"found", "not_found", or "error"
response_msintegerTotal processing time in milliseconds

Costs 1 credit per lookup. Tries common TLDs (.com, .nl, .de, .io, .eu, .co, .net, .org) and validates with DNS + HTTP checks.

Webhooks

Configure a webhook URL to receive notifications when bulk jobs complete. Set your webhook URL in API Keys & Settings.

Webhook Payload

{
  "event": "bulk_job.completed",
  "job_id": "550e8400-...",
  "job_type": "verify",
  "status": "completed",
  "total": 100,
  "summary": {
    "valid": 72,
    "invalid": 15,
    "risky": 8,
    "disposable": 3,
    "unknown": 2
  }
}

Events: bulk_job.completed and bulk_job.failed. Webhooks are HTTPS-only and delivered with a 10-second timeout.

Error Responses

All errors return a JSON object with an error field.

Status CodeMeaning
400Bad request: missing or invalid parameters
401Unauthorized: missing or invalid API key
404Not found: job or resource doesn't exist
429Rate limit exceeded: monthly credits exhausted
500Server error: contact support
503Maintenance mode: the service is temporarily unavailable. Retry after the period indicated in the response.
# Example: rate limit exceeded
{
  "error": "Monthly limit exceeded",
  "monthly_limit": 10000,
  "monthly_used": 10000,
  "resets_at": "2026-03-01T00:00:00Z"
}

Plans & Rate Limits

API usage is limited by your monthly plan quota. Each verification or find request counts as one credit. Unused credits roll over for one month.

Plan Monthly Credits Price
Free600$0/month
Starter10,000$12/month
Growth50,000$49/month
Scale250,000$129/month

Unused credits from the previous month carry over automatically (up to 1x your plan limit), giving you up to 2x credits in any single month.