
[title] Quickstart
[path] /

Verify your first email address with the mailfloss API in under five minutes.

:::hint{type="info"}
**This is the current mailfloss API (v1).** The original email-verification API (`api.mailfloss.com/verify?api_key=…`) is now deprecated and will **sunset on June 1, 2027**. Build new integrations on v1, and plan to migrate existing ones — see [Authentication](authentication) for the `api_key` → Bearer change.
:::

## 1. Get your API key

Your API key lives in the mailfloss dashboard under **Settings → API**. It's a
secret — treat it like a password, keep it server-side, and never embed it in
client-side code or commit it to source control.

## 2. Verify a single email

Send your key as a Bearer token and call `GET /v1/verify`:

```bash
curl https://api.mailfloss.com/v1/verify?email=test@example.com \
  -H "Authorization: Bearer YOUR_API_KEY"
```

A successful call returns the verdict directly as the response body:

```json
{
  "email": "test@example.com",
  "status": "passed",
  "reason": "valid",
  "passed": true
}
```

- `status` — the deliverability verdict for the address: `passed`,
  `undeliverable`, `risky`, or `unknown`.
- `reason` — the specific signal behind the verdict.
- `passed` — a convenience boolean for "safe to send."

Each successful verification consumes one credit from your account. See the
API reference for the full list of `status` and `reason` values.

## 3. Handle errors

Errors come back in a consistent envelope — branch on the stable `code`, never
on the human-readable `message`:

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account is out of verification credits.",
    "type": "billing_error",
    "request_id": "req_a1b2c3"
  }
}
```

Full details in the **Errors** guide.

## 4. Verify in bulk

For lists, submit a batch job and poll for results:

```bash
# Submit
curl -X POST https://api.mailfloss.com/v1/batch-verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["a@example.com", "b@example.com"] }'
# -> { "id": "job_123", ... }

# Poll status
curl https://api.mailfloss.com/v1/batch-verify/job_123/status \
  -H "Authorization: Bearer YOUR_API_KEY"

# Fetch results (paginated) once status is "completed"
curl https://api.mailfloss.com/v1/batch-verify/job_123/results \
  -H "Authorization: Bearer YOUR_API_KEY"
```

POST endpoints accept an optional `Idempotency-Key` header so a retried submit
never double-charges. See the reference for the batch request shape.

## Next steps

- **Authentication** — Bearer vs. the legacy `api_key` parameter, and key handling.
- **Pagination** — how list responses page.
- **Connect an ESP** — verify-first automation across 18 email platforms.
- **SDKs** — official typed clients for Node.js, Python, Ruby, and Go.
- **API reference** — every endpoint, parameter, and response shape.

[title] Authentication
[path] /

Every v1 endpoint requires an API key. There are two ways to send it.

## Bearer token (recommended)

Send your key in the `Authorization` header:

```bash
curl https://api.mailfloss.com/v1/organization \
  -H "Authorization: Bearer YOUR_API_KEY"
```

This is the preferred scheme for all new integrations. It keeps your key out of
URLs, request logs, and browser history.

## Legacy `api_key` query parameter (deprecated)

:::hint{type="warning"}
**Prefer the Bearer header for every integration.** The `api_key` query parameter is deprecated, and the original legacy API that relied on it **sunsets June 1, 2027**. Switching to Bearer is a one-line change (below).
:::

Older integrations pass the key as a query parameter:

```bash
curl "https://api.mailfloss.com/v1/organization?api_key=YOUR_API_KEY"
```

This still works on v1, but it's **soft-deprecated**. Requests authenticated this
way receive a `Deprecation: true` response header. Query parameters are easy to
leak through server logs, proxies, and referrer headers.

**Migrating to Bearer** — move the key out of the query string and into the
`Authorization` header:

```bash
# Before — legacy api_key query parameter
curl "https://api.mailfloss.com/v1/organization?api_key=YOUR_API_KEY"

# After — Bearer token (recommended)
curl https://api.mailfloss.com/v1/organization \
  -H "Authorization: Bearer YOUR_API_KEY"
```

If you supply **both** a Bearer token and an `api_key` parameter on the same
request, the Bearer token wins.

## Getting and managing your key

Your API key is in the mailfloss dashboard under **Settings → API**. Keys are
scoped to your organization.

Treat the key as a secret:

- Keep it server-side. Never ship it in client-side JavaScript, mobile apps, or
  anything a user can inspect.
- Don't commit it to source control. Load it from an environment variable or a
  secrets manager.
- Rotate it if you suspect exposure.

## Key formats

Today's full-scope keys are prefixed `mf_live_`. The API uses the key prefix to
route to its validation strategy, which lets future key types arrive without any
protocol change:

| Prefix       | Meaning                                                |
| ------------ | ------------------------------------------------------ |
| `mf_live_*`  | Full-scope API key (current)                           |
| `mf_rk_*`    | Restricted (scoped) key — *coming in a future release* |
| `mf_oauth_*` | OAuth-issued token — *coming in a future release*      |

You don't need to do anything to prepare for scoped keys or OAuth; they'll be
additive.

## Authentication errors

A missing or rejected key returns a `401` with an `authentication_error`:

```json
{
  "error": {
    "code": "invalid_api_key",
    "message": "The provided API key is invalid.",
    "type": "authentication_error",
    "request_id": "req_a1b2c3"
  }
}
```

Common codes: `missing_api_key` (no key supplied) and `invalid_api_key` (key
rejected). See the **Errors** guide for the full model.

[title] Errors
[path] /

All v1 errors share one envelope. Build your error handling around the stable
`code` field — not the human-readable message.

## The error envelope

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account is out of verification credits.",
    "type": "billing_error",
    "request_id": "req_a1b2c3"
  }
}
```

| Field        | Use it for                                                                                                                     |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `code`       | **Branch on this.** A stable, machine-readable slug. Adding new codes is non-breaking; renaming one is a major-version change. |
| `message`    | Display / logging only. Wording can change at any time — **never pattern-match on it.**                                        |
| `type`       | Coarse category, derived deterministically from the HTTP status (see below). Handy for grouping.                               |
| `request_id` | Echoes the `X-Request-Id` response header. **Quote it in support tickets** so we can trace the request.                        |

## Error categories (`type`)

`type` is a function of the HTTP status code:

| HTTP status        | `type`                  |
| ------------------ | ----------------------- |
| 400, 405, 413, 415 | `invalid_request_error` |
| 401, 403           | `authentication_error`  |
| 402                | `billing_error`         |
| 404                | `not_found_error`       |
| 409                | `conflict_error`        |
| 429                | `rate_limit_error`      |
| 5xx                | `api_error`             |

## HTTP status codes

