Validation API
Standalone website and email validation without creating leads. Perfect for quick checks, integrations, and automated verification workflows.
Overview
The Validation API provides three endpoints for on-demand validation:
- Check Website - Validate website accessibility (synchronous)
- Check Email - Validate email deliverability (hybrid sync/async)
- Poll Job Status - Retrieve results for async validations
Pricing
| Operation | Cost (Stored) | Cost (Display) |
|---|---|---|
| Check Website | 0.001 credits | 1 credit |
| Check Email | 0.001 credits | 1 credit |
| Lead Validation | 0.002 credits | 2 credits |
New Users: Get 2,000 display credits (2.0 stored credits) on signup!
Rate Limits
| Endpoint | Rate Limit |
|---|---|
/check-website | 10 requests/minute |
/check-email | 10 requests/minute |
/leads/validate | 5 requests/minute |
Check Website
Validate website HTTP status and accessibility with intelligent retry logic.
Endpoint: POST /v1/check-website
Authentication: API Key or OAuth 2.0 Bearer Token
Processing: Synchronous - returns results immediately (max ~30s)
Features
- ✅ Intelligent retry with progressive timeouts (10s → 20s → 15s)
- ✅ Smart fallbacks (HTTPS→HTTP, www variants)
- ✅ SSL validation
- ✅ Parked domain detection
- ✅ Redirect chain tracking
- ✅ Response time measurement
Request
curl -X POST https://api.status-check.io/v1/check-website \
-H "X-API-Key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"website": "example.com",
"returnDetails": true
}'
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
website | string | Yes | Website URL to validate (1-255 chars) |
returnDetails | boolean | No | Return full details vs simple status (default: true) |
Response (Success)
{
"website": "https://example.com",
"status": "active",
"valid": true,
"httpStatus": 200,
"finalUrl": "https://example.com/",
"sslValid": true,
"isParked": false,
"responseTimeMs": 245.67,
"redirectChain": [
"https://example.com",
"https://example.com/"
],
"error": null,
"creditsDeducted": 0.001,
"creditsRemaining": 1.999
}
Response Fields
| Field | Type | Description |
|---|---|---|
website | string | Validated website URL |
status | string | Validation status: active, inactive, error |
valid | boolean | True if website is accessible (status == "active") |
httpStatus | number | HTTP response code (200, 404, etc.) |
finalUrl | string | Final URL after following redirects |
sslValid | boolean | Whether SSL certificate is valid |
isParked | boolean | Domain appears to be parked |
responseTimeMs | number | Total response time in milliseconds |
redirectChain | array | Full redirect chain (if any) |
error | string | Error message (if status is error) |
creditsDeducted | number | Credits charged (0.001 stored credits) |
creditsRemaining | number | Your remaining credit balance |
Response (Error)
{
"website": "invalid-domain.xyz",
"status": "error",
"valid": false,
"error": "DNS resolution failed: domain not found",
"creditsDeducted": 0.001,
"creditsRemaining": 1.999
}
Credits are deducted upfront and not refunded on failures. This is standard practice to prevent abuse.
Status Values
| Status | Description |
|---|---|
active | Website is accessible (HTTP 2xx-3xx) |
inactive | Website returned 4xx/5xx or timeout |
error | DNS failure, network error, or other issues |
Validation Strategy
The endpoint uses a three-tier validation approach:
-
Initial Check (10s timeout)
- Try HTTPS with original URL
- If successful → return immediately
-
Retry on Soft Failures (20s timeout)
- Retry if: timeout, 5xx error, or SSL issue
- If successful → return immediately
-
Smart Fallbacks (15s timeout)
- SSL error → try HTTP instead
- DNS/404 error → try www variant
- Return final result
Total maximum time: ~30 seconds
Hard failures (fast fail ~2-3s):
- DNS resolution errors
- Connection refused
- Network unreachable
Check Email
Validate email deliverability with SMTP verification (no email sent).
Endpoint: POST /v1/check-email
Authentication: API Key or OAuth 2.0 Bearer Token
Processing: Hybrid sync/async
Hybrid Processing Model
The endpoint intelligently handles email validation:
- Submit validation to XOR API
- Poll internally for up to
timeoutseconds (default 30s) - If completes within timeout: Return full results synchronously
- If timeout expires: Return
jobIdfor polling - Background task continues polling until complete
Success rate: ~60-70% of validations complete within 30 seconds
Features
- ✅ SMTP verification (no email sent)
- ✅ Disposable email detection
- ✅ Catch-all domain detection
- ✅ Email type classification (corporate, personal, role)
- ✅ Risk scoring (0-100)
- ✅ Service provider identification
- ✅ Optional webhook callback
Request
curl -X POST https://api.status-check.io/v1/check-email \
-H "X-API-Key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"timeout": 30,
"returnDetails": true,
"webhookUrl": "https://yourapp.com/webhook"
}'
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address to validate (must be valid format) |
timeout | number | No | Max seconds to wait (5-60, default: 30) |
returnDetails | boolean | No | Return full details vs simple status (default: true) |
webhookUrl | string | No | Optional webhook for async completion |
Response (Completed Synchronously)
{
"email": "user@example.com",
"status": "valid",
"valid": true,
"catchAll": false,
"disposable": false,
"service": "Google",
"domain": "gmail-smtp-in.l.google.com",
"emailType": "personal",
"emailRisk": "low",
"emailScore": 95,
"waitTime": "12.5s",
"creditsDeducted": 0.001,
"creditsRemaining": 1.999
}
Response (Timeout - Async)
{
"email": "user@example.com",
"status": "processing",
"jobId": "val_abc123def456",
"pollUrl": "/v1/validation-jobs/val_abc123def456",
"estimatedCompletion": "2025-01-15T10:35:00Z",
"message": "Email validation is processing. Poll the provided URL for results or wait for webhook notification.",
"creditsDeducted": 0.001,
"creditsRemaining": 1.999
}
Response Fields (Completed)
| Field | Type | Description |
|---|---|---|
email | string | Validated email address |
status | string | Validation status: valid, invalid, risky, unknown, processing |
valid | boolean | Whether email is deliverable |
catchAll | boolean | Domain accepts all emails (risky) |
disposable | boolean | Disposable/temporary email service |
service | string | Email service provider (e.g., "Google", "Microsoft") |
domain | string | SMTP server domain |
emailType | string | Email type: corporate, personal, role |
emailRisk | string | Risk level: low, medium, high |
emailScore | number | Quality score (0-100) |
waitTime | string | Time waited for results (e.g., "12.5s") |
creditsDeducted | number | Credits charged (0.001) |
creditsRemaining | number | Your remaining balance |
Status Values
| Status | Description |
|---|---|
valid | Email is deliverable |
invalid | Email is not deliverable |
risky | Email might be deliverable (catch-all) |
unknown | Validation inconclusive |
processing | Still validating (async) |
Webhook Callback
If you provide a webhookUrl, you'll receive a POST request when validation completes:
{
"event": "validation.complete",
"jobId": "val_abc123def456",
"email": "user@example.com",
"result": {
"valid": true,
"catch_all": false,
"service": "Google"
},
"timestamp": "2025-01-15T10:35:00Z"
}
Ad-hoc webhooks (via webhookUrl parameter) are:
- ✅ Authenticated (must be logged in)
- ❌ Not signed (no HMAC signature)
- ❌ No retries (one-time delivery)
For production webhooks, use the Webhooks API.
Poll Job Status
Retrieve status and results for an async validation job.
Endpoint: GET /v1/validation-jobs/{jobId}
Authentication: API Key or OAuth 2.0 Bearer Token
Use Case
When check-email returns status: "processing" due to timeout, use this endpoint to poll for results.
Request
curl -X GET https://api.status-check.io/v1/validation-jobs/val_abc123def456 \
-H "X-API-Key: sk_your_api_key"
Response (Completed)
{
"jobId": "val_abc123def456",
"type": "email",
"input": "user@example.com",
"status": "completed",
"result": {
"email": "user@example.com",
"valid": true,
"catch_all": false,
"service": "Google",
"domain": "gmail-smtp-in.l.google.com",
"email_type": "personal",
"email_risk": "low",
"email_score": 95
},
"createdAt": "2025-01-15T10:30:00Z",
"completedAt": "2025-01-15T10:30:45Z",
"elapsedTime": "45s"
}
Response (Still Processing)
{
"jobId": "val_abc123def456",
"type": "email",
"input": "user@example.com",
"status": "processing",
"createdAt": "2025-01-15T10:30:00Z",
"elapsedTime": "12s"
}
Response (Failed)
{
"jobId": "val_abc123def456",
"type": "email",
"input": "user@example.com",
"status": "failed",
"error": "SMTP connection timeout",
"createdAt": "2025-01-15T10:30:00Z",
"completedAt": "2025-01-15T10:31:30Z",
"elapsedTime": "1m 30s"
}
Response Fields
| Field | Type | Description |
|---|---|---|
jobId | string | Validation job identifier |
type | string | Job type: email or website |
input | string | Email or website being validated |
status | string | Job status: processing, completed, failed, timeout |
result | object | Validation results (if completed) |
error | string | Error message (if failed) |
createdAt | datetime | When job was created |
completedAt | datetime | When job finished (if completed) |
elapsedTime | string | Total time elapsed (human-readable) |
Job Lifecycle
processing → completed | failed | timeout
- processing: Validation in progress
- completed: Results available in
resultfield - failed: Validation failed (see
errorfield) - timeout: Exceeded max validation time (5 minutes)
Job TTL
Validation jobs auto-delete after 24 hours. Poll results will return 404 after expiration.
Polling Strategy
async function pollForResults(jobId) {
const maxAttempts = 30; // 1 minute total
const pollInterval = 2000; // 2 seconds
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(`/v1/validation-jobs/${jobId}`, {
headers: { 'X-API-Key': apiKey }
});
const job = await response.json();
if (job.status === 'completed') {
return job.result;
} else if (job.status === 'failed') {
throw new Error(job.error);
}
// Still processing, wait and retry
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Polling timeout');
}
Error Responses
All validation endpoints follow consistent error formatting:
401 Unauthorized
{
"error": "Unauthorized",
"error_code": "INVALID_API_KEY",
"details": {
"message": "Invalid or missing API key"
}
}
402 Payment Required
{
"error": "Insufficient credits",
"required": 0.001,
"available": 0.0,
"displayCreditsRequired": 1,
"displayCreditsAvailable": 0
}
404 Not Found
{
"detail": "Validation job not found or expired"
}
422 Validation Error
{
"error": "Validation Error",
"error_code": "VALIDATION_ERROR",
"details": {
"errors": [
{
"field": "email",
"message": "Invalid email format",
"type": "value_error"
}
]
}
}
429 Rate Limit Exceeded
{
"error": "Rate limit exceeded",
"message": "10 per 1 minute",
"error_code": "RATE_LIMIT_EXCEEDED"
}
Code Examples
Python
import requests
API_KEY = "sk_your_api_key"
BASE_URL = "https://api.status-check.io/v1"
# Check website
response = requests.post(
f"{BASE_URL}/check-website",
headers={"X-API-Key": API_KEY},
json={"website": "example.com", "returnDetails": True}
)
result = response.json()
print(f"Status: {result['status']}, HTTP: {result.get('httpStatus')}")
# Check email (with polling)
response = requests.post(
f"{BASE_URL}/check-email",
headers={"X-API-Key": API_KEY},
json={"email": "user@example.com", "timeout": 30}
)
result = response.json()
if result['status'] == 'processing':
# Poll for results
job_id = result['jobId']
import time
for _ in range(30):
response = requests.get(
f"{BASE_URL}/validation-jobs/{job_id}",
headers={"X-API-Key": API_KEY}
)
job = response.json()
if job['status'] == 'completed':
print(f"Valid: {job['result']['valid']}")
break
time.sleep(2)
else:
print(f"Valid: {result.get('valid')}")
JavaScript/Node.js
const API_KEY = 'sk_your_api_key';
const BASE_URL = 'https://api.status-check.io/v1';
// Check website
async function checkWebsite(website) {
const response = await fetch(`${BASE_URL}/check-website`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ website, returnDetails: true }),
});
const result = await response.json();
console.log(`Status: ${result.status}, HTTP: ${result.httpStatus}`);
return result;
}
// Check email with webhook
async function checkEmail(email, webhookUrl) {
const response = await fetch(`${BASE_URL}/check-email`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
timeout: 30,
returnDetails: true,
webhookUrl,
}),
});
const result = await response.json();
if (result.status === 'processing') {
console.log(`Check ${result.pollUrl} for results`);
} else {
console.log(`Valid: ${result.valid}`);
}
return result;
}
// Usage
await checkWebsite('example.com');
await checkEmail('user@example.com', 'https://yourapp.com/webhook');
cURL
# Check website
curl -X POST https://api.status-check.io/v1/check-website \
-H "X-API-Key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{"website": "example.com", "returnDetails": true}'
# Check email
curl -X POST https://api.status-check.io/v1/check-email \
-H "X-API-Key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"timeout": 30,
"returnDetails": true
}'
# Poll job status
curl -X GET https://api.status-check.io/v1/validation-jobs/val_abc123def456 \
-H "X-API-Key: sk_your_api_key"
Best Practices
1. Handle Async Gracefully
async function checkEmailWithRetry(email) {
const response = await checkEmail(email);
if (response.status === 'processing') {
// Set up background polling or webhook listener
return { status: 'pending', jobId: response.jobId };
}
return response;
}
2. Use Webhooks for Large Batches
// For bulk validation, use webhooks instead of polling
const emails = [...]; // Large list
for (const email of emails) {
await checkEmail(email, 'https://yourapp.com/webhook');
// Don't poll - webhook will notify you
}
3. Implement Exponential Backoff
async function pollWithBackoff(jobId) {
let delay = 2000; // Start with 2s
const maxDelay = 30000; // Max 30s
while (true) {
const job = await getJob(jobId);
if (job.status !== 'processing') {
return job;
}
await sleep(delay);
delay = Math.min(delay * 1.5, maxDelay);
}
}
4. Monitor Credits
async function checkWithCreditMonitoring(email) {
const result = await checkEmail(email);
if (result.creditsRemaining < 100) {
console.warn('Low credits!', result.creditsRemaining);
// Trigger notification or purchase flow
}
return result;
}
FAQ
Q: Why are credits deducted even on failures?
A: This prevents abuse and is industry standard. Validation costs (API calls, SMTP connections) occur regardless of the result.
Q: How long do validation jobs stay available?
A: Jobs auto-delete after 24 hours. Poll results shortly after receiving a jobId.
Q: Can I validate without an API key?
A: No. All validation endpoints require authentication. Create an account to get your API key.
Q: What happens if my webhook fails?
A: Ad-hoc webhooks (via webhookUrl parameter) are not retried. For reliable webhooks, use the Webhooks API with automatic retries.
Q: How accurate is email validation?
A: We use SMTP verification which is ~95% accurate. False positives/negatives can occur with catch-all domains or aggressive spam filters.
Q: Can I validate domains without HTTP/HTTPS?
A: The endpoint normalizes URLs automatically. Submit example.com and we'll try https://example.com, http://example.com, and https://www.example.com.
Related Documentation
- API Reference - Complete API documentation including Leads Management
- Webhooks - Production webhook system
- Credits API - Credit balance and usage
- Rate Limiting - Rate limit details
- Authentication - API key management
Support
Questions about the Validation API?
- Email: support@status-check.io
- Dashboard: app.status-check.io
- API Docs: api.status-check.io/docs