URL: /code/data/people/find-email · Id: `page:/code/data/people/find-email`

# ContactPoint.findEmail

> Find a person’s work email from their name and company domain, or their profile URL, checked in the same call; a miss is free.

`POST https://api.sb/{your-domain}/contact-points/find-email`

Find a person’s work email from their name and company domain, or their profile URL, checked in the same call; a miss is free.

- **Price:** 0.45¢ an address found
- **Success rate:** 95% of 3,296,127 calls
- **Freshness:** Fresh for 90 days
- **Emits:** `ContactPoint.found`
- **Capability:** [Enrichment](https://startupbuilder.dev/systems/sales/enrichment)

```text title="Run it · Ask"
What is Dana Whitfield’s work email at harborview-pm.com? Check it and spend up to 2¢.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.ContactPoint.findEmail({ name: 'Dana Whitfield', hostname: 'harborview-pm.com', maxCost: 0.02 })
```

```json title="Run it · Response"
{
  "address": "dana@harborview-pm.com",
  "confidence": 0.93,
  "result": "deliverable",
  "observedAt": "2026-10-27T14:02:11Z",
  "method": "sampled",
  "cost": {
    "usd": 0,
    "maxUsd": 0.02,
    "units": 2,
    "misses": 1
  }
}
```

## Inputs
| Name | Type | Meaning |
| --- | --- | --- |
| `name` | `string` | The person’s full name; pass it with `hostname`. Or pass `firstName` and `lastName`, or `profileUrl`. |
| `hostname` | [`Hostname`](/code/data/types#hostname) | Their company’s domain. A name without it is refused with `input-missing`. |
| `profileUrl` | `string` | Their LinkedIn profile URL. It finds more addresses than a name does. |
| `check` | `boolean` | Check the mailbox on a hit, in the same call, at the check’s own price. Default `true`. |
| `maxCost` | `number` | The most this person may cost, in USD. Routes are walked cheapest first and stop here. Default `0.02`. |

## Outputs
| Field | Type | What `null` means |
| --- | --- | --- |
| `address` | `string \| null` | No route found an address: a miss, and free. |
| `confidence` | `number \| null`, in score 0 to 1 | No address, or the route gives no confidence. |
| `result` | [`EmailResult \| null`](/code/data/types#emailresult) | No address, or `check: false`. |
| `observedAt` | `string`, in ISO 8601 | Never null. |
| `method` | `Observed['method']` | Never null. |
| `cost` | [`Cost`](/code/data/types#cost), in USD | Never null. In try mode `usd` is 0 and `maxUsd` is what the call would have cost. |

## Read the result
| Field | Value | What it means | What to do |
| --- | --- | --- | --- |
| `address` | `null` from a name | Name-and-domain routes find an address about a third of the time each; a profile URL finds more. | Pass `profileUrl` from `Prospect.find` and try again; the miss cost nothing. (measured hit rates by route: 42% from a profile URL, 31% to 37% from a name) |
| `result` | `catch-all` | The address may be right, but the domain accepts everything. | Send it in the catch-all batch, at most 20% of a day’s sends. (our planning number for cold email) |
| `address` | A domain other than `hostname` | An address at a previous employer: 4 of 48 first finds did this in one live run of 136 calls. | Drop it before the check; find them again from a current profile URL. (a measured run, 8% of first finds) |
| `confidence` | Under 0.7 with no `result` | A guessed pattern, unchecked. | Never send an unchecked address: pass `check: true`. (reviews of unchecked finds: 73 of one team’s 79 bounces were unchecked rows) |

## Effects
**Action class**

None: it reads, so no approval rule names it

**Modes**

- `try`: Runs the read and returns real rows; nothing is saved and nothing is billed.
- `send`: Returns a pending Action at once; its Event carries the rows when the read finishes.
- `do`: Waits for the read and returns the rows, billed per result.

**Idempotency**

The same `Idempotency-Key` with the same input replays the first answer at $0; with other input it returns 409.

**Saved or shared**

Nothing is written to your records; pass it to `Contact.import` to keep it. Readings about people are never shared across startups.

**Emits**

`ContactPoint.found` with `{ address, confidence, result }`

**Performed by**

[Prospector](https://startupbuilder.dev/agents/sales/prospector)

**Price**

About 0.45¢ an address found. At most 2¢ an address found. Free: a miss: no address found. `maxCost` defaults to 2¢. 100 work emails found: 100 × 0.45¢ an address found is about 45¢.

**Reliability**

The first route succeeds 95% of 3,296,127 calls. If it fails, the call refuses with `sources-busy` and nothing is spent.

**Freshness**

A reading younger than 90 days returns at $0. Readings about people are never shared across startups.

**Batch and pages**

Up to 1 person a call. It answers in one response.

**Rate**

[The shared rate rules](/code/data#rate): 10 calls a second per key, and an array input counts as one call.

## Refuses when
This call has no refusals of its own. Every data call can also meet [the shared data-call refusals](/code/refusals#data-calls): [`filter-unsupported`](/code/refusals#filter-unsupported), [`input-missing`](/code/refusals#input-missing), [`limit-exceeded`](/code/refusals#limit-exceeded), [`max-cost`](/code/refusals#max-cost), [`rate-limited`](/code/refusals#rate-limited), [`sources-busy`](/code/refusals#sources-busy), [`venue-unsupported`](/code/refusals#venue-unsupported).

## When it waits
Returns in one response; nothing waits.

## Example

**Ask**

```text
What is Dana Whitfield’s work email at harborview-pm.com? Check it and
spend up to 2¢.
```

**API**

```bash
curl -X POST "https://api.sb/leaseline.app/contact-points/find-email?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","hostname":"harborview-pm.com","maxCost":0.02}'
```

The response is the one in the Run it window above.

**CLI**

```bash
npx startup-builder do ContactPoint.findEmail --try --data '{"name":"Dana Whitfield","hostname":"harborview-pm.com","maxCost":0.02}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.ContactPoint.findEmail({ name: 'Dana Whitfield', hostname: 'harborview-pm.com', maxCost: 0.02 })"
  }
}
```

**SDK**

```ts
import { $ } from 'startup-builder'

const result = await $.try.ContactPoint.findEmail({
  name: 'Dana Whitfield',
  hostname: 'harborview-pm.com',
  maxCost: 0.02,
})
```

To retry, send the same `Idempotency-Key`: the retry returns the first answer for $0. A new key reads again.

A `sk_test_` key answers these the same way every time, at $0 ([every test value](/code/data#test-values)).

| Test value | Always returns | What it is for |
| --- | --- | --- |
| `maxCost: 0.0001` | Refuses with [`max-cost`](/code/refusals#max-cost) | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
| `rate-limited.test` | Refuses with [`rate-limited`](/code/refusals#rate-limited) | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
| `sources-busy.test` | Refuses with [`sources-busy`](/code/refusals#sources-busy) | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |

## Used by
- **Workflows:** [Build a verified list](/capabilities/find-customers/build-a-verified-list) · [Pick who to sell to first](/capabilities/find-customers/pick-who-to-sell-to)
- **Agent tasks:** [Link pitches](/capabilities/earn-first-links/link-pitches)

## Related
[`Prospect.count`](/code/data/people/count) · [`Prospect.find`](/code/data/people/find) · [`Prospect.verify`](/code/data/people/verify) · [`ContactPoint.verifyEmail`](/code/data/people/verify-email) · [`ContactPoint.findPhone`](/code/data/people/find-phone) · [`Contact.enrich`](/code/data/people/enrich)