| Status        | Meaning                                                                |
| ------------- | ---------------------------------------------------------------------- |
| 200           | Success.                                                               |
| 400           | Invalid request — missing or malformed parameter.                      |
| 401           | Invalid credentials — key rejected.                                    |
| 402           | Payment required — out of credits (`insufficient_credits`).            |
| 403           | Forbidden — credentials valid but policy/scope/origin denies.          |
| 404           | Not found — the resource doesn't exist or belongs to another account.  |
| 409           | Conflict — a request with the same `Idempotency-Key` is still running. |
| 413           | Payload too large.                                                     |
| 415           | Unsupported media type — `Content-Type` must be `application/json`.    |
| 422           | Same `Idempotency-Key` reused with a different request body.           |
| 429           | Rate limited — honor `Retry-After`. See the **Rate limits** guide.     |
| 500           | Server error — likely a bug. Retry once with backoff.                  |
| 502, 503, 504 | Upstream unavailable. Retry with backoff.                              |

## Common error codes

Branch on these slugs. The list is grouped by category; see the API reference
per-endpoint for which codes each can return.

**Authentication & permission** — `missing_api_key`, `invalid_api_key`,
`forbidden`, `domain_not_authorized`.

**Input validation** — `missing_email`, `invalid_email`, `missing_emails`,
`invalid_emails`, `missing_job_id`, `invalid_job_id`, `invalid_content_type`,
`invalid_request`.

**Limits** — `payload_too_large`, `rate_limited`.

**Billing** — `insufficient_credits`.

**Not found / conflict** — `not_found`, `job_not_found`, `job_not_completed`,
`idempotency_key_in_progress` (409), `idempotency_key_fingerprint_mismatch`
(422).

**Server / upstream** — `job_creation_failed`, `job_fetch_failed`,
`delete_failed`, `timeout`, `server_error`, `service_unavailable`.

## Recommended handling

1. Switch on the HTTP status for coarse control flow (retry vs. fail).
2. Within a status, switch on `error.code` for specific handling
   (e.g. `insufficient_credits` → prompt a top-up).
3. Log `error.request_id` alongside your own context, and quote it in any
   support ticket.
4. For `429` and `5xx`, retry with exponential backoff — honor `Retry-After`
   when present.

[title] Pagination
[path] /

List endpoints return a consistent envelope so you can page through results the
same way everywhere.

## The list envelope

Only **list/collection** responses are wrapped. Single resources are returned
bare (the object is the response body directly).

```json
{
  "data": [
    { "...": "..." },
    { "...": "..." }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}
```

- `data` — the array of resources for this page.
- `has_more` — `true` if there are more results after this page.
- `next_cursor` — an opaque cursor for the next page, or `null` when there
  are no more results.

Every list returns this envelope from launch — even endpoints that don't
paginate today return `next_cursor: null` and `has_more: false`. Build for it
once and it works across the API.

## Paging through results

Pass the `next_cursor` value back as the `next` query parameter to fetch the
following page. Treat the cursor as opaque — don't parse or construct it.

```bash
curl "https://api.mailfloss.com/v1/jobs?per_page=25" \
  -H "Authorization: Bearer YOUR_API_KEY"
# -> { "data": [...], "pagination": { "next_cursor": "ZXhhbXBsZQ", "has_more": true } }

curl "https://api.mailfloss.com/v1/jobs?per_page=25&next=ZXhhbXBsZQ" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

A typical loop — keep going until `has_more` is `false`:

```python
import requests

session = requests.Session()
session.headers["Authorization"] = "Bearer YOUR_API_KEY"

url = "https://api.mailfloss.com/v1/jobs"
params = {"per_page": 100}
jobs = []

while True:
    page = session.get(url, params=params).json()
    jobs.extend(page["data"])
    if not page["pagination"]["has_more"]:
        break
    params["next"] = page["pagination"]["next_cursor"]
```

## Page size

Control page size with `per_page`. Defaults vary by endpoint, and the maximum
is **100**:

| Endpoint                                                 | Default `per_page` |
| -------------------------------------------------------- | ------------------ |
| `GET /v1/jobs`                                           | 25                 |
| `GET /v1/users`                                          | 25                 |
| `GET .../connections/{id}/blacklist` and `.../whitelist` | 50                 |

Requesting more than 100 is capped at 100. See the API reference for the
per-endpoint default.

[title] Rate limits
[path] /

Every response tells you where you stand against the rate limit. Read the
headers and back off on `429` and you'll never get surprised.

## Rate-limit headers

Every response carries these headers:

| Header                  | Meaning                              |
| ----------------------- | ------------------------------------ |
| `X-RateLimit-Limit`     | Your ceiling for the current window. |
| `X-RateLimit-Remaining` | Requests left in the current window. |
| `X-RateLimit-Reset`     | When the window resets.              |

The standardized draft equivalents (`RateLimit-Limit`, `RateLimit-Remaining`,
`RateLimit-Reset`) are emitted too, so a client built against either spelling
works.

The current limit is **10,000 requests per minute**. (This is the operating
ceiling today, not a contractual floor — don't hard-code it; read
`X-RateLimit-Limit` if you need the live value.)

## When you're limited

Exceeding the limit returns `429` with a `rate_limit_error`:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests.",
    "type": "rate_limit_error",
    "request_id": "req_a1b2c3"
  }
}
```

The response includes a `Retry-After` header — the number of seconds to wait
before retrying. Honor it.

## Handling it well

Retry on `429` (and on `5xx`) with exponential backoff, preferring the
`Retry-After` value when present:

```python
import time, requests

def call_with_retry(session, url, max_retries=5):
    for attempt in range(max_retries):
        resp = session.get(url)
        if resp.status_code != 429:
            return resp
        wait = int(resp.headers.get("Retry-After", 2 ** attempt))
        time.sleep(wait)
    return resp  # give up after max_retries
```

For large workloads, prefer the **batch** endpoints over a tight loop of
single-email calls — submit a job and poll, rather than hammering `/v1/verify`.
See the **Quickstart** and the API reference.

[title] Connect an email platform (ESP)
[path] /

mailfloss can verify and clean the contacts in your email platform
automatically. The Integrations API connects, configures, and manages those
connections across **18 supported platforms** — Klaviyo, Mailchimp, Brevo,
ActiveCampaign, ConvertKit, MailerLite, GetResponse, and more — through one
uniform surface.

Every endpoint takes an ESP `type` slug (e.g. `klaviyo`, `mailchimp`,
`activecampaign`) and addresses a specific connection by its `id`. One account
can hold **multiple connections** of the same type.

:::BlockQuote
**Naming:** the slug for Brevo is `brevo` (not the old `sendinblue`).
:::

## 1. See what's connected

List every integration (connected and available):

```bash
curl https://api.mailfloss.com/v1/integrations \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Or drill into one platform and all of its connections:

```bash
curl https://api.mailfloss.com/v1/integrations/klaviyo \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## 2. Connect

`POST /v1/integrations/{type}/connections` with the platform's credentials.
mailfloss **validates them live** (it fetches your lists during the connect call),
so a `201` means the credentials actually work — not just that they were stored.

Credentials are **encrypted at rest and never returned** by any endpoint.

The credential fields depend on the platform. Single-key platforms (Klaviyo,
MailerLite, Brevo, GetResponse, …) take just an `api_key`:

```bash
curl -X POST https://api.mailfloss.com/v1/integrations/klaviyo/connections \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing Klaviyo",
    "credentials": { "api_key": "pk_xxxxxxxx" }
  }'
```

