URL: /code/data/people/count · Id: `page:/code/data/people/count`

# Prospect.count

> Count the people who match your titles and companies, and how many have a work email on file, free.

`GET https://api.sb/{your-domain}/prospects/count`

Count the people who match your titles and companies, and how many have a work email on file, free.

- **Price:** Free
- **Success rate:** 100% of 2,861,763 calls
- **Freshness:** Fresh for 7 days
- **Emits:** `Prospect.counted`
- **Capability:** [Enrichment](https://startupbuilder.dev/systems/sales/enrichment)

```text title="Run it · Ask"
How many property managers and owners work at US property management companies with 20 to 200 staff? Spend nothing.
```

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

const result = await $.try.Prospect.count({ where: { titles: ['property manager', 'owner'], organizationWhere: { industries: ['property management'], headcount: { min: 20, max: 200 }, countries: ['US'] } }, maxCost: 0 })
```

```json title="Run it · Response"
{
  "count": 6120,
  "withEmail": 3910,
  "ignored": [],
  "observedAt": "2026-10-27T14:02:11Z",
  "method": "estimated"
}
```

## Inputs
| Name | Type | Meaning |
| --- | --- | --- |
| `icp` | `string` | An ICP id; its Persona fills `where`. Pass this or `where`. |
| `where` | [`ProspectFilter`](/code/data/types#prospectfilter) | Titles, seniority, departments, locations, countries, the companies they work at, and `organizationWhere` for the company filters. |
| `kind` | `'person' \| 'creator'` | Count creators by audience instead of people by role. Default `'person'`. |
| `strict` | `boolean` | Refuse with `filter-unsupported`, at $0, instead of listing an unapplied filter in `ignored`. Default `false`. |

## Outputs
| Field | Type | Unit | What `null` means |
| --- | --- | --- | --- |
| `count` | `number` | people | Never null: 0 means no one matched. |
| `withEmail` | `number \| null` | people | The source does not say how many have a work email on file. |
| `ignored` | `string[]` | None. | Never null: empty when every filter you sent was applied. |
| `observedAt` | `string` | ISO 8601 | Never null. |
| `method` | `Observed['method']` | None. | Never null; counts read `'estimated'`. |

## Read the result
| Field | Value | What it means | What to do |
| --- | --- | --- | --- |
| `withEmail` | Under half of `count` | Many of these people will cost a find that misses, which is free, before one that hits. | Plan reach from `withEmail`, not `count`. (the free-miss rule) |
| `count` | Under 900 | At 400 new contacts a month the audience lasts about 2 months. | Widen the titles with `similarTitles`, or add a second role at the same companies. (list saturation math, our planning number) |
| `ignored` | `departments` listed | Department is the people filter routes take least often, about 1 call in 5, so the count is wider than asked. | Put the department words into `titles`, which routes apply on 99% of calls. (filter coverage, measured across 9,229,085 people-search calls) |

## Effects
**Action class**

None: it reads, so no approval rule names it

**Modes**

- `try`: Counts and stores nothing; a count is free in every mode.
- `send`: Returns a pending Action at once; its Event carries the rows when the read finishes.
- `do`: Waits for the count; a count is free in every mode.

**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. A count names no one, so it is shared across startups for the same filters for 7 days.

**Emits**

`Prospect.counted` with `{ count, withEmail, where }`

**Performed by**

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

**Price**

Free. Free: every count, in every mode.

**Reliability**

The first route succeeds 100% of 2,861,763 calls. If it fails, a second route answers at 99.1% of 30,491 calls, and you pay for one.

**Freshness**

A reading younger than 7 days returns at $0. Readings are shared across startups for the same subject and locale.

**Batch and pages**

Up to 1 filter set 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
| Check | Error | Fix | Then call |
| --- | --- | --- | --- |
| A call sent with `strict: true` and a filter no route can apply | [`filter-unsupported`](/code/refusals#filter-unsupported) | Drop that filter, or send without `strict` and read what comes back in `ignored`. | [`Organization.count`](/code/data/organizations/count) |

Every data call can also meet [the shared data-call refusals](/code/refusals#data-calls): [`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).

```json
{
  "type": "https://startupbuilder.dev/errors/filter-unsupported",
  "title": "No route can apply a filter you sent",
  "status": 422,
  "detail": "A call sent with `strict: true` and a filter no route can apply.",
  "fix": "Drop that filter, or send without `strict` and read what comes back in `ignored`.",
  "next": {
    "verb": "Organization.count",
    "input": {
      "where": {
        "industries": [
          "property management"
        ],
        "headcount": {
          "min": 20,
          "max": 200
        },
        "countries": [
          "US"
        ]
      }
    }
  },
  "instance": "https://api.sb/leaseline.app/actions/action_1"
}
```

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

## Example

**Ask**

```text
How many property managers and owners work at US property management
companies with 20 to 200 staff? Spend nothing.
```

**API**

```bash
curl -G "https://api.sb/leaseline.app/prospects/count" \
  -H "Authorization: Bearer $SB_TOKEN" \
  --data-urlencode "mode=try" \
  --data-urlencode 'where={"titles":["property manager","owner"],"organizationWhere":{"industries":["property management"],"headcount":{"min":20,"max":200},"countries":["US"]}}' \
  --data-urlencode 'maxCost=0'
```

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

**CLI**

```bash
npx startup-builder do Prospect.count --try --data '{"where":{"titles":["property manager","owner"],"organizationWhere":{"industries":["property management"],"headcount":{"min":20,"max":200},"countries":["US"]}},"maxCost":0}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Prospect.count({ where: { titles: ['property manager', 'owner'], organizationWhere: { industries: ['property management'], headcount: { min: 20, max: 200 }, countries: ['US'] } }, maxCost: 0 })"
  }
}
```

**SDK**

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

const result = await $.try.Prospect.count({
  where: { titles: ['property manager', 'owner'], organizationWhere: { industries: ['property management'], headcount: { min: 20, max: 200 }, countries: ['US'] } },
  maxCost: 0,
})
```

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
None.

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