# mailfloss API ## API Docs - Verification [Verify a single email address](https://swcgtl60qi.apidog.io/verify-a-single-email-address-45637511e0.md): Performs email verification on a single email address and returns a deliverability verdict. Consumes one credit from the org account on success. Returns the raw engine verdict: batch results for the same address may differ, because batch verdicts have the org's floss-settings overrides applied — see the v1 contract ("Live vs batch verdicts"). - Batch [Submit a batch of emails for async verification](https://swcgtl60qi.apidog.io/submit-a-batch-of-emails-for-async-verification-45637512e0.md): Queues a verification job for the supplied email list. Returns immediately with a job ID; results retrievable via /v1/batch-verify/{id}/results once the job completes. - Batch [Get batch job status](https://swcgtl60qi.apidog.io/get-batch-job-status-45637513e0.md): Poll endpoint for batch job progress. Returns the job's verdict counters (`numImported`, `emailsProcessed`, `numPassed`, `numFailed`, …) plus a `status` string. Counters are absent until processing begins; there is no single percent-complete field — derive progress from `emailsProcessed / numImported`. - Batch [Get batch job results (paginated)](https://swcgtl60qi.apidog.io/get-batch-job-results-paginated-45637514e0.md): Returns the verification results for a completed job, paginated via the per_page + next query parameters. Row verdicts are post-org-override: statuses the org's floss settings are configured to ignore are rewritten to passed/valid before storage, so they may differ from GET /v1/verify for the same address — see the v1 contract ("Live vs batch verdicts"). - Batch [Cancel a batch verification job](https://swcgtl60qi.apidog.io/cancel-a-batch-verification-job-45637515e0.md): Cancels a pending or in-progress batch job. No-op if job has already completed. - Batch [List verification jobs](https://swcgtl60qi.apidog.io/list-verification-jobs-45637516e0.md): Paginated history of the org's verification jobs, newest first. Includes jobs from every source — API submissions, CSV uploads, in-app pasted (`input`) imports, and ESP auto-cleanses — each tagged with a `source` (and `source_integration` for ESP jobs). Filter with `?source=` and/or `?status=`. Each job carries a `results` verdict summary (`passed`/`undeliverable`/`risky`/`unknown`), but ONLY once `status` is `completed` — counts accrue during processing and are `null` until the job finishes (cancelled jobs have partial counts, also `null`). Always paginated with the universal cursor envelope (default per_page 25, max 100); the cursor is opaque — clients MUST NOT parse it. Use `GET /v1/jobs/{id}` for the full per-reason breakdown. - Batch [Get a verification job](https://swcgtl60qi.apidog.io/get-a-verification-job-45637517e0.md): Returns one verification job by id, with the full `results` breakdown including per-reason counts (`reasons`: spam / role_based / disposable / nonexistent / …). As with the list, `results` is `null` until the job's `status` is `completed`. A job id that does not exist or belongs to another org → 404 not_found. (For paginated per-email results use `GET /v1/batch-verify/{id}/results`; to cancel, `POST /v1/batch-verify/{id}/cancel`.) - Account [Account activity timeline](https://swcgtl60qi.apidog.io/account-activity-timeline-45637518e0.md): A compact, newest-first feed of what happened on the account inside a rolling window (`days`, default 30, max 90; `limit` events, default 60, max 200): verification jobs with their outcome AND why they started (`trigger` — manual / autofloss / instafloss / decay_protection / api / cron / staff / system — recorded at job start for jobs created after September 2026, inferred from the job's flags before that: see `trigger_explicit`), settings and connection changes with exact before/after where recorded, and account-state events (support-chat sessions, escalations, ESP connects/disconnects, plan / add-on / auto-refill changes, logins, holds). Built to answer "was this job manual or scheduled?" and "why did my HubSpot run process this many emails?" without guessing. Scoped to the key's account. Ids and internal admin paths only — never emails, IP addresses, user agents, staff identities, tokens or payment data; settings values under credential-looking keys read "redacted". Requires `read:jobs`. - Account [Verify an API key](https://swcgtl60qi.apidog.io/verify-an-api-key-45637519e0.md): Validates the supplied api_key or public_key and returns `{verified: true, status: "success"}`, plus opt-in extras per query toggle: `check_plan` adds `remove_branding`, `check_credits` adds `credits_remaining` (prepaid + subscription credits summed), `get_token` adds the widget signed-proof triple (`XSRF-TOKEN`, `MFCLIENTID`, `SIGNED-PROOF`, also set as cookies). Used by integrations and the widget to verify auth before issuing further calls. For account name, plan, and named credit buckets, see GET /v1/organization. - Account [Read the authenticated account holder](https://swcgtl60qi.apidog.io/read-the-authenticated-account-holder-45637520e0.md): Returns the account holder's identity and security posture — name, email, `email_verified`, `two_factor_enabled`, `country`, and signup date — for the account the API key belongs to. Complements GET /v1/organization (plan/credits/usage) and GET /v1/users/me (the holder as a team-roster seat). Scoped implicitly to the authenticated account — no path parameter. Idempotent read; no credit consumption. - Account [Update the authenticated account holder](https://swcgtl60qi.apidog.io/update-the-authenticated-account-holder-45637521e0.md): Partial update (JSON merge-patch — omitted fields are left unchanged) of the account holder's contact details, organization, address, and email-notification preferences. Body may set any of: `name`, `phone`, `organization`, `vat_id`, `country` (a null clears a scalar), `address` (a partial sub-object), and `notifications` (a partial map of `after_flossing` / `weekly_report` / `monthly_report` / `payment_receipts`). At least one field is required. Returns `200` with the refreshed account (same shape as the GET). Requires the elevated `write:account` scope (owner/admin keys). `email` (login identity), password, two-factor, and the org-level stop-at-credit-limit setting are NOT updatable here. PATCH is idempotent; it does not consume the `Idempotency-Key` header. Plain document write: dashboard follow-on side effects (e.g. the Canadian tax-rate recompute on a CA province change) do NOT run — change CA provinces in the dashboard. - Account [Read the authenticated organization](https://swcgtl60qi.apidog.io/read-the-authenticated-organization-45637522e0.md): Returns plan, named credit buckets (`prepaid` + `subscription`), current-period usage, contact email, and `status` for the org the API key belongs to. Scoped implicitly to the authenticated org — no `:id` path parameter. Idempotent read; no credit consumption. Unlike credit-consuming endpoints, this read still succeeds for a *restricted* account (`suspended` / `paused` / `under_review` / `needs_identity_verification`) and reports the state in `status` — so an automated client can detect, for example, a billing suspension and act on it. A `banned` account is the one exception: it returns `403 forbidden`. - Team [List team members](https://swcgtl60qi.apidog.io/list-team-members-45637523e0.md): Returns the org's team roster — the account owner plus any invited seats — each with a `role` (`administrator`/`contributor`), an `is_primary` flag (the owner), and a `status` (`active`/`invited`/`paused`). `created_at` is the member's account-creation time — `null` for `invited` seats (no account yet), and rarely for a member whose login email no longer matches their seat. Most orgs have a single member (the owner). Always paginated with the universal cursor envelope (default per_page 25, max 100); the cursor is opaque — clients MUST NOT parse it. Members are sorted by email; the owner is identified by `is_primary`, not list position. `role` reflects the seat assignment the dashboard's Team tab displays — display truth, not an enforced-capability guarantee (see the v1 contract). - Team [Get the account owner as a team member](https://swcgtl60qi.apidog.io/get-the-account-owner-as-a-team-member-45637524e0.md): Returns the account this API key belongs to, AS A TEAM SEAT (the same member object as GET /v1/users/{user_id}). Keys are org-scoped, so `me` is always the account OWNER (`is_primary: true`, role `administrator`) — regardless of which team member created the key. For the holder's account identity and security posture (email verification, two-factor, country, signup date), use GET /v1/account instead. - Team [Get a team member](https://swcgtl60qi.apidog.io/get-a-team-member-45637525e0.md): Returns one team member by their opaque `id` (the `usr_<...>` handle from the list). A handle that does not resolve to a member of the authenticated org → 404 not_found. The literal `me` is also accepted and returns the authenticated account holder AS A TEAM SEAT (role + seat info). For the holder's account identity and security posture (email verification, two-factor, country, signup date), use GET /v1/account instead. - Reports [Get verification usage analytics](https://swcgtl60qi.apidog.io/get-verification-usage-analytics-45637526e0.md): Org-level verification usage for one UTC calendar period — a top-level `total`, a `statuses` breakdown (`passed`/`undeliverable`/`risky`/`unknown`, per https://docs.mailfloss.com/status-definitions) and an org-wide `reasons` breakdown (same vocabulary as GET /v1/jobs/{id}). Select with `?period=` (default `this_month`). `period=lifetime` returns the all-time `total` only — `statuses` and `reasons` are `null` (only the grand total is stored). An org with no activity returns a zeroed report (200), not 404. `total` is authoritative; the `statuses` counts may not sum exactly to it. - Webhooks [List webhook subscriptions](https://swcgtl60qi.apidog.io/list-webhook-subscriptions-45637527e0.md): Paginated list of the org's webhook subscriptions — the same subscriptions managed on the dashboard's webhooks page. The signing `secret` is never returned; `has_secret` indicates whether one is set. Always paginated with the universal cursor envelope (default per_page 25, max 100); the cursor is opaque — clients MUST NOT parse it. - Webhooks [Create a webhook subscription](https://swcgtl60qi.apidog.io/create-a-webhook-subscription-45637528e0.md): Creates a webhook subscription — the same result as adding one on the dashboard's webhooks page. Requires `name`, a publicly-reachable http(s) `url`, and at least one event code from the closed `events` enum. `data_source` scopes which connections feed the subscription: `"all"` (default) or a single connection id from GET /v1/integrations/{type}. The optional `secret` enables delivery signing (HMAC-SHA1 of the JSON `data` payload in the `X-Request-Signature` header) and is write-only — it can never be read back. Webhooks are a Business/Pro-plan feature (or the Webhooks add-on): requests from non-entitled plans → `403 forbidden`. The first subscription automatically enables webhook delivery for your account. Delivery is best-effort (no ordering guarantee, may burst); after 5 failed delivery attempts a subscription is automatically deactivated (`active: false`). Honors `Idempotency-Key` (a retried POST with the same key replays the original `201`). - Webhooks [Get a webhook subscription](https://swcgtl60qi.apidog.io/get-a-webhook-subscription-45637529e0.md): Returns one webhook subscription by id. The signing `secret` is never returned (`has_secret` indicates whether one is set). An id that does not exist or belongs to another org → 404 not_found. `created_at`/`updated_at` are null for subscriptions created in the dashboard before timestamps existed. - Webhooks [Update a webhook subscription](https://swcgtl60qi.apidog.io/update-a-webhook-subscription-45637530e0.md): Partial update (JSON merge-patch — omitted fields are left unchanged) of a subscription: any of `name`, `url`, `events` (replaces the whole set), `data_source`, `active` (pause/resume without deleting), and `secret`. Setting `secret` to a non-empty string replaces it; an empty string `""` clears it; omitting it leaves it unchanged. At least one field is required. Returns `200` with the refreshed subscription. Non-entitled plans → `403 forbidden`. An id that does not exist or belongs to another org → 404. PATCH is idempotent; it does not consume the `Idempotency-Key` header. - Webhooks [Delete a webhook subscription](https://swcgtl60qi.apidog.io/delete-a-webhook-subscription-45637531e0.md): Permanently removes a webhook subscription — deliveries stop immediately. Returns `200` with `{ id, deleted: true }`. An id that does not exist or belongs to another org → 404 not_found (so a repeated DELETE is a safe 404). To pause without deleting, PATCH `active: false` instead. - Integrations [List all integrations (connected + disconnected)](https://swcgtl60qi.apidog.io/list-all-integrations-connected-disconnected-45637532e0.md): Returns the full set of 41 ESP integrations, with `connected: true` for those the org has actively connected. Each entry carries `connection_count` and a deterministic `primary` summary because `(org, type)` is 1:N — customers can connect multiple accounts of the same ESP. `primary` is the connection with the lowest `createdAt` (or `null` when `connection_count: 0`); use it for chatbot shortcuts like "is X connected?" without a follow-up DETAIL request. Always paginated with a cursor envelope, even though the underlying set is bounded — so SDKs and chatbots use one pagination code path across every collection endpoint. Default per_page = 10, max 100. Cursor is opaque (base64url JSON); clients MUST NOT parse it. Sort order: connected ESPs first (alphabetical by type), then disconnected. - Integrations [Read one integration with all of its connections](https://swcgtl60qi.apidog.io/read-one-integration-with-all-of-its-connections-45637533e0.md): Returns the per-type universal fields (`type`, `connected`, `connection_count`) plus the full `connections[]` array for the integration `type`. `(org, type)` is 1:N: a customer can connect multiple accounts of the same ESP (e.g. two Mailchimp accounts for different brands); each entry in `connections[]` is one connection with its own stable `id`, customer-set `name`, `status`, and per-connection settings. Connections are ordered by `createdAt` asc (oldest first); `connections[0]` matches the `primary` returned by the LIST endpoint. When the org has no active connections for this type, `connected: false` + `connection_count: 0` + `connections: []` — the response shape stays symmetric so chatbots don't need try/catch on 404 to ask "is X connected?". Unknown `type` (not in the closed ESP enum, including hidden internal types like `csv`/`api`/`input`/`zapier`) → 404 not_found. - Integrations [Connect a new connection (with credentials)](https://swcgtl60qi.apidog.io/connect-a-new-connection-with-credentials-45637534e0.md): Creates a brand-new connection for the ESP `type` with fresh credentials. The credentials shape depends on `type`; the single-key ESPs currently connectable via the API (Klaviyo, MailerLite) take `{ "credentials": { "api_key": "..." }, "name"?: "..." }`. The key is validated against the ESP live before anything is stored (a rejected key → `400 invalid_credentials`, nothing written), then encrypted at rest; it is never returned. On success returns `201` with the new connection in the same shape as GET /v1/integrations/{type}/connections/{id}. A valid ESP slug that cannot be connected via the API yet (OAuth ESPs, or ESPs not wired) → `422 unsupported_integration` (connect it in the dashboard); an unknown slug → `404`. `(org, type)` is 1:N, so this always creates a new connection. Honors `Idempotency-Key` (a retried POST with the same key replays the original `201` instead of creating a duplicate). - Integrations [Read one connection](https://swcgtl60qi.apidog.io/read-one-connection-45637535e0.md): Returns a single connection by id — the same per-connection shape as one entry of GET /v1/integrations/{type}'s `connections[]` (stable `id`, `name`, `status`, `created_at`, `last_synced_at`, the universal `settings` object, and the optional per-type extension). A connection `id` that does not exist or belongs to another org → 404 not_found. - Integrations [Update a connection's settings](https://swcgtl60qi.apidog.io/update-a-connections-settings-45637536e0.md): Partial update (JSON merge-patch — omitted fields are left unchanged) of a connection's cleansing settings. Body may set any of: `manual_mode` (boolean; mode-independent), `autofloss` / `decay_protection` (paid-plan booleans — 403 on the free tier), subject to connector capabilities. Attentive does not support Autofloss, Decay Protection, delete or tag actions; unsupported settings return 422 after applicable plan checks. `aggressiveness` (`normal`/`aggressive` cascade canonical values to all 12 check gates, `custom` detaches from a preset without changing gates), and `checks` (a partial map of the 12 gates — editing ANY gate switches `aggressiveness` to `custom`). `aggressiveness` and `checks` are mutually exclusive in one request (editing checks already implies custom) → 400 if both are sent. At least one field is required. Returns `200` with the refreshed connection (same shape as the GET). A connection `id` that does not exist or belongs to another org → 404. PATCH is idempotent; it does not consume the `Idempotency-Key` header. - Integrations [Disconnect a connection](https://swcgtl60qi.apidog.io/disconnect-a-connection-45637537e0.md): Disconnects (soft-disables) a connection. Its data and stored credentials are retained — this stops all cleansing/processing for the connection and removes it from subsequent reads (it disappears from GET /v1/integrations and GET .../connections/{id}). Returns `200` with a small confirmation `{ id, type, status: "disconnected", disconnected_at }`; no credential fields are returned. A connection `id` that does not exist, belongs to another org, or is already disconnected → 404 not_found (so a repeated DELETE is a safe 404). A connection with Instafloss (Superfloss) enabled is refused with `409 conflict` — its live real-time webhooks must not be left pointed at a disabled connection, so disable Instafloss first, then disconnect (mirrors the dashboard). Reconnecting a connection is a future additive endpoint. - Integrations [Re-sync a connection's audiences](https://swcgtl60qi.apidog.io/re-sync-a-connections-audiences-45637538e0.md): Re-runs the live list/audience fetch for a connection using its stored credentials and refreshes the connection's audiences — use it when lists were renamed/added upstream, or when the connect-time fetch came back empty. The stored credentials are validated against the ESP as part of the fetch: a rejected key → `400 invalid_credentials` and nothing is changed; an unreachable ESP → `503`. On success returns `200` with the refreshed connection (same shape as GET .../connections/{id}). A connection `id` that does not exist or belongs to another org → `404`; a connection of a type that can't be managed via the API → `422 unsupported_integration`. - Integrations [Test a connection's credentials](https://swcgtl60qi.apidog.io/test-a-connections-credentials-45637539e0.md): Checks whether a connection's stored credentials still work — a live, read-only probe against the ESP that writes nothing. Returns `200` with `{ credential_valid, tested_at }`: `true` if the ESP accepted the key just now, or `false` (plus a `reason`) if it rejected them — a rejected key is still a successful test, not an error. Only an ESP we couldn't reach surfaces as `503` (the result is genuinely unknown). A connection `id` that does not exist or belongs to another org → `404`; a type that can't be managed via the API → `422 unsupported_integration`. Ideal for an "is my integration healthy?" check before relying on it. Do NOT send an `Idempotency-Key` with this endpoint — it is a live probe, and a replayed cached result would defeat the point (poll it fresh each time). - Integrations [List a connection's keyword rules](https://swcgtl60qi.apidog.io/list-a-connections-keyword-rules-45637540e0.md): Returns the per-connection keyword rules for the chosen `{list}` (`blacklist` = always-remove, `whitelist` = never-remove). The universal `settings` object on GET /v1/integrations/{type} only reports the COUNTS (`blacklist_count`/`whitelist_count`); this endpoint returns the rules themselves. Each rule carries a stable `id`, the `keyword`, its `match` strategy (`exact`/`contains`), and the `applies_to` segment toggles (localpart/domain/email). Always paginated with the universal cursor envelope (default per_page = 50, max 100); the cursor is opaque — clients MUST NOT parse it. Unknown `type` or `list`, or a connection `id` that does not exist or belongs to another org, → 404 not_found. - Integrations [Add keyword rules](https://swcgtl60qi.apidog.io/add-keyword-rules-45637541e0.md): Adds one or more rules to the connection's `{list}`. Body is always an array: `{ rules: [ { keyword, match, applies_to }, … ] }` (1–1000) — a single keyword is just an array of one. Each `applies_to` must enable at least one of localpart/domain/email. **All-or-nothing**: if any item is invalid the whole request is rejected `400 invalid_request` and nothing is written. Keywords are stored space-stripped and upserted on keyword (re-adding the same keyword updates the existing rule in place — no duplicate). Returns `200` with `{ data: [rules] }` (each with its stable `id`, deduped, in first-seen order). Unknown `type` or `list`, or an unowned connection, → 404 not_found. Honors `Idempotency-Key`. - Integrations [Delete a keyword rule](https://swcgtl60qi.apidog.io/delete-a-keyword-rule-45637542e0.md): Removes one rule from the connection's `{list}` by its `ruleId`. Scoped to the connection — a rule id that does not exist on this connection (or belongs to another org) → 404 not_found. Returns `200` with `{ deleted: true, id }`. - Privacy [Erase stored verification records (data privacy)](https://swcgtl60qi.apidog.io/erase-stored-verification-records-data-privacy-45637543e0.md): Data-privacy erasure API — permanently removes stored verification records for the supplied email addresses. (Renamed from /v1/delete for clarity.) See https://developers.mailfloss.com for the public docs. ## Schemas - [ErrorEnvelope](https://swcgtl60qi.apidog.io/errorenvelope-18375482d0.md):