Email Validator v1.0 1 credit / call
Validate email addresses — syntax, MX/deliverability, disposable and role-based detection.
- Base path
- /api/v1/email-validator
- Methods
- GET or POST — parameters are read identically from the query string or a JSON body
- Auth
- X-Api-Key header (never Authorization: Bearer)
- Price
- 1 credit per call · about $0.0010 at 1,000 credits/USD
- Free tier
- 50 credits, refilled every month — drawn down before your paid balance
- Test mode
- Supported — ksty_test_ keys call this API free of charge
- Rate limit
- 60 calls/minute per key by default, raisable per key
Email Validator API
Validates an email address across four independent layers — syntax, domain deliverability (MX), disposable-domain detection and role-address detection — and returns each result separately so you decide how strict to be. Syntax and normalization always run locally; the MX check is a best-effort DNS lookup you can switch off per call.
What "valid" actually means
There is no single test that proves an address will receive mail — the only certain check is to send a message and watch for a bounce, which you cannot do at signup time. Validation is therefore a stack of cheaper signals, each ruling out a different class of bad address, and valid is a conservative summary of them. Treat the individual checks as the real output and valid as a sensible default.
POST /api/v1/email-validator
X-Api-Key: ksty_test_...
Content-Type: application/json
{"email": "jane.doe@example.com"}
{
"email": "jane.doe@example.com",
"normalized": "jane.doe@example.com",
"valid": true,
"checks": { "syntax": true, "mx": true, "disposable": false, "role": false },
"domain": "example.com"
}
The four checks
Syntax
The address is parsed against the standard email grammar. This catches typos like a missing @, illegal characters or a malformed domain. It is deterministic and offline, so it always runs first — if syntax fails, nothing downstream can succeed.
MX / deliverability
The gateway looks up the domain's DNS records and asks a simple question: can this domain receive mail at all? A domain with an MX record (or a fallback A record) can accept mail; one with neither cannot, no matter how well-formed the address is. This proves the domain is deliverable — not that the specific mailbox exists, which no lookup can tell you.
example.com -> DNS query for MX
-> mail.example.com (has MX) => deliverable
typo-domain.invalid -> no MX, no A => not deliverable
Disposable
The domain is matched against a curated list of throwaway / temporary-mailbox providers (Mailinator, Guerrilla Mail, 10 Minute Mail and similar). These addresses are syntactically perfect and often have valid MX, but exist only to slip past a signup — so a disposable hit forces valid to false.
Role-based
The local-part (the text before the @) is matched against common function addresses like info, support, sales or admin. These reach a team rather than a person. It is reported as a flag, not a failure — you might warn on it for a personal-account signup while happily accepting it on a contact form.
Accuracy & limitations
- Mailbox existence is out of scope. A pass means the address is well-formed and its domain can receive mail — not that the specific inbox exists or is monitored.
- MX is best-effort. If the DNS lookup is slow or inconclusive it returns
null(unknown) rather than failing the call, and an unknown MX result does not on its own make an address invalid. - Lists are heuristic. The disposable and role lists are curated and self-contained; they catch the common cases, not every possible domain or alias.
The MX lookup adds network latency and can occasionally be inconclusive. For high-volume or offline validation — cleaning a large import, for example — send
check_mx: falseto run the fast, fully-local syntax and heuristic checks only.
When to use it
- At signup, to reject typos and disposable addresses before they reach your database.
- Cleaning an existing list, with
check_mx: falsefor speed on large batches. - Gating sensitive flows where you want to flag (not necessarily block) role addresses.
Endpoints
Validate a single email address
true
curl -X POST "https://ksty.ch/api/v1/email-validator" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","check_mx":true}'
<?php
$ch = curl_init('https://ksty.ch/api/v1/email-validator');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Key: YOUR_API_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{ "email": "jane@example.com", "check_mx": true}',
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
const response = await fetch('https://ksty.ch/api/v1/email-validator', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"email": "jane@example.com",
"check_mx": true
})
});
const data = await response.json();
import requests
response = requests.post(
'https://ksty.ch/api/v1/email-validator',
headers={'X-Api-Key': 'YOUR_API_KEY'},
json={
"email": "jane@example.com",
"check_mx": true
},
)
data = response.json()
{
"email": "Jane@Example.com",
"normalized": "jane@example.com",
"valid": true,
"checks": {
"syntax": true,
"mx": true,
"disposable": false,
"role": false
},
"domain": "example.com"
}
Errors
Errors are JSON with a stable error.code — branch on the code, never on
the message. Everything below carries the X-Request-Id of the failed call.
Requests rejected by this API are not charged, and a 502 after a
charge is refunded automatically.
Response headers
Every successful call reports its own cost, so you never have to guess what a request spent or reconcile it later.