Others need more than one field — ActiveCampaign needs your account URL plus a
key; ConvertKit needs a key plus a secret:

```bash
# ActiveCampaign
curl -X POST https://api.mailfloss.com/v1/integrations/activecampaign/connections \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "credentials": {
      "api_url": "https://youraccount.api-us1.com",
      "api_key": "your-activecampaign-key"
    }
  }'

# ConvertKit
curl -X POST https://api.mailfloss.com/v1/integrations/convertkit/connections \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "credentials": { "api_key": "...", "api_secret": "..." } }'
```

`name` is optional and defaults to the platform's display name. The API
reference lists the exact credential fields for every supported platform —
check it for the one you're connecting.

A successful connect returns `201` with the new connection (see its shape
below). Other outcomes:

| Status | Meaning                                    |
| ------ | ------------------------------------------ |
| `400`  | Missing or malformed credentials.          |
| `402`  | Out of verification credits.               |
| `422`  | That `type` isn't connectable via the API. |

`POST` accepts an optional `Idempotency-Key` header so a retried connect won't
create a duplicate.

## 3. The connection object

```json
{
  "id": "cnx_8f3a",
  "name": "Marketing Klaviyo",
  "status": "active",
  "auto_floss_enabled": true,
  "created_at": "2026-06-02T09:00:00Z",
  "last_synced_at": null,
  "settings": {
    "aggressiveness": "normal",
    "verify_first": true,
    "checks": { "disposable": true, "nonexistent": true }
  }
}
```

- `id` — use this to address the connection in every other call.
- `status` — `active` or `disconnected`.
- `auto_floss_enabled` — whether automatic cleaning is on for this
  connection.
- `settings` — how aggressively mailfloss cleans (below).

## 4. Configure cleaning

`PATCH /v1/integrations/{type}/connections/{id}` — a partial update; omitted
fields are left unchanged. Three things you can set:

- `verify_first` (boolean) — verify new contacts before their first send.
- `aggressiveness` — `normal` (recommended preset), `aggressive` (all checks
  on), or `custom` (per-check control).
- `checks` — a map of individual check gates. Editing any gate switches
  `aggressiveness` to `custom`.

`aggressiveness` and `checks` are **mutually exclusive** in a single request
(send one or the other), and at least one field is required.

```bash
curl -X PATCH https://api.mailfloss.com/v1/integrations/klaviyo/connections/cnx_8f3a \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "verify_first": true, "aggressiveness": "aggressive" }'
```

### Keyword rules

Each connection has whitelist/blacklist keyword rules under
`.../connections/{id}/whitelist` and `.../blacklist` (list, add, bulk-add,
delete). See the API reference for the rule shape.

## 5. Disconnect and reconnect

```bash
# Disconnect (stops automatic cleaning; keeps the connection record)
curl -X DELETE https://api.mailfloss.com/v1/integrations/klaviyo/connections/cnx_8f3a \
  -H "Authorization: Bearer YOUR_API_KEY"

# Reconnect a previously disconnected connection
curl -X POST https://api.mailfloss.com/v1/integrations/klaviyo/connections/cnx_8f3a/reconnect \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Next steps

- **Errors** — connect-specific codes and how to handle them.
- **API reference** — exact credential fields per platform, the full `checks`
  gate list, and keyword-rule shapes.

[title] Verifying Webhooks
[path] Untitled/

To validate a webhook came from mailfloss we suggest verifying the webhook payloads with the `x-request-signature` header (which we pass with every webhook that has a webhook secret). If you did not add a webhook secret then this header is not included in the payload. You can add or modify the webhook secret at anytime inside of the mailfloss app by editing the corresponding webhook.

The `x-request-signature` header is a SHA1 HMAC hexdigest computed with the webhook secret and the raw body of the request.

An example in javascript with a webhook secret of "my little pony" is posted below.

```javascript
if (headers['x-request-signature']) {
    const crypto = require('crypto');
    const text = JSON.stringify(request.body);
    const key = "my little pony";
    const hash = crypto.createHmac('sha1', key)
        .update(text)
        .digest('hex');
    
    if (hash === headers['x-request-signature']) {
        console.log('match');
    } else {
        console.log('no match');
    }
}
```

[title] Managing Webhooks
[path] Untitled/

Creating, editing, deleting, and activating/deactivating webhooks can be done inside of the mailfloss app under the section "API & Webhooks".

## Creating Webhooks

To create a webhook click the "Add Webhook" button.

![](https://archbee-doc-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/NzfbLTuq1qsmigb5RKYCv_1.%20Add%20Webhook.jpg "Click \"Add Webhook")

A popup will appear. All fields are required to create a webhook, except webhook secret. The webhook secret is optional and is used to verify webhooks. See section [Verifying Webhooks](https://developers.mailfloss.com/verifying-webhooks) for details. Give the webhook a name, choose your triggers, enter your webhook URL, and choose a source connection from the dropdown. The source can be all sources, CSV files, copy & paste input, or any connected email service provider integration. Once completed, click "Create" to create the webhook or "Create & Activate" to create the webhook and turn it on.

![](https://archbee-doc-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/xsRz5DI7dm2sk2WbzgY_r_mailfloss%20create%20webhook.jpg "Fill out the name, webhook URL, and select a source. At least one trigger must be selected.")

## Editing Webhooks

Once you have created some webhooks, they will be listed under "API & Webhooks". From here, you can click the "Edit" link to edit the webhook or flip the switch on/off to activate/deactivate the webhook.

![](https://archbee-doc-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/-aT-Mlr4HzeRWzDL7Ghqm_3.%20Editing%20webhooks.jpg "Click \"Edit\" to edit the webhook or the switch to turn the webhook on or off")

If you click the "Edit" link you will be taken to that webhook's edit page. From here you can make changes to the webhook. Be sure to click "Save webhook" to save the changes.

![](https://archbee-doc-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/76fuxvhtBfkjZz8TLnuwO_mailfloss%20edit%20webhook.jpg "Click \"Save webhook\" to save any changes that were made.")

## Deleting Webhooks

If you wish to delete a webhook, first visit "API & Webhooks" and click "Edit" on the webhook you wish to delete. You will be taken to the edit webhook page where you can click the "Delete webhook" button to delete the webhook.

![](https://archbee-doc-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/MrydqSd4p77O4cSB3MWC8_5.%20Deleting%20a%20webhook.jpg "Click \"Delete webhook\" to permanently delete the webhook")

[title] Integration Settings API Overview
[path] Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

The integration settings API is used to modify the settings of connected email service providers associated with your mailfloss account. The integration settings API lets you programmatically change the integrations' settings, including adding blacklist/whitelist items, and in the future changing the action, frequency, and aggressiveness options.

For Authentication, Rate Limits, Response Headers, and Response Codes, please refer to these sections in the [Email Verification API](https://developers.mailfloss.com/email-verification-overview).

:::hint{type="danger"}
## The integration settings API is in beta

The API is currently in beta and under active development. While we'll make every effort to maintain consistency, updates may contain breaking changes.
:::

[title] Reference
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

:::Swagger
```json
{
  "headers": [],
  "jsonFileLocation": "https://api.mailfloss.com/swagger_latest.json"
}
```
:::

:::Paragraph{indent="1"}

:::

[title] Code Examples
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

## Add blacklist endpoint

```shell
curl -X POST \
  --url https://api.mailfloss.com/settings/{id}?api_key={api_key} \
  -d '{"type": "blacklist","data":{
 "keyword": "mailfloss.com",
 "localpart": false,
 "domain": true,
 "email": false,
 "match": "exact",
 }}' -H "Content-Type: application/json"
