> ## 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.

# Opérateurs AND / OR

> Remplacez l'opérateur AND/OR par défaut pour n'importe quel filtre à valeurs multiples — référence complète avec exemples prêts à copier.

`filter_conditions` est un tableau optionnel unique sur le corps de la requête. Chaque entrée fait passer un filtre à valeurs multiples du comportement par défaut OR (« correspond à au moins un ») à AND (« correspond à tous »), ou inversement. Les filtres que vous ne listez pas conservent leur comportement par défaut.

## Schéma

<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` et `operator` sont tous deux obligatoires pour chaque entrée. Une entrée ne comportant que `operator` est silencieusement ignorée — il n'existe pas de remplacement global.
</Note>

***

## Pourquoi c'est important

L'opérateur par défaut est OR car la plupart des workflows de prospection recherchent une large couverture : « personnes dans *n'importe lequel* de ces pays », « entreprises taguées avec *n'importe laquelle* de ces verticales ». Pour un ciblage de haute précision — « utilise *toutes les* technologies `Salesforce` + `HubSpot` + `Marketo` » — vous avez besoin de AND.

Le coût d'une erreur :

* **Vous vouliez AND, vous avez eu OR :** la réponse sur-rappelle — vous voyez des entreprises qui ne correspondent qu'à un seul tag, pas à l'ensemble de la stack. Facile à repérer, coûte en qualité de résultat.
* **Vous vouliez OR, vous avez eu AND :** la réponse sous-rappelle — elle retourne généralement un nombre de lignes proche de zéro sur les filtres AND à valeurs multiples, car les tableaux du monde réel contiennent rarement toutes les valeurs demandées. Facile à repérer, ressemble à une requête cassée.

Sous le capot, le moteur compile votre choix d'opérateur vers un opérateur de tableau Postgres natif : `&&` (chevauchement) pour OR, `@>` (contient) pour AND. Les deux sont compatibles avec les index, donc la différence de coût se situe dans la *taille du résultat*, pas dans la latence de la requête.

***

## Clés prises en charge

L'ensemble exact des clés dépend du endpoint que vous appelez :

| Clé                                      | `/companies/search` | `/people/search` | `/companies/advertisements/search` | Par défaut | Ce que signifie `and`                                          |
| ---------------------------------------- | ------------------- | ---------------- | ---------------------------------- | ---------- | -------------------------------------------------------------- |
| `technologies`                           | oui                 | oui              | —                                  | OR         | Possède chaque technologie de la liste                         |
| `categories`                             | oui                 | oui              | —                                  | OR         | Taguée avec chaque catégorie                                   |
| `verticals`                              | oui                 | oui              | —                                  | OR         | Appartient à chaque verticale                                  |
| `vertical_categories`                    | oui                 | oui              | —                                  | OR         | Dans chaque catégorie verticale                                |
| `vertical_sub_categories`                | oui                 | oui              | —                                  | OR         | Dans chaque sous-catégorie verticale                           |
| `keywords`                               | oui                 | oui              | —                                  | OR         | La description contient chaque mot-clé                         |
| `places`                                 | oui                 | oui              | —                                  | OR         | Listée dans chaque lieu                                        |
| `exclude_places`                         | oui                 | oui              | —                                  | OR         | Exclue de chaque lieu                                          |
| `advertisement_target_locations`         | oui                 | —                | —                                  | OR         | L'annonce cible chaque pays (endpoint entreprise)              |
| `advertisement_exclude_target_locations` | oui                 | —                | —                                  | OR         | L'annonce exclut chaque pays                                   |
| `advertisement_search_terms`             | oui                 | —                | —                                  | OR         | Le texte de l'annonce contient chaque terme                    |
| `job_exclude_locations`                  | oui                 | —                | —                                  | OR         | L'offre d'emploi exclut chaque lieu                            |
| `social_media`                           | —                   | oui              | —                                  | OR         | La personne possède tous les comptes de réseaux sociaux listés |
| `target_locations`                       | —                   | —                | oui                                | OR         | L'annonce cible chaque pays (endpoint annonces)                |
| `exclude_target_locations`               | —                   | —                | oui                                | OR         | L'annonce exclut chaque pays                                   |

<Tip>
  Les clés ci-dessus reflètent les tableaux `enum` de la spécification OpenAPI (`company_filter_conditions`, `people_filter_conditions`, `ads_filter_conditions`). L'envoi d'une clé non prise en charge pour un endpoint est silencieusement ignoré.
</Tip>

***

## Exemples

<Tabs>
  <Tab title="Toutes les technologies (entreprises)">
    **Objectif :** des entreprises qui utilisent *toutes* les technologies Python, PostgreSQL et Kubernetes — pas seulement une seule.

    <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>

    Supprimez l'entrée `filter_conditions` pour élargir la recherche à *n'importe laquelle* des trois technologies.
  </Tab>

  <Tab title="Lieux au choix + exclusion">
    **Objectif :** des entreprises situées *dans n'importe lequel* des pays suivants — États-Unis, Canada ou Royaume-Uni — mais jamais à San Francisco.

    OR est déjà la valeur par défaut pour `locations`, donc nous la laissons implicite. `exclude_places` gère le filtre négatif indépendamment — aucun remplacement n'est nécessaire.

    <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="Campagnes publicitaires multi-régions">
    **Objectif :** des publicités ciblant activement *à la fois* l'UE et les États-Unis (campagnes multi-régions) — et non des publicités mono-marché. Utilise le schéma dédié `ads_filter_conditions` avec la clé `target_locations`.

    <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>
      Le endpoint des annonces utilise son propre schéma `ads_filter_conditions` (ensemble de clés plus restreint : `target_locations`, `exclude_target_locations`). Les clés que vous pouvez remplacer sur `/companies/search` et `/people/search` ne s'appliquent *pas* ici.
    </Note>
  </Tab>

  <Tab title="Personnes dans des entreprises multi-stack">
    **Objectif :** des personnes travaillant dans des entreprises ayant installé *à la fois* Salesforce et HubSpot — un signal classique de remplacement de CRM. Démontre le moteur unifié : même clé `technologies`, même opérateur, mais sur `/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>

