Email Finder
Find and verify a person's or company's email address from a domain, website, or business name — optionally narrowed to a specific person. Lookups run asynchronously as jobs: most resolve in a few seconds, but cache misses can take longer while Warmerly scrapes and verifies candidates, so the API returns immediately with either a completed result or a job you poll.
All Email Finder endpoints require X-Api-Key. Endpoints that create or read job
data are project-scoped and also require X-Project-Id; GET /email-finder/quota
is account-level and does not require X-Project-Id.
Single lookup
/email-finder/lookupSubmit one lookup. Provide at least one of domain, website, or name — add
person to narrow the search to a specific individual at that domain/company.
| Field | Type | Description |
|---|---|---|
domain | string | Company domain, e.g. "acme.com". |
website | string | Full website URL; the domain is extracted from it. |
name | string | Business name, used when no domain/website is known. |
location | string | Optional location hint to disambiguate a business name. |
person.firstName | string | Optional first name to target a specific person. |
person.lastName | string | Optional last name to target a specific person. |
curl https://app.warmerly.com/api/v1/email-finder/lookup \
-X POST \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a" \
-H "Content-Type: application/json" \
-d '{
"domain": "acme.com",
"person": { "firstName": "Jane", "lastName": "Doe" }
}'If the answer is already cached, the lookup completes synchronously and returns
200 with the result inline:
{
"status": "done",
"jobId": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10",
"job": {
"id": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10",
"status": "done",
"confidence": 92,
"error": null,
"createdAt": "2026-07-02T09:14:03.000Z",
"completedAt": "2026-07-02T09:14:03.000Z"
},
"result": {
"email": "jane.doe@acme.com",
"confidence": 92,
"verifyStatus": "verified",
"source": "pattern_guess",
"isCatchAll": false,
"mxHost": "aspmx.l.google.com",
"evidenceUrl": "https://acme.com/team",
"providerName": "Google Workspace"
}
}Otherwise it enqueues a job and returns 202 with a pollUrl:
{
"status": "pending",
"jobId": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10",
"pollUrl": "https://app.warmerly.com/api/v1/email-finder/jobs/3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10"
}Poll the job (see below) until status is "done" or "failed".
Bulk lookup
/email-finder/bulkSubmit up to 1,000 lookups in one request. Each item accepts the same fields as a
single lookup. All items are enqueued under a shared batchId you can use to track
progress via Batches.
curl https://app.warmerly.com/api/v1/email-finder/bulk \
-X POST \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "domain": "acme.com", "person": { "firstName": "Jane", "lastName": "Doe" } },
{ "website": "https://widgetco.io" },
{ "name": "Roasted Coffee Co", "location": "Austin, TX" }
]
}'{
"batchId": "6e6f9d0a-4a3f-4c7e-9c86-1b6a4e5c2f01",
"results": [
{ "index": 0, "ok": true, "jobId": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10", "cached": true, "result": { "email": "jane.doe@acme.com", "confidence": 92, "verifyStatus": "verified", "source": "pattern_guess", "isCatchAll": false, "mxHost": "aspmx.l.google.com", "evidenceUrl": "https://acme.com/team", "providerName": "Google Workspace" } },
{ "index": 1, "ok": true, "jobId": "7c1e9b3d-8a2f-4e11-9d0c-5b3a1f4e6c22", "cached": false },
{ "index": 2, "ok": false, "error": "invalid input" }
]
}Each item is evaluated independently — an invalid item (ok: false) does not fail
the rest of the batch. Items that hit the cache resolve immediately (cached: true,
result present); the rest are enqueued (cached: false) and must be polled
individually via their jobId, or tracked in aggregate via batch status.
Get a job
/email-finder/jobs/:idFetch the current status of a lookup job, whether it came from a single or bulk request.
curl https://app.warmerly.com/api/v1/email-finder/jobs/3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10 \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"{
"job": {
"id": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10",
"status": "scraping",
"confidence": null,
"error": null,
"createdAt": "2026-07-02T09:14:03.000Z",
"completedAt": null
},
"result": null
}status moves through pending → resolving → scraping → verifying →
done (or failed). result is populated once status is "done"; on
"failed", check job.error for the reason. A job for a project you don't have
access to (or that doesn't exist) returns 404.
Delete a job
/email-finder/jobs/:idDeletes the job and its discovered email records.
curl https://app.warmerly.com/api/v1/email-finder/jobs/3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10 \
-X DELETE \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"{ "deleted": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10" }Batch status
/email-finder/batches/:idReturns aggregate progress for a bulk lookup, grouped by job status.
curl https://app.warmerly.com/api/v1/email-finder/batches/6e6f9d0a-4a3f-4c7e-9c86-1b6a4e5c2f01 \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"{
"batchId": "6e6f9d0a-4a3f-4c7e-9c86-1b6a4e5c2f01",
"total": 3,
"done": 2,
"pending": 1,
"counts": {
"done": 2,
"scraping": 1
}
}done sums jobs in either done or failed status. Use List results
with batchId to fetch the actual emails once a batch is complete.
List results
/email-finder/resultsLists jobs for the current project, each joined with its winning discovered email (if any), newest first. Cursor-paginated.
| Query param | Type | Description |
|---|---|---|
status | string | Filter by job status: pending, resolving, scraping, verifying, done, failed. |
batchId | uuid | Restrict to jobs from a specific bulk batch. |
minConfidence | integer (0–100) | Only include results with confidence at or above this value. |
cursor | ISO 8601 datetime | Pass the previous response's nextCursor to fetch the next page. |
limit | integer (1–100, default 25) | Page size. |
curl "https://app.warmerly.com/api/v1/email-finder/results?status=done&limit=25" \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"{
"results": [
{
"id": "3f9a2e2a-1c4b-4a2e-9b1e-2f6c8a7d5e10",
"status": "done",
"confidence": 92,
"inputDomain": "acme.com",
"inputName": null,
"batchId": null,
"createdAt": "2026-07-02T09:14:03.000Z",
"email": "jane.doe@acme.com",
"verifyStatus": "verified",
"source": "pattern_guess"
}
],
"nextCursor": "2026-07-02T09:14:03.000Z"
}Pass nextCursor as the cursor query param to fetch the next page; it is null
on the last page.
Quota
/email-finder/quotaReturns your current monthly Email Finder usage. This endpoint is account-level —
it does not require X-Project-Id.
curl https://app.warmerly.com/api/v1/email-finder/quota \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{ "used": 37, "limit": 500, "remaining": 463 }Free-trial workspaces default to 50 lookups/month; paid plans raise the limit.
Both POST /email-finder/lookup and POST /email-finder/bulk check remaining
quota before enqueuing — a bulk request counts against quota by item count. If
the request would exceed your limit, it's rejected with 400:
{
"error": {
"code": "bad_request",
"message": "plan_limit_reached",
"details": {
"allowed": false,
"used": 500,
"limit": 500,
"remaining": 0,
"plan": "growth"
}
}
}Errors
| Status | Code | When |
|---|---|---|
400 | bad_request | Missing X-Project-Id (project-scoped endpoints), invalid body/query, no valid domain/website/name provided, or quota exhausted (*_limit_reached). |
401 | unauthorized | Missing, invalid, or revoked API key. |
404 | not_found | Job or batch doesn't exist, or doesn't belong to the given project. |
429 | too_many_requests | Rate limit exceeded. |
Summarize with AI

