Email verification API — v1
Plain REST. JSON in, JSON out. Every credit works against the API — no separate plan, no per-endpoint surcharge.
Introduction
The Cleanify API runs at https://my.cleanify.io/api/v1 over HTTPS only. All requests return JSON. Every credit in your account works against the API — there is no separate API plan.
Authentication
Generate an API key from the API section of the dashboard sidebar. Name the token and assign the permissions you need — each token is scoped and revocable. Pass the token as a Bearer credential on every request.
curl https://my.cleanify.io/api/v1/ping \ -H "Accept: application/json" \ -H "Authorization: Bearer <api_key>"
Your first request
Verify a single email address. Pass the address as a URL-encoded query parameter:
curl 'https://my.cleanify.io/api/v1/verify?email=hello%4050saas.com' \ -H "Accept: application/json" \ -H "Authorization: Bearer <api_key>"
{
"success": true,
"email": "hello@50saas.com",
"result": "deliverable",
"reason": "accept_all",
"did_you_mean": null,
"type": {
"is_disposable": false,
"is_role": true,
"is_accept_all": true,
"is_free": false
}
} Rate limits
Per-endpoint rate limits prevent runaway clients from starving shared capacity. A 429 response means you hit the ceiling — back off and retry after a few seconds.
| Endpoint | Rate limit |
|---|---|
| /api/v1/ping | 60 per minute |
| /api/v1/credits | 60 per minute |
| /api/v1/verify | 120 per minute |
| /api/v1/bulkverify | 5 per minute |
| /api/v1/check | 120 per minute |
| /api/v1/getresults | 30 per minute |
Ping
Health probe. Returns pong when the entire verification pipeline is online.
curl --location 'https://my.cleanify.io/api/v1/ping' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>'
{ "ping": "pong" } Available credits
Returns the number of verification credits remaining on the account.
curl --location 'https://my.cleanify.io/api/v1/credits' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>'
{
"success": true,
"credits": 49713
} Quick verification
Validate a single email address synchronously. One credit per call. Pass the address as the email query parameter, URL-encoded.
Query parameters
| Field | Type | Description |
|---|---|---|
| string | The email address to verify. URL-encode the @ as %40. Required. |
Example
curl --location 'https://my.cleanify.io/api/v1/verify?email=hello%4050saas.com' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>'
{
"success": true,
"email": "hello@50saas.com",
"result": "deliverable",
"reason": "accept_all",
"did_you_mean": null,
"type": {
"is_disposable": false,
"is_role": true,
"is_accept_all": true,
"is_free": false
}
} Bulk verification
Queue a bulk job. POST the list as a plain-text body, one address per line. Returns a requestId used by the status and results endpoints below.
curl --location 'https://my.cleanify.io/api/v1/bulkverify' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>' \ --header 'Content-Type: text/plain' \ --data-raw 'hello@50saas.com sales@50saas.com this.doesnt.exist.123@gmail.com'
{
"success": true,
"requestId": "..."
} Check bulk verification status
Poll for the progress of a bulk job. Use the requestId returned by /bulkverify.
curl --location 'https://my.cleanify.io/api/v1/check' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>' \ --form 'requestId="..."'
{
"success": true,
"total": 3,
"percentage": 100,
"status": {
"deliverable": 1,
"undeliverable": 0,
"risky": 2,
"unknown": 0,
"duplicate": 0
}
} Bulk verification results
Fetch the grouped results once percentage reaches 100. Addresses are nested under their state, then their reason code.
curl --location 'https://my.cleanify.io/api/v1/getresults' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <api_key>' \ --form 'requestId="..."'
{
"success": true,
"total": 3,
"percentage": 100,
"status": {
"deliverable": 1,
"undeliverable": 0,
"risky": 2,
"unknown": 0,
"duplicate": 0
},
"risky": {
"low_deliverability": [
{
"email": "test1@test.com",
"state": "risky",
"reason": "low_deliverability",
"is_accept_all": true,
"is_disposable": false,
"is_free": false,
"is_mailbox_full": false,
"is_no_reply": false,
"is_role": false,
"is_mx_record": "aspmx.l.google.com",
"is_smtp_provider": "Google"
}
]
},
"deliverable": {
"accepted_email": [
{
"email": "test3@test.com",
"state": "deliverable",
"reason": "accepted_email",
"is_accept_all": false,
"is_disposable": false,
"is_free": true,
"is_mailbox_full": false,
"is_no_reply": false,
"is_role": false,
"is_mx_record": "gmail-smtp-in.l.google.com",
"is_smtp_provider": "Google"
}
]
}
} Verification states & reasons
Every address resolves to one of five states. The reason field narrows the state with a specific cause — useful for segmenting a list.
Deliverable
We can determine with a high level of confidence that the email address is associated with a valid account.
| Reason | Meaning |
|---|---|
| accepted_email | The email address exists and is deliverable. |
Undeliverable
We can determine with a high level of confidence that the email address is not associated with a valid account.
| Reason | Meaning |
|---|---|
| invalid_email | The email address does not pass syntax validations. |
| invalid_domain | The domain does not exist, is not valid, or should not be mailed to. |
| rejected_email | The mail server rejected the address because it does not exist. |
| invalid_smtp | The mail server returned an unexpected or invalid response. |
Risky
Emails seem to be deliverable but should be used with caution due to low quality or deliverability.
| Reason | Meaning |
|---|---|
| low_quality | The email address has quality issues that may make it risky or low value. |
| low_deliverability | The address appears to be deliverable, but deliverability cannot be guaranteed. |
Unknown
The domain is not responding, meaning we cannot determine validity. Re-verify later — this state is not charged in bulk.
| Reason | Meaning |
|---|---|
| no_connect | Could not connect to the mail server. |
| timeout | Mail server session or DNS query timed out. |
| unavailable_smtp | The mail server was unavailable to process our request at this time. |
| unexpected_error | An unexpected error occurred. |
Duplicate
The list contains more than one of the same email. Only the first occurrence is consumed; the rest are flagged and not recharged.
HTTP status codes
| Code | Status | Meaning |
|---|---|---|
| 249 | Try Again | Your request is taking longer than normal. Send the same request again. |
| 400 | Bad Request | Your request is structured incorrectly. |
| 401 | Unauthorized | You did not send an API key. |
| 402 | Payment Required | You don't have enough credits to complete this request. |
| 403 | Forbidden | Your API key is invalid. |
| 404 | Not Found | The specified resource does not exist. |
| 429 | Too Many Requests | You're requesting an endpoint too often — see the rate-limits table above. |
| 500 | Internal Server Error | A server error occurred. Retry or contact support if it persists. |
| 503 | Service Unavailable | Temporarily offline for maintenance. |