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

# CRM

> Contactos, organizations, deals, campañas. Llama describe_schema antes de adivinar la key de un campo.

URL: `https://mcp.chatsailer.com/mcp/crm`

Lee y administra un workspace de Sailer. Las tools de registros toman un
`resource` de `"contact"`, `"organization"` o `"deal"` para cubrir el CRM sin
comerse el presupuesto de tools del cliente. Las campañas y los traces de
conversación tienen sus propias tools. No hay send en una conversación en
vivo.

Una tool que cubre varios resources se lista si tienes **cualquiera** de sus
scopes de lectura o escritura, y después comprueba el scope del resource que
nombraste. Una conexión con `deals:read` ve `search_records` pero no puede
buscar contactos.

Cada workspace define sus propios campos personalizados. El JSON Schema que un
cliente cachea **no** los incluye — los clientes cachean por servidor, no por
tenant. Por eso existe `describe_schema`, y por eso lo llamas primero.

<Note>
  La primera conexión es [solo lectura](/es/mcp/auth). Las tools de write ni
  siquiera aparecen hasta que vuelvas a conectar con el write scope que
  corresponde — `contacts:write`, `organizations:write`, `deals:write` o
  `campaigns:write`.
</Note>

## Oriéntate

### `whoami`

Sin argumentos, sin scope. A qué workspace está ligada esta conexión, quién
la autorizó, `oauth` vs `api_token`, si lee company-wide, y los scopes que
realmente tienes.

> Which Sailer workspace am I connected to?

Una cuenta de Sailer puede pertenecer a varios workspaces. La conexión está
ligada a exactamente uno, elegido en el consent. Ningún argumento de tool
puede cambiarlo.

### `describe_schema`

Necesita cualquiera de `contacts:read`, `organizations:read` o `deals:read`.
`resource` opcional (`"contact"`, `"organization"`, `"deal"`); omítelo para
describir todo lo que esta conexión puede leer.

Devuelve campos built-in y personalizados, cuáles son required o read-only,
opciones de select, y qué keys son filterable, sortable o expandable. En
deals también devuelve los pipelines y stages del workspace — necesitas un
par válido para crear un deal.

> What custom fields does this workspace have?

Usa la `key` que devuelve dentro de `custom_fields` en create y update.
Adivinar desde otro workspace — o desde esta documentación — es cómo obtienes
un error de unknown-field.

## Leer registros

Los ids se ven como `con_8f3a…`, `org_8f3a…`, `deal_8f3a…`. El prefijo **es**
el resource. `get_record` y `update_record` no toman argumento `resource` — un
par que no coincidiera no tendría un ganador con principio.

### `search_records`

Necesita cualquiera de `contacts:read`, `organizations:read` o `deals:read`.
`resource` por defecto es `"contact"`. El scope de lectura del resource
nombrado es lo que autoriza la llamada.

| Argumento  | Qué hace                                                                |
| ---------- | ----------------------------------------------------------------------- |
| `resource` | `"contact"`, `"organization"` o `"deal"`                                |
| `q`        | Texto libre en name, email, phone                                       |
| `filter`   | Árbol de condiciones nested and/or                                      |
| `sort`     | La misma sintaxis que el query `sort` de REST                           |
| `expand`   | Relaciones separadas por coma, p. ej. `owner`                           |
| `limit`    | Tamaño de página                                                        |
| `cursor`   | Opaco. Pasa `next_cursor` de la página anterior de vuelta como `cursor` |

Si `has_more` es true, sigue paginando. No cuentes una página y la llames
población — para eso está `count_records`. Los cursors son opacos, el mismo
contrato que la [paginación REST](/es/guides/pagination).

> Find contacts created in the last 7 days.

> Find deals in Negotiation.

### `get_record`

Necesita cualquiera de `contacts:read`, `organizations:read` o `deals:read`.
`id`, `expand` opcional. El prefijo de `id` selecciona el resource.

> Show me contact `con_…`

> Show me deal `deal_…`

Faltante, borrado o fuera de lo que puedes ver: not found. El mismo siguiente
paso en los tres casos — busca de nuevo.

### `count_records`

Necesita cualquiera de `contacts:read`, `organizations:read` o `deals:read`.
El mismo `resource` / `filter` / `q` que search, sin paging.

> How many contacts are in this workspace?

> How many organizations are in this workspace?

## Escribir registros

Llama `describe_schema` primero. Las keys de custom-field desconocidas o
read-only se rechazan, no se ignoran.

Lo required al crear depende de `resource`:

| `resource`       | Required                                                                                |
| ---------------- | --------------------------------------------------------------------------------------- |
| `"contact"`      | `first_name`, `phone` (único por workspace, guardado como E.164)                        |
| `"organization"` | `name`                                                                                  |
| `"deal"`         | `title`, `pipeline_id`, `stage_id` — y al menos uno de `contact_id` o `organization_id` |

