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

> ## Agent Instructions
> Forager is a REST API for B2B people, company and job post data: contact lookups (phone numbers, personal emails, work emails), person, company and job post search, and bulk data feeds.
> Server: https://api-v2.forager.ai. Send the API key in the X-API-KEY header. Most paths include {account_id}. Read FORAGER_API_KEY and FORAGER_ACCOUNT_ID from the environment; never put the key in client-side code, logs or prompts.
> To add Forager to a project, follow https://www.forager.ai/docs/guides/agent-quickstart.md. To pick an endpoint, read https://www.forager.ai/docs/guides/choose-an-endpoint.md. For end-to-end builds, see https://www.forager.ai/docs/recipes/overview.md.
> Most requests spend credits. Do not guess costs; use https://www.forager.ai/docs/api-overview/credit-pricing.md and ask the user before spending credits.
> Use only endpoints and fields defined in https://www.forager.ai/docs/openapi.yaml. Forager has no MCP server for the API yet; the /mcp endpoint on this site searches the documentation only.

# Build a prospect list by role and company

> Search people by job title and company filters, resolve filter IDs with autocomplete, then look up contacts only for the people you keep.

```text Recipe prompt theme={"theme":{"light":"github-light","dark":"github-dark"}}
Implement this recipe in my project: https://www.forager.ai/docs/recipes/prospect-list.md

Build a prospect list builder. Resolve industry names to IDs with the Forager industries autocomplete, then run a person role search with a title, role_is_current set to true and those industry IDs, paging with the page field. Let the user review the people, then look up phone numbers only for those they keep. Handle empty results, a 403, and a 429 with backoff on both search and autocomplete, and cache autocomplete IDs. Keep the API key server-side in FORAGER_API_KEY with FORAGER_ACCOUNT_ID. Add tests that stub the HTTP calls.
```

