Skip to main content
Every Contact Search and Company Search endpoint takes the same filter object. Write it once and send it to count, preview, insights, or exports on either surface without changes. A filter is plain JSON — a nested tree of objects with a type field. It is not GraphQL, and there is no query language to learn or GraphQL endpoint to call. Build it with whatever your language uses for JSON. The one difference is which columns each surface accepts: contact endpoints take person, company, and job fields, while company endpoints take company fields only. See Search for companies for what that rules out. Every column is documented in the Person-Organization-Insight data dictionary.

Start with one condition

A filter is a group containing a list of children. The simplest one holds a single condition:
Use POST /v2/contact/count to check the result before adding complexity.

Combine conditions

Add more entries to children. The group’s op decides how they combine — AND requires all of them, OR requires any.
eq reads value, a single item. in reads valueList, an array. Sending the wrong one is the most common cause of a 422.

Nest groups for mixed logic

To express “in the United States and (software or financial services)”, nest a group inside a group:
Set "negate": true on any group to exclude everything it matches.

Add SmartSearch nodes

SmartSearch nodes match on meaning rather than characters. They are ordinary children — they sit in the same children list as conditions, nest inside groups, and negate the same way. Job title — the role a person holds, however it’s worded:
Company description — what a company does:
Company look-alike — companies resembling one you name:
All three take the same four match presets — exact, similar, related, broad — or a raw maxDistance if you’d rather set your own threshold. Never both.

Node reference

Four node types, told apart by type. Every node also accepts joinWithPrevious (AND or OR) to control how it binds to the preceding sibling, and an optional id of your own for round-tripping state from an interface.

A filter using everything

Conditions, a nested OR, two SmartSearch types, and a negated exclusion — in one tree:
Read it as: in the US, and VP or C-Level, and (demand gen or marketing ops), and at a company selling software to mid-market retailers, and not at a company resembling competitor.com. See SmartSearch for how the presets are calibrated per target and more worked combinations.

Operator reference

Every node also accepts joinWithPrevious (AND or OR) to control how it binds to the preceding sibling, and an optional id of your own for round-tripping state from an interface.

Find available columns and values

GET /v2/contact/columns returns every column, what it holds, and which ones offer a fixed set of values. Add ?include=values to receive those value lists in the same response. GET /v2/contact/company/columns does the same for the company surface, listing company fields only.
Request the catalog once at startup and cache it. Building filter inputs from distinctValues avoids searches that silently match nothing because a value was spelled differently than stored. GET /v2/contact/columns/{column}/values returns values for a single multiselect column, with an optional search parameter. Open-ended columns — job title, company name, email address — return 400; filter those with contains instead.

Filter limits

Handle filter errors

A rejected filter returns 422. As with every validation error across the API, detail is an array identifying each problem, and code names the rule that was broken:
loc points at the part of the filter that failed, and msg explains what’s wrong. See Rate limits and error codes for the shared error format. Include request_id when contacting support@revenuebase.ai — it identifies the individual request in our logs.

Next steps