API Integration Guide
Learn how to integrate GTMAPIs email validation into your application with best practices and real-world examples.Quick Integration
1. Get Your API Key
First, generate an API key from your dashboard:- Test keys (
gtm_test_*) for development - Live keys (
gtm_live_*) for production
2. Store Securely
Never hardcode API keys. Use environment variables:Copy
GTMAPIS_API_KEY=gtm_test_your_key_here
3. Make Your First Request
Copy
const validateEmail = async (email) => {
const response = await fetch('https://api.gtmapis.com/v1/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ email })
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
};
// Usage
const result = await validateEmail('john@company.com');
console.log(result.result); // 'valid', 'invalid', etc.
Common Integration Patterns
Sign-Up Form Validation
Validate emails during user registration:Copy
// React component example
import { useState } from 'react';
export function SignUpForm() {
const [email, setEmail] = useState('');
const [validating, setValidating] = useState(false);
const [validation, setValidation] = useState(null);
const validateEmail = async () => {
setValidating(true);
try {
const response = await fetch('/api/validate-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
const result = await response.json();
setValidation(result);
// Show feedback to user
if (result.result === 'valid') {
// ✅ Good to go
return true;
} else if (result.result === 'valid_role_based') {
// ⚠️ Warn but allow
alert('This appears to be a generic email (info@, support@). Consider using a personal email.');
return true;
} else {
// ❌ Block signup
alert('Please enter a valid email address.');
return false;
}
} finally {
setValidating(false);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
// Validate before submitting
const isValid = await validateEmail();
if (isValid) {
// Proceed with signup
submitSignUp({ email });
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onBlur={validateEmail} // Validate on blur
required
/>
{validating && <span>Validating...</span>}
{validation && (
<span className={validation.result === 'valid' ? 'text-green-600' : 'text-red-600'}>
{validation.reason || 'Valid email'}
</span>
)}
<button type="submit">Sign Up</button>
</form>
);
}
Lead Import Pipeline
Validate imported leads before adding to CRM:Copy
async function processLeadImport(leads) {
const validated = [];
const rejected = [];
// Process in batches of 100
for (let i = 0; i < leads.length; i += 100) {
const batch = leads.slice(i, i + 100);
const emails = batch.map(lead => lead.email);
const response = await fetch('https://api.gtmapis.com/v1/validate/bulk', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ emails })
});
const results = await response.json();
// Merge results with original leads
batch.forEach((lead, index) => {
const validation = results.results[index];
if (validation.b2b_outbound_quality === 'high') {
// High-quality lead - add to CRM
validated.push({
...lead,
email_quality: 'high',
validation_result: validation
});
} else if (validation.result === 'valid_role_based') {
// Role-based - add with flag
validated.push({
...lead,
email_quality: 'low',
is_role_based: true,
validation_result: validation
});
} else {
// Invalid/risky - reject
rejected.push({
...lead,
rejection_reason: validation.reason,
validation_result: validation
});
}
});
// Rate limit delay
await new Promise(resolve => setTimeout(resolve, 500));
}
return { validated, rejected };
}
Email List Cleaning Service
Build a SaaS email cleaning service:Copy
// Express.js API endpoint
app.post('/api/clean-list', async (req, res) => {
const { userId, emails } = req.body;
try {
// Check user credits
const user = await db.users.findById(userId);
if (user.credits < emails.length * 0.4) { // Estimate 40% will be charged
return res.status(402).json({
error: 'Insufficient credits',
required: Math.ceil(emails.length * 0.4),
available: user.credits
});
}
// Validate emails
const results = [];
for (let i = 0; i < emails.length; i += 100) {
const batch = emails.slice(i, i + 100);
const response = await fetch('https://api.gtmapis.com/v1/validate/bulk', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ emails: batch })
});
const batchResults = await response.json();
results.push(...batchResults.results);
}
// Deduct credits (only for charged validations)
const creditsCharged = results.filter(r => r.credits_charged > 0).length;
await db.users.updateById(userId, {
credits: user.credits - creditsCharged
});
// Save validation history
await db.validations.create({
userId,
totalEmails: emails.length,
creditsCharged,
results
});
res.json({
results,
summary: {
total: results.length,
high_quality: results.filter(r => r.b2b_outbound_quality === 'high').length,
role_based: results.filter(r => r.result === 'valid_role_based').length,
invalid: results.filter(r => r.result === 'invalid').length,
credits_charged: creditsCharged
}
});
} catch (error) {
console.error('Validation error:', error);
res.status(500).json({ error: 'Validation failed' });
}
});
Background Job Processing
Process large lists asynchronously:Copy
// Using BullMQ for job queue
import { Queue, Worker } from 'bullmq';
const validationQueue = new Queue('email-validation');
// Add job
async function queueValidation(userId, emails) {
await validationQueue.add('validate', {
userId,
emails,
timestamp: Date.now()
});
}
// Process job
const worker = new Worker('email-validation', async (job) => {
const { userId, emails } = job.data;
// Update progress
await job.updateProgress(0);
const results = [];
for (let i = 0; i < emails.length; i += 100) {
const batch = emails.slice(i, i + 100);
const response = await fetch('https://api.gtmapis.com/v1/validate/bulk', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ emails: batch })
});
const batchResults = await response.json();
results.push(...batchResults.results);
// Update progress
const progress = ((i + 100) / emails.length) * 100;
await job.updateProgress(Math.min(100, progress));
await new Promise(resolve => setTimeout(resolve, 500));
}
// Send notification email
await sendEmail(userId, {
subject: 'Email Validation Complete',
results
});
return results;
});
Best Practices
Error Handling
Always handle errors gracefully:Copy
async function validateWithRetry(email, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.gtmapis.com/v1/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ email })
});
if (response.status === 429) {
// Rate limit - wait and retry
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Retrying after ${retryAfter}s...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return await response.json();
} catch (error) {
if (attempt === maxRetries) {
console.error(`Failed after ${maxRetries} attempts:`, error);
throw error;
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Caching Results
Cache validation results to reduce API calls:Copy
const cache = new Map();
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days
async function validateWithCache(email) {
const cacheKey = email.toLowerCase();
// Check cache
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.result;
}
// Validate
const result = await validateEmail(email);
// Cache result
cache.set(cacheKey, {
result,
timestamp: Date.now()
});
return result;
}
Rate Limit Management
Implement rate limiting on your side:Copy
import Bottleneck from 'bottleneck';
// Limit to 900 requests/minute (safe margin)
const limiter = new Bottleneck({
maxConcurrent: 10, // Concurrent requests
minTime: 67 // Min 67ms between requests (900/min)
});
// Wrap API calls
const validateEmail = limiter.wrap(async (email) => {
const response = await fetch('https://api.gtmapis.com/v1/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.GTMAPIS_API_KEY
},
body: JSON.stringify({ email })
});
return await response.json();
});
Testing
Test Mode
Use test keys for development:Copy
const apiKey = process.env.NODE_ENV === 'production'
? process.env.GTMAPIS_LIVE_KEY
: process.env.GTMAPIS_TEST_KEY;
Mock for Unit Tests
Mock API responses in tests:Copy
// Jest example
jest.mock('node-fetch');
test('validates email successfully', async () => {
fetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
email: 'test@example.com',
result: 'valid',
b2b_outbound_quality: 'high',
credits_charged: 1
})
});
const result = await validateEmail('test@example.com');
expect(result.result).toBe('valid');
});