![Build a prospect list: role, company and location filters produce a list of people](https://mintcdn.com/forager/OnhSHNo_LBQ7yKjR/images/recipes/build-prospect-list-role-company.svg?fit=max\&auto=format\&n=OnhSHNo_LBQ7yKjR\&q=85\&s=1eb78300b14f41a9566995ae38075d55)

## What you'll build

A list builder with a review step. You describe the people you want by title and company industry. Forager returns matching people with their current role and company. You keep the ones you want and spend credits on contact data only for those.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart LR
  A[Industry name] --> B[Autocomplete IDs]
  B --> C[Role search]
  C --> D[Review list]
  D --> E[Contact lookup]
```

## Steps

**1. Resolve filter names to IDs**

Search filters take IDs, not names. Call [Industries lookup](https://www.forager.ai/docs/openapi/autocomplete/v1_industry_lookup.md) with `q`. The response has `results`, each with an `id` and `text`.

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -G "https://api-v2.forager.ai/api/$FORAGER_ACCOUNT_ID/datastorage/autocomplete/industries/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  --data-urlencode "q=software"
```

```python Python (requests) theme={"theme":{"light":"github-light","dark":"github-dark"}}
import os, requests

BASE = f"https://api-v2.forager.ai/api/{os.environ['FORAGER_ACCOUNT_ID']}/datastorage"
HEADERS = {"X-API-KEY": os.environ["FORAGER_API_KEY"]}

r = requests.get(f"{BASE}/autocomplete/industries/", headers=HEADERS, params={"q": "software"}, timeout=30)
r.raise_for_status()
industry_ids = [int(item["id"]) for item in r.json()["results"][:1]]
```

```javascript JavaScript (fetch) theme={"theme":{"light":"github-light","dark":"github-dark"}}
const BASE = `https://api-v2.forager.ai/api/${process.env.FORAGER_ACCOUNT_ID}/datastorage`;
const headers = {
  "X-API-KEY": process.env.FORAGER_API_KEY,
  "Content-Type": "application/json",
};

const res = await fetch(`${BASE}/autocomplete/industries/?q=software`, { headers });
if (!res.ok) throw new Error(`Forager ${res.status}`);
const industryIds = (await res.json()).results.slice(0, 1).map((item) => Number(item.id));
```

The `id` comes back as a string and the search expects integers, so convert it. Let the user pick the right match instead of taking the first. Other filters work the same way; see [Find filter values](https://www.forager.ai/docs/guides/find-filter-values.md).

**2. Search people by role**

Send a `POST` to [Person role search](https://www.forager.ai/docs/openapi/people/datastorage_person_role_search_create.md). `role_title` supports a boolean text query.

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://api-v2.forager.ai/api/$FORAGER_ACCOUNT_ID/datastorage/person_role_search/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role_title": "VP Sales", "role_is_current": true, "organization_industries": [123], "page": 1}'
```

```python Python (requests) theme={"theme":{"light":"github-light","dark":"github-dark"}}
r = requests.post(
    f"{BASE}/person_role_search/",
    headers=HEADERS,
    json={
        "role_title": "VP Sales",
        "role_is_current": True,
        "organization_industries": industry_ids,
        "page": 1,
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
people = [hit["person"] for hit in data["search_results"]]
```

```javascript JavaScript (fetch) theme={"theme":{"light":"github-light","dark":"github-dark"}}
const r = await fetch(`${BASE}/person_role_search/`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    role_title: "VP Sales",
    role_is_current: true,
    organization_industries: industryIds,
    page: 1,
  }),
});
if (!r.ok) throw new Error(`Forager ${r.status}`);
const data = await r.json();
const people = data.search_results.map((hit) => hit.person);
```

Each hit has `person` (with `id`, `full_name` and `linkedin_info`), `role_title`, and `organization` (with `name` and `domain`). `total_search_results` is the match count. Narrow by company with `organization_employees_start` and `organization_employees_end`, `organization_locations`, or `organization_domains`. To count matches first, use [Person role search totals](https://www.forager.ai/docs/openapi/people/datastorage_person_role_search_totals_create.md), which takes the same body.

**3. Look up contacts for the people you keep**

After review, call [Phone numbers lookup](https://www.forager.ai/docs/openapi/phones/datastorage_person_contacts_lookup_phone_numbers_create.md) once per kept person. Use [Personal emails lookup](https://www.forager.ai/docs/openapi/personal-emails/datastorage_person_contacts_lookup_personal_emails_create.md) the same way, or the [bulk work email lookup](https://www.forager.ai/docs/recipes/bulk-work-emails.md).

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://api-v2.forager.ai/api/$FORAGER_ACCOUNT_ID/datastorage/person_contacts_lookup/phone_numbers/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id": 123}'
```

```python Python (requests) theme={"theme":{"light":"github-light","dark":"github-dark"}}
kept = people[:5]  # replace with the people the user approved
numbers = {}
for person in kept:
    r = requests.post(f"{BASE}/person_contacts_lookup/phone_numbers/", headers=HEADERS, json={"person_id": person["id"]}, timeout=30)
    r.raise_for_status()
    numbers[person["id"]] = [row["phone_number"] for row in r.json()]
```

```javascript JavaScript (fetch) theme={"theme":{"light":"github-light","dark":"github-dark"}}
const kept = people.slice(0, 5); // replace with the people the user approved
const numbers = {};
for (const person of kept) {
  const r = await fetch(`${BASE}/person_contacts_lookup/phone_numbers/`, {
    method: "POST",
    headers,
    body: JSON.stringify({ person_id: person.id }),
  });
  if (!r.ok) throw new Error(`Forager ${r.status}`);
  numbers[person.id] = (await r.json()).map((row) => row.phone_number);
}
```

## Handle the edge cases

* **Not found.** If `search_results` is empty, tell the user and suggest loosening a filter. A person with no phone numbers returns an empty list.
* **403.** The key is missing or invalid. Fix the credentials; do not retry.
* **429.** Autocomplete allows 10 requests per second per account, so cache IDs. Back off on any 429. See [errors and rate limits](https://www.forager.ai/docs/errors-and-rate-limits.md).
* **Paging.** Request further pages with `page` until you have the number of hits in `total_search_results`.
* **Credits.** A role search costs 1 credit per request and a phone number lookup 15 credits per lookup. Autocomplete is free. See [credit pricing](https://www.forager.ai/docs/api-overview/credit-pricing.md).

## Related

> [card] [Search people by role](https://www.forager.ai/docs/guides/search-people-by-role.md)
>
> Every role search filter.

> [card] [Find filter values](https://www.forager.ai/docs/guides/find-filter-values.md)
>
> Which autocomplete feeds which filter.

> [card] [Search organizations](https://www.forager.ai/docs/guides/search-organizations.md)
>
> Start from companies instead of titles.


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