> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pubrio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AND / OR Operators

> Override the default AND/OR operator for any multi-value filter — full reference with copyable examples.

`filter_conditions` is a single optional array on the request body. Each entry promotes one multi-value filter from the default OR ("match any") behaviour to AND ("match all"), or vice versa. Filters you don't list keep their defaults.

## Schema

<CodeGroup>
  ```json JSON theme={null}
  {
    "filter_conditions": [
      { "key": "technologies", "operator": "and" },
      { "key": "verticals",    "operator": "or"  }
    ]
  }
  ```

  ```typescript TypeScript theme={null}
  type FilterCondition = {
    /** Filter name to override. See "Supported keys" below. */
    key: string;
    /** Case-insensitive: "and" | "or". Default is "or" for arrays. */
    operator: "and" | "or";
  };

  type SearchRequest = {
    // …all your other filters…
    filter_conditions?: FilterCondition[];
  };
  ```
</CodeGroup>

<Note>
  `key` and `operator` are both required on every entry. An entry with only `operator` is silently ignored — there is no global override.
</Note>

***

## Why it matters

The default operator is OR because most prospecting workflows want broad reach: "people in *any* of these countries", "companies tagged with *any* of these verticals". For high-precision targeting — "uses *all* of `Salesforce` + `HubSpot` + `Marketo`" — you need AND.

The cost of being wrong:

* **Wanted AND, got OR:** the response over-recalls — you see companies that match only one tag, not the full stack. Easy to spot, costs result-quality.
* **Wanted OR, got AND:** the response under-recalls — usually returns near-zero rows on multi-value AND filters because real-world arrays rarely contain every requested value. Easy to spot, looks like a broken query.

Under the hood, the engine compiles your operator choice to a native Postgres array operator: `&&` (overlap) for OR, `@>` (contains) for AND. Both are index-friendly, so the cost difference is in *result size*, not query latency.

***

## Supported keys

The exact key set depends on the endpoint you're calling:

| Key                                      | `/companies/search` | `/people/search` | `/companies/advertisements/search` | Default | What `and` means                            |
| ---------------------------------------- | ------------------- | ---------------- | ---------------------------------- | ------- | ------------------------------------------- |
| `technologies`                           | yes                 | yes              | —                                  | OR      | Has every tech in the list                  |
| `categories`                             | yes                 | yes              | —                                  | OR      | Tagged with every category                  |
| `verticals`                              | yes                 | yes              | —                                  | OR      | Belongs to every vertical                   |
| `vertical_categories`                    | yes                 | yes              | —                                  | OR      | In every vertical category                  |
| `vertical_sub_categories`                | yes                 | yes              | —                                  | OR      | In every vertical sub-category              |
| `keywords`                               | yes                 | yes              | —                                  | OR      | Description contains every keyword          |
| `places`                                 | yes                 | yes              | —                                  | OR      | Listed in every place                       |
| `exclude_places`                         | yes                 | yes              | —                                  | OR      | Excluded from every place                   |
| `advertisement_target_locations`         | yes                 | —                | —                                  | OR      | Ad targets every country (company endpoint) |
| `advertisement_exclude_target_locations` | yes                 | —                | —                                  | OR      | Ad excludes every country                   |
| `advertisement_search_terms`             | yes                 | —                | —                                  | OR      | Ad copy contains every term                 |
| `job_exclude_locations`                  | yes                 | —                | —                                  | OR      | Job posting excludes every location         |
| `social_media`                           | —                   | yes              | —                                  | OR      | Person has all listed social-media accounts |
| `target_locations`                       | —                   | —                | yes                                | OR      | Ad targets every country (ads endpoint)     |
| `exclude_target_locations`               | —                   | —                | yes                                | OR      | Ad excludes every country                   |

<Tip>
  The keys above mirror the `enum` arrays in the OpenAPI spec (`company_filter_conditions`, `people_filter_conditions`, `ads_filter_conditions`). Sending an unsupported key for an endpoint is silently ignored.
</Tip>

***

## Recipes