```

## Bulk add blacklist endpoint

```shell
curl -X POST \
  --url https://api.mailfloss.com/settings/{id}?api_key={api_key} \
  -d '{"type": "blacklist", "data":[{
 "keyword": "mailfloss.net",
 "localpart": false,
 "domain": true,
 "email": false,
 "match": "exact"
 }, {
 "keyword": "mailfloss.io",
 "localpart": false,
 "domain": true,
 "email": false,
 "match": "exact"
 }, {
 "keyword": "mailfloss.us",
 "localpart": false,
 "domain": true,
 "email": false,
 "match": "exact"
 }]}' -H "Content-Type: application/json"
```

[title] Rate Limits
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

The API is rate-limited to a maximum of **50** requests per minute. As you integrate the mailfloss API, ensure your application does not exceed this limit. You can check the response headers to see your rate limit remaining.

You can have at most **10** bulk email verification sessions at any given time.

[title] Legacy API (sunsets 2027-06-01)
[path] /

:::hint{type="warning"}
## These APIs sunset on June 1, 2027

The pages in this section document the **original mailfloss API** (`api.mailfloss.com/...?api_key=`). It is deprecated and will be retired on **June 1, 2027**. Build new integrations on the [v1 API](https://developers.mailfloss.com/quickstart) and migrate existing ones before the sunset date.
:::

The original mailfloss API is split into three areas, each with a v1 successor:

- **Email Verification API** — verify single addresses. → v1 [`/v1/verify`](https://developers.mailfloss.com/quickstart)
- **Integration Settings API** — manage connected ESP settings. → v1 `/v1/integrations`
- **Data Privacy API** — erase stored verification records. → v1 `/v1/erasures`

Authentication also changed: the legacy `?api_key=` query parameter is replaced by a Bearer token in v1. See the v1 [Authentication](https://developers.mailfloss.com/authentication) guide for the one-line migration.

[title] Code Examples
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

## Single verification endpoint

```shell
curl --request GET \
  --url 'https://api.mailfloss.com/verify?email={email_address}&api_key={api_key}'
```

## Batch verification endpoint

```shell
curl -X POST \
  --url https://api.mailfloss.com/batch-verify?api_key={api_key} \
  -d '{"emails":["email_address1", "email_address2"]}' -H "Content-Type: application/json"
```

## Get batch verification job status

```shell
curl --request GET \
  --url 'https://api.mailfloss.com/batch-verify/{id}/status?api_key={api_key}'
```

## Get batch verification results of completed job

```shell
curl --request GET \
  --url 'https://api.mailfloss.com/batch-verify/{id}?api_key={api_key}'
```

[title] Reference
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

:::Swagger
```json
{
  "headers": [],
  "jsonFileLocation": "https://api.mailfloss.com/integration_settings.json"
}
```
:::

[title] Response Headers
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

The Content-Type of the requests should be `application/json`. The Content-Type of responses will be `application/json`.

Along with each response, the following HTTP headers are included:

- `x-ratelimit-limit` - The rate limit of 50 requests per minute.
- `x-ratelimit-remaining` - The rate limit remaining in the current window

[title] Data Privacy API Overview
[path] Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

The Data Privacy API helps you comply with end-user data deletion requests mandated by global privacy laws such as GDPR and CCPA. The API lets you programmatically submit requests to delete email addresses that may exist in your mailfloss account.

For Authentication, Rate Limits, Response Headers, and Response Codes, please refer to these sections in the [Email Verification API](https://developers.mailfloss.com/email-verification-overview).

:::hint{type="danger"}
## The data privacy API is in beta

The API is currently in beta and under active development. While we'll make every effort to maintain consistency, updates may contain breaking changes.
:::

:::hint{type="danger"}
## Data erasure is permanent

The delete endpoint results in permanent deletion of data from our servers and cannot be undone.
:::

:::hint{type="warning"}
## Deletions do not prevent future insertions

Using this API doesn't prevent the deleted email addresses from re-entering mailfloss in the future. The responsibility to ensure they do not is yours.
:::

[title] Reference
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

:::Swagger
```json
{
  "headers": [],
  "jsonFileLocation": "https://api.mailfloss.com/privacy_api.json"
}
```
:::

[title] Authentication
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

All of your requests needs to be authenticated with your API key and passed in as a query parameter `api_key`.

API keys can be generated and found in the mailfloss dashboard under the API section [https://app.mailfloss.com/api](https://app.mailfloss.com/api)

[title] SDKs
[path] /

Official, typed clients for the v1 API in four languages. Each one covers the
full public surface — single verification, batch jobs, ESP integrations and
keyword rules, usage reports — and handles auth, retries, and idempotency for
you.

| Language             | Package                                                                          | Requires    |
| -------------------- | -------------------------------------------------------------------------------- | ----------- |
| Node.js / TypeScript | [`@mailfloss/sdk`](https://www.npmjs.com/package/@mailfloss/sdk)                 | Node.js 18+ |
| Python               | [`mailfloss`](https://pypi.org/project/mailfloss/)                               | Python 3.9+ |
| Ruby                 | [`mailfloss`](https://rubygems.org/gems/mailfloss)                               | Ruby 2.6+   |
| Go                   | [`github.com/mailfloss/mailfloss-go`](https://github.com/mailfloss/mailfloss-go) | Go 1.24+    |

All four are MIT-licensed and zero-dependency (standard library only), retry `429`/`5xx`
responses honoring `Retry-After`, and attach an `Idempotency-Key` to every
POST so a retried batch submit never double-charges.

You don't need an SDK — every endpoint is plain HTTP + JSON, as shown in the
[Quickstart](quickstart). The SDKs just save you the plumbing.

## Authentication

Every client sends your key as `Authorization: Bearer <key>` (see
[Authentication](authentication)). Get your key from the dashboard under
**Settings → API**.

The recommended setup is the `MAILFLOSS_API_KEY` environment variable — each
client reads it when constructed with no arguments, which keeps the key out of
your source tree:

```bash
export MAILFLOSS_API_KEY="mf_live_your_key_here"
```

You can also pass the key explicitly (shown per language below). If no key is
found, the constructor raises a configuration error rather than failing later
on the first request.

## Install and verify an email

### Node.js / TypeScript

```bash
npm install @mailfloss/sdk
```

```ts
import { Mailfloss } from "@mailfloss/sdk";

// Reads MAILFLOSS_API_KEY, or pass it: new Mailfloss({ apiKey: "mf_live_..." })
const mailfloss = new Mailfloss();

const result = await mailfloss.verify({ email: "jane@acme.com" });

