v1

CleanValidate API

Verify any email address or clean lists in bulk with a single REST endpoint. Built for production — low latency, predictable pricing, and no SDK required.

Base URL: https://cleanvalidate.com/api/public/v1
Auth: Bearer token
Format: JSON

Introduction

The CleanValidate API exposes the same engine that powers our dashboard. It performs syntax checks, MX-record lookups, SMTP probes, catch-all detection and disposable / role-account filtering, then returns a normalized result.

All endpoints share the base URL:

https://cleanvalidate.com/api/public/v1

Authentication

Every request must include a Authorization: Bearer <key> header. Create a key from your API Keys page. Keys are shown only once at creation — store them securely. Lost keys cannot be recovered; create a new one and revoke the old.

Authorization: Bearer cv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Requests without a valid key return 401 Unauthorized.

Verify single email

Verify one email and consume 1 credit.

GET
/api/public/v1/verify?email={email}
POST
/api/public/v1/verify

Request

curl "https://cleanvalidate.com/api/public/v1/verify?email=test@example.com" \
  -H "Authorization: Bearer cv_live_..."

Or as JSON:

curl -X POST "https://cleanvalidate.com/api/public/v1/verify" \
  -H "Authorization: Bearer cv_live_..." \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com"}'

Response 200

{
  "email": "test@example.com",
  "status": "valid",
  "score": 95,
  "reason": "Mailbox accepts mail",
  "suggestion": null,
  "checks": {
    "syntax": true,
    "mx": true,
    "smtp": true,
    "catch_all": false,
    "disposable": false,
    "free_provider": false,
    "role_account": false,
    "mailbox_exists": "yes"
  }
}

Verify in bulk

Verify up to 100 emails per request. Each verified email consumes 1 credit. For larger lists, use the dashboard bulk uploader or page through this endpoint.

POST
/api/public/v1/verify/bulk

Request

curl -X POST "https://cleanvalidate.com/api/public/v1/verify/bulk" \
  -H "Authorization: Bearer cv_live_..." \
  -H "Content-Type: application/json" \
  -d '{"emails":["a@example.com","b@example.com","c@example.com"]}'

Response 200

{
  "count": 3,
  "credits_used": 3,
  "summary": { "valid": 2, "risky": 1, "invalid": 0, "unknown": 0 },
  "results": [
    { "email": "a@example.com", "status": "valid",  "score": 95, "reason": "...", "checks": { ... } },
    { "email": "b@example.com", "status": "risky",  "score": 65, "reason": "...", "checks": { ... } },
    { "email": "c@example.com", "status": "valid",  "score": 90, "reason": "...", "checks": { ... } }
  ]
}

Response object

FieldTypeDescription
emailstringEchoed email, lowercased.
statusenumvalid · risky · invalid · unknown
scorenumber 0–100Confidence score.
reasonstringHuman-readable explanation.
suggestionstring | nullTypo-fix suggestion (e.g. gnail.com → gmail.com).
checks.syntaxboolValid RFC-5322 syntax.
checks.mxboolDomain has MX records.
checks.smtpboolSMTP server reachable.
checks.catch_allboolDomain accepts any address.
checks.disposableboolTemporary / disposable provider.
checks.free_providerboolFree webmail (Gmail, Yahoo, …).
checks.role_accountboolRole-based (info@, support@, …).
checks.mailbox_existsenumyes · no · unknown

Status meanings

  • valid — safe to send to. Mailbox confirmed.
  • risky — deliverable but unreliable (catch-all, role address, privacy provider). Send with caution.
  • invalid — will bounce. Do not send.
  • unknown — verification was inconclusive (provider blocked, timeout). Not charged when caused by upstream rate-limits.

Credits & billing

Each successfully verified email consumes 1 credit. Credits are deducted from your plan balance. If your balance is too low for a bulk request, the API returns 402 Insufficient credits without performing any verification. Top up from the Billing page.

Provider rate-limit refunds: if the upstream provider rate-limits us on individual rows, those rows are refunded automatically and not counted against your balance.

Rate limits

Reasonable usage limits apply per API key. The bulk endpoint accepts up to 100 emails per request; for larger sets, send sequential requests or use the dashboard uploader.

Errors

Errors return JSON with an error field and the appropriate HTTP status.

HTTPMeaning
400Bad request — invalid email or JSON body.
401Missing, invalid, or revoked API key.
402Insufficient credits.
429Upstream rate limit — retry shortly.
500Internal error — please retry or contact support.
{ "error": "Insufficient credits" }

Code samples

Node.js / TypeScript

const res = await fetch("https://cleanvalidate.com/api/public/v1/verify?email=test@example.com", {
  headers: { Authorization: `Bearer ${process.env.CLEANVALIDATE_KEY}` },
});
const data = await res.json();
console.log(data.status, data.score);

Python

import os, requests

r = requests.post(
    "https://cleanvalidate.com/api/public/v1/verify/bulk",
    headers={"Authorization": f"Bearer {os.environ['CLEANVALIDATE_KEY']}"},
    json={"emails": ["a@example.com", "b@example.com"]},
)
print(r.json())

PHP

$ch = curl_init("https://cleanvalidate.com/api/public/v1/verify?email=test@example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  "Authorization: Bearer " . getenv("CLEANVALIDATE_KEY"),
]);
$response = json_decode(curl_exec($ch), true);
echo $response["status"];

Go

req, _ := http.NewRequest("GET", "https://cleanvalidate.com/api/public/v1/verify?email=test@example.com", nil)
req.Header.Set("Authorization", "Bearer " + os.Getenv("CLEANVALIDATE_KEY"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))

Support

Questions or feature requests? Email support@cleanvalidate.com or open a ticket from the Support page in your dashboard.