Skip to main content

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:
GTMAPIS_API_KEY=gtm_test_your_key_here

3. Make Your First Request

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:
// 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:
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:
// 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:
// 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:
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:
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:
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:
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:
// 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');
});

Next Steps