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

# Buscar contactos

> Busca y ordena contactos con filtros avanzados y paginación por página.

Busca contactos mediante filtros avanzados. La API limita automáticamente los resultados a los contactos disponibles para tu API key.

<Info>
  Consulta primero [Obtener esquema de contactos](/contactos/obtener-schema). Usa `fields[].id` para construir filtros y criterios de orden.
</Info>

## Endpoint

```text theme={null}
POST /contacts/search
```

## Body

| Campo     | Tipo      | Default                 | Descripción                                                                    |
| --------- | --------- | ----------------------- | ------------------------------------------------------------------------------ |
| `esQuery` | `object`  | —                       | Consulta formada con los operadores documentados en esta página. Es requerida. |
| `page`    | `integer` | `0`                     | Página basada en cero. Los valores negativos se convierten en `0`.             |
| `limit`   | `integer` | `50`                    | Resultados por página. La API acepta de `1` a `100`.                           |
| `sort`    | `array`   | `updatedAt` descendente | Criterios de orden aplicados en secuencia.                                     |

Cada elemento de `sort` contiene:

| Campo       | Tipo        | Descripción                      |                      |
| ----------- | ----------- | -------------------------------- | -------------------- |
| `property`  | `string`    | Identificador técnico del campo. |                      |
| `direction` | \`ascending | descending\`                     | Dirección del orden. |

## Cómo nombrar los campos

Obtén los identificadores con [Obtener esquema de contactos](/contactos/obtener-schema):

* Usa `fields[].id` para búsquedas de texto completo, existencia, rangos y ordenamiento: `email`, `createdAt` o `<field-id>`.
* Agrega `.keyword` para coincidencias exactas sobre texto, listas o teléfonos: `email.keyword`, `phoneNumbers.keyword` o `<field-id>.keyword`.
* No uses `fields[].ui.label`; es una etiqueta visible y puede cambiar.

## Operadores de consulta

| Operador          | Uso                                                               |
| ----------------- | ----------------------------------------------------------------- |
| `match_all`       | Devuelve todos los contactos disponibles.                         |
| `term`            | Coincidencia exacta con un valor.                                 |
| `terms`           | Coincidencia con cualquiera de varios valores.                    |
| `match`           | Búsqueda de texto dentro de un campo específico.                  |
| `exists`          | Comprueba que un campo tenga valor.                               |
| `range`           | Compara números o fechas con `gt`, `gte`, `lt` y `lte`.           |
| `bool`            | Combina consultas con `must`, `filter`, `should` y `must_not`.    |
| `__contactSearch` | Busca texto o fragmentos en nombre, apellidos, email y teléfonos. |

### Consultas comunes

<AccordionGroup>
  <Accordion title="Todos los contactos">
    ```json theme={null}
    {
      "esQuery": {
        "match_all": {}
      }
    }
    ```
  </Accordion>

  <Accordion title="Texto libre en nombre, email o teléfono">
    `__contactSearch` ignora mayúsculas y acentos. Separa el texto por espacios y exige que cada término aparezca en alguno de los campos de nombre, apellidos, email o teléfonos.

    ```json theme={null}
    {
      "esQuery": {
        "match_all": {},
        "__contactSearch": "maria garcia"
      }
    }
    ```

    También acepta un arreglo:

    ```json theme={null}
    {
      "esQuery": {
        "match_all": {},
        "__contactSearch": ["maria", "garcia"]
      }
    }
    ```
  </Accordion>

  <Accordion title="Texto dentro de un campo específico">
    Usa `match` con el `id` del campo:

    ```json theme={null}
    {
      "esQuery": {
        "match": {
          "firstName": {
            "query": "maria",
            "operator": "and"
          }
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="Email exacto">
    ```json theme={null}
    {
      "esQuery": {
        "term": {
          "email.keyword": "contacto@example.com"
        }
      }
    }
    ```

    Para buscar un fragmento del email, usa `__contactSearch`.
  </Accordion>

  <Accordion title="Teléfono exacto o parcial">
    Para una coincidencia exacta usa el mismo formato almacenado:

    ```json theme={null}
    {
      "esQuery": {
        "term": {
          "phoneNumbers.keyword": "+525500000000"
        }
      }
    }
    ```

    Para buscar por los últimos dígitos:

    ```json theme={null}
    {
      "esQuery": {
        "match_all": {},
        "__contactSearch": "0000"
      }
    }
    ```
  </Accordion>

  <Accordion title="Cualquiera de varios valores">
    Usa `terms` para filtrar por cualquiera de los valores permitidos de un campo:

    ```json theme={null}
    {
      "esQuery": {
        "terms": {
          "<status-field-id>.keyword": ["Prospecto", "Cliente"]
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="Campo con valor">
    ```json theme={null}
    {
      "esQuery": {
        "exists": {
          "field": "email"
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="Rango de fechas">
    Los campos `createdAt` y `updatedAt` usan milisegundos Unix:

    ```json theme={null}
    {
      "esQuery": {
        "range": {
          "createdAt": {
            "gte": 1720000000000,
            "lt": 1722600000000
          }
        }
      }
    }
    ```

    Para campos de fecha configurables, usa valores ISO 8601 según su `jsonSchema`.
  </Accordion>

  <Accordion title="Combinaciones booleanas">
    * `must`: todas las consultas deben coincidir.
    * `filter`: todas deben coincidir; úsalo para filtros exactos.
    * `should`: una o más pueden coincidir. Controla el mínimo con `minimum_should_match`.
    * `must_not`: excluye coincidencias.

    ```json theme={null}
    {
      "esQuery": {
        "bool": {
          "filter": [
            {
              "exists": {
                "field": "email"
              }
            },
            {
              "terms": {
                "<status-field-id>.keyword": ["Prospecto", "Cliente"]
              }
            }
          ],
          "must_not": [
            {
              "term": {
                "email.keyword": "bloqueado@example.com"
              }
            }
          ]
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Solicitud completa

Este ejemplo busca una coincidencia exacta por correo:

```bash theme={null}
curl -X POST "https://api.insuranceboosters.com/api/v1/contacts/search" \
  -H "Content-Type: application/json" \
  -H "x-ib-api-key: TU_API_KEY" \
  -d '{
    "esQuery": {
      "term": {
        "email.keyword": "contacto@example.com"
      }
    },
    "page": 0,
    "limit": 20,
    "sort": [
      {
        "property": "updatedAt",
        "direction": "descending"
      }
    ]
  }'
```

## Respuesta exitosa (`200`)

```json theme={null}
{
  "success": true,
  "hits": [
    {
      "id": "<contact-id>",
      "firstName": "María",
      "lastName1": "García",
      "email": "contacto@example.com",
      "phoneNumbers": ["+525500000000"],
      "createdAt": 1720000000000,
      "updatedAt": 1720000000000
    }
  ],
  "total": 1,
  "page": 0,
  "limit": 20,
  "hasMore": false
}
```

Incrementa `page` mientras `hasMore` sea `true`. Conserva el mismo `esQuery`, `limit` y `sort` durante todo el recorrido.

## Errores frecuentes

| HTTP  | Qué significa                        | Qué hacer                                 |
| ----- | ------------------------------------ | ----------------------------------------- |
| `400` | Falta `esQuery` o no es un objeto.   | Envía una consulta JSON válida.           |
| `401` | API key inválida o faltante.         | Verifica `x-ib-api-key`.                  |
| `500` | No fue posible ejecutar la búsqueda. | Reintenta; si continúa, contacta soporte. |


## OpenAPI

````yaml openapi/contactos-v1.yaml POST /contacts/search
openapi: 3.1.0
info:
  title: Insurance Boosters API — Contactos
  version: 1.0.0
  description: >-
    API pública para consultar el esquema y crear, listar, buscar, actualizar o
    eliminar contactos.
  license:
    name: Propietaria
    url: https://insuranceboosters.com
servers:
  - url: https://api.insuranceboosters.com/api/v1
    description: Producción
security:
  - IbApiKey: []
tags:
  - name: Contactos
    description: Administración de contactos.
paths:
  /contacts/search:
    post:
      tags:
        - Contactos
      summary: Buscar contactos
      operationId: searchContacts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchContactsRequest'
            example:
              esQuery:
                term:
                  email.keyword: contacto@example.com
              page: 0
              limit: 20
              sort:
                - property: updatedAt
                  direction: descending
      responses:
        '200':
          description: Página de resultados.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchContactsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    SearchContactsRequest:
      type: object
      required:
        - esQuery
      properties:
        esQuery:
          $ref: '#/components/schemas/ContactSearchQuery'
        page:
          type: integer
          minimum: 0
          default: 0
        limit:
          type: integer
          minimum: 1
          maximum: 100
          default: 50
        sort:
          type: array
          items:
            $ref: '#/components/schemas/ContactSort'
    SearchContactsResponse:
      type: object
      required:
        - success
        - hits
        - total
        - page
        - limit
        - hasMore
      properties:
        success:
          type: boolean
          const: true
        hits:
          type: array
          items:
            $ref: '#/components/schemas/Contact'
        total:
          type: integer
          minimum: 0
        page:
          type: integer
          minimum: 0
        limit:
          type: integer
          minimum: 1
          maximum: 100
        hasMore:
          type: boolean
    ContactSearchQuery:
      type: object
      description: Consulta formada con los operadores documentados en la guía de búsqueda.
      additionalProperties: true
      properties:
        __contactSearch:
          description: >-
            Texto o términos para buscar en nombre, apellidos, email y
            teléfonos.
          oneOf:
            - type: string
            - type: array
              items:
                type: string
    ContactSort:
      type: object
      required:
        - property
        - direction
      properties:
        property:
          type: string
          description: Identificador técnico del campo.
        direction:
          type: string
          enum:
            - ascending
            - descending
          description: Dirección del orden.
    Contact:
      allOf:
        - $ref: '#/components/schemas/ContactInput'
        - type: object
          required:
            - id
            - createdAt
            - updatedAt
          properties:
            id:
              type: string
              description: ID del contacto.
            createdAt:
              type: integer
              description: Fecha de creación en milisegundos Unix.
            updatedAt:
              type: integer
              description: Fecha de última actualización en milisegundos Unix.
    Error:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
    ContactInput:
      type: object
      description: Campos editables configurados para tu cuenta.
      additionalProperties: true
      properties:
        firstName:
          type: string
          minLength: 1
          maxLength: 100
          description: Nombre.
        lastName1:
          type: string
          minLength: 1
          maxLength: 100
          description: Primer apellido.
        lastName2:
          type: string
          maxLength: 100
          description: Segundo apellido.
        email:
          type: string
          format: email
          description: Correo electrónico.
        phoneNumbers:
          type: array
          description: Teléfonos del contacto.
          items:
            type: string
  responses:
    BadRequest:
      description: La solicitud no cumple el esquema de contactos.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: API key inválida o faltante.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Error inesperado.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    IbApiKey:
      type: apiKey
      in: header
      name: x-ib-api-key

````