JavaScript Examples
Complete code examples for integrating Status Check with Node.js and JavaScript applications.
Basic Setup
const API_KEY = 'sk_live_your_api_key_here';
const BASE_URL = 'https://api.status-check.io';
// Helper function for API calls
async function apiCall(endpoint, options = {}) {
const response = await fetch(`${BASE_URL}${endpoint}`, {
...options,
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
if (response.status === 402) {
throw new Error('Insufficient credits');
}
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
return response.json();
}
Single Lead Validation
Create and Validate a Lead
async function validateLead(email, website) {
const result = await apiCall('/v1/leads', {
method: 'POST',
body: JSON.stringify({
email,
website,
validate: true,
validateDomain: true,
validateEmail: true,
}),
});
return result;
}
// Usage
validateLead('john@example.com', 'https://example.com')
.then(result => {
console.log('✓ Lead validated successfully');
console.log(` Lead ID: ${result.leadId}`);
console.log(` Score: ${result.leadDeliverabilityRating}/100`);
console.log(` Email Valid: ${result.emailValid}`);
console.log(` Domain Status: ${result.domainHttpStatus}`);
console.log(` Recommendation: ${result.leadRecommendation}`);
})
.catch(error => {
console.error('✗ Validation failed:', error.message);
});
Get Lead Details
async function getLead(leadId) {
return apiCall(`/v1/leads/${leadId}`, {
method: 'GET',
});
}
// Usage
const lead = await getLead('lead_abc123');
console.log(`Email: ${lead.email}`);
console.log(`Score: ${lead.leadDeliverabilityRating}`);
Bulk Lead Processing
Validate Multiple Leads
async function bulkValidateLeads(leads) {
return apiCall('/v1/leads/bulk', {
method: 'POST',
body: JSON.stringify({
leads,
validateDomain: true,
validateEmail: true,
}),
});
}
// Usage
const leads = [
{
email: 'alice@company.com',
website: 'https://company.com',
firstName: 'Alice',
lastName: 'Smith',
},
{
email: 'bob@startup.io',
website: 'https://startup.io',
firstName: 'Bob',
lastName: 'Jones',
},
];
bulkValidateLeads(leads)
.then(result => {
console.log(`Created: ${result.created} leads`);
console.log(`Skipped: ${result.skipped} duplicates`);
});
Query Leads with Filters
async function queryLeads(filters = {}) {
const params = new URLSearchParams();
if (filters.minScore) {
params.append('minDeliverabilityRating', filters.minScore);
}
if (filters.emailValid !== undefined) {
params.append('emailValid', filters.emailValid);
}
params.append('limit', filters.limit || 50);
const result = await apiCall(`/v1/leads?${params}`, {
method: 'GET',
});
return result.leads;
}
// Usage - Get high-quality leads
const highQualityLeads = await queryLeads({
minScore: 85,
emailValid: true,
});
console.log(`Found ${highQualityLeads.length} high-quality leads`);
highQualityLeads.forEach(lead => {
console.log(` • ${lead.email} - Score: ${lead.leadDeliverabilityRating}`);
});
CustomFields for Flexible Data
Use customFields for CSV imports, industry-specific data, or any custom properties.
Create Lead with CustomFields
async function createLeadWithCustomData(email, website, customData = {}) {
/**
* Create lead with custom fields for arbitrary data
*
* @param {string} email - Lead's email
* @param {string} website - Lead's website
* @param {object} customData - Custom key-value pairs (max 50 fields, 1KB/value)
* @returns {Promise<object>} Created lead with customFields
*/
const payload = {
email,
website,
firstName: customData.firstName || '',
lastName: customData.lastName || '',
company: customData.company || '',
title: customData.title || '',
validate: true,
validateDomain: true,
validateEmail: true,
customFields: {
// Industry-specific
industry: customData.industry,
vertical: customData.vertical,
employeeCount: customData.employeeCount,
annualRevenue: customData.annualRevenue,
// Sales tracking
leadSource: customData.leadSource,
leadScore: customData.leadScore,
// Any other custom data from CSV or forms
...Object.fromEntries(
Object.entries(customData).filter(
([key]) =>
![
'firstName',
'lastName',
'company',
'title',
'industry',
'vertical',
'employeeCount',
'annualRevenue',
'leadSource',
'leadScore',
].includes(key)
)
),
},
};
// Remove undefined/null values from customFields
payload.customFields = Object.fromEntries(
Object.entries(payload.customFields).filter(([_, v]) => v != null)
);
return apiCall('/v1/leads', {
method: 'POST',
body: JSON.stringify(payload),
});
}
// Usage - CSV Import Example
const csvRow = {
firstName: 'John',
lastName: 'Doe',
company: 'Acme Corp',
title: 'CTO',
industry: 'SaaS',
employeeCount: '50-100',
annualRevenue: '$5M-$10M',
leadSource: 'Trade Show',
customColumn1: 'Custom data from CSV',
importDate: '2025-01-15',
};
const lead = await createLeadWithCustomData(
'john@acme.com',
'https://acme.com',
csvRow
);
console.log(`Lead created: ${lead.id}`);
console.log(`CustomFields:`, lead.customFields);
Update Lead with CustomFields (Merge Behavior)
CustomFields merge with existing data instead of replacing.
async function updateLeadCustomFields(leadId, updates, customUpdates = null) {
/**
* Update lead with optional customFields merging
*
* CustomFields behavior:
* - Existing custom fields are preserved
* - New fields are added
* - Updated fields override existing values
*
* @param {string} leadId - Lead ID to update
* @param {object} updates - Standard field updates
* @param {object} customUpdates - Custom field updates (merged with existing)
* @returns {Promise<object>} Updated lead
*/
const payload = { ...updates };
if (customUpdates) {
payload.customFields = customUpdates;
}
return apiCall(`/v1/leads/${leadId}`, {
method: 'PUT',
body: JSON.stringify(payload),
});
}
// Usage Example 1: Initial customFields
let lead = await updateLeadCustomFields(
'lead_abc123',
{ notes: 'Initial contact' },
{
industry: 'SaaS',
employeeCount: '50-100',
timezone: 'America/Los_Angeles',
}
);
console.log('Added custom fields:', lead.customFields);
// Usage Example 2: Merge new customFields
lead = await updateLeadCustomFields(
'lead_abc123',
{ notes: 'Follow-up scheduled' },
{
industry: 'FinTech', // Override existing
lastContactDate: '2025-01-15', // Add new field
nextFollowUp: '2025-01-22', // Add new field
}
);
// Result:
// {
// "customFields": {
// "industry": "FinTech", ← Updated
// "employeeCount": "50-100", ← Preserved
// "timezone": "America/Los_Angeles", ← Preserved
// "lastContactDate": "2025-01-15", ← Added
// "nextFollowUp": "2025-01-22" ← Added
// }
// }
console.log('Merged custom fields:', lead.customFields);
TypeScript Types for CustomFields
interface CustomFields {
// Industry-specific
industry?: string;
vertical?: string;
employeeCount?: string;
annualRevenue?: string;
// Sales tracking
leadSource?: string;
leadScore?: number;
lastContactDate?: string;
nextFollowUp?: string;
// CSV import fields
[key: string]: string | number | boolean | null | undefined;
}
interface Lead {
id: string;
email: string;
website: string;
firstName: string;
lastName: string;
company: string;
title: string;
customFields: CustomFields;
// ... other fields
}
// Usage with TypeScript
const lead: Lead = await createLeadWithCustomData(
'john@acme.com',
'https://acme.com',
{
firstName: 'John',
company: 'Acme Corp',
industry: 'SaaS',
employeeCount: '50-100',
}
);
CustomFields Validation
CustomFields have limits to prevent abuse:
// ✅ Valid customFields
const validCustomFields = {
industry: 'SaaS',
employeeCount: '50-100',
// ... up to 50 total fields
};
// ❌ Invalid - Too many fields (> 50)
const tooManyFields = Object.fromEntries(
Array.from({ length: 51 }, (_, i) => [`field${i}`, `value${i}`])
);
// ❌ Invalid - Field name too long (> 100 chars)
const longFieldName = {
thisIsAVeryLongFieldNameThatExceedsTheMaximumAllowedLengthOf100CharactersAndShouldBeRejected:
'value',
};
// ❌ Invalid - Value too large (> 1KB)
const largeValue = {
largeField: 'x'.repeat(1500), // > 1KB
};
// Error handling for customFields validation
try {
await createLeadWithCustomData('test@example.com', 'example.com', {
customFields: tooManyFields,
});
} catch (error) {
if (error.response?.status === 422) {
console.error('CustomFields validation failed:', error.response.data);
// "customFields cannot exceed 50 fields"
}
}
React Hook for CustomFields
import { useState } from 'react';
function useLeadWithCustomFields() {
const [lead, setLead] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const createLead = async (email, website, customData) => {
setLoading(true);
setError(null);
try {
const result = await createLeadWithCustomData(email, website, customData);
setLead(result);
return result;
} catch (err) {
setError(err.response?.data || err.message);
throw err;
} finally {
setLoading(false);
}
};
const updateCustomFields = async (leadId, customUpdates) => {
setLoading(true);
setError(null);
try {
const result = await updateLeadCustomFields(leadId, {}, customUpdates);
setLead(result);
return result;
} catch (err) {
setError(err.response?.data || err.message);
throw err;
} finally {
setLoading(false);
}
};
return { lead, loading, error, createLead, updateCustomFields };
}
// Usage in React component
function LeadForm() {
const { lead, loading, createLead } = useLeadWithCustomFields();
const handleSubmit = async (formData) => {
await createLead('john@acme.com', 'https://acme.com', {
firstName: formData.firstName,
company: formData.company,
industry: formData.industry,
employeeCount: formData.employeeCount,
});
};
return <div>{/* Form JSX */}</div>;
}
Webhook Integration
Register a Webhook
async function createWebhook(name, url, events) {
return apiCall('/v1/webhooks', {
method: 'POST',
body: JSON.stringify({
name,
url,
events,
active: true,
}),
});
}
// Usage
const webhook = await createWebhook(
'Production Webhook',
'https://your-app.com/webhooks/status-check',
['validation.complete', 'credits.low']
);
console.log(`Webhook ID: ${webhook.webhook_id}`);
console.log(`Secret: ${webhook.secret}`); // Save this securely!
Verify Webhook Signatures
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
Express.js Integration
Webhook Handler
const express = require('express');
const crypto = require('crypto');
const app = express();
// IMPORTANT: Use raw body parser for webhook signature verification
app.use('/webhooks', express.raw({ type: 'application/json' }));
const WEBHOOK_SECRET = 'whsec_your_secret_here';
app.post('/webhooks/status-check', (req, res) => {
// Get raw body and signature
const payload = req.body.toString();
const signature = req.headers['x-webhook-signature'];
// Verify signature
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Parse event
const event = JSON.parse(payload);
// Handle different event types
switch (event.event) {
case 'validation.complete':
console.log(`✓ Validation complete for batch ${event.batchId}`);
console.log(` Results: ${event.successfulValidations}/${event.totalLeads}`);
// Process validation results...
break;
case 'credits.low':
console.log(`⚠ Credit balance low: ${event.currentBalance} credits`);
// Send alert notification...
break;
default:
console.log(`Received unknown event: ${event.event}`);
}
// Always respond quickly (200 OK)
res.json({ status: 'received' });
});
// Regular JSON parser for other routes
app.use(express.json());
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
API Client Class
class StatusCheckClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.status-check.io';
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.error || `HTTP ${response.status}`);
}
return response.json();
}
// Lead methods
async createLead(data) {
return this.request('/v1/leads', {
method: 'POST',
body: JSON.stringify(data),
});
}
async getLead(leadId) {
return this.request(`/v1/leads/${leadId}`);
}
async queryLeads(filters = {}) {
const params = new URLSearchParams(filters);
return this.request(`/v1/leads?${params}`);
}
async bulkCreateLeads(leads) {
return this.request('/v1/leads/bulk', {
method: 'POST',
body: JSON.stringify({ leads }),
});
}
// Webhook methods
async createWebhook(data) {
return this.request('/v1/webhooks', {
method: 'POST',
body: JSON.stringify(data),
});
}
async listWebhooks() {
return this.request('/v1/webhooks');
}
async deleteWebhook(webhookId) {
return this.request(`/v1/webhooks/${webhookId}`, {
method: 'DELETE',
});
}
}
// Usage
const client = new StatusCheckClient('sk_live_your_key');
// Create and validate a lead
const lead = await client.createLead({
email: 'test@example.com',
website: 'https://example.com',
validate: true,
});
console.log(`Score: ${lead.leadDeliverabilityRating}`);
Next.js Integration
API Route Handler
// pages/api/webhooks/status-check.js
import crypto from 'crypto';
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === `sha256=${expected}`;
}
export const config = {
api: {
bodyParser: false, // Disable built-in parser for raw body
},
};
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Read raw body
const chunks = [];
for await (const chunk of req) {
chunks.push(chunk);
}
const payload = Buffer.concat(chunks).toString();
// Verify signature
const signature = req.headers['x-webhook-signature'];
const secret = process.env.STATUSCHECK_WEBHOOK_SECRET;
if (!verifySignature(payload, signature, secret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Parse and handle event
const event = JSON.parse(payload);
switch (event.event) {
case 'validation.complete':
// Update database with results
console.log(`Validation complete: ${event.batchId}`);
break;
case 'credits.low':
// Send notification
console.log(`Credits low: ${event.currentBalance}`);
break;
}
res.json({ received: true });
}
Server-Side Lead Validation
// pages/api/validate-lead.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { email, website } = req.body;
try {
const response = await fetch('https://api.status-check.io/v1/leads', {
method: 'POST',
headers: {
'X-API-Key': process.env.STATUSCHECK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
website,
validate: true,
validateDomain: true,
validateEmail: true,
}),
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const result = await response.json();
res.json({
valid: result.leadDeliverabilityRating >= 70,
score: result.leadDeliverabilityRating,
recommendation: result.leadRecommendation,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
React Hook
Custom Hook for Lead Validation
import { useState } from 'react';
function useLeadValidation() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [result, setResult] = useState(null);
const validateLead = async (email, website) => {
setLoading(true);
setError(null);
try {
const response = await fetch('/api/validate-lead', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, website }),
});
if (!response.ok) {
throw new Error('Validation failed');
}
const data = await response.json();
setResult(data);
return data;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
};
return {
validateLead,
loading,
error,
result,
};
}
// Usage in component
function LeadForm() {
const { validateLead, loading, result, error } = useLeadValidation();
const [email, setEmail] = useState('');
const [website, setWebsite] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
const validation = await validateLead(email, website);
if (validation.valid) {
alert(`✓ Lead is valid! Score: ${validation.score}/100`);
} else {
alert(`✗ Lead quality is low. Score: ${validation.score}/100`);
}
} catch (err) {
alert(`Error: ${err.message}`);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="url"
value={website}
onChange={(e) => setWebsite(e.target.value)}
placeholder="Website"
required
/>
<button type="submit" disabled={loading}>
{loading ? 'Validating...' : 'Validate Lead'}
</button>
{error && <div className="error">{error}</div>}
{result && (
<div className="result">
<p>Score: {result.score}/100</p>
<p>Recommendation: {result.recommendation}</p>
</div>
)}
</form>
);
}
Advanced Examples
Batch Processing with Progress
async function processBatchWithProgress(leads, onProgress) {
// Start validation
const batch = await apiCall('/v1/leads/validate', {
method: 'POST',
body: JSON.stringify({
leadIds: leads.map(l => l.leadId),
validateDomain: true,
validateEmail: true,
}),
});
const batchId = batch.batchId;
// Poll for status (or use webhooks)
return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
try {
const status = await apiCall(`/v1/batches/${batchId}`);
onProgress({
status: status.status,
progress: status.progress || 0,
});
if (status.status === 'complete') {
clearInterval(interval);
resolve(status);
} else if (status.status === 'failed') {
clearInterval(interval);
reject(new Error('Batch failed'));
}
} catch (error) {
clearInterval(interval);
reject(error);
}
}, 5000); // Check every 5 seconds
});
}
// Usage
processBatchWithProgress(leads, ({ status, progress }) => {
console.log(`Status: ${status}, Progress: ${progress}%`);
})
.then(result => {
console.log('✓ Batch complete!');
})
.catch(error => {
console.error('✗ Batch failed:', error);
});
Retry Logic with Exponential Backoff
async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
// Don't retry on client errors (4xx except 429)
if (error.message.includes('400') || error.message.includes('404')) {
throw error;
}
// Check for rate limit
if (error.message.includes('429')) {
const delay = baseDelay * Math.pow(2, i);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
// Last retry
if (i === maxRetries - 1) {
throw lastError;
}
// Exponential backoff
const delay = baseDelay * Math.pow(2, i);
console.log(`Request failed. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
// Usage
const result = await retryWithBackoff(() =>
validateLead('test@example.com', 'https://example.com')
);
Export Results to CSV
function exportToCSV(leads, filename = 'validated_leads.csv') {
const headers = [
'email',
'website',
'firstName',
'lastName',
'leadDeliverabilityRating',
'emailValid',
'domainHttpStatus',
'leadRecommendation',
];
const rows = leads.map(lead =>
headers.map(header => JSON.stringify(lead[header] || '')).join(',')
);
const csv = [headers.join(','), ...rows].join('\n');
// Browser download
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
console.log(`✓ Exported ${leads.length} leads to ${filename}`);
}
// Usage
const leads = await queryLeads({ limit: 1000 });
exportToCSV(leads);
TypeScript Support
Type Definitions
interface Lead {
leadId: string;
email: string;
website?: string;
firstName?: string;
lastName?: string;
leadDeliverabilityRating: number;
emailValid: boolean;
emailScore: number;
domainHttpStatus: number;
domainScore: number;
leadRecommendation: 'high_priority' | 'validate' | 'research' | 'skip';
validationStatus: 'pending' | 'validating' | 'verified' | 'warning' | 'risky' | 'error';
createdAt: string;
updatedAt: string;
}
interface ValidationResult {
leadId: string;
status: string;
batchId?: string;
}
interface WebhookEvent {
event: string;
timestamp: string;
userId?: string;
batchId?: string;
totalLeads?: number;
successfulValidations?: number;
failedValidations?: number;
}
// Client class with types
class TypedStatusCheckClient {
constructor(private apiKey: string) {}
async createLead(data: Partial<Lead>): Promise<Lead> {
// Implementation...
}
async getLead(leadId: string): Promise<Lead> {
// Implementation...
}
async queryLeads(filters?: {
minScore?: number;
emailValid?: boolean;
limit?: number;
}): Promise<Lead[]> {
// Implementation...
}
}