console.log(result.status);     // "passed" | "undeliverable" | "risky" | "unknown"
console.log(result.passed);     // true when safe to send
console.log(result.reason);     // e.g. "available"
console.log(result.suggestion); // typo fix, when one is detected
```

### Python

```bash
pip install mailfloss
```

```python
from mailfloss import Mailfloss

# Reads MAILFLOSS_API_KEY, or pass it: Mailfloss(api_key="mf_live_...")
client = Mailfloss()

result = client.verify("jane@acme.com")

print(result["status"])   # "passed" | "undeliverable" | "risky" | "unknown"
print(result["passed"])   # True when safe to send
print(result["reason"])   # e.g. "available"
if result.get("suggestion"):
    print("Did you mean:", result["suggestion"])
```

### Ruby

```sh
gem install mailfloss
```

```ruby
require "mailfloss"

# Reads MAILFLOSS_API_KEY, or pass it: Mailfloss::Client.new(api_key: "mf_live_...")
client = Mailfloss::Client.new

result = client.verify(email: "jane@acme.com")

result[:status]     # "passed" | "undeliverable" | "risky" | "unknown"
result[:passed]     # true when safe to send
result[:reason]     # e.g. "available"
result[:suggestion] # typo fix, when one is detected
```

Responses are parsed with **symbol keys**.

### Go

```bash
go get github.com/mailfloss/mailfloss-go
```

```go
package main

import (
	"context"
	"fmt"
	"log"

	mailfloss "github.com/mailfloss/mailfloss-go"
)

func main() {
	// Reads MAILFLOSS_API_KEY, or pass it: mailfloss.New(mailfloss.WithAPIKey("mf_live_..."))
	client, err := mailfloss.New()
	if err != nil {
		log.Fatal(err)
	}

	res, err := client.Verify.Check(context.Background(), mailfloss.VerifyParams{
		Email: "jane@acme.com",
	})
	if err != nil {
		log.Fatal(err)
	}

	// Status is one of: passed, undeliverable, risky, unknown
	fmt.Printf("%s -> %s (%s) passed=%t\n", res.Email, res.Status, res.Reason, res.Passed)
}
```

## Batch verification

Submit a job, poll its status, then page through results — the same flow as the
[Quickstart](quickstart), one method per step. Pass an optional `webhook_url`
to be notified on completion instead of polling.

### Node.js / TypeScript

```ts
const { id } = await mailfloss.batchVerify.create({
  emails: ["jane@acme.com", "bob@example.com"],
  webhook_url: "https://example.com/hooks/mailfloss", // optional; omit to poll
});

const { status, progress } = await mailfloss.batchVerify.status(id);

const page = await mailfloss.batchVerify.results(id, { per_page: 100 });
console.log(page.results);
```

### Python

```python
job = client.batch_verify.create(
    emails=["jane@acme.com", "bob@example.com"],
    webhook_url="https://example.com/hooks/mailfloss",  # optional; omit to poll
)

status = client.batch_verify.status(job["id"])
print(status["status"], status.get("progress"))

page = client.batch_verify.results(job["id"], per_page=500)
for row in page.get("results", []):
    print(row)
```

### Ruby

```ruby
batch = client.batch_verify.create(
  emails: ["jane@acme.com", "bob@example.com"],
  webhook_url: "https://example.com/hooks/mailfloss" # optional; omit to poll
)

status = client.batch_verify.status(batch[:id])
puts "#{status[:status]} #{status[:progress]}"

page = client.batch_verify.results(batch[:id], per_page: 100)
page[:results]
```

### Go

```go
job, err := client.BatchVerify.Create(ctx, mailfloss.BatchVerifyCreateParams{
	Emails:     []string{"jane@acme.com", "bob@example.com"},
	WebhookURL: "https://example.com/hooks/mailfloss", // optional; omit to poll
})

status, err := client.BatchVerify.Status(ctx, job.ID)
fmt.Printf("job %s: %s (%.0f%%)\n", job.ID, status.Status, status.Progress)

page, err := client.BatchVerify.Results(ctx, job.ID, mailfloss.BatchVerifyResultsParams{
	PerPage: 1000,
})
for _, r := range page.Results {
	fmt.Printf("%s -> %s (%s)\n", r.Email, r.Status, r.Reason)
}
```

## Errors

Non-2xx responses surface as a language-native error carrying the same fields
as the JSON envelope documented in [Errors](errors) — `status`, `code`,
`message`, `type`, and `request_id`. Branch on the stable `code`, never on
`message`.

| Language             | Error type                                                                                                 |
| -------------------- | ---------------------------------------------------------------------------------------------------------- |
| Node.js / TypeScript | `MailflossError` (config problems: `MailflossConfigError`)                                                 |
| Python               | `MailflossError` (config problems: `MailflossConfigError`)                                                 |
| Ruby                 | `Mailfloss::APIError` (config problems: `Mailfloss::ConfigurationError`; both subclass `Mailfloss::Error`) |
| Go                   | `*mailfloss.Error`, matched with `errors.As`                                                               |

```python
from mailfloss import Mailfloss, MailflossError

try:
    client.jobs.get("does-not-exist")
except MailflossError as err:
    print(err.status)      # 404
    print(err.code)        # stable machine-readable code
    print(err.request_id)  # quote this to support
```

## Pagination

List endpoints return a `{ data, pagination }` envelope. Pass
`pagination.next_cursor` back as the `cursor` parameter to fetch the next page
— see [Pagination](pagination) for the full model.

## Next steps

- **API reference** — every endpoint, parameter, and response shape.
- **Connect an ESP** — verify-first automation across 18 email platforms.
- **Webhooks** — get notified instead of polling.

[title] Installing the Widget
[path] Untitled/

The mailfloss widget allows you to verify emails in real-time conveniently at the point of entry, most commonly on form inputs.

## Getting started:

You’ll have to get your mailfloss widget and your public key. In order to do that, you need your mailfloss account.
Once that is done, you’ll find your public key and embed code under the "Apps & Plugins" section of the mailfloss application.

## How to install:

The installation is simple. Just copy and paste the code snippet below into your HTML file. The only part you need to modify is the **window\.mf\_settings** object. Here, you can customize the widget settings and input your publicKey. Be sure to include your publicKey, as the widget won't function without it.

Copy and paste this snippet into your HTML file.

```javascript
<script type="text/javascript">
let mailfloss = window.mailfloss = window.mailfloss || [];
window.mf_settings = {
            "publicKey": "<your public key>"
        };
