Skip to main content

Use case

Discover professional or personal email addresses for leads for sales outreach, CRM enrichment, or lead qualification.

Endpoint

POST https://api.sixtyfour.ai/find-email

API Reference

See the full request/response schema and parameters in the API Reference.

Pricing

See Credits & Pricing Guide for credit costs.

Errors

For error responses (400, 403, 422, etc.), see Handling Errors.

Email modes

The mode parameter controls which type of email the API returns. Defaults to Professional if omitted.
ModeDescriptionReturned in
Professional (default)Discovers company emails tied to the lead’s employer domain.email field
PersonalDiscovers personal emails (e.g., Gmail, Yahoo). The email field still returns the company email when found.personal_email field
If the input lead already includes an email field, the API returns it unchanged with appropriate status and type. In Personal mode, if the existing email is a personal email, the API returns immediately without additional processing or cost.

Response format

The email and personal_email fields contain a list of tuples. Each tuple consists of:
  • Email address (string)
  • Validation status (string, always uppercase):
    • OK — The email address has been validated and is likely deliverable.
    • UNKNOWN — Validation was inconclusive — typically because the domain is a catch-all.
    • NOT_FOUND — No email could be discovered for this lead.
  • Email type (string, always uppercase):
    • COMPANY — Tied to the company domain.
    • PERSONAL — A personal email address (e.g., Gmail, Yahoo).

Sync usage

curl -X POST "https://api.sixtyfour.ai/find-email" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lead": {
      "name": "Sarah Chen",
      "company": "Pacific View Studios",
      "title": "Creative Director & Lead Photographer",
      "linkedin": "https://www.linkedin.com/in/sarah-chen-photography"
    },
    "mode": "PERSONAL"
  }'

Async pattern

For production workflows, use /find-email-async to submit a job and poll for results. This avoids long-lived HTTP connections and lets you parallelize many lookups without blocking your client. The flow is:
  1. SubmitPOST /find-email-async with the same body as the sync endpoint. Response includes a task_id.
  2. PollGET /job-status/{task_id} until status is completed, failed, or cancelled.
  3. Read result — When completed, the discovered emails are in the result field, in the same shape as the sync response.
The async start endpoint returns uppercase RUNNING. Subsequent /job-status/{task_id} calls return lowercase statuses. charge_amount is returned in cents, not credits.

Polling example

import requests
import time

response = requests.post(
    "https://api.sixtyfour.ai/find-email-async",
    headers={"x-api-key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
        "lead": {
            "name": "Sarah Chen",
            "company": "Pacific View Studios",
            "linkedin": "https://www.linkedin.com/in/sarah-chen-photography"
        },
        "mode": "PROFESSIONAL"
    }
)
response.raise_for_status()
task_id = response.json()["task_id"]

while True:
    status = requests.get(
        f"https://api.sixtyfour.ai/job-status/{task_id}",
        headers={"x-api-key": "YOUR_API_KEY"}
    ).json()

    if status["status"] == "completed":
        results = status["result"]
        break
    if status["status"] in ("failed", "cancelled"):
        raise RuntimeError(f"Job {status['status']}: {status.get('error', 'Unknown error')}")

    time.sleep(5)

Webhook callback

Pass a webhook_url to receive the result via HTTP POST instead of polling. The signed payload, retry behavior, and verification steps are documented in Outgoing Webhooks.
POST /find-email-async
{
  "lead": {
    "name": "Sarah Chen",
    "company": "Pacific View Studios",
    "linkedin": "https://www.linkedin.com/in/sarah-chen-photography"
  },
  "webhook_url": "https://your-server.com/webhooks/sixtyfour"
}

Bulk processing

Use /find-email-bulk (sync) or /find-email-bulk-async (async) to process up to 100 leads in a single call. Both accept a leads array and the same mode, verify_emails, providers, and webhook_url fields as the single-lead endpoints.

Bulk sync

Returns 200 OK with results once every lead is processed. Best for small batches where you want a single round-trip.
curl -X POST "https://api.sixtyfour.ai/find-email-bulk" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      {
        "name": "Sarah Chen",
        "company": "Pacific View Studios",
        "linkedin": "https://www.linkedin.com/in/sarah-chen-photography"
      },
      {
        "name": "John Doe",
        "company": "Example Corp",
        "linkedin": "https://linkedin.com/in/johndoe"
      }
    ],
    "mode": "PROFESSIONAL"
  }'

Bulk async

Submit a batch, get back a task_id, then poll /job-status/{task_id} (or set webhook_url to receive a callback). Recommended for batches of more than a handful of leads, or when you don’t want to hold a long-lived HTTP connection.
import requests
import time

response = requests.post(
    "https://api.sixtyfour.ai/find-email-bulk-async",
    headers={"x-api-key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
        "leads": [
            {
                "name": "Sarah Chen",
                "company": "Pacific View Studios",
                "linkedin": "https://www.linkedin.com/in/sarah-chen-photography"
            },
            {
                "name": "John Doe",
                "company": "Example Corp",
                "linkedin": "https://linkedin.com/in/johndoe"
            }
        ],
        "mode": "PROFESSIONAL"
    }
)
response.raise_for_status()
task_id = response.json()["task_id"]

while True:
    status = requests.get(
        f"https://api.sixtyfour.ai/job-status/{task_id}",
        headers={"x-api-key": "YOUR_API_KEY"}
    ).json()

    if status["status"] == "completed":
        results = status["result"]
        break
    if status["status"] in ("failed", "cancelled"):
        raise RuntimeError(f"Job {status['status']}: {status.get('error', 'Unknown error')}")

    time.sleep(10)