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

# Changelog

> Forager API changelog: dated updates to the API, Web App and documentation, including new endpoints, changed behavior and new guides.

![Forager API changelog: dated updates tagged API or Docs, with an RSS feed](https://mintcdn.com/forager/OnhSHNo_LBQ7yKjR/images/illustrations/forager-api-changelog-updates.svg?fit=max\&auto=format\&n=OnhSHNo_LBQ7yKjR\&q=85\&s=1343966c77eda9e8a2cb523afd452417)

New endpoints, behavior changes and fixes in the Forager API, the Forager Web App and these docs, newest first. Filter by tag (API, Web App or Docs, and New, Improvement, Breaking or Fix), or subscribe with the [RSS feed](https://www.forager.ai/docs/changelog/rss.xml).

**2026-10-06**

Find a person's work email and check that it is deliverable, charged only when an address is found.

## Work email lookup v2

![Work email lookup v2: name and domain or a LinkedIn identifier go in, a 202 job id comes back, and polling or a webhook returns a found work email](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-work-email-lookup-v2-async.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=c953c383a1aa222b3469a285589ae701)

The new [work email lookup](https://www.forager.ai/docs/openapi/work-emails) finds a person's work address and checks that it is deliverable before you are charged. Send a `POST` to `/api/v2/{account_id}/datastorage/person_contacts_lookup/work_emails/` and you get a job id back right away.

### Why it matters

* **Pay only for results**: credits are charged once, and only when an address is found. Polling is free.
* **Two ways to identify a person**: `first_name`, `last_name` and `domain` together, or a `linkedin_public_identifier` alone, in which case Forager uses the person's name and current employer from its dataset.
* **Nothing waits on verification**: the lookup runs asynchronously, so your app, job runner or agent never holds a connection open while an address is verified.

### How to use it

Submit the person, then poll `status_check_url` or pass a `webhook_url` to be called when the job finishes.

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://api-v2.forager.ai/api/v2/$FORAGER_ACCOUNT_ID/datastorage/person_contacts_lookup/work_emails/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name": "Jane", "last_name": "Doe", "domain": "example.com"}'
```

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

resp = requests.post(
    f"https://api-v2.forager.ai/api/v2/{os.environ['FORAGER_ACCOUNT_ID']}/datastorage/person_contacts_lookup/work_emails/",
    headers={"X-API-KEY": os.environ["FORAGER_API_KEY"]},
    json={"first_name": "Jane", "last_name": "Doe", "domain": "example.com"},
)
job = resp.json()  # 202 Accepted
```

```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const resp = await fetch(
  `https://api-v2.forager.ai/api/v2/${process.env.FORAGER_ACCOUNT_ID}/datastorage/person_contacts_lookup/work_emails/`,
  {
    method: "POST",
    headers: { "X-API-KEY": process.env.FORAGER_API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ first_name: "Jane", last_name: "Doe", domain: "example.com" }),
  },
);
const job = await resp.json(); // 202 Accepted
```

```json 202 submit (illustrative) theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "job_id": "6f1c2a4e-8b37-4d0e-9a51-3c7e2b9d1f08",
  "status": "queued",
  "status_check_url": "https://api-v2.forager.ai/api/v2/1234/datastorage/person_contacts_lookup/work_emails/6f1c2a4e-8b37-4d0e-9a51-3c7e2b9d1f08/",
  "webhook_url": ""
}
```

```json 200 poll, completed (illustrative) theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "job_id": "6f1c2a4e-8b37-4d0e-9a51-3c7e2b9d1f08",
  "status": "completed",
  "result": "found",
  "emails": ["jane.doe@example.com"],
  "error_code": null,
  "person_id": 377104562,
  "submitted_lookup": {
    "first_name": "Jane",
    "last_name": "Doe",
    "domain": "example.com",
    "linkedin_public_identifier": ""
  },
  "date_created": "2026-10-21T14:02:31.000000Z",
  "date_completed": "2026-10-21T14:02:39.917000Z"
}
```

### Details

* **Job states**: `queued`, `running`, `awaiting_provider`, `completed` or `failed`. A finished job has `result` set to `found` or `not_found`. While a job runs, the `Retry-After` header says when to poll again.
* **Bulk**: send many people at once to the [bulk endpoint](https://www.forager.ai/docs/openapi/work-emails/v2_datastorage_person_contacts_lookup_work_emails_bulk_create.md). Duplicates in a batch collapse into one lookup, and a batch your balance can't cover is rejected with nothing charged.
* **Rate limits**: the single lookup is limited for interactive use. Use bulk for enrichment runs.

> [!TIP]
>
> Polling never uses credits, so poll as often as `Retry-After` allows.

[API reference](https://www.forager.ai/docs/openapi/work-emails) · [Find work emails in bulk](https://www.forager.ai/docs/guides/bulk-work-emails.md) · [Credits and pricing](https://www.forager.ai/docs/api-overview/credit-pricing.md)

**2026-09-24**

A person's current role now always comes first, then past roles by most recent end date.

## Roles return newest first

![A person's roles listed newest first: the current role, then past roles by most recent end date](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-person-roles-newest-first-order.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=c4fa31d9fe1648f207047cc981df8b2a)

The `roles` array on a person now comes back in a fixed order: the current role first, then past roles by most recent end date. The same request returns the same order every time.

### What changed

* **Before**: roles could come back in any order, and the order could differ between identical calls.
* **After**: roles where `is_current` is `true` come first, then the rest by `end_date`, newest first.
* **Where**: [person detail lookup](https://www.forager.ai/docs/openapi/people/datastorage_person_detail_lookup_create.md), [reverse lookup by email](https://www.forager.ai/docs/openapi/people/datastorage_person_detail_reverse_lookup_by_email_create.md), [reverse lookup by phone number](https://www.forager.ai/docs/openapi/people/datastorage_person_detail_reverse_lookup_by_phone_number_create.md), and saved-list enrichment in the [Forager Web App](https://app.forager.ai).

```json roles (illustrative excerpt) theme={"theme":{"light":"github-light","dark":"github-dark"}}
"roles": [
  { "role_title": "Director of Data Engineering", "is_current": true,  "start_date": "2022-03-01", "end_date": null },
  { "role_title": "Senior Data Engineer",         "is_current": false, "start_date": "2017-06-01", "end_date": "2022-02-01" }
]
```

If you sorted roles yourself to find someone's current job, you can now read `roles[0]`. Nothing else in the response changed, and there is no change to credits or rate limits.

[Person detail lookup](https://www.forager.ai/docs/openapi/people/datastorage_person_detail_lookup_create.md) · [Enrich a contact](https://www.forager.ai/docs/guides/enrich-a-contact.md)

**2026-09-24**

Report a phone outcome without knowing who answered: is\_correct\_person is now optional.

## Phone feedback: is\_correct\_person is optional

![Phone feedback request with two required fields, phone\_number and contact\_status, and an optional is\_correct\_person shown as null](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-phone-feedback-optional-field.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=495d03d78e411c2d44d14fd71feb15bd)

On the [phone number feedback endpoint](https://www.forager.ai/docs/openapi/feedback/datastorage_feedback_phone_numbers_create.md), only `phone_number` and `contact_status` are required now. A dialer can report whether a number connected even when nobody confirmed who picked up.

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

### Details

* **`contact_status`**: `connected` or `disconnected`.
* **`is_correct_person`**: optional. Leave it out when you don't know, and it is stored as unknown and returned as `null`. That is different from `false`, which means the number reached someone else.
* **Limits**: the feedback endpoints are free and share 60 requests per minute per account.

[Phone number feedback](https://www.forager.ai/docs/openapi/feedback/datastorage_feedback_phone_numbers_create.md) · [Report bad data](https://www.forager.ai/docs/guides/report-bad-data.md)

**2026-07-09**

Autocomplete endpoints now need your API key and an account-scoped path, like every other endpoint.

## Autocomplete requires an API key

![Autocomplete call with an account-scoped path and an X-API-KEY header, limited to 10 requests per second per account](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-autocomplete-api-key-account-scope.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=2f80b90ff4c0200fecc96e9074c590df)

> [!WARNING]
>
> Since 2026-07-09, the [autocomplete endpoints](https://www.forager.ai/docs/openapi/autocomplete) need your API key and the account-scoped path. The old unauthenticated paths are deprecated and will be removed, so move any calls that still use them.

The six endpoints that turn a text value into a filter ID (industries, locations, organizations, organization keywords, person skills and web technologies) now work like every other Forager endpoint: authenticated, account-scoped and rate limited.

### What changed

* **Path**: `/api/{account_id}/datastorage/autocomplete/<type>/`.
* **Auth**: send your key in the `X-API-KEY` header. A missing or invalid key returns `403`.
* **Rate limit**: 10 requests per second per account. Above that you get `429`.
* **Responses**: unchanged, still `results` with `id` and `text`, and `pagination.more`. Autocomplete stays free.

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

```json Response (illustrative) theme={"theme":{"light":"github-light","dark":"github-dark"}}
{ "results": [{ "id": "2950159", "text": "Berlin, Germany" }], "pagination": { "more": false } }
```

### Migrate

**1. Find old calls**

Search your code for autocomplete requests that don't send `X-API-KEY`.

**2. Add your Account ID and key**

Put your Account ID in the path and send the `X-API-KEY` header.

**3. Debounce and handle 429**

Call autocomplete at most 10 times per second, for example by debouncing typing, and back off when you get `429`.

[Autocomplete reference](https://www.forager.ai/docs/openapi/autocomplete) · [Find filter values](https://www.forager.ai/docs/guides/find-filter-values.md) · [Errors and rate limits](https://www.forager.ai/docs/errors-and-rate-limits.md)

**2026-07-01**

Personal email lookups now return consumer mailbox addresses only, and charge nothing when none are left.

## Personal email returns consumer addresses only

![Personal email filter: webmail addresses are returned, work and school addresses are dropped](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-personal-email-consumer-addresses-only.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=1825b46cb7c9fd43a8cab5091eb34db0)

The [personal email lookup](https://www.forager.ai/docs/openapi/personal-emails) now returns only addresses on free webmail and consumer providers such as Gmail, Outlook, Yahoo, iCloud and Proton. You get the inbox a person reads at home, not a stale work address.

### What changed

* **Left out**: corporate, educational (`.edu`, `.ac.uk`) and other custom domains. Use the [work email lookup](https://www.forager.ai/docs/openapi/work-emails) for work addresses.
* **Nothing left after filtering**: you get the same empty response as for a person with no personal emails, and no credits are charged.
* **Unchanged**: request and response formats. Each address still comes with `email_type` and `validation_status`.

```json Response (illustrative) theme={"theme":{"light":"github-light","dark":"github-dark"}}
[
  { "email": "jane.doe.home@gmail.com", "email_type": "personal", "validation_status": "valid" }
]
```

[Personal email lookup](https://www.forager.ai/docs/openapi/personal-emails) · [Enrich a contact](https://www.forager.ai/docs/guides/enrich-a-contact.md)

**2026-06-17**

Tell Forager which phone numbers and emails worked, so contact data gets better with use.

## Contact feedback endpoints

![Phone, personal email and work email feedback with connected or valid and disconnected or invalid outcomes, sent to Forager](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-contact-data-feedback-endpoints.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=5b1eb8b73288b5a0f7f672fad496ecc2)

Three new [feedback endpoints](https://www.forager.ai/docs/openapi/feedback) let you report what happened when you used a phone number, personal email or work email from Forager. Send a `POST` with the contact and its outcome after a call or a send.

### Why it matters

* **Close the loop from your dialer or sequencer**: report outcomes automatically, right after each call or bounce.
* **Flag the wrong person, not just a dead contact**: `is_correct_person` separates "this number works but it isn't Jane" from "this number is dead".
* **Free**: feedback requests don't use credits.

### How to use it

```bash Phone theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://api-v2.forager.ai/api/$FORAGER_ACCOUNT_ID/datastorage/feedback/phone_numbers/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone_number": "+12025550142", "contact_status": "disconnected", "person_id": 377104562}'
```

```bash Work email theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://api-v2.forager.ai/api/$FORAGER_ACCOUNT_ID/datastorage/feedback/work_emails/" \
  -H "X-API-KEY: $FORAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "jane.doe@example.com", "contact_status": "invalid", "is_correct_person": true}'
