---
title: "Find people from public data"
method: POST
path: "/public/search"
tags: ["public"]
---

# Find people from public data

`POST /public/search`

Search for people through an anonymous public web search; no connected account is needed. Results are public data, never signed-in LinkedIn details (connection degree, who engaged with a post, whether someone is reachable by message). Found profiles are saved as contacts and render as a people list; narrate a one-line count. limit (1-300, default 15) is how many profiles ONE call targets: a specific number sets it, a volume word with no ceiling raises it toward 100-300. Pass every plausible title, seniority, or city as an array on the SAME filter field in ONE call. more:true continues the SAME filters past people already found. exhaustion:"axes-exhausted" means every angle was tried: suggest a real change, do not call more:true again. exhaustion:"batch-failed" is a temporary vendor hiccup. A signal that would show in a headline (years in role, a school, a tool, freelance) belongs in filters.keywords, not a visit-first pass. When they asked for somebody in particular rather than describing a crowd, pass their words as sentence ALONGSIDE the facets: that is what answers a named question directly instead of slicing a market. A result returns everybody it found, including people already in the contact list, marked completeness "already-a-contact": that is an ANSWER, never a reason to search again with other words. Asked who somebody is, name them and say they are already saved.

## Request body

- object
  - `filters` object, required — Search facets. Provide at least one of title, location, company, industry, or keywords.
    - `title` union — Role or job title facet. One value or a list of alternatives.
      - string
      - string[]
    - `location` union — City, region, or country facet. One value or a list of alternatives.
      - string
      - string[]
    - `company` union — Company name facet. One value or a list of alternatives.
      - string
      - string[]
    - `industry` union — Industry facet. One value or a list of alternatives.
      - string
      - string[]
    - `seniority` union — Seniority facet. One value or a list of alternatives.
      - string
      - string[]
    - `keywords` string — Free-text keywords appended to the search query.
    - `countryCode` string — ISO alpha-2 country code used to scope results to one country.
  - `limit` integer — Target number of profiles to return.
  - `save` boolean — When true, found profiles are saved to your contacts.
  - `chain` object — Optional two-step mode for DISCOVERING companies the caller does not already know by name (an industry, sector, or location ask): first find companies matching filters.industry/filters.location, then search this role inside each. Do NOT set this when specific companies are already named — pass them directly as filters.company instead (no chain needed): that searches those exact companies' roles directly, at lower cost and without a discovery step that can fail.
    - `role` string, required — Role searched inside each matched company.
    - `companiesLimit` integer — How many companies to search inside.
  - `more` boolean — Continue past the people an earlier search on these same filters already returned, instead of returning them again. What counts as already returned is the position the last search reached, kept server side.
  - `sentence` string — What the person actually asked, in their own words, when they asked for somebody in particular rather than describing a crowd: a named person, a role at a named organisation, everyone at one, or people who used to work there. Send it ALONGSIDE the facets, never instead of them. It is what lets the search answer a named question directly instead of slicing a market that has no such answer.

## Response `200`

Found and enriched people