<Tabs>
  <Tab title="All-of techs (companies)">
    **Goal:** companies that use *all of* Python, PostgreSQL, and Kubernetes — not just one.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "technologies": [37, 152, 408],
          "filter_conditions": [
            { "key": "technologies", "operator": "and" }
          ],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "technologies": [37, 152, 408],
              "filter_conditions": [
                  { "key": "technologies", "operator": "and" }
              ],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          technologies: [37, 152, 408],
          filter_conditions: [
            { key: "technologies", operator: "and" }
          ],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>

    Drop the `filter_conditions` entry to widen the search to *any* of the three.
  </Tab>

  <Tab title="Any-of locations + exclude">
    **Goal:** companies in *any of* the US, Canada, or UK, but never in San Francisco.

    OR is already the default for `locations`, so we leave it implicit. `exclude_places` handles the negative filter independently — no override needed.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "locations": ["US", "CA", "GB"],
          "exclude_places": ["San Francisco"],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "locations": ["US", "CA", "GB"],
              "exclude_places": ["San Francisco"],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          locations: ["US", "CA", "GB"],
          exclude_places: ["San Francisco"],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Multi-region ad campaigns">
    **Goal:** advertisements actively targeting *both* the EU and the US (multi-region campaigns) — not single-market ads. Uses the dedicated `ads_filter_conditions` schema with the `target_locations` key.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/advertisements/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "target_locations": ["US", "DE", "FR"],
          "filter_conditions": [
            { "key": "target_locations", "operator": "and" }
          ],
          "start_dates": ["2026-01-01"],
          "end_dates":   ["2026-04-22"],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/advertisements/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "target_locations": ["US", "DE", "FR"],
              "filter_conditions": [
                  { "key": "target_locations", "operator": "and" }
              ],
              "start_dates": ["2026-01-01"],
              "end_dates":   ["2026-04-22"],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/advertisements/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          target_locations: ["US", "DE", "FR"],
          filter_conditions: [
            { key: "target_locations", operator: "and" }
          ],
          start_dates: ["2026-01-01"],
          end_dates:   ["2026-04-22"],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>

    <Note>
      The ads endpoint uses its own `ads_filter_conditions` schema (smaller key set: `target_locations`, `exclude_target_locations`). The keys you can override on `/companies/search` and `/people/search` do *not* apply here.
    </Note>
  </Tab>

  <Tab title="People at multi-stack companies">
    **Goal:** people working at companies that have *both* Salesforce and HubSpot installed — a classic CRM-displacement signal. Demonstrates the unified engine: same `technologies` key, same operator, but on `/people/search`.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/people/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "people_titles": ["RevOps", "Sales Operations"],
          "technologies": [114, 287],
          "filter_conditions": [
            { "key": "technologies", "operator": "and" }
          ],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/people/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "people_titles": ["RevOps", "Sales Operations"],
              "technologies": [114, 287],
              "filter_conditions": [
                  { "key": "technologies", "operator": "and" }
              ],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/people/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          people_titles: ["RevOps", "Sales Operations"],
          technologies: [114, 287],
          filter_conditions: [
            { key: "technologies", operator: "and" }
          ],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>
  </Tab>
</Tabs>

***

## Common mistakes

<AccordionGroup>
  <Accordion title="Forgetting key, sending only operator" icon="circle-xmark">
    There is no global "default operator" toggle. Every entry must name a specific filter:

    ```json theme={null}
    // Ignored — no key
    { "filter_conditions": [{ "operator": "and" }] }

    // Correct — overrides only the technologies filter
    { "filter_conditions": [{ "key": "technologies", "operator": "and" }] }
    ```
  </Accordion>

  <Accordion title="Expecting entries to compose" icon="circle-xmark">
    Entries are independent per-key overrides — they do not chain. Listing both `technologies` and `verticals` does not create a Boolean expression between them; each one just sets its own array's operator.

    The combination *across* filter keys is always AND (every filter must match). You cannot OR-combine two distinct filter dimensions through `filter_conditions`. If you need a true OR-of-different-filters search, run two requests and merge results client-side.
  </Accordion>

  <Accordion title="Using AND on a long array" icon="triangle-exclamation">
    AND is `column @> ARRAY[…]` — every value must be present. With 8+ values you almost always get zero rows because real-world tagging is sparse. Keep AND-overridden arrays at 2-4 values; use OR for exploratory or category-level filtering.
  </Accordion>

  <Accordion title="Wrong key on /people/search company filters" icon="circle-xmark">
    On `/people/search`, the people-API name is `company_places` / `company_locations`. But inside `filter_conditions[].key` you must use the **engine name** — `places`, `locations`. The remap happens internally before `filter_conditions` is consulted.

    ```json theme={null}
    // Won't override — engine doesn't see "company_places" as a filter key
    { "filter_conditions": [{ "key": "company_places", "operator": "and" }] }

    // Correct
    { "filter_conditions": [{ "key": "places", "operator": "and" }] }
    ```

    Full remap table on the [People + Company Filters](/en/developer-guides/filters/people-with-company-filters#key-remap-reference) page.
  </Accordion>
</AccordionGroup>

<Tip>
  When in doubt, omit `filter_conditions` first and check your result count against expectations. Add overrides only for filters where the default doesn't match your intent — this keeps the request payload smaller and easier to debug.
</Tip>

***

## See also

<CardGroup cols={2}>
  <Card title="Filters Overview" icon="filter" href="/en/developer-guides/filters/overview">
    The mental model — start here if `filter_conditions` is your first stop.
  </Card>

  <Card title="People + Company Filters" icon="users-rectangle" href="/en/developer-guides/filters/people-with-company-filters">
    How to layer company filters into `/people/search`, including the key-remap.
  </Card>

  <Card title="Company Search reference" icon="building" href="/en/api-reference/endpoint/companies/search">
    Full request schema for `/companies/search` (includes `company_filter_conditions`).
  </Card>

  <Card title="People Search reference" icon="user" href="/en/api-reference/endpoint/people/search">
    Full request schema for `/people/search` (includes `people_filter_conditions`).
  </Card>
</CardGroup>
