Skip to main content

POST /v1/validate

Validate a single email address through the 4-layer validation pipeline.

Endpoint

POST https://api.gtmapis.com/v1/validate

Headers

HeaderRequiredDescription
Content-TypeYesMust be application/json
X-API-KeyYesYour API key (gtm_test_* or gtm_live_*)

Request Body

FieldTypeRequiredDescription
emailstringYesThe email address to validate

Example Request

curl -X POST https://api.gtmapis.com/v1/validate \
  -H "Content-Type: application/json" \
  -H "X-API-Key: gtm_test_your_key_here" \
  -d '{"email":"john@company.com"}'

Response

Success Response (200 OK)

Valid Personal Email

{
  "email": "john@company.com",
  "result": "valid",
  "reason": "",
  "is_role_based": false,
  "is_free_provider": false,
  "is_catch_all": false,
  "b2b_outbound_quality": "high",
  "credits_charged": 1,
  "charge_reason": "Valid personal email with high B2B outbound quality"
}

Role-Based Email (FREE)

{
  "email": "info@company.com",
  "result": "valid_role_based",
  "reason": "Role-based email address",
  "is_role_based": true,
  "role_type": "information",
  "is_free_provider": false,
  "b2b_outbound_quality": "low",
  "credits_charged": 0,
  "charge_reason": "Role-based email - free for low B2B value"
}

Catch-All Domain (FREE)

{
  "email": "anyone@catchall.com",
  "result": "risky",
  "reason": "Catch-all domain detected",
  "is_role_based": false,
  "is_catch_all": true,
  "catch_all_confidence": "high",
  "b2b_outbound_quality": "none",
  "credits_charged": 0,
  "charge_reason": "Catch-all domain - cannot verify individual mailbox"
}

Invalid Email (FREE)

{
  "email": "notreal@fakeemail123.com",
  "result": "invalid",
  "reason": "Domain has no MX records",
  "validation_layer": "dns",
  "b2b_outbound_quality": "none",
  "credits_charged": 0,
  "charge_reason": "Invalid email does not consume credits"
}

Unknown Verification (FREE)

{
  "email": "john@restrictive.com",
  "result": "unknown",
  "reason": "SMTP verification not permitted",
  "smtp_response": "550 5.7.1 Recipient verification not allowed",
  "b2b_outbound_quality": "none",
  "credits_charged": 0,
  "charge_reason": "Unable to verify - no credit charged"
}

Response Fields

email
string
required
The validated email address
result
string
required
Validation result: valid, valid_role_based, risky, invalid, or unknownSee Result Categories for details
reason
string
required
Human-readable explanation of the validation result
is_role_based
boolean
required
true if the email is a generic business inbox (info@, support@, etc.)
is_free_provider
boolean
required
true if the domain is a free email provider (Gmail, Yahoo, Outlook, etc.)
is_catch_all
boolean
true if the domain accepts all email addresses (can’t verify specific mailbox)
catch_all_confidence
string
Confidence level: high, medium, or low (only present if is_catch_all is true)
b2b_outbound_quality
string
required
B2B outbound value: high (worth using), low (role-based), or none (invalid/risky)See B2B Quality Scoring for details
credits_charged
integer
required
Number of credits charged: 0 (free) or 1 (charged)Only valid personal emails with b2b_outbound_quality: "high" are charged
charge_reason
string
required
Explanation of why credits were or weren’t charged
role_type
string
Category of role-based email (e.g., “information”, “support”, “sales”)Only present if is_role_based is true
validation_layer
string
Layer where validation stopped: syntax, dns, smtp, or catchallUseful for debugging failures
smtp_response
string
Raw SMTP server response (when applicable)Useful for understanding SMTP-level issues

Error Responses

400 Bad Request

{
  "error": "Bad Request",
  "message": "Email field is required"
}
Common causes:
  • Missing email field
  • Empty email string
  • Malformed JSON

401 Unauthorized

{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
Common causes:
  • Missing X-API-Key header
  • Invalid or revoked API key
  • Incorrect API key format

429 Too Many Requests

{
  "error": "Rate limit exceeded",
  "message": "You have exceeded the rate limit of 1000 requests per minute",
  "retry_after": 60
}
Solution: Wait for the retry_after seconds before making more requests

500 Internal Server Error

{
  "error": "Internal Server Error",
  "message": "An unexpected error occurred"
}
Solution: Retry the request or contact support if the issue persists

Performance

  • Cached DNS: ~50ms average
  • Uncached DNS: ~500ms average
  • Full SMTP validation: ~2s average

Best Practices

Error Handling

Always handle all possible result types:
const result = await validateEmail('john@company.com');

switch (result.result) {
  case 'valid':
    // High-value email - use in campaigns
    if (result.b2b_outbound_quality === 'high') {
      addToCampaign(result.email);
    }
    break;

  case 'valid_role_based':
    // Low-value email - use with caution
    addToSecondaryList(result.email);
    break;

  case 'risky':
    // Catch-all - avoid in campaigns
    markAsRisky(result.email);
    break;

  case 'invalid':
    // Remove from list
    removeFromList(result.email);
    break;

  case 'unknown':
    // Can't verify - test carefully
    addToTestList(result.email);
    break;
}

Rate Limiting

For high-volume validation, use the bulk endpoint:
// Instead of this (1000 requests)
for (const email of emails) {
  await validateEmail(email);  // ❌ Slow, hits rate limit
}

// Do this (10 requests for 1000 emails)
const chunks = chunkArray(emails, 100);
for (const chunk of chunks) {
  await validateBulk(chunk);  // ✅ Fast, under rate limit
}

Next Steps