Bulk Lists API
Submit a list of email addresses for bulk validation, check its progress, and download the results, all from your own code. For the dashboard workflow, see Bulk Validation.
Endpoints
POST https://api.mailcop.net/v1/lists
GET https://api.mailcop.net/v1/lists/:id
GET https://api.mailcop.net/v1/lists/:id/export
Authentication
Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Create a list
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
emails |
array of strings | Yes | The addresses to validate |
validation_type |
string | No | mx (default, 1 credit each) or smtp (10 credits each, Premium only) |
title |
string | No | A label for the list, up to 255 characters. Defaults to Email List of and the creation time |
block_disposable_emails |
boolean | No | Mark disposable addresses as bad |
catch_all |
boolean | No | Run catch-all detection |
Element rules
Each element of emails must be one address:
- No whitespace, control characters, commas, or semicolons inside the element (leading and trailing whitespace is trimmed, and empty elements are ignored)
- At most 254 characters
- Send one address per element. A single string such as
"[email protected],[email protected]"is rejected
Duplicates are removed automatically, ignoring case, and are not charged. They are reported as a count in duplicates; the duplicate addresses themselves are not returned. Elements with no recognizable address are dropped and not charged. The total in the response reflects the rows actually created.
Limits
- At most 50,000 elements per request
- Request body at most 5 MB
Both return 413. Split larger lists across several requests.
Example request
curl -X POST https://api.mailcop.net/v1/lists \
-H "Authorization: Bearer tm_live_abc123..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: import-2026-11-06-001" \
-d '{
"title": "November signups",
"validation_type": "mx",
"emails": ["[email protected]", "[email protected]"]
}'
Success (202 Accepted)
The list is queued for validation. The Location header holds the URL of the new list.
{
"id": "k3x9m2p7q4w8z5n6r1ta",
"title": "November signups",
"status": "pending",
"validation_type": "mx",
"total": 2,
"good": 0,
"bad": 0,
"pending": 0,
"duplicates": 0,
"failure_reason": null,
"created_at": "2026-11-06T10:15:00Z",
"completed_at": null,
"export_url": "https://api.mailcop.net/v1/lists/k3x9m2p7q4w8z5n6r1ta/export"
}
Idempotency
Send an Idempotency-Key header (up to 255 characters) to make retries safe. Within 24 hours, a repeat request with the same key and the same body returns 200 with the existing list (not 202) instead of creating another one and charging again. Reusing a key with a different emails array or validation_type returns 422. If a request with the same key is still being processed, you get 409 Conflict with a Retry-After header (in seconds). Wait and retry.
A failed list is never replayed; the same key creates a new list. The failed list’s unused credits were already refunded.
Credits
Credits for the unique addresses are locked when validation starts. The 402 for a short balance is checked at request time, so a list accepted with 202 can still fail later with email_list.failed if your credits run out before it starts. SMTP validation on a non-Premium plan also returns 402.
Check a list
curl https://api.mailcop.net/v1/lists/k3x9m2p7q4w8z5n6r1ta \
-H "Authorization: Bearer tm_live_abc123..."
Response (200 OK)
| Field | Description |
|---|---|
id |
List identifier |
title |
The title you provided, or the default Email List of ... title |
status |
pending, validating, completed, or failed |
validation_type |
mx or smtp |
total |
The submitted count until rows exist, then the number of rows created, after duplicates and unrecognizable elements are dropped |
good, bad, pending |
Counts by result so far |
duplicates |
Number of duplicate addresses removed |
failure_reason |
Why the list failed, or null |
created_at |
When the list was created |
completed_at |
When validation finished, or null |
export_url |
Where to download the results |
Validation can wait in a queue under heavy load, so a list may stay pending for a while before it starts. Poll no more often than every 15 seconds, or use webhooks instead.
Export results
curl "https://api.mailcop.net/v1/lists/k3x9m2p7q4w8z5n6r1ta/export?output=csv&good_only=true" \
-H "Authorization: Bearer tm_live_abc123..." \
-o good_emails.csv
Parameters
| Parameter | Description |
|---|---|
output |
jsonl (default) or csv |
good_only |
true to export only good addresses |
CSV output always includes the extended columns: email, status, validation_type, reason, reason_code, role_account, free_provider, catch_all_domain, and result. JSONL output has one JSON object per line with email, the full validation result, and status.
In JSONL, email is the lowercased address from the result once the address is validated. In CSV, email keeps the spelling you submitted.
For spreadsheet safety, CSV cells that start with =, +, -, @, a tab, or a carriage return are prefixed with '. Use JSONL when you join results back to your data by machine.
The X-Total-Count response header holds the number of rows in the export.
Partial export
You can export a list while it is still running. Addresses not yet validated appear with their current status, and on a failed list they appear as not_validated. Those addresses were not charged.
One export at a time
Each account can run one export at a time. A second export while another is streaming returns 429 with Retry-After: 120. Wait and retry.
Webhooks
email_list.startedfires when processing begins, after the file is parsed and with the real total. It does not fire when credits are short.email_list.completedfires when validation finishes.email_list.failedfires when a list fails: no valid addresses, insufficient credits, validation could not start, or a stall with no progress for 30 minutes.
See Webhooks for payloads.
Errors
| Status | Meaning |
|---|---|
400 |
Invalid emails, element, output, or Idempotency-Key |
402 |
Insufficient credits, or SMTP on a non-Premium plan |
404 |
List not found |
409 |
A request with the same Idempotency-Key is still in progress |
413 |
More than 50,000 elements or a body over 5 MB |
422 |
Unknown validation_type, or an Idempotency-Key reused with a different request |
429 |
Rate limit exceeded, or an export is already running |
See Error Handling for details.