### `create_record`

Necesita cualquiera de `contacts:write`, `organizations:write` o
`deals:write`. Fila nueva. Prefiere `upsert_contact` si la persona puede
existir ya — un duplicado no se revierte automáticamente.

> Create a contact named Ana with phone +5511999999999.

> Create an organization named Acme.

### `update_record`

Necesita cualquiera de `contacts:write`, `organizations:write` o
`deals:write`. Solo `id` — sin argumento `resource`. Destructivo: sobrescribe
lo que envías. Omite un campo para dejarlo; envía `null` para vaciarlo. Lee
primero si pretendías append.

> Set Ana's email to [ana@example.com](mailto:ana@example.com).

### `upsert_contact`

Scope: `contacts:write`. Solo contactos. Match por phone, después de
canonicalization — `(11) 98765-4321` y `+55 11 98765-4321` son la misma
persona. El `on_match` por defecto es `update`; `ignore` devuelve la fila
existente sin tocarla.

El resultado te dice qué rama corrió (`created` vs `matched_existing`). El
registro solo no.

> Add or update the contact with this phone number.

## Deals

### `move_deal_stage`

Scope: `deals:write`. `deal_id`, más `stage_name` o `stage_id`.

Da `stage_name` — el nombre como aparece en el board, matched
case-insensitively — y se resuelve **dentro del propio pipeline de este
deal**. No puedes mover un deal al stage de otro pipeline por accidente. Usa
`stage_id` solo si ya tienes uno.

> Move Acme to Negotiation.

## Campañas

### `list_campaigns`

Scope: `campaigns:read`. Más nuevas primero. `status` opcional, `limit` 1–100
(default 25). Úsalo para obtener un `campaign_id`.

> List this workspace's campaigns.

### `get_campaign`

Scope: `campaigns:read`. Una campaña más una página de sus participants.
`participant_limit` opcional (default 25; `0` para la campaña sola).
`projected_send_at` es una estimación, no un compromiso.

Para performance agregada, llama `get_campaign_analytics` — esto devuelve
filas, no totales.

> Who is in this campaign, and where does each contact stand?

### `get_campaign_analytics`

Scope: `campaigns:read`. Una campaña, una familia de métricas.

| `metric`          | Qué obtienes                         |
| ----------------- | ------------------------------------ |
| `big_numbers`     | Conteos y tasas de titular (default) |
| `status_funnel`   | Funnel de lifecycle                  |
| `daily_metrics`   | Serie por día                        |
| `error_breakdown` | Dónde fallaron los envíos            |

`window_start` / `window_end` opcionales (UTC). Por defecto, los últimos 30
días.

Estas familias **no son intercambiables**. `big_numbers` y `daily_metrics`
usan un "answered" estricto (un inbound que califica, clasificado como
reply). `status_funnel` usa el status de lifecycle, que suele ser un número
más grande. Las tasas en `big_numbers` van de 0–100, no fracciones.

Cada respuesta lleva `_meta.caveats`. Léelos antes de comparar dos números.
Una diferencia entre dos familias no es un cambio en el tiempo.

> Show me campaign performance. Read the caveats before you summarize.

### `add_campaign_participants`

Scope: `campaigns:write`. **Destructivo.** Envía mensajes reales a personas
reales. Confirma con el usuario antes de llamar.

Enrolar un contacto en una campaña en curso significa que la campaña le va a
escribir en su propio horario — un mensaje de WhatsApp a un número de teléfono
real. Eso no se puede retractar una vez enviado.

Los contactos ya tienen que existir; esto no los crea. Usa `search_records` o
`upsert_contact` primero. Quien ya está en la campaña se reporta en
`already_present` y no se enrola dos veces. No hay forma de hacer que una
campaña envíe de inmediato desde aquí.

> Add these contacts to the campaign. Confirm with me before you call it.

## Conversaciones

No hay tool que liste conversaciones ni que envíe un mensaje en una. REST
puede listarlas y recuperarlas; un modelo llega a una conversación desde el
contacto con el que ya está trabajando. Enviar en una conversación en vivo no
está cableado a propósito — usa el [sandbox de Studio](/es/mcp/studio) si
necesitas probar un turno.

### `get_conversation_trace`

Scopes: `conversations:read` e `inference:read`. `conversation_id`, `since`
opcional.

Explica por qué el agente ruteó una conversación real como lo hizo: cada
routing edge que consideró, qué condiciones pasaron y los valores que
comparó. La parte útil suele ser los edges que *perdieron*. Pasa `since` para
acotar esto a un turno — sin él, un hilo largo devuelve mucho historial.

Esto no incluye prompts, completions del modelo, nombres de modelo, token
counts ni costo.

> Why did the agent say that to this customer?
