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. Plans start at $9/mo with SMTP verification and a 14-day money-back guarantee.
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": "user@example.com"}'Get Results
Receive comprehensive validation results:
{
"valid": true,
"email": "user@example.com",
"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('user@example.com');
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 = [
'user1@example.com',
'user2@example.com',
'invalid@disposable.com'
];
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('user@example.com');
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 = [
'user1@example.com',
'user2@example.com',
'invalid@disposable.com'
];
$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";2FA Node.js SDK
Dedicated SDK for two-factor authentication via email OTP. Separate package from the validation SDK.
Installation
npm install @verifykit.io/2faQuick Start
import { VerifyKit2FA } from '@verifykit.io/2fa';
const client = new VerifyKit2FA({
apiKey: process.env.VERIFYKIT_API_KEY!
});
// Send a verification code
const { request_id } = await client.sendOtp('user@example.com');
// Verify the code the user entered
const result = await client.verifyOtp(request_id, '847293');
if (result.valid) {
console.log('User verified!');
}Features
2FA PHP SDK
Dedicated PHP SDK for two-factor authentication via email OTP. Zero dependencies beyond ext-json.
Installation
composer require verifykit-io/2fa-php-sdkQuick Start
use VerifyKit2FA\VerifyKit2FA;
$client = new VerifyKit2FA(
apiKey: $_ENV['VERIFYKIT_API_KEY']
);
// Send a verification code
$result = $client->sendOtp('user@example.com');
$requestId = $result->requestId;
// Verify the code the user entered
$verification = $client->verifyOtp($requestId, '847293');
if ($verification->valid) {
echo 'User verified!';
}Features
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": "user@example.com" }Syntax + MX + Disposable (100k+ domains, updated daily) checks. 85% accuracy. For real-time forms.
{ "email": "user@example.com", "skip_smtp": true }Response
{
"valid": true,
"email": "user@example.com",
"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.
Automatic Duplicate Removal (Pro+)
On Pro and Unlimited plans, we automatically remove duplicate emails before validation. Only unique emails count toward your quota.
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": [
"user1@example.com",
"user2@example.com",
"user3@example.com"
],
"skip_smtp": false // Optional: defaults to false (includes SMTP)
}Response
{
"results": [
{
"email": "user1@example.com",
"valid": true,
"score": 0.95,
"quality_grade": "excellent",
"reachable": "safe"
},
{
"email": "user2@example.com",
"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
}
}Two-Factor Auth (2FA)
Overview
Send and verify one-time passcodes (OTP) via email for two-factor authentication.
Plan Availability
- Growth — 25,000 OTP codes/month
- Pro — 50,000 OTP codes/month
- Unlimited — 100,000 OTP codes/month
/v1/2fa/sendSend a 6-digit OTP verification code to an email address. The code expires after 10 minutes.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address to send the code to | |
| app_name | string | No | Your app name (max 50 chars). Shown in the email subject and body for branding. |
| delivery | string | No | "email" (default) sends via VerifyKit. "api" returns the code in the response for you to deliver yourself. |
Request
curl -X POST https://api.verifykit.io/v1/2fa/send \
-H "Authorization: Bearer vk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "app_name": "MyApp"}'Response
{
"request_id": "2fa_abc123...",
"expires_in": 600,
"message": "Verification code sent"
}Bring Your Own Email (delivery: "api")
Set delivery to "api" to receive the OTP code in the response instead of having VerifyKit send the email. This lets you use your own email service for consistent branding.
curl -X POST https://api.verifykit.io/v1/2fa/send \
-H "Authorization: Bearer vk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "delivery": "api"}'Response (delivery: "api")
{
"request_id": "2fa_abc123...",
"expires_in": 600,
"message": "Verification code generated",
"code": "847293"
}/v1/2fa/verifyVerify a 6-digit OTP code. Codes are single-use and are invalidated after 5 failed attempts.
Request
curl -X POST https://api.verifykit.io/v1/2fa/verify \
-H "Authorization: Bearer vk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"request_id": "2fa_abc123...", "code": "847293"}'Response (success)
{
"valid": true,
"request_id": "2fa_abc123...",
"message": "Verification successful"
}Response (failure)
{
"valid": false,
"request_id": "2fa_abc123...",
"message": "Invalid verification code"
}SDK Examples
Node.js
import { VerifyKit2FA } from '@verifykit.io/2fa';
const client = new VerifyKit2FA({
apiKey: process.env.VERIFYKIT_API_KEY!
});
// Send an OTP code (app_name is optional, for branded emails)
const { request_id } = await client.sendOtp('user@example.com', {
appName: 'MyApp'
});
// Or use delivery: "api" to get the code and send it yourself
const { request_id: rid, code } = await client.sendOtp('user@example.com', {
delivery: 'api'
});
// code = "847293" — send it via your own email service
// Verify the code the user entered
const result = await client.verifyOtp(request_id, '847293');
if (result.valid) {
console.log('User verified!');
}PHP
use VerifyKit2FA\VerifyKit2FA;
$client = new VerifyKit2FA(apiKey: $_ENV['VERIFYKIT_API_KEY']);
// Send an OTP code (app_name is optional, for branded emails)
$result = $client->sendOtp('user@example.com', 'MyApp');
$requestId = $result->requestId;
// Or use delivery "api" to get the code and send it yourself
$result = $client->sendOtp('user@example.com', delivery: 'api');
// $result->code = "847293" — send it via your own email service
// Verify the code the user entered
$verification = $client->verifyOtp($requestId, '847293');
if ($verification->valid) {
echo 'User verified!';
}Security & Limits
Codes are deleted after successful verification
Codes expire after 600 seconds
Code invalidated after 5 wrong attempts
Max 5 codes per email per 10-minute window
Error Codes
| Status | Error | Description |
|---|---|---|
| 400 | Validation Error | Invalid email or code format |
| 403 | Forbidden | Plan does not include 2FA (upgrade to Growth+) |
| 429 | Rate Limited | Too many codes sent or monthly limit exceeded |
| 500 | Internal Server Error | Unexpected error processing request |
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:
// user@gmial.com → Suggests: user@gmail.com
// test@hotmial.com → Suggests: test@hotmail.com
// hello@yaho.com → Suggests: hello@yahoo.comQuality 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));
}Plans & Pricing
Four plans designed to grow with you. Each tier builds on the previous one, unlocking more features as your needs grow.
Starter
- 5,000 validations/month
- Single API key
- Real SMTP verification
- Validation history
Growth
- 15,000 validations/month
- Single API key
- Real SMTP verification
- Validation history
- Bulk validation
- Email OTP 2FA (25k/mo)
Pro
- 50,000 validations/month
- Unlimited API keys
- Duplicate removal
- Webhooks & callbacks
- Email OTP 2FA (50k/mo)
Unlimited
- Unlimited validations
- Unlimited API keys
- All Pro features
- Dedicated support
- Fair usage up to 5M/month
- Email OTP 2FA (100k/mo)
What's Included in Each Validation Tier
Not all validation is equal. Here's exactly what checks run at each tier so you know what you're getting.
Pattern-based checks that run instantly. Good for catching typos and obvious fakes, but cannot confirm if a mailbox actually exists.
Syntax validation
RFC 5322 format checks
MX record lookup
Verifies domain has mail servers
Disposable detection
100k+ throwaway domains
Role-based detection
Flags info@, admin@, support@
Free provider detection
Gmail, Yahoo, Outlook, etc.
Deliverability score
0.0 - 1.0 confidence score
Note: Basic validation tells you if an email looks valid. It checks format and domain, but cannot confirm the mailbox exists. For that, you need SMTP verification.
Everything in basic validation, plus we connect to the recipient's mail server to verify the mailbox actually exists. This is the only way to know if an email is truly deliverable.
SMTP mailbox check
Connects to mail server, verifies mailbox exists
Catch-all detection
Identifies domains accepting all emails
Full inbox detection
Flags mailboxes that can't receive mail
Deliverability state
safe / risky / invalid classification
Quality grading
excellent / good / fair / poor
Validation history
Browse and filter past results
Feature Breakdown by Plan
Each plan includes everything from the tier below it, plus new features. New features at each tier are highlighted.
| Feature | Starter | Growth | Pro | Unlimited |
|---|---|---|---|---|
| Monthly validations | 5,000 | 15,000 | 50,000 | Unlimited |
| API keys | 1 | 1 | Unlimited | Unlimited |
| Rate limit | 150/min | 300/min | 500/min | 2,000/min |
| Basic validation | ✓ | ✓ | ✓ | ✓ |
| Real SMTP verification | ✓ | ✓ | ✓ | ✓ |
| Validation history | ✓ | ✓ | ✓ | ✓ |
| Bulk validation | ✗ | ✓ | ✓ | ✓ |
| Email OTP 2FA | ✗ | 25k/mo | 50k/mo | 100k/mo |
| Duplicate removal | ✗ | ✗ | ✓ | ✓ |
| Webhooks & callbacks | ✗ | ✗ | ✓ | ✓ |
| Dedicated support | ✗ | ✗ | ✗ | ✓ |
| Fair usage up to 5M/month | ✗ | ✗ | ✗ | ✓ |
What Each Upgrade Unlocks
Unlock bulk validation to validate up to 1,000 emails per request and Email OTP 2FA with 25,000 codes/month. Your validation quota increases from 5,000 to 15,000/month.
Unlock unlimited API keys for multi-app setups, automatic duplicate removal in bulk requests, and webhooks & callbacks for async workflows. 2FA quota increases to 50,000 codes/month. Quota jumps to 50,000 validations/month with 500 requests/minute rate limit.
Remove all volume limits with unlimited validations under a fair usage policy of up to 5M/month. Get dedicated support with direct access to our team. 2FA quota increases to 100,000 codes/month. Rate limit increases to 2,000 requests/minute.
Rate Limits
Rate limits protect the API and ensure fair usage across all users.
Limits by Plan
150 requests/minute, 5,000 validations/month
300 requests/minute, 15,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.
Real SMTP Verification
Real SMTP verification available from the Starter plan. Competitors charge separately for this critical feature or lock it behind expensive tiers.
Advanced Fraud Prevention
Comprehensive disposable email detection with 100k+ known domains (updated daily) plus intelligent pattern matching for new services.
Automatic Duplicate Removal
Pro and Unlimited plans automatically remove duplicate emails in bulk validations. 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 | ✅ From $19/mo | ⚠️ Extra cost | ✅ Yes | ✅ Yes |
| Instant Results | ✅ <3s | ❌ Queue | ❌ Queue | ⚠️ Slow |
| Duplicate Removal | ✅ Pro+ | ❌ 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 Project
Building a product with user signups. Need accurate SMTP verification, validation history, and bulk processing for periodic list cleaning.
Growing SaaS / Agency
Running email campaigns for multiple clients or managing several apps. Need unlimited API keys, webhooks, duplicate removal, and high volume.
High-Volume SaaS / Enterprise
Large user base with continuous signups. Need unlimited validations with predictable costs and dedicated support. Fair usage up to 5M/month.
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