# Email validation

> Check whether addresses can receive mail, and suppress the ones that cannot.

URL: https://docs.workwae.com/reference/email-validation

Guides: [Email validation](/guides/email-validation).

| Method | Path | Operation | Scope |
| --- | --- | --- | --- |
| `GET` | `/v1/email-validations` | [List earlier validation results](#list-earlier-validation-results) | `read` |
| `POST` | `/v1/email-validations` | [Validate email addresses](#validate-email-addresses) | `write` |

## List earlier validation results

`GET /v1/email-validations`

TypeScript SDK method: `workwae.emailValidations.list()`

One item per address a validation request answered, newest first, kept for the deployment's retention period (90 days by default). address keeps those containing it, reachability those with that verdict. Readable whether or not the deployment validates.

Required scope: `read`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `address` | query | string | no | At most 320 characters. Example `"ada@example.com"`. |
| `reachability` | query | "safe" \| "risky" \| "invalid" \| "unknown" | no |  |
| `limit` | query | integer | no | 1 to 200. Default `50`. |
| `cursor` | query | string | no | 1 to 512 characters. Example `"eyJ0eG5pZCI6IjQyIiwiaWQiOjEwMDF9"`. |

### Responses

- **200** OK (application/json, object)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | object[] | yes |  |
| `items[].id` | string (uuid) | yes | Example `"c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b"`. |
| `items[].createdAt` | string (date-time) | yes | Example `"2026-05-04T09:30:00.000Z"`. |
| `items[].address` | string | yes | Example `"ada@example.com"`. |
| `items[].reachability` | "safe" \| "risky" \| "invalid" \| "unknown" | yes |  |
| `items[].validSyntax` | boolean | yes |  |
| `items[].domainAcceptsMail` | boolean \| null | yes |  |
| `items[].deliverable` | boolean \| null | yes |  |
| `items[].disabled` | boolean \| null | yes |  |
| `items[].fullInbox` | boolean \| null | yes |  |
| `items[].catchAll` | boolean \| null | yes |  |
| `items[].disposable` | boolean \| null | yes |  |
| `items[].roleAccount` | boolean \| null | yes |  |
| `items[].suppressed` | boolean | yes |  |
| `items[].cached` | boolean | yes |  |
| `items[].checkedAt` | string (date-time) | yes | Example `"2026-05-04T09:30:00.000Z"`. |
| `nextCursor` | string \| null | yes | Example `"eyJ0eG5pZCI6IjQyIiwiaWQiOjEwMDF9"`. |

- **Errors**, by status and `code` (see [Errors](/guides/errors)):
  - 400: `invalid_input`, `invalid_idempotency_key`, `invalid_cursor`
  - 401: `unauthenticated`, `api_key_expired`
  - 403: `missing_scope`, `role_forbidden`, `account_token_forbidden`, `account_scope_forbidden`, `mcp_only_key`
  - 409: `idempotency_key_in_progress`
  - 413: `payload_too_large`
  - 422: `idempotency_key_reused`
  - 429: `rate_limited`, `too_many_requests`
  - 500: `internal_error`
  - 503: `overloaded`

## Validate email addresses

`POST /v1/email-validations`

TypeScript SDK method: `workwae.emailValidations.create()`

Checks whether each address (up to 10) can receive mail, without sending any: syntax, the domain's mail servers and an SMTP conversation with the recipient's server. Takes seconds per address. An address checked within the deployment's cache period (7 days by default) gets that result back, cached, unless refresh is set or it was unknown. The addresses checked again count toward the plan's emailValidationsPerDay; reused results do not, and a request that does not fit is refused whole. On a billed plan with included validation credits, each address checked again also spends one credit (included credits first, then purchased ones; reused results are free), and a request the balance cannot cover is refused whole with 402 validation_credits_exhausted. A request that fails costs no credits. With suppressInvalid, addresses found invalid go on the global suppression list. Every result is kept in the history (GET /v1/email-validations). Needs the write scope; requests are held to a per-minute limit (beyond it, rate_limited with Retry-After).

Required scope: `write`.

### Request body (required)

Content type `application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `addresses` | string (email)[] | yes | 1 to 10 items. |
| `suppressInvalid` | boolean | no | Default `false`. |
| `refresh` | boolean | no | Default `false`. |

### Responses

- **200** OK (application/json, object)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `results` | object[] | yes |  |
| `results[].address` | string | yes | Example `"ada@example.com"`. |
| `results[].reachability` | "safe" \| "risky" \| "invalid" \| "unknown" | yes |  |
| `results[].validSyntax` | boolean | yes |  |
| `results[].domainAcceptsMail` | boolean \| null | yes |  |
| `results[].deliverable` | boolean \| null | yes |  |
| `results[].disabled` | boolean \| null | yes |  |
| `results[].fullInbox` | boolean \| null | yes |  |
| `results[].catchAll` | boolean \| null | yes |  |
| `results[].disposable` | boolean \| null | yes |  |
| `results[].roleAccount` | boolean \| null | yes |  |
| `results[].suppressed` | boolean | yes |  |
| `results[].cached` | boolean | yes |  |
| `results[].checkedAt` | string (date-time) | yes | Example `"2026-05-04T09:30:00.000Z"`. |

- **Errors**, by status and `code` (see [Errors](/guides/errors)):
  - 400: `invalid_input`, `invalid_idempotency_key`, `email_validation_disabled`
  - 401: `unauthenticated`, `api_key_expired`
  - 402: `plan_required`, `validation_credits_exhausted`
  - 403: `missing_scope`, `role_forbidden`, `account_token_forbidden`, `account_scope_forbidden`, `mcp_only_key`, `plan_limit_validations`
  - 409: `idempotency_key_in_progress`
  - 413: `payload_too_large`
  - 422: `idempotency_key_reused`
  - 429: `rate_limited`, `too_many_requests`
  - 500: `internal_error`
  - 502: `email_validation_unavailable`, `email_validation_suspended`
  - 503: `overloaded`
