> Reverse Contact API documentation. This is the Markdown copy of https://docs.reversecontact.com/use-cases/get-a-work-email-or-phone
> Every page is listed at https://docs.reversecontact.com/llms.txt, every endpoint with its credit cost and status at https://docs.reversecontact.com/catalog.json

# Get a work email or a phone number

> Find a work email or phone number from a Social profile URL with the API. Poll async results, check credit costs and verify existing email addresses.

- Last verified: 2026-11-04

Find a work email or phone number from a Social profile URL, a person id, or a full name with a company domain. The lookup runs in the background, so save the job id and poll for the result. You can also verify an email address from another source.

## Which endpoint

| Input you have | Endpoint | Cost | Mode |
| --- | --- | --- | --- |
| Profile URL, person id, or name and company domain | [Find Email](https://docs.reversecontact.com/endpoints/contact-email) | 3 credits for a professional email, 5 for a personal one, 8 when an `any` lookup finds both. A lookup with no match is free | Asynchronous |
| Profile URL, person id, or name and company domain | [Find Phone](https://docs.reversecontact.com/endpoints/contact-phone) | 20 credits when at least one number is found. A lookup with no match is free | Asynchronous |
| An email address to check | [Verify Email](https://docs.reversecontact.com/endpoints/contact-email-verify) | 1 credit per verdict, including `unknown`. A failed check is refunded | Asynchronous |

## How it works

Set `RC_API_KEY` to your [API key](https://docs.reversecontact.com/authentication). Install the [TypeScript SDK](https://docs.reversecontact.com/sdk/javascript), [Python SDK](https://docs.reversecontact.com/sdk/python) or [CLI](https://docs.reversecontact.com/guides/cli) for your chosen example. The cURL examples also use `jq`.

### Start the lookup

Send a profile `url` to Find Email, or replace `url` with `fullName: "Jane Doe"` and `companyDomain: "acme.com"`. Set `emailType: "professional"` to find a work email.

For a phone lookup, use `/v2/contact/phone`, `client.contact.findPhone()` or `client.contact.find_phone()` with the same identity fields. Omit `emailType`.

**Code Examples**

```bash [cURL]
curl --fail-with-body -sS -X POST https://api.reversecontact.com/v2/contact/email \
  -H "Authorization: Bearer $RC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.social.com/in/janedoe", "emailType": "professional"}' > contact-job.json
export WEBHOOK_ID=$(jq -er .data.webhookId contact-job.json)
printf 'Save this job id: %s\n' "$WEBHOOK_ID"
# For a phone instead, post to /v2/contact/phone without emailType.
```
```typescript [TypeScript SDK]
import ReverseContact from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const job = await client.contact.findEmail({
  url: "https://www.social.com/in/janedoe",
  emailType: "professional"
});
// For a phone instead: client.contact.findPhone({ url: "https://www.social.com/in/janedoe" })
console.log("Save this job id:", job.id);
```
```python [Python SDK]
import os

from reversecontact import ReverseContact

with ReverseContact(api_key=os.environ["RC_API_KEY"]) as client:
    job = client.contact.find_email(
        url="https://www.social.com/in/janedoe", email_type="professional"
    )
    # For a phone instead: client.contact.find_phone(url="https://www.social.com/in/janedoe")
    print("Save this job id:", job.id)
```
```bash [CLI]
rc contact email --url https://www.social.com/in/janedoe --json > contact-job.json
export WEBHOOK_ID=$(jq -er .data.webhookId contact-job.json)
printf 'Save this job id: %s\n' "$WEBHOOK_ID"
# For a phone instead: rc contact phone --url https://www.social.com/in/janedoe
```

### Wait for the result

Set the `WEBHOOK_ID` environment variable to the id from the first step. When the job completes, retrieve the email or phone array from `data.result`. Each entry contains `value` and `type`.

Polling is free and recommended. For optional push delivery, pass `webhookUrl` when starting the lookup and follow the [Webhooks guide](https://docs.reversecontact.com/guides/webhooks).

**Code Examples**

```bash [cURL]
while :; do
  result=$(curl --fail-with-body -sS --max-time 30 \
    "https://api.reversecontact.com/v2/webhooks/$WEBHOOK_ID?wait=20" \
    -H "Authorization: Bearer $RC_API_KEY") || break
  case "$(printf '%s' "$result" | jq -r '.data.status')" in
    succeeded) printf '%s' "$result" | jq '.data.result'; break ;;
    errored) printf '%s' "$result" | jq '.data | {errorCode, creditsConsumed}'; break ;;
    created|in_progress) sleep 2 ;;
    *) printf '%s\n' "$result"; break ;;
  esac
done
```
```typescript [TypeScript SDK]
import ReverseContact, { JobFailedError } from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const jobId = process.env.WEBHOOK_ID;
if (!jobId) throw new Error("Set WEBHOOK_ID to the saved job id");

try {
  const done = await client.jobs.wait(jobId);
  console.log(done.data.result, "credits:", done.data.creditsConsumed);
} catch (error) {
  if (error instanceof JobFailedError) {
    console.log("Lookup failed:", error.errorCode, "credits:", error.creditsConsumed);
  } else {
    throw error;
  }
}
```
```python [Python SDK]
import os

from reversecontact import JobFailedError, ReverseContact

with ReverseContact(api_key=os.environ["RC_API_KEY"]) as client:
    try:
        done = client.jobs.wait(os.environ["WEBHOOK_ID"])
        if done.data is not None:
            print(done.data.result, "credits:", done.data.credits_consumed)
    except JobFailedError as error:
        print("Lookup failed:", error.error_code, "credits:", error.credits_consumed)
```
```bash [CLI]
rc task "$WEBHOOK_ID" --wait --timeout 300
```

### Verify before you send

Use Verify Email if you want to check an address from a form, CRM or another source. Find Email already returns verified addresses, so you do not need to check those again. Poll the new job for `data.result.status`, one of `valid`, `risky`, `invalid` or `unknown`.

**Code Examples**

```bash [cURL]
curl --fail-with-body -sS -X POST https://api.reversecontact.com/v2/contact/email/verify \
  -H "Authorization: Bearer $RC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "jane.doe@acme.com"}' > verify-job.json
WEBHOOK_ID=$(jq -er .data.webhookId verify-job.json)
printf 'Save this job id: %s\n' "$WEBHOOK_ID"

while :; do
  result=$(curl --fail-with-body -sS --max-time 30 \
    "https://api.reversecontact.com/v2/webhooks/$WEBHOOK_ID?wait=20" \
    -H "Authorization: Bearer $RC_API_KEY") || break
  case "$(printf '%s' "$result" | jq -r '.data.status')" in
    succeeded) printf '%s' "$result" | jq '.data.result'; break ;;
    errored) printf '%s' "$result" | jq '.data | {errorCode, creditsConsumed}'; break ;;
    created|in_progress) sleep 2 ;;
    *) printf '%s\n' "$result"; break ;;
  esac
done
```
```typescript [TypeScript SDK]
import ReverseContact, { JobFailedError } from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const job = await client.contact.verifyEmail({ email: "jane.doe@acme.com" });
console.log("Save this job id:", job.id); // resume after a restart with client.jobs.wait(id)

try {
  // Long polls until the job ends, 30 minutes at most by default.
  const done = await job.wait();
  console.log(done.data.result?.email, done.data.result?.status);
} catch (error) {
  if (error instanceof JobFailedError) console.log("Ended without a verdict:", error.errorCode, "credits:", error.creditsConsumed);
  else throw error;
}
```
```python [Python SDK]
import os

from reversecontact import JobFailedError, ReverseContact

with ReverseContact(api_key=os.environ["RC_API_KEY"]) as client:
    job = client.contact.verify_email(email="jane.doe@acme.com")
    print("Save this job id:", job.id)  # resume after a restart with client.jobs.wait(id)

    try:
        # Long polls until the job ends, 30 minutes at most by default.
        done = job.wait()
        if done.data and done.data.result:
            print(done.data.result.email, done.data.result.status)
    except JobFailedError as error:
        print("Ended without a verdict:", error.error_code)
```

## What it costs

Find Email charges for the kind of email found: **3 credits for a professional email**, **5 for a personal one**, and **8 when an `any` lookup finds both**. At job creation, `professional` debits 3 credits. For `personal` and `any`, the API debits 5, then adjusts the balance to the result. An `any` request needs at least 8 credits available before starting. A lookup that finds no email is refunded.

Find Phone costs **20 credits when at least one phone number is found**. A lookup with no match costs 0 credits.

Verify Email costs **1 credit per verdict**, including `unknown`. A failed check without a verdict is refunded.

Polling costs nothing. A webhook delivery failure remains billed when the lookup found contact data or verification produced a verdict.

> [!NOTE]
> 1,000 lookups that find 600 professional emails cost 600 × 3 = **1,800 credits**. The 400 that find nothing are refunded. Separately, 100 successful phone lookups cost **2,000 credits**, and checking 100 addresses from your CRM that each receive a verdict costs **100 credits**.

## Good to know

Live jobs can take tens of minutes. Save the job id before waiting, and resume polling the same id after a timeout instead of starting a new paid lookup.

The SDKs send an `Idempotency-Key` for contact calls. To retry across process restarts, save and reuse your own key with the same request. See [Find Email retries](https://docs.reversecontact.com/endpoints/contact-email#idempotency-key-header).

For a whole contact file, use [Bulk enrichment](https://docs.reversecontact.com/guides/bulk-enrichment) or [keep contacts in a List](https://docs.reversecontact.com/guides/lists). Follow the [rate limit guide](https://docs.reversecontact.com/guides/rate-limits) when sending many lookups.

## FAQ

### How do I find a work email from a Social profile URL with the API?

Send the profile `url` to `POST /v2/contact/email` with `emailType: "professional"`, then poll the returned job id. Find Email returns the address in `data.result`, with `value` and `type` for each email.

### How many credits does Find Email cost?

Find Email costs 3 credits when a professional email is found and 5 for a personal one. An `any` lookup costs 3, 5 or 8 credits, with 8 charged when both kinds are found. A lookup that finds no email is refunded.

### Do I need a webhook to get a work email or phone number?

No. Polling is the recommended way to retrieve Find Email and Find Phone results. Each poll costs 0 credits and needs no public HTTPS endpoint. For push delivery, pass `webhookUrl` in the request.

### Do I need to verify an email returned by Find Email?

No. Find Email already returns verified addresses. Use Verify Email to check an address from a form, CRM or another source. Each verdict costs 1 credit, including `unknown`.

### How much does finding a phone number cost?

Find Phone costs 20 credits when at least one phone number is found. A lookup with no match costs 0 credits, and reading the job result by polling is free.