- object
  - `source` 'public', required
  - `provider` string, required — The search provider that answered.
  - `query` string, required — The exact query sent, so a thin result set can be read rather than guessed at.
  - `existingCount` integer — How many of the people returned were already in your contacts. They ARE in `contacts` like everyone else, marked completeness "already-a-contact", and were not re-fetched because their profile was already read once. Absent when there were none. Not a reason to search again: the search already answered.
  - `askedFor` integer — How many results carry the words YOU typed, rather than the words the search expanded them into. Zero on a full result set that otherwise looks healthy is a strong caveat worth telling the reader about, most often meaning the job title or company named was not found. It is a caveat and not a verdict: a partial result, or a title nobody writes in a headline, can also read zero. Corroborate before saying the person or company does not exist.
  - `refused` 'nothing-to-search' | 'wants-companies' — Set when the request could not be searched at all. 'nothing-to-search' means nothing in it named anybody. 'wants-companies' means it asked for organisations, which this operation does not find: use the company search instead. Neither is a retry: say what happened and change the request.
  - `notFound` string[] — People you named by name that the search could not find. When this is set, no result is that person: say so rather than presenting the people returned as them.
  - `urlsFound` integer, required — Total profile URLs found.
  - `newUrls` integer, required — Profiles fetched on this call. People already in your contacts are returned too, from the search result, without being fetched again.
  - `hydrated` integer, required — Profiles fetched and enriched in this call.
  - `searches` integer — How many searches it took to find these people.
  - `searchesFailed` integer — Searches that did not reach the provider. When this is high the result says nothing about the market.
  - `moreAvailable` boolean — Whether asking again with more can still reach people you have not seen.
  - `exhaustion` 'more-available' | 'axes-exhausted' | 'batch-failed' — Finer than moreAvailable: 'axes-exhausted' means every search angle for this audience has genuinely been tried, calling again with more will not find anybody new. 'batch-failed' means this attempt could not reach the search provider, worth retrying. 'more-available' is the ordinary case.
  - `axesTried` object[] — What was actually tried, broken down by search angle, against what each angle could still do.
    - `axis` string, required — Which search angle this row covers, e.g. title, city, school, tool.
    - `queriesPlanned` integer, required — How many searches this angle could run in total.
    - `attempted` integer, required — How many of those have actually run so far.
    - `yielded` integer, required — New people this angle has contributed.
    - `exhausted` boolean, required — Whether this angle has nothing left to try.
  - `axesAvailable` object[] — Every search angle this audience supports and how many queries each could run — the full potential, whether or not it has been searched yet. Free to compute, no extra searches run to produce it.
    - `axis` string, required — A search angle this audience supports, e.g. title, city, school, tool.
    - `queries` integer, required — How many searches that angle could run in total.
  - `countryRiskNote` object — A non-blocking caveat about this market, e.g. a country whose profiles are hard to tell apart from a bigger anglophone one. Never a reason to withhold or shrink the result — surface it as a caution alongside the real count, never in place of one.
    - `risk` 'low' | 'medium' | 'high', required — How likely this country/title combination is to return false-positive matches from elsewhere.
    - `reason` string, required — Why, in plain language.
  - `rateLimited` integer — Profiles found but deferred because the scraping pool is busy.
  - `note` string — Explanation when part of the result set was deferred.
  - `contacts` object[], required
    - `name` string, nullable, required
    - `headline` string, nullable, required
    - `company` string, nullable, required
    - `location` string, nullable, required
    - `profileUrl` string, nullable, required
    - `completeness` string, required
    - `summary` string — The profile's About text, when the public page carried one.
    - `connections` integer — Connection count, when the public page carried one.
    - `imageUrl` string — The profile's display photo (from the public page's og:image), when the public page carried one. A raw LinkedIn CDN URL — may expire over time, unlike a re-hosted avatar.
    - `education` string — School name from the public page, when present.
    - `followers` integer — Public follower count from the preview page, when present. Not a login-only exact count.
    - `badge` string — Public profile badge from the preview page, when present.
    - `languages` string[] — Languages listed on the public preview page, when present.
    - `positions` object[] — Visible employers from the public preview page, when present.
      - `companyName` string, required
      - `title` string, nullable, required
      - `companyUrl` string, nullable, required
      - `startDate` object, nullable, required
        - `year` number, required
      - `endDate` object, nullable, required
        - `year` number, required
      - `isCurrent` boolean, required
    - `educations` object[] — Visible schools from the public preview page, when present.
      - `schoolName` string, required
      - `schoolUrl` string, nullable, required
      - `startDate` object, nullable, required
        - `year` number, required
      - `endDate` object, nullable, required
        - `year` number, required
    - `recentPosts` object[] — A sample of the person's own public feed posts from the preview page, when present. Search returns at most three; the saved contact keeps the fuller public list.
      - `url` string, nullable, required
      - `text` string, nullable, required
      - `likes` number, nullable, required
      - `datePublished` string, nullable, required

## Other responses

- `400` — The server cannot or will not process the request due to something that is perceived to be a client error.
- `401` — Although HTTP specifies "unauthorized", this response means "unauthenticated". Authenticate to continue. NOTE: 401 is also returned with code "linkedin_not_connected" when the caller IS authenticated but has no connected LinkedIn account — connect LinkedIn (not re-authenticate) to continue.
- `403` — The client does not have access rights to the content.
- `404` — The server cannot find the requested resource.
- `409` — The request conflicts with the current state of the server.
- `410` — The requested content has been permanently deleted from the server.
- `422` — The request was well-formed but was unable to be followed due to semantic errors.
- `429` — Rate limit exceeded. Read error.retryAfter for the wait time in seconds.
- `500` — The server encountered a situation it does not know how to handle.
- `502` — LinkedIn returned a server error or the proxy connection failed. Retry after a few seconds.
- `503` — Proxy capacity temporarily exceeded. Retry after a few seconds.

## Changes

> 8 revisions in range; 1 not diffed.

- **2026-08-24** `bc5eae2eb212` — 4 info
  - added the new optional request property `sentence`
  - added the optional property `askedFor` to the response with the `200` status
  - added the optional property `notFound` to the response with the `200` status
  - added the optional property `refused` to the response with the `200` status
- **2026-08-19** `1ad91026000b` — 2 warning, 21 info
  - removed the optional property `creditsUsed` from the response with the `200` status
  - removed the optional property `retryAfter` from the response with the `200` status
  - added the new optional request property `more`
  - added the optional property `axesAvailable` to the response with the `200` status
  - …19 more
- **2026-07-26** `463db127267a` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/berea/apis/bereach-api/changes/public/search/post.md)

---

[API](https://skmtc.dev/berea/apis/bereach-api.md) · [All operations](https://skmtc.dev/berea/apis/bereach-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/berea/bereach-api/revisions/bc5eae2eb212/schema)
