Verify one address
On this page
Checks one email address in real time and returns its category, status and a plain reason. Use it on sign-up and lead forms.
/api/v1/api-validation/singleQuery parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The address to verify. URL-encode it: addresses can contain + and other characters that mean something in a URL. |
Send your API key as Authorization: Bearer <your-api-key>. See Using your API key.
Request
curl -G "https://simplecold.com/api/v1/api-validation/single" \
--data-urlencode "[email protected]" \
-H "Authorization: Bearer YOUR_API_KEY"const API = "https://simplecold.com/api/v1";
const apiKey = process.env.SIMPLECOLD_API_KEY;
async function verify(email) {
const res = await fetch(
`${API}/api-validation/single?email=${encodeURIComponent(email)}`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
const body = await res.json();
if (!res.ok) {
// Errors use { code: "FAILURE", message }; input errors use { success: false, message }
throw new Error(`${res.status}: ${body.message ?? body.error}`);
}
return body.payload;
}
const result = await verify("[email protected]");
console.log(result.category, result.status, "-", result.statusMessage);
if (result.suggestion) console.log("Did you mean", result.suggestion, "?");import os
import requests
API = "https://simplecold.com/api/v1"
API_KEY = os.environ["SIMPLECOLD_API_KEY"]
def verify(email: str) -> dict:
res = requests.get(
f"{API}/api-validation/single",
params={"email": email}, # requests URL-encodes this for you
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{res.status_code}: {body.get('message') or body.get('error')}")
return body["payload"]
result = verify("[email protected]")
print(result["category"], result["status"], "-", result["statusMessage"])<?php
const API = 'https://simplecold.com/api/v1';
function verify(string $email): array
{
$ch = curl_init(API . '/api-validation/single?' . http_build_query(['email' => $email]));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SIMPLECOLD_API_KEY')],
CURLOPT_TIMEOUT => 30,
]);
$body = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
// Errors use { code: "FAILURE", message }; input errors use { success: false, message }
throw new RuntimeException($status . ': ' . ($body['message'] ?? $body['error'] ?? 'request failed'));
}
return $body['payload'];
}
$result = verify('[email protected]');
echo $result['category'], ' ', $result['status'], ' - ', $result['statusMessage'], PHP_EOL;
if ($result['suggestion']) {
echo 'Did you mean ', $result['suggestion'], '?', PHP_EOL;
}-G puts the --data-urlencode value in the query string of a GET request.
Set your client timeout above 12 seconds, or you will cut off answers you would otherwise get.
{
"code": "SUCCESS",
"message": "Successfully performed operation.",
"payload": {
"email": "[email protected]",
"domain": "example.com",
"status": "mailbox_found",
"statusMessage": "The mailbox exists and accepts mail.",
"category": "deliverable",
"failType": "none",
"mxLocation": "US",
"siteLocation": "US",
"siteLanguage": "EN",
"suggestion": null
},
"requestId": "9b07c1d2-..."
}The result is always inside payload. Code that reads category from the top level of the response gets undefined.
Response fields
| Field | Type | Description |
|---|---|---|
email | string | The address that was checked, trimmed and lowercased. |
domain | string | The domain part of the address. |
category | string | What to act on: deliverable, risky or undeliverable, or pending while the check is still running. Treat any other value as unknown. |
status | string | The reason code: the specific outcome, such as mailbox_found, accept_all, disposable or mailbox_not_found. See Statuses and categories. |
statusMessage | string | A plain-language reason you can show to a person or store in a CRM. |
failType | string | permanent, temporary or none. temporary means a later re-check may give a different answer. |
mxLocation | string | null | Country code where the domain's mail servers appear to be. |
siteLocation | string | null | Country code where the domain's website appears to be. |
siteLanguage | string | null | Language of the domain's website. |
suggestion | string | null | A likely correction when the domain looks misspelled (for example [email protected] → [email protected]); otherwise null. We never change the address for you. |
Status values
The status field holds one of these reason codes. Each maps to one category:
| Category | Reason codes |
|---|---|
deliverable | mailbox_found |
risky | accept_all, role_address, disposable, mailbox_unconfirmed, blocked_by_server, no_response |
undeliverable | mailbox_not_found, mailbox_disabled, rejected, server_error, no_mail_server, invalid_format, possible_typo |
pending | processing |
Statuses and categories explains each one.
Typos
When the domain looks like a misspelling of a common provider (gmial.com, hotmial.com, gmail.con), the address is reported as possible_typo with a suggestion:
{
"email": "[email protected]",
"domain": "gmial.com",
"status": "possible_typo",
"statusMessage": "Possible typo. Did you mean [email protected]?",
"category": "undeliverable",
"failType": "permanent",
"mxLocation": null,
"siteLocation": null,
"siteLanguage": null,
"suggestion": "[email protected]"
}Check the suggested address separately if you want to use it.
Slow mail servers: the processing status
Most checks finish in a few seconds. Some mail servers deliberately answer slowly (greylisting), so a check can take up to a minute. Instead of keeping your request open, the API answers within about 12 seconds. If the mailbox has not answered yet, you get:
{
"email": "[email protected]",
"domain": "example.com",
"status": "processing",
"statusMessage": "Still checking this mailbox. Ask again in about a minute; you will not be charged again.",
"category": "pending",
"failType": "none",
"mxLocation": null,
"siteLocation": null,
"siteLanguage": null,
"suggestion": null
}The check keeps running on our side. To get the final result:
/api/v1/api-validation/single/resultcurl -G "https://simplecold.com/api/v1/api-validation/single/result" \
--data-urlencode "[email protected]" \
-H "Authorization: Bearer YOUR_API_KEY"It takes the same email query parameter and returns one of three things:
| Response | Meaning | What to do |
|---|---|---|
200 with status: "processing" | Still running | Wait and ask again. |
200 with any other status | Finished | Store it. The pending marker is cleared. |
404, No check in progress for this email. | Nothing pending for this address | You already collected the result, or no check was started. |
Collecting a result never uses credits. Calling GET /api-validation/single again for the same address within 30 minutes doesn't charge again either. Each address is charged once, when its final result is ready.
Poll every 10 to 20 seconds for up to 3 minutes. /single/result shares the single endpoint's limit of 100 requests per minute. Once you have read a finished result, a second call returns 404, so save it the first time.
Errors
| HTTP | Body | Cause |
|---|---|---|
400 | { "success": false, "message": "Please check your input and try again.", "data": [...] } | email is missing or not a valid address. Don't retry; treat the address as invalid. |
400 | { "code": "FAILURE", "message": "Insufficient credits.", "data": null } | Your balance can't cover the request (Please buy credits. when it is empty). |
401 | { "code": "FAILURE", "message": "Invalid API key", "data": null } | See authentication errors. |
404 | { "code": "FAILURE", "message": "No check in progress for this email.", "data": null } | /single/result only: nothing pending for this address. |
429 | { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Maximum 100 requests per minute per API key.", "data": { "policy": "...", "retryAfterSeconds": 6, ... }, "status": 429, "error": "..." } | Over 100 requests per minute with this API key. Wait Retry-After seconds. See Rate limits. |
The full response formats are described in the introduction.
Test it
Test addresses return fixed results and don't use credits:
curl -G "https://simplecold.com/api/v1/api-validation/single" \
--data-urlencode "[email protected]" \
-H "Authorization: Bearer YOUR_API_KEY"A 200 with "code": "SUCCESS" and "status": "accept_all" in the payload means your integration works. See Test emails for the full list.