FirstSales Email API
Email address validation and risk checks.
Email address validation and risk checks.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/firstsales-io:firstsales-io-email-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Firstsales Io Email API
version: 1.0.0
contact:
name: FirstSales Support
email: firstsales@support.communicate.so
url: https://firstsales.io
license:
name: Terms of Service
url: https://firstsales.io/terms-of-service/
termsOfService: https://firstsales.io/terms-of-service/
x-apiVersioning:
strategy: url-path
current: v1
pattern: https://firstsales.io/api/v1/{operation}
policyUrl: https://firstsales.io/developers/#versioning
note: A breaking change ships under a new prefix (/api/v2/); v1 keeps its contract. The unprefixed /api/{operation} form is an unversioned alias of the current version and may change without notice - call the /api/v1/ form.
x-deprecationPolicy:
minimumNoticeDays: 180
signalling: 'A deprecated version''s responses carry Deprecation: true and a Sunset header with the retirement date (RFC 8594), plus a Link rel="deprecation" to the migration notes.'
announcement: https://firstsales.io/developers/#deprecation-policy
policyUrl: https://firstsales.io/developers/#deprecation-policy
currentlyDeprecated: []
description: 'Operations tagged Email across 2 of this provider''s published API definitions: firstsales-io-openapi.json, openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://firstsales.io
description: Production
security: []
tags:
- name: Email
description: Email address validation and risk checks.
paths:
/api/v1/email/validate:
post:
operationId: validateEmail
summary: Validate an email address's deliverability
description: 'Checks email format, then resolves the domain''s DNS to confirm it exists and has MX records, and flags reserved/disposable/free-provider domains. Use this before sending outreach to filter out addresses that cannot receive mail. Rate limit: 20 requests/minute per IP.'
tags:
- Email
security: []
x-rateLimit:
limit: 20
windowSeconds: 60
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
required:
- email
responses:
'200':
description: Validation result (still 200 even when the email is invalid — check `valid`).
content:
application/json:
schema:
$ref: '#/components/schemas/EmailValidationResult'
'400':
description: Invalid request — bad input, missing field, or malformed value.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded for this endpoint. Wait Retry-After seconds and retry.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://firstsales.io
description: Production
/api/v1/email/disposable:
post:
operationId: checkDisposableEmail
summary: Score an email domain for disposable/temporary-mailbox risk
description: 'Runs six weighted checks (known disposable database, domain age via RDAP, MX validity, reputation, naming pattern, MX cross-reference) and returns a 0-100 score plus a safe/suspicious/disposable/high_risk classification. Use this to filter throwaway addresses out of a lead list. Rate limit: 20 requests/minute per IP.'
tags:
- Email
security: []
x-rateLimit:
limit: 20
windowSeconds: 60
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
required:
- email
responses:
'200':
description: Disposable-risk assessment.
content:
application/json:
schema:
$ref: '#/components/schemas/DisposableCheckResult'
'400':
description: Invalid request — bad input, missing field, or malformed value.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded for this endpoint. Wait Retry-After seconds and retry.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://firstsales.io
description: Production
/api/v1/email/catchall:
post:
operationId: checkCatchAllDomain
summary: Detect whether a domain accepts mail to any mailbox (catch-all)
description: 'Sends live SMTP RCPT TO probes with random non-existent mailboxes at the domain''s primary MX host and infers catch-all behavior from acceptance/rejection. Use this to avoid false-positive ''valid'' verdicts on catch-all domains. Slower than the other email checks (real SMTP round-trips). Rate limit: 20 requests/minute per IP.'
tags:
- Email
security: []
x-rateLimit:
limit: 20
windowSeconds: 60
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
domain:
type: string
example: example.com
required:
- domain
responses:
'200':
description: Catch-all detection result.
content:
application/json:
schema:
$ref: '#/components/schemas/CatchAllResult'
'400':
description: Invalid request — bad input, missing field, or malformed value.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded for this endpoint. Wait Retry-After seconds and retry.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://firstsales.io
description: Production
components:
schemas:
MxRecord:
type: object
properties:
exchange:
type: string
priority:
type: number
required:
- exchange
- priority
Error:
type: object
description: Shared error envelope used by public endpoints and the rate-limit wrapper. Mail-tester handler errors use MailTesterError.
properties:
error:
type: string
description: Machine-readable error code, e.g. `invalid_input`.
message:
type: string
description: Human-readable explanation.
hint:
type: string
description: How to fix the request.
required:
- error
- message
- hint
CatchAllResult:
type: object
properties:
isCatchAll:
type: boolean
confidence:
type: string
enum:
- high
- medium
- low
checks:
type: array
items:
type: object
properties:
label:
type: string
status:
type: string
enum:
- pass
- warn
- fail
detail:
type: string
required:
- label
- status
- detail
score:
type: number
minimum: 0
maximum: 100
required:
- isCatchAll
- confidence
- checks
- score
EmailValidationResult:
type: object
properties:
valid:
type: boolean
domain:
type: string
domainExists:
type: boolean
hasMx:
type: boolean
isReserved:
type: boolean
isDisposable:
type: boolean
isFreeProvider:
type: boolean
mxRecords:
type: array
items:
$ref: '#/components/schemas/MxRecord'
error:
type: string
message:
type: string
required:
- valid
- domain
- domainExists
- hasMx
- isReserved
- isDisposable
- isFreeProvider
DisposableCheckResult:
type: object
properties:
score:
type: number
minimum: 0
maximum: 100
classification:
type: string
enum:
- safe
- suspicious
- disposable
- high_risk
checks:
type: array
items:
type: object
properties:
label:
type: string
status:
type: string
enum:
- pass
- warn
- fail
detail:
type: string
weight:
type: number
required:
- label
- status
- detail
- weight
details:
type: object
properties:
domain:
type: string
isDisposable:
type: boolean
domainAge:
type:
- object
- 'null'
properties:
registeredAt:
type: string
ageDays:
type: number
mxRecords:
type: array
items:
$ref: '#/components/schemas/MxRecord'
hasMx:
type: boolean
patternMatch:
type: boolean
databaseMatch:
type: boolean
required:
- score
- classification
- checks
- details
x-refined-from:
- firstsales-io-openapi.json
- openapi.json
x-apiVersioning:
strategy: url-path
current: v1
pattern: https://firstsales.io/api/v1/{operation}
policyUrl: https://firstsales.io/developers/#versioning
note: A breaking change ships under a new prefix (/api/v2/); v1 keeps its contract. The unprefixed /api/{operation} form is an unversioned alias of the current version and may change without notice - call the /api/v1/ form.
x-deprecationPolicy:
minimumNoticeDays: 180
signalling: 'A deprecated version''s responses carry Deprecation: true and a Sunset header with the retirement date (RFC 8594), plus a Link rel="deprecation" to the migration notes.'
announcement: https://firstsales.io/developers/#deprecation-policy
policyUrl: https://firstsales.io/developers/#deprecation-policy
currentlyDeprecated: []