> ## Documentation Index
> Fetch the complete documentation index at: https://docs.seamless.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Email → Profile

> Turn a work or personal email address into a full B2B profile: name, title, company, seniority, phones, LinkedIn, and job history.

> [!NOTE]
>
> **Endpoint** `POST /contacts/research` · **Credits** 1 per email · **Delivery** async (poll or webhook) · **Versions** v1, v2

## Introduction

Send an email address and get back the person behind it: full name, current title and company, seniority, department, location, LinkedIn profile, direct dials, mobile numbers, other emails, and job history. Use it to enrich inbound leads, clean CRM records, and route form fills.

There are two ways to resolve an email:

| Option | Endpoint | Returns | Cost |
| - | - | - | - |
| **Full profile** (recommended) | `POST /contacts/research` with `contacts[].email` | Complete record including phones | 1 credit per email |
| **Profile preview** (v2) | `POST /v2/search/contacts` with `emailAddress` | Name, title, company, location, `searchResultId`. No phones. Up to 100 emails per call. | Charged per results returned |

## AI agent prompt

```text theme={null}
Read https://docs.seamless.ai/llms.txt and https://docs.seamless.ai/api-catalog/email-to-profile.
Using my Seamless.AI API key from SEAMLESS_API_KEY, write a function that takes an email address,
calls POST https://api.seamless.ai/api/client/v1/contacts/research with {"contacts":[{"email": <email>}]},
polls GET /contacts/research/poll?requestIds=<requestId> every 3 seconds until status is done,
and returns the contact's name, title, company, phones, and LinkedIn URL.
```

## Authentication

Send your API key in the `Token` header, or `Authorization: Bearer <token>` with [OAuth](/authentication/oauth). Create a key under [Settings → Public API](/authentication/api-keys).

## Example

```bash cURL theme={null}
curl -X POST https://api.seamless.ai/api/client/v1/contacts/research \
  -H "Token: $SEAMLESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contacts": [ { "email": "jane.doe@acme.com" } ] }'
```

```python Python theme={null}
import os, time, requests

BASE = "https://api.seamless.ai/api/client/v1"
H = {"Token": os.environ["SEAMLESS_API_KEY"]}

def email_to_profile(email):
    r = requests.post(f"{BASE}/contacts/research", headers=H,
                      json={"contacts": [{"email": email}]}).json()
    request_id = r["requestIds"][0]
    while True:
        p = requests.get(f"{BASE}/contacts/research/poll", headers=H,
                         params={"requestIds": request_id}).json()["data"][0]
        if p["status"] not in ("queued", "researching"):
            return p
        time.sleep(3)

print(email_to_profile("jane.doe@acme.com")["contact"])
```

```javascript Node.js theme={null}
const BASE = "https://api.seamless.ai/api/client/v1";
const H = { Token: process.env.SEAMLESS_API_KEY, "Content-Type": "application/json" };

const { requestIds } = await (await fetch(`${BASE}/contacts/research`, {
  method: "POST", headers: H,
  body: JSON.stringify({ contacts: [{ email: "jane.doe@acme.com" }] }),
})).json();

let result;
do {
  await new Promise((r) => setTimeout(r, 3000));
  result = (await (await fetch(`${BASE}/contacts/research/poll?requestIds=${requestIds[0]}`, { headers: H })).json()).data[0];
} while (["queued", "researching"].includes(result.status));
console.log(result.contact);
```

```bash Preview (v2) theme={null}
curl -X POST https://api.seamless.ai/api/client/v2/search/contacts \
  -H "Token: $SEAMLESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emailAddress": ["jane.doe@acme.com", "sam@globex.com"] }'
```

The research call returns `202` with one entry in `requestIds` per contact. Poll each ID until `status` is no longer `queued` or `researching`, or receive results by [webhook](/receive-research-results-with-webhooks).

## Reference

| Parameter | Type | Required | Description |
| - | - | - | - |
| `contacts[].email` | string | Yes | Work or personal email address. Up to 500 contacts per request. |
| `listIds` | integer\[] | No | Add each researched contact to these Seamless lists. |
| `skipDeduplicationCheck` | boolean | No | Research again even if your org researched this contact recently. Uses credits. |

## Response

When `status` is `done`, `contact` holds the full record. Key fields:

| Field | Description |
| - | - |
| `fullName`, `jobTitle`, `seniority`, `department` | Who the person is and what they do |
| `companyName`, `companyDomain`, `companySize`, `companyIndustry` | Where they work |
| `email`, `email1`-`email3`, `email{n}EmailAI` | Emails with validation status |
| `contactPhone1`, `contactPhone1DataType`, `companyPhone1` | Direct dial or mobile, and company phone |
| `lIProfileUrl` | LinkedIn profile |
| `contactLocation`, `localTime` | Location and timezone |
| `jobHistory`, `startedAtCurrentCompany` | Tenure and prior roles |

See the [Data dictionary](/api-catalog/data-dictionary) for every field.

## Errors

| Status | Meaning |
| - | - |
| `401` | Missing or invalid API key |
| `422` | `insufficientCredits` or `missingLicense` |
| `429` | Rate limit reached. Wait until `X-RateLimit-Reset`. |
| Poll `not found` | No person matched the email. |

## Related

* [Phone → Profile](/api-catalog/phone-to-profile)
* [LinkedIn URL → Profile](/api-catalog/linkedin-to-profile)
* [Contact Research API](/api-catalog/contact-enrichment)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.