Documentation
Complete API reference and developer guides for integrating VerifyKit email validation into your application.
Getting Started
Quick Start
Get started with VerifyKit in 3 steps. You'll be validating emails in under 3 minutes.
Get Your API Key
Sign up at verifykit.io/dashboard and create an API key. Free tier includes 1,000 validations/month.
Make Your First Request
Use your API key to validate an email address:
curl -X POST https://api.verifykit.io/v1/verify \
-H "Authorization: Bearer vk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'Get Results
Receive comprehensive validation results:
{
"valid": true,
"email": "[email protected]",
"reachable": "safe",
"score": 0.95,
"disposable": false,
"role_based": false,
"mx": {
"valid": true,
"records": ["mail.example.com"]
},
"smtp": {
"valid": true,
"state": "deliverable"
}
}SDKs
Official SDKs make integration with VerifyKit even easier. Choose your preferred language and get started in minutes.
Node.js SDK
Official Node.js SDK with TypeScript support, automatic retries, and comprehensive error handling.
Installation
npm install @verifykit.io/sdkQuick Start
import { VerifyKit } from '@verifykit.io/sdk';
const client = new VerifyKit({
apiKey: process.env.VERIFYKIT_API_KEY!
});
// Validate a single email
const result = await client.validate('[email protected]');
if (result.valid) {
console.log('Email is valid!');
console.log('Score:', result.score);
console.log('Reachable:', result.reachable);
} else {
console.log('Email is invalid');
}Features
Bulk Validation
// Validate multiple emails at once
const emails = [
'[email protected]',
'[email protected]',
'[email protected]'
];
const result = await client.validateBulk(emails);
console.log(`Validated ${result.summary.total} emails`);
console.log(`Valid: ${result.summary.valid}`);
console.log(`Invalid: ${result.summary.invalid}`);
// Check individual results
result.results.forEach(r => {
console.log(`${r.email}: ${r.valid ? '✓' : '✗'}`);
});Error Handling
import {
VerifyKit,
ValidationError,
RateLimitError,
AuthenticationError
} from '@verifykit.io/sdk';
try {
const result = await client.validate(email);
// Handle success
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid input:', error.message);
} else if (error instanceof RateLimitError) {
console.error('Rate limited. Retry after:', error.retryAfter);
} else if (error instanceof AuthenticationError) {
console.error('Invalid API key');
}
}Configuration
const client = new VerifyKit({
apiKey: process.env.VERIFYKIT_API_KEY!,
timeout: 30000, // Request timeout in ms
maxRetries: 3, // Max retry attempts
debug: false // Enable debug logging
});
// Skip SMTP verification for faster results
const result = await client.validate(email, {
skipSmtp: true
});
// Get usage statistics
const usage = await client.getUsage();
console.log(`Used: ${usage.current}/${usage.limit}`);
console.log(`Remaining: ${usage.remaining}`);PHP SDK
Official PHP SDK with full type safety, automatic retries, and comprehensive error handling. Supports PHP 7.4+ and PHP 8.x.
Installation
composer require verifykit-io/php-sdkQuick Start
<?php
require_once __DIR__ . '/vendor/autoload.php';
use VerifyKit\VerifyKit;
$client = new VerifyKit([
'apiKey' => $_ENV['VERIFYKIT_API_KEY']
]);
// Validate a single email
$result = $client->validate('[email protected]');
if ($result->valid) {
echo "Email is valid!\n";
echo "Score: {$result->score}\n";
echo "Reachable: {$result->reachable}\n";
} else {
echo "Email is invalid\n";
}Features
Bulk Validation
<?php
// Validate multiple emails at once
$emails = [
'[email protected]',
'[email protected]',
'[email protected]'
];
$result = $client->validateBulk($emails);
echo "Validated {$result->summary->total} emails\n";
echo "Valid: {$result->summary->valid}\n";
echo "Invalid: {$result->summary->invalid}\n";
// Check individual results
foreach ($result->results as $r) {
echo "{$r->email}: " . ($r->valid ? '✓' : '✗') . "\n";
}Error Handling
<?php
use VerifyKit\VerifyKit;
use VerifyKit\Exception\ValidationException;
use VerifyKit\Exception\RateLimitException;
use VerifyKit\Exception\AuthenticationException;
try {
$result = $client->validate($email);
// Handle success
} catch (ValidationException $e) {
echo "Invalid input: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
echo "Rate limited. Retry after: {$e->retryAfter}\n";
} catch (AuthenticationException $e) {
echo "Invalid API key\n";
}Configuration
<?php
$client = new VerifyKit([
'apiKey' => $_ENV['VERIFYKIT_API_KEY'],
'timeout' => 30000, // Request timeout in ms
'maxRetries' => 3, // Max retry attempts
'debug' => false // Enable debug logging
]);
// Skip SMTP verification for faster results
$result = $client->validate($email, skipSmtp: true);
// Get usage statistics
$usage = $client->getUsage();
echo "Used: {$usage->current}/{$usage->limit}\n";
echo "Remaining: {$usage->remaining}\n";More SDKs Coming Soon
We're working on official SDKs for more languages. Vote for your preferred language or request a new one.
Authentication
VerifyKit uses API keys for authentication. Include your API key in the Authorization header of every request.
Authorization: Bearer vk_live_your_api_key_hereSecurity Best Practices
- Never commit API keys to version control
- Store keys in environment variables
- Use different keys for development and production
- Rotate keys if they're compromised
- Never expose keys in client-side code
Environment Variables
VERIFYKIT_API_KEY=vk_live_your_api_key_here
VERIFYKIT_BASE_URL=https://api.verifykit.ioAPI Reference
/v1/verifyValidate a single email address. Returns comprehensive validation results including syntax, MX records, SMTP verification, and deliverability score.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address to validate | |
| skip_smtp | boolean | No | Skip SMTP verification for faster results |
Real SMTP Verification Included By Default
Unlike competitors who charge extra for SMTP verification, we include it by default in every validation. This ensures 97%+ accuracy out of the box. Use skip_smtp: true only when you need faster results for low-value use cases.
Validation Options
Syntax + MX + Disposable + SMTP verification. 97%+ accuracy.
{ "email": "[email protected]" }Syntax + MX + Disposable (100k+ domains, updated daily) checks. 85% accuracy. For real-time forms.
{ "email": "[email protected]", "skip_smtp": true }Response
{
"valid": true,
"email": "[email protected]",
"reachable": "safe",
"score": 0.95,
"quality_grade": "excellent",
"disposable": false,
"role_based": false,
"free_provider": false,
"mx": {
"valid": true,
"records": ["mail.example.com"]
},
"smtp": {
"valid": true,
"state": "deliverable",
"full_inbox": false
},
"syntax": {
"valid": true,
"username": "user",
"domain": "example.com"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| valid | boolean | Overall validation result |
| score | number | Quality score (0.0 - 1.0) |
| quality_grade | string? | "excellent", "good", "fair", or "poor" (only present for emails with valid syntax and MX records) |
| reachable | string | "safe", "risky", or "unknown" |
| disposable | boolean | Temporary/disposable email service |
| role_based | boolean | Generic role address (info@, support@) |
Understanding Quality Scores & Grades
All emails receive a quality score (0.0-1.0). However, quality grades are only assigned to emails that pass basic validation (valid syntax + valid MX records). This ensures grades are only applied to potentially deliverable emails.
Score Calculation Weights:
- • SMTP Verification (40%) - Most important: actual deliverability
- • Syntax Validation (20%) - Basic email format
- • MX Records (20%) - DNS validation
- • Disposable Check (10%) - Fraud prevention
- • Role-based (5%) - Quality indicator
- • Free Email (5%) - Quality indicator
High deliverability, low risk. Safe for critical communications.
Acceptable quality. Moderate deliverability expected.
Use with caution. High bounce risk. Monitor closely.
Not recommended. High rejection probability.
💡 Tip: Use quality grades to segment your email lists and prioritize high-quality leads.
/v1/verify/bulkValidate up to 1,000 email addresses in a single request. Results are returned instantly for batches under 100 emails.
Free Duplicate Removal
We automatically remove duplicate emails before validation at no extra cost. Competitors charge for this feature.
Performance
Instant results in 2-3 seconds
Results in 5-15 seconds
Cost Savings Example
Clean a list of 10,000 emails (with 2,000 duplicates):
You save $40 (50%) with automatic duplicate removal!
Request Body
{
"emails": [
"[email protected]",
"[email protected]",
"[email protected]"
],
"skip_smtp": false // Optional: defaults to false (includes SMTP)
}Response
{
"results": [
{
"email": "[email protected]",
"valid": true,
"score": 0.95,
"quality_grade": "excellent",
"reachable": "safe"
},
{
"email": "[email protected]",
"valid": false,
"score": 0.2,
"quality_grade": "poor",
"reachable": "risky"
}
],
"summary": {
"total": 2,
"valid": 1,
"invalid": 1,
"processing_time_ms": 420
}
}/v1/statsGet usage statistics for your API key, including validations used, remaining quota, and rate limit status.
Response
{
"current_usage": 750,
"monthly_limit": 1000,
"percentage_used": 75,
"plan": "free",
"period_start": "2024-01-01T00:00:00Z",
"period_end": "2024-01-31T23:59:59Z",
"rate_limit": {
"requests_per_minute": 10,
"requests_remaining": 8
}
}Use Cases
Real-world scenarios where VerifyKit helps you build better products and save money.
Prevent Fake Signups
Block disposable and temporary email addresses at registration. Stop fake accounts before they enter your system.
async function validateSignup(email) {
const result = await fetch('https://api.verifykit.io/v1/verify', {
method: 'POST',
headers: {
'Authorization': 'Bearer vk_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({ email }) // Full SMTP verification by default
}).then(r => r.json());
// Block disposable emails
if (result.disposable) {
throw new Error('Please use a permanent email address');
}
// Block low-quality emails
if (result.score < 0.7) {
throw new Error('Email appears invalid');
}
return result.valid;
}Clean Email Lists
Validate your email list before campaigns. Remove invalid addresses, reduce bounce rates, improve deliverability.
import requests
def clean_email_list(email_list):
response = requests.post(
'https://api.verifykit.io/v1/verify/bulk',
headers={'Authorization': 'Bearer vk_live_...'},
json={'emails': email_list} # Full SMTP verification included
)
results = response.json()
# Filter valid, deliverable emails
clean_list = [
r['email'] for r in results['results']
if r['valid'] and r['reachable'] == 'safe' and r['score'] > 0.7
]
print(f"Original: {len(email_list)} emails")
print(f"Clean: {len(clean_list)} emails")
print(f"Removed: {len(email_list) - len(clean_list)} invalid")
return clean_listReal-time Form Validation
Validate emails as users type. Provide instant feedback, improve UX, catch typos before submission.
function EmailInput() {
const [email, setEmail] = useState('');
const [status, setStatus] = useState('idle');
const [error, setError] = useState('');
const validateEmail = useDebouncedCallback(async (value) => {
if (!value) return;
setStatus('validating');
try {
const result = await fetch('https://api.verifykit.io/v1/verify', {
method: 'POST',
headers: {
'Authorization': 'Bearer vk_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: value,
skip_smtp: true // Fast validation for real-time feedback
})
}).then(r => r.json());
if (!result.valid) {
setError('Email address appears invalid');
setStatus('error');
} else if (result.disposable) {
setError('Please use a permanent email address');
setStatus('error');
} else {
setError('');
setStatus('valid');
}
} catch (err) {
setStatus('idle');
}
}, 500);
return (
<input
type="email"
value={email}
onChange={(e) => {
setEmail(e.target.value);
validateEmail(e.target.value);
}}
className={status === 'error' ? 'border-red-500' : ''}
/>
);
}Smart Typo Detection & Correction
Automatically detect and suggest corrections for common email typos. Improve data quality and reduce user frustration.
async function validateWithTypoCheck(email) {
const result = await fetch('https://api.verifykit.io/v1/verify', {
method: 'POST',
headers: {
'Authorization': 'Bearer vk_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, skip_smtp: true })
}).then(r => r.json());
// Check for typo suggestion
if (result.did_you_mean) {
// Show suggestion to user
const useCorrection = confirm(
`Did you mean: ${result.did_you_mean}?`
);
if (useCorrection) {
// Validate the corrected email
return validateWithTypoCheck(result.did_you_mean);
}
}
return result;
}
// Example results:
// [email protected] → Suggests: [email protected]
// [email protected] → Suggests: [email protected]
// [email protected] → Suggests: [email protected]Quality Grades & Score-based Filtering
Every email receives a quality score (0.0-1.0) and a human-readable grade (excellent/good/fair/poor). Use these to segment users and personalize onboarding.
Quality Grade Calculation:
Note: Grades are only assigned to emails with valid syntax and MX records
async function segmentUser(email) {
const result = await verifyEmail(email);
// Use quality_grade for cleaner logic
switch (result.quality_grade) {
case 'excellent':
// High quality - auto-approve, skip extra verification
return {
segment: 'premium',
actions: ['enable_full_access', 'skip_email_verification'],
onboarding: 'fast_track'
};
case 'good':
// Good quality - standard flow
return {
segment: 'standard',
actions: ['send_verification_email'],
onboarding: 'normal'
};
case 'fair':
// Risky - require extra verification
return {
segment: 'risky',
actions: ['require_phone_verification', 'limit_initial_access'],
onboarding: 'cautious'
};
case 'poor':
default:
// Low quality or no grade - reject
return {
segment: 'reject',
actions: ['block_signup'],
message: 'Please use a valid email address'
};
}
}
// Or use numeric scores for more granular control
if (result.score >= 0.9) { /* ... */ }
else if (result.score >= 0.7) { /* ... */ }Error Handling
Handle API errors gracefully to ensure a smooth user experience.
HTTP Status Codes
Success
Request completed successfully
Bad Request
Invalid parameters or malformed request
Unauthorized
Invalid or missing API key
Rate Limited
Too many requests, retry after indicated time
Server Error
Internal error, retry with exponential backoff
Example Error Handling
async function validateWithRetry(email, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch('https://api.verifykit.io/v1/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.VERIFYKIT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (response.ok) {
return await response.json();
}
// Handle specific errors
if (response.status === 401) {
throw new Error('Invalid API key');
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited, waiting ${retryAfter}s`);
await sleep(retryAfter * 1000);
continue;
}
if (response.status === 400) {
const error = await response.json();
throw new Error(`Validation error: ${error.message}`);
}
// Retry on server errors
if (response.status >= 500) {
const backoff = Math.pow(2, i) * 1000;
console.log(`Server error, retrying in ${backoff}ms`);
await sleep(backoff);
continue;
}
} catch (error) {
if (i === maxRetries - 1) throw error;
const backoff = Math.pow(2, i) * 1000;
await sleep(backoff);
}
}
throw new Error('Max retries exceeded');
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}Rate Limits
Rate limits protect the API and ensure fair usage across all users.
Limits by Plan
60 requests/minute, 1,000 validations/month
500 requests/minute, 50,000 validations/month
2,000 requests/minute, unlimited validations
How Monthly Quotas Work
Monthly quotas reset on the 1st of each calendar month at 00:00 UTC. Everyone's quota refreshes at the same time, making it predictable and easy to plan.
When you subscribe mid-month, you receive your full monthly quota immediately. For example:
This means your first month is always a bonus - no prorating!
We believe in being generous with our users. Rather than complicated proration or billing cycle tracking, we give you a full quota when you join. Simple, fair, and no surprises.
Rate Limit Headers
Every API response includes rate limit information in the headers:
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 495
X-RateLimit-Reset: 1640000000
X-Monthly-Limit: 50000
X-Monthly-Usage: 1250
Retry-After: 60Monitor these headers to avoid hitting rate limits. When you receive a 429 status, wait for the time specified in Retry-After before retrying.
Why Choose VerifyKit?
VerifyKit offers the same accuracy as industry leaders, with better value for SMBs, agencies, and indie developers.
SMTP Included by Default
Real SMTP verification included in every validation at no extra cost. Competitors charge separately for this critical feature.
Advanced Fraud Prevention
Comprehensive disposable email detection with 100k+ known domains (updated daily) plus intelligent pattern matching for new services.
Free Duplicate Removal
Automatically remove duplicate emails in bulk validations at no extra charge. Only pay for unique emails.
Instant Bulk Results
Get instant results for up to 100 emails. Competitors make you wait in a queue.
Smart Typo Detection
Automatically detect and suggest corrections for typos like gmial.com → gmail.com.
97%+ Accuracy
Same accuracy as ZeroBounce and NeverBounce, powered by real SMTP verification.
Feature Comparison
| Feature | VerifyKit | ZeroBounce | NeverBounce | Hunter.io |
|---|---|---|---|---|
| SMTP Verification | ✅ Included | ⚠️ Extra cost | ✅ Yes | ✅ Yes |
| Instant Results | ✅ <3s | ❌ Queue | ❌ Queue | ⚠️ Slow |
| Free Duplicates | ✅ Yes | ❌ Charged | ❌ Charged | ❌ Charged |
| Unlimited API Calls | ✅ Yes | ❌ Limited | ❌ Limited | ❌ Limited |
| Unlimited Plan | ✅ Available | ❌ No | ❌ No | ❌ No |
| Modern API | ✅ Yes | ⚠️ Legacy | ⚠️ Legacy | ✅ Yes |
Choose Your Use Case
Indie Developer / Small SaaS
Building a product with user signups. Need to validate emails at registration and occasionally clean your user list.
Small Agency / Marketing Team
Running email campaigns for multiple clients. Clean email lists monthly, validate new leads, ensure high deliverability.
High-Volume SaaS / Enterprise
Large user base with continuous signups. Need unlimited validations with predictable costs. No surprise bills.
Agency ROI Example
How agencies use VerifyKit to deliver better results to clients while maintaining healthy profit margins:
Bottom line: Deliver better campaign results to clients while maintaining 80% profit margins on email validation services.
Code Examples
Ready-to-use code snippets in popular languages and frameworks.
Node.js / Express
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const VERIFYKIT_API_KEY = process.env.VERIFYKIT_API_KEY;
app.post('/api/signup', async (req, res) => {
const { email, name } = req.body;
try {
// Validate email with VerifyKit (includes SMTP verification)
const validation = await axios.post(
'https://api.verifykit.io/v1/verify',
{ email },
{
headers: {
'Authorization': `Bearer ${VERIFYKIT_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
const result = validation.data;
// Block invalid or disposable emails
if (!result.valid || result.disposable) {
return res.status(400).json({
error: 'Invalid email address'
});
}
// Continue with signup...
res.json({ success: true });
} catch (error) {
console.error('Validation error:', error);
res.status(500).json({ error: 'Server error' });
}
});
app.listen(3000);Python / Django
import requests
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import os
VERIFYKIT_API_KEY = os.getenv('VERIFYKIT_API_KEY')
@require_http_methods(["POST"])
def signup(request):
email = request.POST.get('email')
name = request.POST.get('name')
# Validate email with VerifyKit (includes SMTP verification)
response = requests.post(
'https://api.verifykit.io/v1/verify',
headers={
'Authorization': f'Bearer {VERIFYKIT_API_KEY}',
'Content-Type': 'application/json'
},
json={'email': email}
)
result = response.json()
# Block invalid or disposable emails
if not result['valid'] or result['disposable']:
return JsonResponse({
'error': 'Invalid email address'
}, status=400)
# Continue with signup...
return JsonResponse({'success': True})Ruby / Rails
require 'net/http'
require 'json'
class SignupsController < ApplicationController
def create
email = params[:email]
name = params[:name]
# Validate email with VerifyKit (includes SMTP verification)
uri = URI('https://api.verifykit.io/v1/verify')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{ENV['VERIFYKIT_API_KEY']}"
request['Content-Type'] = 'application/json'
request.body = { email: email }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
# Block invalid or disposable emails
unless result['valid'] && !result['disposable']
render json: { error: 'Invalid email address' }, status: 400
return
end
# Continue with signup...
render json: { success: true }
end
endPHP / Laravel
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class SignupController extends Controller
{
public function store(Request $request)
{
$email = $request->input('email');
$name = $request->input('name');
// Validate email with VerifyKit (includes SMTP verification)
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('VERIFYKIT_API_KEY'),
'Content-Type' => 'application/json'
])->post('https://api.verifykit.io/v1/verify', [
'email' => $email
]);
$result = $response->json();
// Block invalid or disposable emails
if (!$result['valid'] || $result['disposable']) {
return response()->json([
'error' => 'Invalid email address'
], 400);
}
// Continue with signup...
return response()->json(['success' => true]);
}
}
?>Questions?
Need help integrating VerifyKit? Have a specific use case not covered here? We're here to help.
Contact Support