Skip to main content
Pubrio’s search endpoints (/companies/search, /people/search, /companies/advertisements/search) share a single filter engine. You compose a request body once and the same rules apply across endpoints — including the way multi-value filters combine, how locations are matched, and how you override the default operator with filter_conditions.

Why a unified filter engine?

One schema, three endpoints

Company-level filters like technologies, verticals, and founded_dates work identically on /companies/search, /people/search, and inside Monitor company_filters — you learn them once.

Per-filter AND/OR

The default is OR (match any). Promote individual filters to AND (match all) by adding one entry to filter_conditions — without touching the rest of the body.

Postgres-native operators

Array filters compile to native Postgres operators — && (overlap) for OR, @> (contains) for AND. Index-friendly, no application-side post-filtering.

Same filters in Monitors

The company_filters block in Monitors accepts the same shape, so a working search payload is also a working monitor payload.

Anatomy of a search request

Every search request is built from three layers in the same JSON body:
LayerWhere it livesExamples
People filterstop-level keyspeople_titles, management_levels, departments, people_locations
Company filtersnested under company_filters: {...} (recommended) — also accepted at top leveltechnologies, verticals, founded_dates, employees, company_locations
Operator overridesfilter_conditions array (inside company_filters when overriding company keys)[{ "key": "technologies", "operator": "and" }]
A minimal /people/search request that uses all three layers:
curl -X POST https://api.pubrio.com/people/search \
  -H "Content-Type: application/json" \
  -H "pubrio-api-key: YOUR_API_KEY" \
  -d '{
    "people_titles": ["VP of Engineering", "CTO"],
    "company_filters": {
      "technologies": ["Kubernetes", "Docker"],
      "is_enable_similarity_search": true,
      "company_locations": ["US"]
    },
    "per_page": 25,
    "page": 1
  }'

company_filters: keep company-level keys grouped

The company_filters: {...} wrapper object is the recommended way to send company-level filters — it visually separates which keys filter the person from which filter the company, and matches the shape Monitors already use, so payloads transfer cleanly between search and monitor configurations. Both styles work; the engine flattens the wrapped form to the top level before processing, and top-level keys win on conflict:
{
  "people_titles": ["VP of Engineering"],
  "company_filters": {
    "technologies": [37, 152],
    "founded_dates": [2015, 2023],
    "company_locations": ["US"]
  }
}
When you add a filter_conditions override for a company-level key, put it inside company_filters so it travels with the keys it overrides.

Same shape on the /search/similar variants

POST /companies/search/similar and POST /people/search/similar accept the same filter body as their non-similar counterparts (including the company_filters wrapper and filter_conditions). Each one adds a similarity step on top:
What they need extraWhat you get extra
/companies/search/similarA reference company — domain_search_id, domain, linkedin_url, or domainsEach result gets a similarity_score (float, 0-1) and rows are ordered by similarity descending
/people/search/similarA reference person/title — one of people_titles, people_search_id, linkedin_url, linkedin_urls, or peoplesSame — similarity_score per row, ordered by similarity
The response envelope is otherwise identical to the standard search endpoint. Filters narrow the candidate pool before similarity ranking is applied — so combining company_locations: ["US"] with /people/search/similar returns the closest US-based people to your reference titles, which is the “find more people like X within these constraints” pattern.

AND vs OR — the one decision you make per filter

Multi-value filters (technologies, verticals, keywords, categories, …) accept an array. The operator decides what “match” means:
Match any value. Returns rows whose array overlaps with the input.
{
  "technologies": ["Python", "PostgreSQL", "Kubernetes"],
  "is_enable_similarity_search": true
}
A company is included if its tech stack contains at least one of Python, PostgreSQL, or Kubernetes. Compiles to Postgres column && ARRAY[...].Use when: you want broad reach — “interested in any of these”, “located in any of these countries”.
Filters not listed in filter_conditions use the default operator (OR within an array, AND across distinct filter keys). You only declare the overrides — never the defaults.

What you can override

Each endpoint accepts overrides for a different set of keys. The keys come from the OpenAPI enum on each *_filter_conditions schema:

Company endpoint

company_filter_conditions keys: keywords, verticals, vertical_categories, vertical_sub_categories, technologies, categories, advertisement_target_locations, advertisement_exclude_target_locations, advertisement_search_terms, places, exclude_places, job_exclude_locations.

People endpoint

people_filter_conditions keys (delegate to the company engine): keywords, verticals, vertical_categories, vertical_sub_categories, technologies, categories, places, exclude_places, plus social_media.

Ads endpoint

ads_filter_conditions keys: target_locations, exclude_target_locations. Smaller set because ads only filter by impression country.
When using /people/search, the filter_conditions[].key for company-level locations uses the bare name from the company engine — places, exclude_places — not the prefixed people-API name (company_places). See People + Company Filters.

Performance tips

Locations, employee buckets, and founded_dates are indexed and reduce the candidate set faster than free-text or vertical filters. Combine them with one or two precise filters before reaching for similarity search.
column @> ARRAY[a, b, c, …] requires every value to be present. Cardinality grows fast — a 10-tech AND on a category with average 3 tech tags returns near-zero rows and forces a full scan. Prefer 2-4 values per AND filter; switch to OR for exploratory queries.
If you can’t supply slug IDs (verticals, technologies, categories) and only have free-text strings, set is_enable_similarity_search: true and similarity_score: 0.7. The engine resolves matches before applying the filter — much cheaper than scanning text.
employees: [[201, 500], [501, 1000]] (an array of buckets) and revenues: [1000000, 5000000] (a single min/max range) are faster and more idiomatic than long ID lists.

Next steps

filter_conditions

Reference page — every supported key, every default, and copyable AND/OR recipes.

People + Company Filters

Use any company filter inside /people/search. The headline new feature of the unified engine.

Company Search reference

Full request/response schema for /companies/search.

People Search reference

Full request/response schema for /people/search.
Looking for the dashboard-side filtering walkthrough? See Filtering & Exporting Contacts in the Knowledge Base.