***

## Erreurs courantes

<AccordionGroup>
  <Accordion title="Oublier key, n'envoyer que operator" icon="circle-xmark">
    Il n'existe pas de bascule globale « opérateur par défaut ». Chaque entrée doit nommer un filtre spécifique :

    ```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="S'attendre à ce que les entrées se combinent" icon="circle-xmark">
    Les entrées sont des remplacements indépendants par clé — elles ne s'enchaînent pas. Lister à la fois `technologies` et `verticals` ne crée pas d'expression booléenne entre elles ; chacune définit simplement l'opérateur de son propre tableau.

    La combinaison *entre* les clés de filtre est toujours AND (chaque filtre doit correspondre). Vous ne pouvez pas combiner en OR deux dimensions de filtre distinctes via `filter_conditions`. Si vous avez besoin d'une véritable recherche OR entre différents filtres, exécutez deux requêtes et fusionnez les résultats côté client.
  </Accordion>

  <Accordion title="Utiliser AND sur un long tableau" icon="triangle-exclamation">
    AND correspond à `column @> ARRAY[…]` — chaque valeur doit être présente. Avec 8 valeurs ou plus, vous obtenez presque toujours zéro ligne, car le tagging en conditions réelles est épars. Limitez les tableaux avec AND à 2-4 valeurs ; utilisez OR pour un filtrage exploratoire ou au niveau catégorie.
  </Accordion>

  <Accordion title="Mauvaise clé sur les filtres d'entreprise de /people/search" icon="circle-xmark">
    Sur `/people/search`, le nom côté API people est `company_places` / `company_locations`. Mais à l'intérieur de `filter_conditions[].key`, vous devez utiliser le **nom du moteur** — `places`, `locations`. Le remappage se fait en interne avant que `filter_conditions` ne soit consulté.

    ```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" }] }
    ```

    Table de remappage complète sur la page [Filtres personnes + entreprise](/fr/developer-guides/filters/people-with-company-filters#key-remap-reference).
  </Accordion>
</AccordionGroup>

<Tip>
  En cas de doute, omettez d'abord `filter_conditions` et vérifiez votre nombre de résultats par rapport à vos attentes. N'ajoutez des remplacements que pour les filtres où le comportement par défaut ne correspond pas à votre intention — cela garde le payload de la requête plus léger et plus facile à déboguer.
</Tip>

***

## Voir aussi

<CardGroup cols={2}>
  <Card title="Vue d'ensemble des filtres" icon="filter" href="/fr/developer-guides/filters/overview">
    Le modèle mental — commencez ici si `filter_conditions` est votre première étape.
  </Card>

  <Card title="Filtres personnes + entreprise" icon="users-rectangle" href="/fr/developer-guides/filters/people-with-company-filters">
    Comment intégrer des filtres d'entreprise dans `/people/search`, y compris le remappage des clés.
  </Card>

  <Card title="Référence Recherche entreprise" icon="building" href="/fr/api-reference/endpoint/companies/search">
    Schéma complet de la requête pour `/companies/search` (inclut `company_filter_conditions`).
  </Card>

  <Card title="Référence Recherche personnes" icon="user" href="/fr/api-reference/endpoint/people/search">
    Schéma complet de la requête pour `/people/search` (inclut `people_filter_conditions`).
  </Card>
</CardGroup>