mailfloss.push(mf_settings),
(function() {
    let first_script = document.getElementsByTagName('script')[0]; 
    let script = document.createElement('script');
    script.type = "text/javascript", script.async = !0,
    script.src = "https://cdn.mailfloss.io/v1/index.min.js",
    first_script.parentNode.insertBefore(script, first_script)
})();
</script>
```

### Things to take into consideration:

In order for the widget to work correctly, you must have an input with at least one attribute with a value of "email" on the page where the widget is installed.

[title] Event Triggers
[path] Untitled/

There are 20 triggers to choose from. These include status updates, category reason updates, contact modifications, and flossing completed. You can see the full list of triggers when you create a new webhook or edit an existing one.

:::hint{type="info"}
## Payload information

In the payload we POST to your webhook URL, you will have an event key with a value in dot notation. For example, a status of undeliverable is sent as "status.undeliverable"
:::

## Status triggers

- Status: Undeliverable - status.undeliverable
- Status: Unknown - status.unknown
- Status: Risky - status.risky

## Reason triggers

- Reason: Illegitimate - reason.illegitimate
- Reason: Bounced - reason.bounced
- Reason: Invalid - reason.invalid
- Reason: Blacklisted - reason.blacklisted
- Reason: Role - reason.role
- Reason: Complainer - reason.complainer
- Reason: Spam - reason.spam
- Reason: Available - reason.available
- Reason: Banned - reason.banned
- Reason: Disposable - reason.disposable
- Reason: Deactivated - reason.deactivated
- Reason: Nonexistent - reason.nonexistent
- Reason: Inbox Full - reason.inbox\_full
- Reason: Unverified - reason.unverified
- Reason: Accept All - reason.accept\_all

## Contact triggers

- Contact: Fixed - contact.fixed
- Contact: Unsubscribed - contact.unsubscribed
- Contact: Deleted - contact.deleted
- Contact. Tagged - contact.tagged
- Contact: Updated - contact.updated

## Floss session triggers

- Flossing Completed - job.finished

[title] JavaScript Widget Overview
[path] /

The mailfloss JavaScript widget verifies email addresses as users enter them on your web forms. This email verification process happens in real-time to help prevent invalid and at-risk email addresses from clogging up your database, reduce bounces, and recover misspelled email addresses.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/yGUejq6E8IJ_sYX6JSjSr/BCZdkF-mUkudX19rHdKt3_demowidget.gif" size="72" width="918" height="282" position="flex-start" showCaption="false"}

Installation is straightforward and requires copying and pasting a few lines of code for insertion into HTML pages. As such, it may require a developer or IT specialist with permission to modify the HTML.

:::hint{type="danger"}
## The javaScript widget is in beta

The JavaScript widget is a new plugin of mailfloss. And like all of our new plugins, we label them as beta.&#x20;

The JavaScript widget is currently in beta and under active development. While we'll make every effort to maintain consistency, updates may contain breaking changes.
:::

:::hint{type="info"}
## Considerations

The JavaScript widget is well-suited for various forms and pages including login, registration, and contact pages.

It is worth noting that while the JavaScript widget is performant and visually pleasing, it does affect the user experience. If this is a concern, you may wish to use one of our set-and-forget integrations instead. These integrations work in real-time as well, in the backend, and do not have the associated user experience friction.

The integrations also do not require modifying any HTML of any online forms, which may be preferable in many situations.
:::

[title] API Overview
[path] Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

mailfloss offers a simple API enabling you to thoroughly check and verify email addresses right at the point of entry into your system.

In addition to checking the syntax, the actual existence of an email address using MX records, and the Simple Mail Transfer Protocol (SMTP), detecting whether the requested mailbox is configured to catch all incoming email traffic, the mailfloss API also identifies role-based email addresses, email addresses from free email providers, and disposable domains.

Combined with typo checks, email address suggestions, and more, these structures will make it simple to automatically filter "real" customers from typos, spammers, abusers, and increase response and success rates of your email campaigns.

You can get all of this with a single API call like the following.

```shell
curl --request GET \
  --url 'https://api.mailfloss.com/verify?email={email_address}&api_key={api_key}'
