Email Verifier REST API Reference
This guide explains Verify addresses programmatically — 8 REST endpoints for single and bulk verification, credit checks, job management, CSV export, plus auth and scope details. so you can complete the TrekMail task with confidence.
Article details
Type, difficulty, plans, and last updated info.
▼
Article details
Type, difficulty, plans, and last updated info.
- Type
- Reference
- Difficulty
- Intermediate
- Plans
- Nano · Starter · Pro · Agency
- Last updated
- Jun 23, 2026
Verify email addresses programmatically using TrekMail's REST API. Endpoints require an API token with the appropriate scope: verify:read for read-only access, verify:write for mutations.
Authentication
Include your API token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
Scopes must be explicitly enabled when creating or editing your API token. They are not granted by default.
verify:read— check credits, list jobs, view job status and resultsverify:write— submit verifications, cancel jobs, delete jobs (also grants read access)
Idempotency
All write endpoints (POST /verify, POST /verify/bulk, POST /verify/bulk/{jobId}/cancel, DELETE /verify/bulk/{jobId}) require an Idempotency-Key header. Send any client-generated unique value, typically a UUIDv4:
Idempotency-Key: 0a3a6f5a-7c5c-4a3a-bc11-7e6e2c5f7a91
If the same key is replayed within 24 hours, the original response is returned without re-executing the action — safe for client retries. Missing the header on a write endpoint returns 422 missing_idempotency_key.
Endpoints
GET /api/v1/verify/credits
Returns the current credit balance for your account. Requires verify:read scope.
Response (200):
{
"monthly_limit": 5000,
"monthly_used": 1200,
"monthly_remaining": 3800,
"purchased_balance": 10000,
"total_available": 13800,
"plan": "pro",
"resets_at": "2026-04-01T00:00:00Z"
}
POST /api/v1/verify
Verify a single email address in real-time. Response is padded to a minimum of 200ms to prevent timing attacks.
Request:
{
"email": "user@example.com",
"mode": "deep"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | The email address to verify |
mode |
string | No | "quick" (default, 1 credit) or "deep" (2 credits for business domains; 1 credit for Gmail / Yahoo / Outlook / iCloud / AOL — Deep can't add accuracy for free-provider mailboxes, so we don't charge for it). |
Response (200):
{
"status": "safe",
"trust_score": 95,
"mode": "deep",
"reason": "All checks passed",
"checks": {
"syntax": true,
"mx": true,
"mx_routable": true,
"disposable": false,
"role_based": false,
"free_provider": false,
"spf": true,
"dmarc": true,
"bounce_listed": false,
"gibberish": false,
"typo_suggestion": null,
"plus_addressing": false,
"dnsbl_listed": false,
"domain_age_days": 365,
"gravatar_exists": true,
"name_detected": true,
"profanity_detected": false,
"domain_has_website": true,
"spam_trap_score": 0,
"breached_domain": false,
"smtp_status": "accepted"
},
"mx_host": "aspmx.l.google.com",
"smtp_status": "accepted"
}
Deep-mode-only response fields:
| Field | Type | Description |
|---|---|---|
checks.name_detected |
boolean | Whether a recognizable name was found in the local part |
checks.profanity_detected |
boolean | Whether offensive language was detected in the local part |
checks.domain_has_website |
boolean | Whether the domain has a live website |
checks.spam_trap_score |
integer | Spam trap heuristic score (0 = no match, higher = more likely a trap) |
checks.breached_domain |
boolean | Whether the domain appears in a known data breach database (informational) |
checks.smtp_status |
string | "accepted", "rejected", "inconclusive", or "skipped" |
smtp_status |
string | Top-level convenience field, same as checks.smtp_status |
These fields are only present when mode is "deep". In Quick mode, they are omitted from the response.
Credits: Quick mode deducts 1 credit. Deep mode deducts 2 credits.
POST /api/v1/verify/bulk
Submit a list of emails for async bulk verification. Returns immediately with a job ID.
Request:
{
"emails": ["a@example.com", "b@test.com", "..."],
"name": "March campaign list",
"mode": "deep"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
emails |
array | Yes | List of email addresses (max 50,000) |
name |
string | No | Optional label for the job |
mode |
string | No | "quick" (default) or "deep". Deep mode costs 2 credits per email for business domains, 1 credit per email for free providers (Gmail, Yahoo, Outlook, etc.) — see pricing. |
- Maximum 50,000 emails per request
- Duplicates are automatically removed
- If an identical list was submitted within 24 hours, the existing job is returned
Response (201):
{
"job_id": 42,
"total": 1500,
"status": "pending",
"rejected_count": 0,
"rejected_sample": [],
"credits_charged": 1884,
"breakdown": {
"probe": 192,
"skip": 1308,
"deep_savings": 1308
}
}
| Field | Description |
|---|---|
credits_charged |
Total credits actually deducted for this job. |
breakdown.probe |
Addresses that get the full Deep SMTP probe (business domains). Billed at 2 credits each in Deep mode. |
breakdown.skip |
Addresses on free-provider domains (Gmail, Yahoo, Outlook, iCloud, AOL, …). Billed at 1 credit each — Deep can't add accuracy for them. |
breakdown.deep_savings |
Credits saved by this rule vs. flat 2-credit Deep pricing across the entire list. |
In Quick mode, breakdown.deep_savings is always 0 and every address is billed at 1 credit.
Response (200) — duplicate detected:
{
"job_id": 41,
"status": "completed",
"message": "Duplicate list detected. Returning existing job.",
"duplicate": true
}
GET /api/v1/verify/bulk/{jobId}
Check the status of a bulk verification job. Requires verify:read scope.
Query parameters:
page— results page number (default: 1)search— filter results by partial email match (e.g.?search=@gmail.com)
Response (200) — processing:
{
"id": 42,
"name": "March campaign list",
"status": "processing",
"total_count": 1500,
"processed_count": 750,
"progress": 50,
"created_at": "2026-03-23T10:00:00Z",
"completed_at": null,
"results_summary": null
}
Response (200) — completed:
{
"id": 42,
"name": "March campaign list",
"status": "completed",
"total_count": 1500,
"processed_count": 1500,
"progress": 100,
"created_at": "2026-03-23T10:00:00Z",
"completed_at": "2026-03-23T12:00:00Z",
"results_summary": {
"safe": 1200,
"valid": 150,
"risky": 80,
"invalid": 60,
"unknown": 10
},
"results": {
"data": [
{
"email": "user@example.com",
"status": "safe",
"trust_score": 95,
"reason": "All checks passed",
"mx_host": "aspmx.l.google.com"
}
],
"current_page": 1,
"last_page": 15,
"per_page": 100,
"total": 1500
}
}
Results are included when the job is completed, partial, or cancelled with results. Results are paginated (default 100 per page; pass ?per_page=N up to a maximum of 1000). Use ?page=2 to paginate. Use ?search=term to filter results by partial email match.
Partial status: A job ends as partial when some addresses were processed but the full list didn't complete (cancelled mid-run, or auto-aborted by the platform). Credits for the unfinished portion are refunded automatically. Treat partial like completed — the returned results and results_summary cover the addresses that did finish.
GET /api/v1/verify/bulk/{jobId}/download
Download results as a CSV file. Available for completed, partial, and cancelled jobs (with results).
Query parameters:
filter—all(default),safe, orsafe_risky
Response: Streamed CSV with columns: email, status, score, reason, mx_host. Deep mode jobs include an additional smtp_status column.
GET /api/v1/verify/bulk
List all verification jobs for your account with pagination. Requires verify:read scope.
Query parameters:
page— page number (default: 1)per_page— results per page (default: 25, max: 100)status— filter by job status:pending,processing,completed,partial,cancelled,failed
Response (200):
{
"jobs": [
{
"job_id": 42,
"name": "March campaign list",
"status": "completed",
"total": 1500,
"processed": 1500,
"progress": 100,
"created_at": "2026-03-23T10:00:00Z",
"completed_at": "2026-03-23T12:00:00Z"
},
{
"job_id": 43,
"name": "Newsletter cleanup",
"status": "processing",
"total": 3000,
"processed": 1200,
"progress": 40,
"created_at": "2026-03-23T14:00:00Z",
"completed_at": null
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 8,
"last_page": 1
}
}
POST /api/v1/verify/bulk/{jobId}/cancel
Cancel a running verification job and refund credits for unprocessed emails. Requires verify:write scope.
Response (200):
{
"status": "cancelled",
"credits_refunded": 40
}
Response (409) — job already complete:
{
"error": "job_already_complete",
"message": "Cannot cancel a completed job."
}
DELETE /api/v1/verify/bulk/{jobId}
Permanently delete a verification job and all its results. Intended for GDPR compliance. Requires verify:write scope.
The job must not be actively processing. Cancel it first if needed.
Response (200):
{
"deleted": true
}
Response (409) — job still processing:
{
"error": "job_still_processing",
"message": "Cancel the job before deleting. Use POST /api/v1/verify/bulk/{jobId}/cancel first."
}
Error codes
| Status | Code | Meaning |
|---|---|---|
| 402 | insufficient_credits |
Not enough credits to process this request |
| 403 | insufficient_scope |
API token missing verify:write scope |
| 404 | not_found |
Job not found or belongs to another account |
| 409 | job_not_complete |
Cannot download results for in-progress job |
| 409 | job_already_complete |
Cannot cancel a job that has already finished |
| 409 | job_still_processing |
Cannot delete a job that is still processing — cancel first |
| 422 | validation_error |
Invalid request (missing email, too many emails, etc.) |
| 422 | missing_idempotency_key |
Write endpoint called without an Idempotency-Key header |
| 429 | rate_limit_exceeded |
Too many requests — retry after cooldown |
Rate limits
- Single verification: 60 requests/minute per account
- Bulk submission: 10 requests/minute per account
- Job status polling: 120 requests/minute per account
MCP Tools
Eight MCP tools are available for AI agent integration:
| Tool | Description |
|---|---|
verify_email |
Verify a single email address |
verify_email_bulk |
Submit a bulk verification job |
verify_job_status |
Check job progress and results (supports search filter) |
verify_job_download |
Download job results as CSV |
verify_credits |
Check remaining credit balance |
verify_list_jobs |
List all verification jobs with pagination and status filter |
verify_cancel_job |
Cancel a running job and refund unprocessed credits |
verify_delete_job |
Permanently delete a job and all results (GDPR) |
See AI Agents & API for MCP setup instructions.
Related articles
Jump to nearby guides that continue the workflow.