# Easy Email Verification API reference

> Generated from the [OpenAPI specification](https://www.easyemailverification.com/openapi.json) (API version 1.2.0, source fb9a3ec).
> Do not edit by hand. Setup guide for AI agents: https://www.easyemailverification.com/agents.md

Base URL: `https://api.easyemailverification.com/v1`

## Overview

REST API to verify email addresses one at a time, in small batches, or as bulk lists.

### Authentication

Every request needs an API key, created in the dashboard under
[API Settings](https://dashboard.easyemailverification.com/apisettings).

**Recommended:** send the key in the `X-API-Key` header.

**Also supported** (all endpoints keep accepting them):

- `apikey` query parameter (`GET /verify`, `GET /credits`)
- `apikey` header (`POST /verify` and `/bulk/*`)
- `Authorization` header, as `Authorization: <key>` or `Authorization: token <key>`

If a request carries more than one of them, `apikey` wins over `X-API-Key`, which wins
over `Authorization`.

Keys created for the JavaScript widget (keys with an authorized domain) are rejected
by these endpoints with `401`.

Keep API keys on a trusted server. Do not use them in browser or mobile code.

### Sandbox

Use the public key `eev_sandbox_key` to test an integration without an account and
without spending credits. It works on `GET /verify`, `POST /verify` and `GET /credits`,
only accepts addresses at `sandbox.easyemailverification.com` (plus `typo@gmial.com`),
and answers with fixed results chosen by the local part:

| Address | Answer |
| --- | --- |
| `valid@sandbox.easyemailverification.com` | `valid`, `accepted_email` |
| `invalid@sandbox.easyemailverification.com` | `invalid`, `rejected_email` |
| `unknown@sandbox.easyemailverification.com` | `unknown`, `timeout` |
| `disposable@sandbox.easyemailverification.com` | `valid`, `disposable: true` |
| `catchall@sandbox.easyemailverification.com` | `valid`, `accept_all: true` |
| `role@sandbox.easyemailverification.com` | `valid`, `role: true` |
| `typo@gmial.com` | `invalid`, `did_you_mean: typo@gmail.com` |
| `quota@sandbox.easyemailverification.com` | `402` (no credits) |
| `ratelimit@sandbox.easyemailverification.com` | `429` (simulated) |

Any other sandbox address returns `invalid`. Sandbox responses carry the header
`X-EEV-Sandbox: true` and are limited to 60 requests per minute per IP.

## Endpoints

### GET /verify

Verify a single email address.

Verifies one email address. Each verification consumes one credit, except when the
receiving server could not be reached (`reason: no_connect`).

`success: true` means the request was processed; it does not mean the address is
deliverable. Use `result`, `reason` and `safe_to_send`. Do not treat `unknown` as `valid`.

**API key:** `X-API-Key` header, `apikey` query, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `email` | query | yes | Email address to verify. URL-encode it (for example `+` as `%2B`). |
| `apikey` | query | no | API key. Optional when the key is sent in a header (`X-API-Key` recommended). |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Verification result. | [VerificationResult](#verificationresult) `application/json` |
| 400 | Missing API key (`message: "Apikey is null"`), empty `email`, or (sandbox key) an address outside the sandbox domain. When the `email` parameter is absent, the framework returns its default error body. | [VerificationError](#verificationerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [VerificationError](#verificationerror) `application/json` |
| 402 | The account has no credits left. | [VerificationError](#verificationerror) `application/json` |
| 429 | Sandbox key only (sandbox rate limit or the simulated `ratelimit@` address). | [VerificationError](#verificationerror) `application/json` |

Example `200` response:

```json
{
  "email": "john@gmail.com",
  "result": "invalid",
  "reason": "rejected_email",
  "disposable": false,
  "accept_all": false,
  "role": false,
  "free": true,
  "user": "john",
  "domain": "gmail.com",
  "mx_record": "gmail-smtp-in.l.google.com",
  "mx_domain": "google.com",
  "safe_to_send": false,
  "did_you_mean": "",
  "success": true,
  "message": "Processing time: 812 ms",
  "http_code": "200"
}
```

### POST /verify

Verify a small batch of email addresses.

Verifies up to 50 email addresses in one request and returns one result per address.
Each address consumes one credit, except `reason: no_connect`.
For larger lists use the bulk endpoints.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Request body** (`application/json`): [BatchRequest](#batchrequest)

```json
{
  "emails": [
    "john@gmail.com",
    "mary@example.com"
  ]
}
```

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | One result per address, in the same shape as `GET /verify`. | array of [VerificationResult](#verificationresult) `application/json` |
| 400 | No API key, or (sandbox key) an address outside the sandbox domain. | [VerificationErrorList](#verificationerrorlist) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [VerificationErrorList](#verificationerrorlist) `application/json` |
| 402 | The account has no credits left. | [VerificationErrorList](#verificationerrorlist) `application/json` |
| 429 | Too many addresses in one request. | [VerificationErrorList](#verificationerrorlist) `application/json` |

### POST /bulk/upload

Upload a list for bulk verification.

Uploads a TXT or CSV file with one email address per line and starts an asynchronous
verification job. Lines that contain `@` and are longer than 5 characters are counted.
The account needs enough credits for every counted line. Maximum file size: 16 MB.
Poll `GET /bulk/status/{id}` and download the result with `GET /bulk/download/{id}`.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Request body** (`multipart/form-data`): object

- `file`: TXT or CSV file, one email address per line.

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | File accepted and job created. | [BulkUploadAccepted](#bulkuploadaccepted) `application/json` |
| 400 | Missing API key, or the file has no valid email addresses. | [BulkError](#bulkerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [BulkError](#bulkerror) `application/json` |
| 402 | Not enough credits for the number of addresses in the file. | [BulkError](#bulkerror) `application/json` |
| 500 | The file could not be read. | [BulkError](#bulkerror) `application/json` |

### GET /bulk/status

List the bulk jobs of the account.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Jobs of the account that owns the API key. | [BulkJobList](#bulkjoblist) `application/json` |
| 400 | No API key, or the sandbox key (not supported on bulk endpoints). | [BulkError](#bulkerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [BulkError](#bulkerror) `application/json` |

### GET /bulk/status/{id}

Get the status of a bulk job.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `id` | path | yes | Job id (`list_id`) returned by `POST /bulk/upload`. |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Job status. | [BulkJobStatus](#bulkjobstatus) `application/json` |
| 400 | No API key, or the sandbox key (not supported on bulk endpoints). | [BulkError](#bulkerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [BulkError](#bulkerror) `application/json` |
| 404 | Job not found, or it belongs to another account. | [BulkError](#bulkerror) `application/json` |

### GET /bulk/download/{id}

Download the results of a completed bulk job.

Returns the results as CSV with the header
`Email,Result,Reason,Disposable,AcceptAll,Role,Free,User,Domain,MXRecord,DomainMX,IsSafeToSend,DidYouMean,Success,Message,HttpCode`.
Jobs and their results are deleted automatically 30 days after upload.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `id` | path | yes | Job id (`list_id`) returned by `POST /bulk/upload`. |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | CSV file (`Content-Disposition: attachment; filename=results.csv`). | string `text/plain` |
| 400 | No API key, or the sandbox key (not supported on bulk endpoints). | [BulkError](#bulkerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [BulkError](#bulkerror) `application/json` |
| 404 | Job not found, not completed yet, or it belongs to another account. | [BulkError](#bulkerror) `application/json` |

### DELETE /bulk/{id}

Delete a bulk job and its results.

**API key:** `X-API-Key` header, `apikey` header, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `id` | path | yes | Job id (`list_id`) returned by `POST /bulk/upload`. |
| `apikey` | header | no | API key. Optional when the key is sent in `X-API-Key` (recommended) or `Authorization`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Job deleted. | [BulkDeleted](#bulkdeleted) `application/json` |
| 400 | No API key, or the sandbox key (not supported on bulk endpoints). | [BulkError](#bulkerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [BulkError](#bulkerror) `application/json` |
| 404 | Job not found, or it belongs to another account. | [BulkError](#bulkerror) `application/json` |

### GET /credits

Remaining credits of the account.

Does not consume credits. With the sandbox key it returns fixed values.

**API key:** `X-API-Key` header, `apikey` query, `Authorization` header.

**Parameters**

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `apikey` | query | no | API key. Optional when the key is sent in a header (`X-API-Key` recommended). |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Remaining credits. | [Credits](#credits) `application/json` |
| 400 | No API key. | [SimpleError](#simpleerror) `application/json` |
| 401 | Unknown API key, or a widget-only key. | [SimpleError](#simpleerror) `application/json` |

Example `200` response:

```json
{
  "success": true,
  "credits_remaining": 1250,
  "subscription_remaining": 250,
  "persistent_remaining": 1000,
  "subscription_credits": 500
}
```

## Schemas

### VerificationResult

Result of one verification. All fields are always present.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string, nullable | yes | Address that was verified, normalized to lowercase. |
| `result` | string, nullable | yes | Overall result. Check `reason` for details. One of: `valid`, `invalid`, `unknown`. |
| `reason` | string, nullable | yes | Detail of the result. Known values: `accepted_email` (SMTP server accepted the address), `rejected_email` (mailbox does not exist), `invalid_email` (invalid syntax), `invalid_domain` (domain does not exist), `no_mx_record` (domain has no MX record), `invalid_mx_record`, `no_connect` (could not connect to the receiving server; no credit is consumed), `timeout`, `unavailable_smtp`, `unexpected_error`, `temporarily_blocked` (greylisted), `exceeded_storage` (mailbox full). New values may be added; treat unknown values as inconclusive. |
| `disposable` | boolean | yes | Known temporary/disposable address. |
| `accept_all` | boolean | yes | Catch-all domain; it accepts any mailbox, so the address cannot be confirmed. |
| `role` | boolean | yes | Role address such as support@ or postmaster@. |
| `free` | boolean | yes | Address from a popular free provider (Gmail, Outlook, Yahoo...). |
| `user` | string, nullable | yes | Local part of the address. |
| `domain` | string, nullable | yes | Domain part of the address. |
| `mx_record` | string, nullable | yes | MX host that receives mail for the domain. |
| `mx_domain` | string, nullable | yes | Domain of the MX host. |
| `safe_to_send` | boolean | yes | Whether the address is considered safe for sending. |
| `did_you_mean` | string | yes | Suggested correction when a typo is detected; empty string otherwise. |
| `success` | boolean | yes | Whether the request was processed. It does not mean the address is deliverable. |
| `message` | string, nullable | yes | Error description, or processing information on success. |
| `http_code` | string, nullable | yes | HTTP status code repeated in the body, as a string. |

### VerificationError

Error response of `GET /verify`. Same shape as a result, with `success: false`.

Same fields as [VerificationResult](#verificationresult).

### VerificationErrorList

Error response of `POST /verify`: a list with one error item.

Array of [VerificationResult](#verificationresult).

### BatchRequest

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `emails` | array of string | yes | Addresses to verify (maximum 50). |

### Credits

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | yes |  |
| `credits_remaining` | integer | yes | Total verifications left (subscription + prepaid). |
| `subscription_remaining` | integer | yes | Left in the current subscription period. |
| `persistent_remaining` | integer | yes | Prepaid credits that do not expire with the period. |
| `subscription_credits` | integer | yes | Credits granted per subscription period. |

### SimpleError

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | yes | One of: `false`. |
| `message` | string | yes |  |
| `http_code` | string | yes |  |

### BulkError

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | string | yes | One of: `error`. |
| `message` | string | yes |  |

### BulkUploadAccepted

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | string | yes | One of: `accepted`. |
| `list_id` | string | yes | Job id used by the other bulk endpoints. |
| `filename` | string | yes |  |
| `uploaded` | integer | yes | Number of addresses counted in the file. |
| `message` | string | yes |  |

### BulkJobStatusValue

`not_enough_credits`: processing stopped because the account ran out of credits.

Type: string. One of: `queued`, `processing`, `completed`, `failed`, `deleted`, `not_enough_credits`, `unknown`.

### BulkJobStatus

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `list_id` | string | yes |  |
| `status` | [BulkJobStatusValue](#bulkjobstatusvalue) | yes |  |
| `progress` | integer | yes | Percentage processed. |
| `started_at` | string (date-time), nullable | no | Upload time. |
| `estimated_finish` | string (date-time), nullable | no | Completion time once the job is completed; null before that. |
| `totals` | object, nullable | no | Counters; null before processing starts. |

### BulkJobList

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | string | yes | One of: `ok`. |
| `total_lists` | integer | yes |  |
| `lists` | array of object | yes |  |

### BulkDeleted

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | string | yes | One of: `deleted`. |
| `list_id` | string | yes |  |
| `message` | string | yes |  |