```

:::hint{type="info"}
## Recommendations

Treat any timeouts as unknown, and if at point of entry, allow the result to pass. It is not uncommon for many smaller email hosts to take many seconds, and for this reason, the result may not come in a timely manner. Rather than force the user to wait, let them proceed.

Pass a webhook URL to our batch-verify endpoint to avoid polling for results. This is more efficient.

All API calls should be made server-side.
:::

:::hint{type="danger"}
## The publicly available API is in beta

The API is currently in beta and under active development. While we'll make every effort to maintain consistency, updates may contain breaking changes.
:::

The mailfloss email verification API allows you to add email verification to any part of your software, ideal for signup, registration, onboarding, and other points of entry.

You will need an API key and an account with mailfloss to use the API. The API key can be generated inside of the mailfloss dashboard.

:::hint{type="warning"}
## Make API calls on the server-side only

The API is not suitable for use in client-side scripts (e.g. React, Angular, Vue, jQuery, and other Javascript frameworks) because our verification endpoints do not allow cross-domain requests. Using it directly in the browser would require exposing sensitive API credentials giving anyone access to your account. Please make all requests server-side.

If you do not have access to the server-side consider using our [javascript widget](https://developers.mailfloss.com/javascript-widget-overview) instead.
:::

[title] Response Codes
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

The API makes use of standard HTTP response codes to indicate the success or failure of a request. The 2xx series of response codes indicate success, 4xx indicates an error from the client-side, and a 5xx error indicates a server-side error.&#x20;

Please check response codes and handle accordingly. Contact us if you run into repeated issues, especially in the 5XX error range.

Here are the HTTP response codes the mailfloss API utilizes:

- **200** - Success
- **400** - Email address or Id not supplied
- **401** - Invalid API key
- **402** - Insufficient credits
- **403** - No API key provided
- **404** - Job not found or job not finished&#x20;
- **405** - Method not allowed
- **413** - Payload too large. Too many email addresses
- **414** - Request Entity Too Large
- **415** - Invalid Content Type. Must be application/json
- **429** - Rate limit exceeded
- **500** - Timeout
- **502** - Bad Gateway
- **503** - Failed to create job
- **504** - Gateway Time-out

[title] Reference
[path] /

:::Swagger
```json
{
  "headers": [],
  "jsonFileLocation": "https://api.mailfloss.com/v1/openapi.json"
}
```
:::

[title] Webhooks Overview
[path] /

Webhooks are a method mailfloss uses to send information to other apps quickly when something happens inside of mailfloss. They have a message, or payload, and are sent to a unique URL that you provide. Webhooks, in general, are almost always faster than polling, and require less work on your end.

:::hint{type="danger"}
## Webhooks are in beta

Webhooks are a new feature to mailfloss. And like all of our new features, we label them as beta. Webhooks are currently in beta and under active development. While we'll make every effort to maintain consistency, updates may contain breaking changes.
:::

Webhooks allow you to send an HTTP POST to the URL(s) of your choosing anytime certain events occur in your mailfloss account. All of our webhook events contain payloads serialized as JSON.

Webhooks can be managed inside the mailfloss app. On the webhooks page, you'll be able to create, edit, and remove webhooks.

Each webhook requires a name, at least one trigger event to subscribe to, a URL to POST to, and a data source.

Webhooks are available to our Business and Pro subscribers, and available as an add-on to our Lite subscribers. Webhooks are not available to non-subscribers.

:::hint{type="info"}
## Considerations

Webhooks are not guaranteed to be published. They are sent on a best effort basis.

You should not rely on the order in which webhook messages are published.

Some payloads may come quickly and in bursts due to the nature of email verification. Ensure your webhook URL can handle the load.
:::

[title] Retries and Errors
[path] Untitled/

We expect your endpoint to respond with a `200` return code. In case the request returns with a non `200` response code, we will continue retrying after 1 minute with an exponential backoff for **5** retries. If we fail after 5 retries, we will stop retrying and will deactivate the webhook.

[title] Widget Configuration Options
[path] Untitled/

The mailfloss widget allows you to verify emails in real-time, fast and easy.

## Default values in settings

The widget comes with default settings, which you can choose to keep or customize. Below is a list of the default settings and their descriptions.&#x20;

If you're happy with these defaults, you're all set to start using the widget.

### Timing

- **rateLimitUserAttempts:** This sets the maximum number of verification attempts that a user can perform within a specific time period. Default is: 10.
- **rateLimitStartsWithin:** If the user exceeds rateLimitUserAttempts within rateLimitStartsWithin, the user will be rate-limited. The value of rateLimitStartsWithin is set in milliseconds. Default is: 10000.
- **rateLimitWaitTime:** The time period a user must wait before verification will begin again. Once this period is over, the user can start verifying again, and the process repeats. The value of rateLimitWaitTime is set in milliseconds. Default is: 10000.
- **maxVerificationTime:** sets the maximum time allowed for a verification process to complete. If the time exceeds this limit, the process will be aborted. The value of maxVerificationTime is set in milliseconds. Default is: 10000.
- **doneTypingTime:** sets the time the widget waits after a user stops typing before starting the verification process. This delay allows the user to complete their input before the verification process begins. *The value of doneTypingTime is set in milliseconds*. Default is: 1500.
- **overlayDisplayTime:** sets the time duration in milliseconds for which the dropdown overlay remains visible after it appears. Once the overlayDisplayTime has elapsed, the dropdown overlay disappears automatically. Default is: 2500.

### Messages

- **validMessage:** This message is displayed in the dropdown when the email entered by the user is valid. Default is: "Valid email".
- **invalidMessage:** This message is displayed in the dropdown when the email entered by the user is invalid. Default is: "Invalid email".
- **verifyingMessage:** This message is displayed in the dropdown when the widget is verifying the email entered by the user. Default is: "Verifying..."
- **suggestionMessage:** This message is displayed in the dropdown when a suggestion is made to the user due to a potential misspelled domain. Default is: "Maybe you meant:".
- **regexFailMessage:** This message is displayed when the user types something that is not a valid email address according to the specified regular expression. Default is: "Please enter a valid email".

### Allowed Categories

- **statusAllowedValues:** This is an array that lets you specify the allowed values for the status of the email. The possible values are valid, unknown, and risky. You can enter any combination of these values that you want to be allowed. Default is: \['passed', 'unknown', 'risky'].
- **reasonAllowedValues:** This is an array object that lets you specify the allowed values for the reason of the email status. The possible values are valid, accept\_all, and unverified. You can enter any combination of these values that you want to be allowed. Default is: \['valid', 'accept\_all', 'unverified'].
- **blockRoleAddresses:** This is a boolean that, when set to true, blocks all role-based email addresses. Default is: false.
- **blockFreeAddresses:** This is a boolean that, when set to true, blocks all free email addresses such as Gmail, Yahoo, Hotmail, and AOL. Default is: false.
- **blockDisposableAddresses:** This is a boolean that, when set to true, blocks all disposable email addresses. Default is: true.

### CSS Settings

- **verifyingSpinnerColor:** Sets the color of the loading spinner. Default is: #3498db.****
- **boxshadowValid:** Sets the box shadow for a valid email response.&#x20;
  Default is: 0px 4px 5px 1px rgba(21, 157, 3, 0.2).
- **boxshadowInvalid:** Sets the box shadow for an invalid email response.&#x20;
  Default is: 0px 4px 5px 1px rgba(157, 3, 3, 0.2).
- **boxshadowDefault:** Sets the box shadow for a default response.&#x20;
  Default is: 0px 4px 5px 1px rgba(0, 0, 0, 0.1).
- **borderRadiusResponse:** Sets the border radius for the response message box. Default is: 5px.
- **borderInputDefault:** Sets the border for the input when no response has been given.&#x20;
  Default is: 1px solid #e1e0e0.
- **borderInputValid:** Sets the border for the input when a valid email response has been given.&#x20;
  Default is: 1px solid green.
- **borderInputInvalid:** Sets the border for the input when an invalid email response has been given. Default is: 1px solid red.
- **colorInvalid:** Sets the color for the response message when the email is invalid.&#x20;
  Default is: red.
- **colorValid:** Sets the color for the response message when the email is valid. Default is: green.

### Others&#x20;

- **autoDetect:** This is a boolean object that, when set to true, enables the widget to automatically detect the input field for email verification. If set to false, the widget will not automatically detect the input field and an inputSelector should be specified, instead. Default is: true.
- **inputSelector:** If autoDetect is set to false, this object should be set with a string value containing the class or ID of the input field that the user wants to use for email verification, written like this: "#inputIdName"/ ".inputClassName". The widget will use this selector to target and verify the email entered in the specified input field. If left undefined and autoDetect is disabled, the widget will not work. Default is: "".&#x20;
- **offerSuggestion:&#x20;**&#x54;his is a boolean object that, when set to true, enables the widget to offer suggestions in case the email entered by the user is potentially a typo. If set to false, the widget will not ask the user if they meant to type the suggested email. Default is: true.
- **poweredBy:** This is a boolean object that, when set to true, displays the mailfloss logo in the widget. This option may not be available depending on your subscription plan. Default is: true.
- **showDropdownBox:** This is a boolean object that, when set to true, displays the dropdown box in the widget. If set to false, the widget will not display the dropdown box. Default is: true.
- **borderHighlight:** This is a boolean object that, when set to true, highlights the border of the input field with a color that indicates whether the email entered is valid or invalid. By default, the border is green for valid emails and red for invalid emails. Default is: true.
- **ignoreInputs:** is an array where you can enter the name, class or id of the inputs that you want the widget to ignore. When the widget is scanning the page for inputs to verify, it will skip any input whose name, id, or class matches the names specified in this array. This can be useful if you have inputs that you don't want to be verified by the widget and autoDetect is disabled. It must be in an array. e.g: \['emailClass'].
  Default is: undefined.
- **publicKey:** This is a string where you must put your API key so that the widget can work. This is a required parameter, and without it, the widget will not function.
- **debugMode:** This is a boolean that, when set to true, activates the debug mode of the widget. This mode is used for debugging purposes and provides additional information about the widget's behavior. Default is: false.
- **afterVerification:** This setting works as a callback. In case you want to use the API response in one of your functions, you can assign the name of your function as the value of afterVer.  Every time you make a verification, your function will be returned with the API response as string. To use it as an object you can use JSON.parse(response). You can see an example of this at the bottom of this page. **Widget Setup Examples / Example 4.**
  **Note:&#x20;**&#x49;f you want to console.log the response, remember to enable the debugMode on the settings.

## Customizing your widget

In order to customize your widget, you need to pass the custom settings into the `window.mf_settings` object with the modified value. Initially, only the publicKey is set in this object.

Inside this object, there will be every setting that you want to change.

```javascript
// It will look like this:

