Email Verifier REST API Reference
Verify addresses programmatically — 8 REST endpoints for single and bulk verification, credit checks, job management, CSV export, plus auth and scope details.
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
- Sep 10, 2026
The Email Verifier API is served under /api/v1. Use the TrekMail host that your account uses for sign-in. Examples below use https://YOUR-TREKMAIL-HOST as a placeholder.
Authentication and scopes
Pass an API token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
Enable scopes when you create the token:
| Scope | Required for |
|---|---|
verify:read |
Credits, job lists, job status and downloads. |
verify:write |
Single checks, bulk submission, cancellation and deletion. |
Give a client both scopes if it must submit work and then read or download the result.
Host and request format
All examples use JSON request bodies and a Bearer token. The dashboard file uploader is separate from the API: POST /verify/bulk accepts an emails JSON array, not a multipart file. Use the exact host that belongs to the account and token. A token or balance from one branded host should not be assumed to work on another host.
Send Content-Type: application/json for POST /verify and POST /verify/bulk requests. Store the token and the idempotency value outside client-side code.
Idempotency
POST /api/v1/verify/bulk and DELETE /api/v1/verify/bulk/{jobId} require an Idempotency-Key header. Generate a new value for each intended operation and reuse that value only when retrying the same operation.
Idempotency-Key: 58dfa0de-96eb-4521-a0f9-2e5eac6721ee
Single verification and job cancellation do not require that header. A bulk request is also protected by duplicate-list detection for the same normalized list and mode within 24 hours, but an idempotency key is still the correct retry mechanism.
Handling an uncertain network outcome
If your application loses the response to a bulk request, do not generate a new idempotency key and submit another list. Repeat the identical request with the same key. Store the key with the source-list identifier until TrekMail returns a job ID. This keeps a retry connected to the original intended operation rather than creating an avoidable second charge.
Endpoint summary
| Method and path | Scope | Purpose |
|---|---|---|
GET /verify/credits |
verify:read |
Read available credits. |
POST /verify |
verify:write |
Verify one address immediately. |
POST /verify/bulk |
verify:write |
Create an asynchronous bulk job. |
GET /verify/bulk/{jobId} |
verify:read |
Read job progress and available results. |
GET /verify/bulk/{jobId}/download |
verify:read |
Download a CSV export. |
GET /verify/bulk |
verify:read |
List jobs. |
POST /verify/bulk/{jobId}/cancel |
verify:write |
Cancel a pending or running job. |
DELETE /verify/bulk/{jobId} |
verify:write |
Permanently delete a non-running job. |
Prepend /api/v1 to every path in this table.
Read credit balance
GET /api/v1/verify/credits
On the standard TrekMail host, the response includes the plan allowance and purchased balance:
{
"monthly_limit": 300,
"monthly_used": 120,
"monthly_remaining": 180,
"purchased_balance": 5000,
"total_available": 5180,
"plan": "pro",
"trialing": false,
"resets_at": "2026-10-01T00:00:00+00:00"
}
On a White Label host, only purchased credits are available to the branded product, so the response contains purchased_balance and total_available.
Example request:
curl https://YOUR-TREKMAIL-HOST/api/v1/verify/credits \
-H "Authorization: Bearer YOUR_API_TOKEN"
Read the balance immediately before a large submission. A balance response is a snapshot, so an application that submits several jobs should record the amount charged in each bulk response instead of calculating later from a stale number.
Balance fields
| Field | Meaning |
|---|---|
monthly_limit |
The plan allowance for the current reset period. |
monthly_used |
Credits already spent from that allowance. |
monthly_remaining |
Allowance still available before purchased credits are needed. |
purchased_balance |
Credits bought separately and not yet spent. |
total_available |
The spendable amount for the next job on this host. |
resets_at |
The next known reset time when available. |
White Label balance responses intentionally have fewer fields because the branded product uses purchased credits only.
Verify one address
POST /api/v1/verify
{
"email": "person@example.com",
"mode": "quick"
}
| Field | Required | Notes |
|---|---|---|
email |
Yes | A single email address, up to 320 characters. |
mode |
No | quick is the default; deep is accepted when Deep is available. |
The response includes email, status, trust_score, checks, provider, risk_factors and credits_remaining. On the standard host, credits_remaining has monthly and purchased values. The detailed checks shape can vary by mode and by what the receiving provider makes available.
Quick costs 1 credit. Deep normally costs 2 credits, while provider-specific exceptions are calculated at 1 credit. If verification cannot run after the charge, the single-address request refunds that charge and returns a temporary-unavailable response.
Example request:
curl -X POST https://YOUR-TREKMAIL-HOST/api/v1/verify \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"person@example.com","mode":"quick"}'
Use the top-level status, trust_score, provider and risk_factors as the normal application contract. checks contains useful supporting evidence, but the individual keys can differ when an upstream check is skipped, unavailable or Deep mode obtains extra information.
Single-result interpretation
| Field | Use it for |
|---|---|
email |
Match the result to the normalized input your application stored. |
status |
Place the address into your review or campaign workflow. |
trust_score |
Sort or prioritize work within a status, not as a substitute for consent. |
provider |
Explain which domain the verifier considered. |
risk_factors |
Present a concise review reason to an operator. |
checks |
Show supporting detail when the operator needs to understand a result. |
Do not make an application treat an accepted remote response as an ownership or permission check. Keep subscription, opt-out and contact-preference decisions separate.
Create a bulk job
POST /api/v1/verify/bulk
{
"emails": ["first@example.com", "second@example.net"],
"name": "September contacts",
"mode": "deep"
}
| Field | Required | Notes |
|---|---|---|
emails |
Yes | Array of up to 50,000 submitted entries. Syntactically invalid entries are excluded and reported. |
name |
No | A label up to 255 characters. |
mode |
No | quick by default, or deep when available. |
Duplicates are normalized before pricing. A successful new job returns 201 with:
{
"job_id": 42,
"total": 2,
"status": "pending",
"rejected_count": 0,
"rejected_sample": [],
"credits_charged": 4,
"breakdown": {"probe": 2, "skip": 0, "deep_savings": 0}
}
probe and skip explain the Deep price calculation. deep_savings is the difference from charging every submitted address at the full Deep rate. A duplicate list returns the existing job_id and status instead of starting another job.
Example request:
curl -X POST https://YOUR-TREKMAIL-HOST/api/v1/verify/bulk \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 58dfa0de-96eb-4521-a0f9-2e5eac6721ee" \
-d '{"name":"September contacts","mode":"deep","emails":["first@example.com","second@example.net"]}'
The API tests the submitted values for valid email syntax before job admission. If every entry is rejected, it returns 422 and does not create a job. If some are rejected, the successful response reports rejected_count and up to five values in rejected_sample. Do not rely on that small sample as a complete data-cleaning report; retain the source validation result in your own importer.
Bulk-submission checklist
- Read and normalize the source in your own application.
- Limit the request to 50,000 submitted entries.
- Generate and persist an idempotency key before the request.
- Keep the job name meaningful enough for an operator to recognize later.
- Store
job_id,credits_chargedand the pricing breakdown returned by TrekMail. - Poll the stored
job_id; do not infer completion from the original HTTP request.
Read a job
GET /api/v1/verify/bulk/{jobId}
The base response includes job_id, name, status, total, processed, progress, summary, created_at and completed_at.
When results are available for a completed, partial or failed job, the response also includes:
{
"results": [
{
"email": "person@example.com",
"status": "valid",
"trust_score": 82,
"checks": {},
"provider": "example.com",
"risk_factors": ["no_dmarc"]
}
],
"pagination": {"page": 1, "per_page": 100, "total": 1, "last_page": 1}
}
Optional query parameters:
| Parameter | Notes |
|---|---|
page |
Results page number. |
per_page |
1 to 500; default 100. |
status |
pending, queued, safe, valid, risky, invalid or unknown. |
search |
Literal partial-email search, up to 320 characters. |
A cancelled job with processed rows is downloadable, but use the download endpoint for its export.
Read job states without guessing
| Status | Meaning for an API client |
|---|---|
pending |
The job was accepted and is waiting for processing. |
processing |
Work is running. Use processed and progress for a user-facing update. |
completed |
The full job finished. Read results or download the CSV. |
partial |
A subset completed. Review it as a subset, not as a full-list result. |
cancelled |
The job was stopped. Processed rows may still be downloaded. |
failed |
The job could not complete. Read the state and error context before retrying. |
An API client should poll with backoff. Do not issue a new bulk submission simply because the existing job is still pending or because a network request timed out locally.
Status response example
{
"job_id": 42,
"name": "September contacts",
"status": "processing",
"total": 1500,
"processed": 400,
"progress": 27,
"summary": {"safe": 220, "valid": 105, "risky": 55, "invalid": 20},
"created_at": "2026-09-04T13:15:00+00:00",
"completed_at": null
}
The summary can grow as work completes. Use processed and total for a progress display rather than summing only the categories your application currently recognizes.
Download a job
GET /api/v1/verify/bulk/{jobId}/download
The download is available for completed, partial or cancelled jobs that have processed rows. It streams a CSV with Email, Status, Trust Score, Provider and Risk Factors columns.
| Query parameter | Allowed values |
|---|---|
filter |
all (default), safe, safe_risky (Safe + Valid + Risky). |
Example:
curl -o september-results.csv \
"https://YOUR-TREKMAIL-HOST/api/v1/verify/bulk/42/download?filter=safe_risky" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Save the downloaded output within the 15-day results-retention period. The CSV is an export for your own workflow; it does not change consent, subscriptions or contact records in another system.
The download endpoint returns a conflict while no processed export is available. Check the job's state first. A successful request streams the CSV rather than returning a JSON wrapper, so handle it as a file response in your HTTP client.
List jobs
GET /api/v1/verify/bulk
Use page, per_page and optional status. per_page defaults to 20 and accepts 1 to 100. Job status values are pending, processing, completed, partial, cancelled and failed.
The response contains a jobs array and a pagination object. Each job record has its ID, name, status, total, processed count, progress and timestamps.
Example:
curl "https://YOUR-TREKMAIL-HOST/api/v1/verify/bulk?status=processing&per_page=20" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Use the list endpoint when your worker restarts or when you need to reconcile job IDs. Do not treat a job name as a unique identifier; store the returned numeric job_id.
Job-list response shape
{
"jobs": [
{
"job_id": 42,
"name": "September contacts",
"status": "completed",
"total": 1500,
"processed": 1500,
"progress": 100,
"created_at": "2026-09-04T13:15:00+00:00",
"completed_at": "2026-09-04T13:28:00+00:00"
}
],
"pagination": {"page": 1, "per_page": 20, "total": 1, "last_page": 1}
}
Use the status query parameter when an operations page needs only active or only finished work. Pagination is important for accounts that verify many lists; do not assume one response contains the complete history.
Cancel a job
POST /api/v1/verify/bulk/{jobId}/cancel
Cancel only pending or running work. A successful response is:
{"status":"cancelled","credits_refunded":40}
The refund is for unprocessed work. If the job became terminal before the cancellation reached it, the API returns a conflict instead of changing its result.
curl -X POST https://YOUR-TREKMAIL-HOST/api/v1/verify/bulk/42/cancel \
-H "Authorization: Bearer YOUR_API_TOKEN"
Cancellation does not delete a job. Download processed rows if required, or delete the finished record afterwards.
Delete a job
DELETE /api/v1/verify/bulk/{jobId}
Cancel a running job first. Deletion permanently removes the job and its results after TrekMail securely removes the staged source list. A successful response is:
{"deleted":true}
curl -X DELETE https://YOUR-TREKMAIL-HOST/api/v1/verify/bulk/42 \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Idempotency-Key: 843ef0c5-4dc0-4c09-bacd-5bd0fe87e847"
This operation is permanent for the verifier record. It does not retract CSV files that your application already downloaded, so apply your own retention process to those copies.
Deletion order
- Read the job status.
- Cancel it if it is pending or processing.
- Save any processed export you must retain.
- Delete the non-running verifier job with an idempotency key.
- Remove any copies your own system holds according to its privacy and retention rules.
Errors and retries
| Status | Typical reason | What to do |
|---|---|---|
| 402 | Not enough credits. | Add credits or reduce the job. |
| 404 | The job does not belong to this account or does not exist. | Check the ID and token account. |
| 409 | A job cannot be downloaded, cancelled or deleted in its current state. | Read its status and take the indicated next step. |
| 422 | Invalid input, unavailable Deep mode or missing idempotency key where required. | Correct the request. |
| 429 | Request rate limit reached. | Retry later with backoff. |
| 503 | Temporary verification failure. | Retry later. |
Single verification has a route limit of 60 requests per minute, and bulk submission has a route limit of 10 requests per minute. Build retry logic with backoff, preserve the same idempotency key for a bulk retry and do not retry a request blindly after an unknown network outcome.
A safe retry pattern
- Generate and persist one idempotency key before a bulk submission.
- Submit the request with that key.
- If the response is lost, retry the identical request with the same key.
- Persist the returned
job_idand stop creating new submissions for that source list. - Poll that job until it reaches a terminal state, then download or process its result.
For a single verification, a temporary 503 means the service could not complete the check. Retry later with normal backoff. Do not convert that response into an Invalid result in your own database.
Keep contact data safe
Email lists are personal data in many contexts. Send only the data needed for verification, limit token access to the system that performs the job and avoid logging full address arrays in application logs. When logging is needed, store the job ID, count, timing and high-level outcome rather than the complete list.
Results are retained by TrekMail for 15 days. Plan for your own secure export storage or deletion path before integrating high-volume lists.
Verification signals do not prove a person's ownership, consent or future delivery. Keep permission and suppression handling in your application even when an address scores Safe.
Related articles
Jump to nearby guides that continue the workflow.