Introduction
The Kluno API lets you verify whether an email address is real, deliverable, and safe to send to, in real time. It runs the same 12-layer engine as our dashboard, returning a single, honest verdict for every address.
The API is plain HTTP and JSON. There is no SDK to install. A single GET or POST request is all you need. It works out of the box with Clay HTTP columns, Zapier, n8n, or any backend.
Honest by design. When an address genuinely can't be confirmed, Kluno returns unknown instead of guessing valid. Your sender reputation is worth more than a prettier accuracy number.
Authentication
Every request must include your secret API key. You can find it in your dashboard under the API tab. Pass it one of two ways:
- As a query parameter:
?key=YOUR_API_KEY - As a request header:
x-api-key: YOUR_API_KEY
Keep your API key secret. Never expose it in client-side JavaScript or a public repo. If a key leaks, rotate it from the dashboard.
Base URL
Verify an email
Verify a single email address. Both methods behave identically, so use whichever fits your stack.
Example request
# GET with query params curl "https://kluno.xyz/api/v1/verify?email=john@company.com&key=YOUR_API_KEY"
Example response
{
"email": "john@company.com",
"account": "john",
"domain": "company.com",
"status": "valid",
"sub_status": "",
"free_email": false,
"role_based": false,
"did_you_mean": null,
"mx_found": true,
"smtp_provider": "Microsoft 365",
"processed_at": "2026-07-29T12:04:11.482Z"
}Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | yes | The email address to verify. |
key | string | yes* | Your API key. *Required unless passed via the x-api-key header. |
Response fields
Every successful verification returns the following JSON object:
| Field | Type | Description |
|---|---|---|
email | string | The address that was verified (normalized, lowercased). |
account | string | The local part, everything before the @. |
domain | string|null | The domain part, everything after the @. |
status | string | The primary verdict. See status values. |
sub_status | string | A specific reason behind the verdict. See sub-status values. |
free_email | boolean | true for free consumer providers (Gmail, Yahoo, Outlook.com, etc.). |
role_based | boolean | true for role accounts like info@, support@, admin@. |
did_you_mean | string|null | A suggested correction when a likely typo is detected (e.g. gmial.com → gmail.com). |
mx_found | boolean | Whether the domain has valid MX (mail exchange) records. |
smtp_provider | string|null | The mailbox provider, e.g. Microsoft 365, Google Workspace, Other. |
processed_at | string | ISO-8601 timestamp of when the verification ran. |
Status values
The status field is the headline verdict. It is always one of:
| Value | Meaning | Safe to send? |
|---|---|---|
| valid | The mailbox exists and accepts mail. | Yes |
| invalid | The mailbox does not exist or the domain can't receive mail. | No, will bounce |
| catch-all | The domain accepts all addresses, so the specific mailbox can't be confirmed. | Use judgment |
| unknown | The provider blocked verification (greylisting, tarpit, timeout). We won't guess. | Use judgment |
| spamtrap | Matches a known spam-trap pattern. Sending can damage your reputation. | No |
| do_not_mail | A role account (e.g. info@). Technically valid but risky for cold outreach. | Use judgment |
Sub-status values
When present, sub_status explains the why behind the status. An empty string means no additional detail (typically for a clean valid).
| Value | Description |
|---|---|
no_mx_record | The domain has no MX records, so it cannot receive email. |
dns_timeout | DNS lookup timed out; the domain could not be resolved. |
mailbox_not_found | The SMTP server rejected the specific mailbox. |
catch_all_domain | The domain accepts all mail, so the mailbox can't be individually confirmed. |
role_based | A role account such as info@, sales@, admin@. |
disposable_email | A temporary / throwaway email domain. |
possible_typo | A likely misspelling was detected, see did_you_mean. |
spamtrap | Matches a known spam trap or complaint address. |
undeliverable_unknown | Genuinely undeterminable. The provider gave no reliable signal. |
Errors & status codes
Errors return a non-200 HTTP status with a JSON body of the shape { "error": "message" }.
| Code | Meaning |
|---|---|
| 200 | Success. Verification result returned. |
| 400 | Bad request. The email parameter is missing. |
| 401 | Unauthorized. The API key is missing or invalid. |
| 402 | Out of credits. Your monthly allowance is used up. |
| 429 | Too many requests. Slow down and retry. |
Rate & credits
- Each unique verification uses 1 credit.
- Repeated lookups of the same address are served from cache and are free.
- Requests are processed with a concurrency limiter, so large bursts (e.g. a Clay run) queue safely instead of failing.
Building a Clay workflow? Drop the GET URL straight into an HTTP enrichment column and map the response fields to Clay columns. See the Clay tab in your dashboard for a ready-made setup.
Code examples
cURL
curl "https://kluno.xyz/api/v1/verify?email=john@company.com&key=YOUR_API_KEY"JavaScript (fetch)
const res = await fetch( "https://kluno.xyz/api/v1/verify?email=john@company.com&key=YOUR_API_KEY" ); const data = await res.json(); console.log(data.status); // "valid"
Python (requests)
import requests r = requests.get("https://kluno.xyz/api/v1/verify", params={ "email": "john@company.com", "key": "YOUR_API_KEY", }) print(r.json()["status"]) # "valid"
PHP
$url = "https://kluno.xyz/api/v1/verify?email=john@company.com&key=YOUR_API_KEY"; $data = json_decode(file_get_contents($url), true); echo $data["status"]; // "valid"
Ready to try it? Create a free account and grab your API key with 500 verifications a month, no credit card.