POST /v1/validate
Validate a single email address through the 4-layer validation pipeline.
Endpoint
POST https://api.gtmapis.com/v1/validate
| Header | Required | Description |
|---|
Content-Type | Yes | Must be application/json |
X-API-Key | Yes | Your API key (gtm_test_* or gtm_live_*) |
Request Body
| Field | Type | Required | Description |
|---|
email | string | Yes | The 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
The validated email address
Validation result: valid, valid_role_based, risky, invalid, or unknownSee Result Categories for details
Human-readable explanation of the validation result
true if the email is a generic business inbox (info@, support@, etc.)
true if the domain is a free email provider (Gmail, Yahoo, Outlook, etc.)
true if the domain accepts all email addresses (can’t verify specific mailbox)
Confidence level: high, medium, or low (only present if is_catch_all is true)
B2B outbound value: high (worth using), low (role-based), or none (invalid/risky)See B2B Quality Scoring for details
Number of credits charged: 0 (free) or 1 (charged)Only valid personal emails with b2b_outbound_quality: "high" are charged
Explanation of why credits were or weren’t charged
Category of role-based email (e.g., “information”, “support”, “sales”)Only present if is_role_based is true
Layer where validation stopped: syntax, dns, smtp, or catchallUseful for debugging failures
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
- 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