```

### Details

* **Endpoints**: [`phone_numbers`](https://www.forager.ai/docs/openapi/feedback/datastorage_feedback_phone_numbers_create), [`personal_emails`](https://www.forager.ai/docs/openapi/feedback/datastorage_feedback_personal_emails_create) and [`work_emails`](https://www.forager.ai/docs/openapi/feedback/datastorage_feedback_work_emails_create).
* **`contact_status`**: `connected` or `disconnected` for phones, `valid` or `invalid` for emails.
* **Optional**: `is_correct_person`, `person_id` and `name`.
* **Response**: `201` with the stored record, its `id` and `date_created`.
* **Rate limit**: 60 requests per minute per account, shared by the three endpoints.

[Feedback reference](https://www.forager.ai/docs/openapi/feedback) · [Report bad data](https://www.forager.ai/docs/guides/report-bad-data.md)

**2025-12-03**

Profile identifiers with accented or other non-ASCII characters now match.

## LinkedIn identifiers with encoded characters

![A URL-encoded LinkedIn identifier is decoded to an accented name and matched to a person](https://mintcdn.com/forager/EGsWCxLOYv1Cb__c/images/illustrations/changelog-linkedin-encoded-identifiers-support.svg?fit=max\&auto=format\&n=EGsWCxLOYv1Cb__c\&q=85\&s=f9aa5a089b9ac2c8a4fbc2ded94a57d2)

`linkedin_public_identifier` values that contain URL-encoded UTF-8 characters, such as `jos%C3%A9-garc%C3%ADa` for an accented name, are now accepted and matched. Before, they failed to match. No action needed: send the identifier as it appears in the profile URL.

[Person detail lookup](https://www.forager.ai/docs/openapi/people/datastorage_person_detail_lookup_create.md)


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