Skip to main content
POST /people/search accepts every company filter that POST /companies/search accepts. You no longer need to pre-fetch companies, collect their IDs, and feed them into a second people query — one request does both layers.

Two parameter families, one body

A /people/search request body is split conceptually into two filter families. They live at the same level in the JSON, and you mix them freely.
Filter on attributes of the person:
ParameterDescription
people_titlesJob titles (free text or slug)
management_levelsfounder, c_suite, vp, director, manager, …
departmentsmaster_engineering, master_sales, …
department_functionsSub-department / function slugs
people_locationsCountry codes for the person’s location
people_groupsSaved group IDs
peoplesSpecific people_search_id values
linkedin_urlsPerson LinkedIn URLs
social_mediaPer-network social-media handles
The company_ prefix exists only on the location/place filters because the bare places / locations names are already used for the person’s address. Everything else uses the bare company name (technologies, not company_technologies).

Build a query in four steps

1

Decide the people predicate

Who, exactly? Title, seniority, department, country. Keep this layer at the top level of the body — the company predicate usually does the precision work.
2

Decide the company predicate

Which companies do they need to work at? Industry, size, founded year, HQ country, technology stack. Group these under a company_filters: {...} object so it’s obvious which layer each key belongs to.
3

Pick AND/OR per filter via filter_conditions

For any multi-value filter that needs precision (e.g., “uses all of these techs”), add an entry to filter_conditions inside company_filters. Defaults are OR.
4

Send the request

POST /people/search. Both styles are accepted, but company_filters: {...} reads cleaner and matches the Monitors payload shape.

Complete example

The query: VPs of Engineering or CTOs at US-based mid-market companies founded between 2015 and 2023, employing 100-5,000 people, that use both Kubernetes and Docker, but excluding companies HQ’d in San Francisco.
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": {
      "company_locations": ["US"],
      "company_exclude_places": ["San Francisco"],
      "founded_dates": [2010, 2024],
      "employees": [[100, 500], [501, 1000], [1001, 5000]],
      "technologies": ["Kubernetes", "Docker"],
      "is_enable_similarity_search": true
    },

    "per_page": 25,
    "page": 1
  }'

Key remap reference

When /people/search hands company filters to the shared engine, the location/place keys are renamed to their bare forms. The bare names are what the engine — and filter_conditions[].key — actually see:
You send (people-API name)Engine sees (company-API name)
company_locationslocations
company_exclude_locationsexclude_locations
company_placesplaces
company_exclude_placesexclude_places
technologies, verticals, vertical_categories, vertical_sub_categories, categories, keywords, founded_dates, employees, revenuespassed through unchanged
This is why filter_conditions[].key for company-level locations uses the bare names:
{
  "company_places": ["New York", "Boston"],
  "filter_conditions": [
    { "key": "places", "operator": "and" }
  ]
}
{ "key": "company_places", "operator": "and" } is silently ignored — the engine doesn’t recognise the prefixed name. Always reference the engine name in filter_conditions.

Joins behind the scenes

Adding any company-level filter switches the people-to-company join from LEFT JOIN to INNER JOIN. People without a recognised company on file are excluded from the result, even when they match every people-level filter.
If your search drops to zero rows the moment you add company_locations or technologies, check whether your dataset has companies linked to the people you expect. The engine prefers correctness over recall here — it never invents companies to satisfy the filter.
You’ll see this same join behaviour reflected in the response: every returned person includes a populated company object whenever any company filter was applied.

Common patterns

Target a fixed list of companies (companies or domains), then layer on people-level filters to find the right buyers inside each one.
{
  "people_titles": ["VP Marketing", "CMO"],
  "management_levels": ["vp", "c_suite"],
  "company_filters": {
    "companies": ["67c4696b-…", "f1e2d3c4-…", "0a9b8c7d-…"]
  }
}
Describe the company shape, not specific accounts. Use ranges and verticals — the engine returns the people that fit.
{
  "people_titles": ["Head of Engineering"],
  "company_filters": {
    "verticals": [12, 47],
    "company_locations": ["US", "CA"],
    "founded_dates": [2015, 2023],
    "employees": [[51, 200], [201, 500]],
    "filter_conditions": [
      { "key": "verticals", "operator": "and" }
    ]
  }
}
Find buyers at companies running a specific stack. AND on technologies is the typical override.
{
  "people_titles": ["RevOps", "Sales Operations"],
  "departments": ["master_sales"],
  "company_filters": {
    "technologies": [114, 287, 452],
    "filter_conditions": [
      { "key": "technologies", "operator": "and" }
    ]
  }
}
Find decision-makers at companies that use a competitor’s product (one tech) but not yours (excluded via categories or a separate filter pass).
{
  "people_titles": ["VP Sales"],
  "management_levels": ["vp"],
  "company_filters": {
    "technologies": [287]
  }
}
Then re-run with technologies: [114] (your product’s tag ID) and diff client-side.

Next steps

filter_conditions

Full reference — every key, every default, copyable AND/OR recipes.

Filters Overview

The mental model behind the unified filter engine.

People Search reference

Full request/response schema for /people/search.

Company Search reference

Full request/response schema for /companies/search.