Email Verification API: Design Deliverability Checks

An email verification API should help you decide how to handle a discovered work address in a downstream workflow. It should not turn every address into an automatic send decision. Your pipeline needs to preserve the address, its deliverability status, the time you received that status, and the action your systems took next.
What an email verification API should establish
An email verification API should establish the current deliverability assessment for a discovered work address, not make a permanent claim about a mailbox.
There are two separate operations in an email enrichment workflow:
- Finding a work email address: resolving an address for a person you identified through a LinkedIn URL, an email address, or a name plus employer.
- Checking email deliverability: probing the returned address and assigning a deliverability status.
These operations can happen in one enrichment run. They should still remain distinct in your data model and downstream logic. A person record may resolve without an email address. An address may be found but receive a status that your sending system should suppress or defer.
That distinction matters because identity resolution answers one question: “Who is this person?” Email verification answers another: “What did the deliverability check conclude when this address was checked?”
A work address is not a permanent property of a person. People change employers. Domains change mail handling. A mailbox that accepted mail at the time of an enrichment run may later become unavailable. An email validation API gives you an operational signal for a point in time. It does not remove the need for suppression lists, sender controls, engagement handling, or regular data-quality review.
In Enrichments, work email is an explicit person field. You ask for it with fields: ["email"]; it is not returned merely because you ran a people search or enrichment. The deliverability check is included when an email is found. You are charged for an address that is returned, not for an unsuccessful attempt to find one.
That design is useful for email hygiene. You can keep workflows that do not need email focused on identity, title, seniority, department, location, and company data. You only request the more sensitive and more expensive field when an actual downstream process requires it.
email field by name. Build a separate branch for workflows that need a work address rather than adding it to every enrichment request.Model verification outcomes as explicit states
Email verification status should be a controlled field with explicit handling rules, not a free-text note and not a boolean.
The available outcome vocabulary is:
verifiedprobableunverifiedriskyundeliverableunknown
Your application should store the exact returned value. Do not collapse every state into valid or invalid. That loses information your activation and review processes need.
Use a downstream policy for every status
A practical policy separates addresses that can proceed from addresses that need a different action.
| Email verification status | Practical downstream handling |
|---|---|
verified | Allow the address into the workflow your policy permits. Keep normal suppression, opt-out, and engagement controls in place. |
probable | Defer to a more cautious path. You may hold it for review, use a lower-risk workflow, or wait for another signal before activation. |
unverified | Do not assume it is send-ready. Preserve the record and recheck later if the workflow still needs the address. |
risky | Suppress from ordinary outreach until your policy explicitly allows another treatment. Keep the status available for review. |
undeliverable | Suppress the address from sending. Do not turn it into an activation candidate merely because the person record resolved. |
unknown | Treat the result as unresolved for sending decisions. Preserve it and defer, review, or re-run the workflow later. |
The exact policy belongs to your organization. The important engineering choice is making that policy executable. Put it in a shared function, a workflow rule, or a clearly versioned transformation. Do not leave it as tribal knowledge in a campaign checklist.
For example, your activation service can map an email verification status to an internal action:
{
"verified": "eligible",
"probable": "review",
"unverified": "defer",
"risky": "suppress",
"undeliverable": "suppress",
"unknown": "defer"
}
The internal action names are yours. The source status should remain unchanged alongside them. This lets you update policy later without rewriting the original enrichment result.
Store status with the address and check time
Store the work email, the returned status, and a timestamp for when your system received the completed result. If you use queued jobs, job.finishedAt is a useful job-level timestamp for that purpose. Preserve the job ID as well when you need an audit trail.
A record in your warehouse or CRM sync layer should retain enough context to answer:
- Which address did you receive?
- What email verification status came back?
- When did your system receive the completed check?
- Which enrichment job produced it?
- Which policy action did your downstream system apply?
- Was the address later suppressed, reviewed, or rechecked?
This is more durable than writing an address into a single “email” field and losing the state that made it usable or unusable for a particular workflow.
Decide where verification belongs in the data flow
Verification belongs at the point where a work address becomes relevant, with a later quality-control step for records that remain in use.
There are several reasonable places to run email validation. Each solves a different operational problem.
Verify at capture
Verification at capture fits a form, import, or handoff where an address enters your system for the first time.
This approach prevents unreviewed addresses from immediately entering downstream lists. It works best when you own the capture path and can require a status before a record reaches activation.
Its limitation is time. A captured address can change after it enters your system. Capture-time verification is useful history, but it is not a permanent send authorization.
Verify during email enrichment
Verification during email enrichment keeps identity resolution and address quality in the same record flow.
This is often the cleanest model when you begin with identifiers such as a LinkedIn URL, an existing email, or a name plus employer. You request the fields you need, including email, then handle the returned person data and email verification status together.
That gives you a coherent record path:
- Submit identities for enrichment.
- Request
emailonly when the workflow needs a work address. - Wait for the enrichment result.
- Read each record-level result.
- Store the person data, returned email, status, and job context.
- Apply your downstream status policy.
This reduces the chance that a later system joins an address to the wrong person or loses the provenance of the check.
Verify before an activation step
A pre-activation check is useful when data can sit in a warehouse, CRM, or audience before it is used.
This pattern separates data collection from activation. Your enrichment system can maintain person and company context. A later workflow requests or rechecks email when there is a real operational reason to use it.
That is also a credit-control decision. Email lookup costs 2 credits per work address found. A people enrichment costs 0.5 credits per person resolved. Asking for email only in workflows that need it keeps the request aligned with the use case.
Verify during a data-quality review
A review workflow helps you revisit records that were deferred, returned as unknown, or have been sitting in a downstream system.
Use the original status as evidence, not as a substitute for a new result. Enrichment is live, so the same query can legitimately return different data later. Your review process should preserve both the historical result and the newer result rather than overwriting history without context.
For many teams, the useful design is not choosing only one point in the flow. It is combining enrichment-integrated checking when you first need an address with a controlled review process for records that remain operationally important.
Design reliable asynchronous verification workflows
Your email verification workflow must handle both inline responses and queued jobs.
Enrichments returns small requests inline. A people search asking for 10 results or fewer, or an enrichment request containing 5 rows or fewer, can return with results already populated and a terminal job.status.
Larger requests are queued. A request that asks for the email field is also queued, even if it would otherwise be small. Sending async: true or Prefer: respond-async queues the request as well.
This means your client cannot assume that every POST creates work to poll. It also cannot assume that a successful HTTP response contains completed records.
Every search, enrichment, and job poll uses the same response envelope:
{
"job": {
"object": "job",
"id": "job_id",
"type": "people_enrich",
"status": "queued",
"fields": ["email"],
"requestedCount": 0,
"resultCount": 0,
"creditsUsed": 0,
"error": null,
"createdAt": "timestamp",
"startedAt": null,
"finishedAt": null,
"url": "url"
},
"results": null,
"page": null,
"estimatedCredits": 0
}
The important points are structural:
- Read status from
job.status, not a top-levelstatus. - Read the job ID from
job.id, not a top-levelid. - Treat
results: nullas incomplete work, not an empty result set. - Poll
GET /api/v1/jobs/{id}untiljob.statusis terminal. - Treat
succeeded,empty,failed, andcancelledas terminal job statuses. - Use the opaque forward-only cursor in
pagewhen results are paged.
GET /api/v1/jobs/{id} always returns HTTP 200. HTTP success only means the poll request worked. It does not mean the job succeeded. Your code must inspect job.status.
Make retries intentionally idempotent
Retries are safe only when you send the same Idempotency-Key header as the original request.
That header is not optional if your client might retry after a timeout, network interruption, or worker restart. With the same key, the retry is deduplicated. Without it, the platform treats the retry as a new request: it creates another job, takes another hold, and can be charged as a separate run.
Generate an idempotency key before submitting the request. Persist it with your internal run record. Reuse it for every retry of that same logical operation.
curl -X POST /api/v1/people/enrich \
-H "Authorization: Bearer $ENRICHMENTS_API_KEY" \
-H "Idempotency-Key: $RUN_KEY" \
-H "Content-Type: application/json"
Do not generate a new key inside a retry loop. A new key describes a new request.
The API documentation at /docs and its OpenAPI document at /api/v1/openapi are useful references when you build the client. The generated OpenAPI document comes from the same schemas that validate requests.
Handle results at both job and record level
A terminal job status does not mean every submitted identity produced usable data.
When results are present, each entry is a wrapper:
{
"position": 0,
"status": "succeeded",
"data": {},
"evidence": {},
"error": null
}
The person or company record is inside data. The wrapper itself has its own status, error, and input position.
Record-level statuses are:
pendingrunningsucceedednot_foundfailed
Your job handler should inspect each wrapper. Do not assume that a job with job.status: "succeeded" means every input resolved. Some records can be not_found or failed while the overall job reaches a terminal state.
A safe result-processing pattern is:
- Wait for a terminal
job.status. - Confirm that
resultsis present. - Page through results when the response provides a forward cursor in
page. - Read each wrapper’s
position,status,data, anderror. - Write back only fields from wrappers that succeeded.
- Route
not_foundandfailedrecords to distinct handling paths. - Keep the original input identifier and job ID with every writeback.
Enrichment returns one row per input in input order. Use that guarantee, but do not rely on position alone. Preserve your own stable record identifier in the system that created the batch. Your writeback process should join the returned wrapper to that identifier before updating a CRM, warehouse, or activation table.
For example, not_found can mean no enrichment result was delivered for that input. That should not be silently converted into a blank email field that overwrites an existing value. A failed item should retain its error context for operational review. In both cases, no delivered data means no charge for that unresolved lookup.
This is also why append-only usage and processing logs are useful. You need to distinguish “no result,” “result deferred by policy,” and “result accepted into a downstream workflow.” Those are different events with different owners.
Keep verification useful without overclaiming certainty
Email verification should inform responsible sending controls, not replace them.
A verified email status is a deliverability result from the time of the check. It does not establish that a person wants contact. It does not establish permission under your organization’s obligations. It does not replace your unsubscribe process, suppression handling, audience rules, or review of engagement signals.
Work email addresses in this workflow come from public sources. Personal contact details are not part of the field catalogue. Even for a work address, your organization remains responsible for deciding whether contact is lawful and appropriate.
Use the returned email verification status together with first-party information you already hold. That can include an existing relationship, a documented business purpose, internal suppression rules, and engagement signals generated through your own systems. Keep those decisions separate from the enrichment response itself.
A durable email hygiene workflow has clear boundaries:
- The enrichment step resolves available data.
- The deliverability check returns a controlled status.
- Your policy maps that status to an internal action.
- Your activation system applies consent, suppression, and sender controls.
- Your data-quality process revisits records when needed.
That separation keeps the system honest. You avoid treating discovered data as automatically actionable, and you can explain why a record was sent, deferred, reviewed, or suppressed.
Frequently asked questions
- What should an email verification API establish?
- An email verification API should establish the current deliverability assessment for a discovered work address. It is an operational signal from the time of the check, not a permanent claim about a mailbox or a send authorization.
- What email verification statuses should an application store?
- Store the exact returned status: verified, probable, unverified, risky, undeliverable, or unknown. Do not reduce these states to a simple valid-or-invalid field, because downstream workflows need the original result.
- How should email verification statuses be handled downstream?
- Map each status to an explicit internal action such as eligible, review, defer, or suppress. Keep the source status alongside the internal action so policy can change without rewriting the original enrichment result.
- What data should be stored with an email verification result?
- Retain the work email, returned verification status, the time your system received the completed result, and the enrichment job ID. Also preserve the downstream policy action and any later suppression, review, or recheck context.
- When should email verification run in a data workflow?
- Verification can run at capture, during email enrichment, before activation, or during a data-quality review. A durable workflow can use enrichment-integrated checking when an address is first needed and revisit records later when they remain important.
Keep reading
Put this into practice
Enrichments resolves people and companies from a REST API, an MCP server, the chat agent or a CSV upload, checks every email address it finds, and bills you only for the data that comes back.
Start enriching for free