window.mf_settings = {
  // name of the setting : value,
  "publicKey": "<your public key>",
  "validMessage": "this email is valid"
}
```

Here's a list of things you can change and how:

```Text
The values below are the default values, feel free to changed them to your preference.

TIMING
  * rateLimitUserAttempts: 10, 
  * rateLimitStartsWithin: 10000,
  * rateLimitWaitTime: 10000,  
  * maxVerificationTime: 10000,
  * doneTypingTime: 1500,
  * overlayDisplayTime: 2500,

MESSAGES 
  * validMessage: 'Valid email',
  * invalidMessage: 'Invalid email',
  * verifyingMessage: 'Verifying...', 
  * suggestionMessage: 'Maybe you meant: ',  
  * regexFailMessage: 'Please enter a valid email',
  
ALLOWED CATEGORIES
  * statusAllowedValues: ['passed', 'unknown', 'risky'],
  * reasonAllowedValues: ['valid', 'accept_all', 'unverified'], 
  * blockRoleAddresses: false,
  * blockFreeAddresses : false,
  * blockDisposableAddresses: true,
    
CSS
  * verifyingSpinnerColor: '#3498db',
  * boxshadowValid: '0px 4px 5px 1px rgba(21, 157, 3, 0.2)',
  * boxshadowInvalid: '0px 4px 5px 1px rgba(157, 3, 3, 0.2)', 
  * boxshadowDefault: '0px 4px 5px 1px rgba(0, 0, 0, 0.1)', 
  * borderRadiusResponse: '5px', 
  * borderInputDefault: '1px solid #e1e0e0', 
  * borderInputValid: '1px solid green',
  * borderInputInvalid: '1px solid red',
  * colorInvalid: 'red',
  * colorValid: 'green'

OTHERS
  * autoDetect: true,
  * inputSelector: "",
  * poweredBy: true,  
  * showDropdownBox: true,
  * borderHighlight: true,
  * ignoreInputs: [],     
  * debugMode : true,
  * publicKey : ""
  
```

##

## Widget Setup Examples

Here are some common scenarios to give you some ideas on how to setup your widget.

### Example 1: Basic setup

```javascript
<script>
    let mailfloss = window.mailfloss = window.mailfloss || [],
    mf_settings = {
        publicKey : "<your public key>",      
      };
      mailfloss.push([mf_settings]),
      (function() {
          first_script = document.getElementsByTagName('script')[0], script =   document.createElement('script');
          script.type = "text/javascript", script.async = !0,
          script.src = "https://cdn.mailfloss.io/v1/index.min.js", 
          first_script.parentNode.insertBefore(script, first_script)
      })();
  </script>
```

### Example 2: Rate limit setup

The user will have 5 attempts per day. In this case, the widget setup looks like:

```javascript
<script>
    let mailfloss = window.mailfloss = window.mailfloss || [],
    mf_settings = {
        rateLimitUserAttempts: 5, 
        rateLimitStartsWithin: 86400000, //a day in miliseconds
        rateLimitWaitTime: 86400000,
        publicKey : "<your public key>"       
      };
      mailfloss.push([mf_settings]),
      (function() {
          first_script = document.getElementsByTagName('script')[0], script = document.createElement('script');
          script.type = "text/javascript", script.async = !0,
          script.src = "https://cdn.mailfloss.io/v1/index.min.js", 
          first_script.parentNode.insertBefore(script, first_script)
      })();
  </script>
```

We want to limit the user to only 5 attempts (rateLimitUserAttempts), per day (rateLimitStartsWithin will be 86400000 miliseconds = a day). And the time we want the user to be rate limited will also be a day (rateLimitWaitTime). The user will need to come back tomorrow once 5 attempts have been used for the day.

A more common setup to keep bots and abusers away might look like this:

```javascript
<script>
    let mailfloss = window.mailfloss = window.mailfloss || [],
    mf_settings = {
        rateLimitUserAttempts: 5, 
        rateLimitStartsWithin: 10000, 
        rateLimitWaitTime: 30000,
        publicKey : "<your public key>"
      };
      mailfloss.push([mf_settings]),
      (function() {
          first_script = document.getElementsByTagName('script')[0], script = document.createElement('script');
          script.type = "text/javascript", script.async = !0,
          script.src = "https://cdn.mailfloss.io/v1/index.min.js", 
          first_script.parentNode.insertBefore(script, first_script)
      })();
  </script>
```

We want to limit the user to 5 attempts (rateLimitUserAttempts) every 10 seconds (rateLimitStartsWithin). If the user reaches the 5 attempts within 10 seconds, then the rate limit will be activated and the user will need to wait for 30 seconds (rateLimitWaitTime) before they can try again.

### Example 3:  How to setup the widget to match your brand colors&#x20;

```javascript
<script>
    let mailfloss = window.mailfloss = window.mailfloss || [],
    mf_settings = {
        boxshadowValid: '0px 4px 5px 1px rgba(245, 40, 145, 0.8)', 
		borderInputValid: '5px solid green', 
		colorValid: 'rgba(236, 187, 30, 0.8)', 
        boxshadowInvalid: '0px 4px 5px 1px rgba(0, 187, 231, 0.8)', 
        borderInputInvalid: '5px solid red', 
        colorInvalid: 'rgba(236, 187, 231, 0.8)', 
        colorValid: 'rgba(236, 187, 30, 0.8)',
        publicKey : "<your public key>"  
      };
      mailfloss.push([mf_settings]),
      (function() {
          first_script = document.getElementsByTagName('script')[0], script = document.createElement('script');
          script.type = "text/javascript", script.async = !0,
         script.src = "https://cdn.mailfloss.io/v1/index.min.js", 
          first_script.parentNode.insertBefore(script, first_script)
      })();
  </script>
```

### Example 4:  How to use the afterVerification (callback) setting&#x20;

```javascript
<script>
  function callback(response) {
    const responseObject = JSON.parse(response);
    console.log(responseObject);
    //code where you are using the response here
  }
</script>
<script>
    let mailfloss = window.mailfloss = window.mailfloss || [],
    mf_settings = {
        debugMode: true, // to print console.log messages in the callback
        afterVerification: callback, //name of your callback function    
        publicKey : "<your public key>"
      };
      mailfloss.push([mf_settings]),
      (function() {
          first_script = document.getElementsByTagName('script')[0], script = document.createElement('script');
          script.type = "text/javascript", script.async = !0,
         script.src = "https://cdn.mailfloss.io/v1/index.min.js", 
          first_script.parentNode.insertBefore(script, first_script)
      })();
  </script>
```

[title] Code Examples
[path] Untitled/Untitled/

:::hint{type="warning"}
## Legacy API — sunsets June 1, 2027

This page documents the original mailfloss API, which is being retired on **June 1, 2027**. New integrations should use the [v1 API](https://developers.mailfloss.com/quickstart).
:::

## Deletion endpoint

```shell
curl -X POST \
  --url https://api.mailfloss.com/delete?api_key={api_key} \
  -d '{"emails":["email_address1", "email_address2"]}' -H "Content-Type: application/json"
```
