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

# Conversations

> Listar, consultar y actualizar conversaciones.

## GET /conversations

Lista conversaciones ordenadas por más recientes. Paginación cursor-based.

**Scope requerido:** `conversations:read`

### Parámetros

| Parámetro | Tipo   | Default | Descripción                                                 |
| --------- | ------ | ------- | ----------------------------------------------------------- |
| `cursor`  | string | —       | Cursor de la respuesta anterior                             |
| `limit`   | number | `50`    | Resultados por página (máx 100)                             |
| `status`  | string | —       | Filtrar por estado: `open`, `pending`, `resolved`, `closed` |
| `search`  | string | —       | Buscar por nombre o teléfono del contacto                   |

### Request

```bash theme={null}
curl "https://api.waspytech.com/api/v2/conversations?limit=20&status=open" \
  -H "Authorization: Bearer wspy_..."
```

### Response `200`

```json theme={null}
{
  "data": [
    {
      "id": "conv-uuid",
      "contactId": "contact-uuid",
      "phoneNumberId": "channel-uuid",
      "status": "open",
      "assignedTo": "agent-uuid",
      "lastMessageAt": "2026-04-13T14:32:00.000Z",
      "lastMessagePreview": "Hola, quería consultar sobre mi pedido",
      "lastMessageDirection": "inbound",
      "lastMessageStatus": "delivered",
      "serviceWindowExpiresAt": "2026-04-14T14:32:00.000Z",
      "createdAt": "2026-04-10T10:00:00.000Z",
      "contact": {
        "id": "contact-uuid",
        "phoneNumber": "+5491126032641",
        "name": "María García"
      }
    }
  ],
  "meta": { "requestId": "...", "cursor": "2026-04-13T14:32:00.000Z|conv-uuid", "hasMore": true }
}
```

***

## GET /conversations/by-phone/:phone

Buscar una conversación por número de teléfono.

**Scope requerido:** `conversations:read`

```bash theme={null}
curl "https://api.waspytech.com/api/v2/conversations/by-phone/5491126032641" \
  -H "Authorization: Bearer wspy_..."
```

<Info>
  **Tolerancia de formato:** este endpoint normaliza el input antes de buscar. Acepta:

  * Con o sin `+` inicial: `+5491126032641` o `5491126032641`
  * Argentinos con o sin el `9` móvil: `+5491126032641` o `+541126032641`
  * Solo dígitos sin código país: lo prepende según el contexto del tenant
  * Argentinos con prefijo viejo `15`: `+5411 15 26032641` (lo elimina automáticamente)

  Devuelve la conversación más reciente que matchea cualquiera de las variantes generadas. Si tenés dudas, pasá el formato canónico E.164 con `+` y código país.
</Info>

***

## GET /conversations/:id

Obtener una conversación por ID.

**Scope requerido:** `conversations:read`

***

## PATCH /conversations/:id

Actualizar estado o asignación de una conversación.

**Scope requerido:** `conversations:write`

### Body (todos opcionales)

| Campo        | Tipo           | Descripción                               |
| ------------ | -------------- | ----------------------------------------- |
| `status`     | string         | `open`, `pending`, `resolved`, `closed`   |
| `assignedTo` | string \| null | UUID del agente, o `null` para desasignar |

### Request

```bash theme={null}
curl -X PATCH https://api.waspytech.com/api/v2/conversations/CONV_ID \
  -H "Authorization: Bearer wspy_..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "resolved",
    "assignedTo": null
  }'
```

***

## GET /conversations/:id/messages

Listar mensajes de una conversación. Paginación cursor-based, orden: más antiguos primero.

**Scope requerido:** `conversations:read`

### Parámetros

| Parámetro | Tipo   | Default | Descripción                     |
| --------- | ------ | ------- | ------------------------------- |
| `cursor`  | string | —       | Cursor de la respuesta anterior |
| `limit`   | number | `50`    | Resultados por página (máx 100) |

```bash theme={null}
curl "https://api.waspytech.com/api/v2/conversations/CONV_ID/messages?limit=50" \
  -H "Authorization: Bearer wspy_..."
```

### Response

```json theme={null}
{
  "data": [
    {
      "id": "msg-uuid",
      "conversationId": "conv-uuid",
      "direction": "inbound",
      "type": "text",
      "content": { "text": "Hola, quería consultar sobre mi pedido" },
      "status": "delivered",
      "waMessageId": "wamid.xxx",
      "createdAt": "2026-04-13T14:32:00.000Z"
    }
  ],
  "meta": { "requestId": "...", "cursor": "...", "hasMore": false }
}
```

## POST /conversations/:id/read

Marca la conversación como leída. Resetea `unreadCount` a 0 y manda read receipt (doble check azul) a Meta para el último mensaje entrante con `waMessageId`.

**Scope requerido:** `conversations:write`

```bash theme={null}
curl -X POST https://api.waspytech.com/api/v2/conversations/{id}/read \
  -H "Authorization: Bearer wspy_..."
```

Respuesta:

```json theme={null}
{
  "data": {
    "conversationId": "uuid",
    "markedMessageId": "wamid.HBgL...",
    "deliveredToMeta": true
  },
  "meta": { "requestId": "..." }
}
```

`deliveredToMeta: false` significa que se reseteó `unreadCount` pero no había un mensaje inbound elegible para read receipt (o falló el llamado a Meta).

## POST /conversations/:id/typing

Muestra "escribiendo…" al contacto. Meta auto-clarea el indicador a los \~25s o cuando el negocio envía un mensaje.

**Scope requerido:** `conversations:write`

```bash theme={null}
curl -X POST https://api.waspytech.com/api/v2/conversations/{id}/typing \
  -H "Authorization: Bearer wspy_..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "on" }'
```

| Campo           | Valor                                 |
| --------------- | ------------------------------------- |
| `status: "on"`  | Manda typing indicator a Meta         |
| `status: "off"` | No-op (Meta no soporta apagar manual) |

Response:

```json theme={null}
{
  "data": {
    "conversationId": "uuid",
    "status": "on",
    "deliveredToMeta": true
  },
  "meta": { "requestId": "..." }
}
```

Cuando `deliveredToMeta: false`, la response incluye un campo `reason` con el motivo:

| `reason`               | Significado                                                                      |
| ---------------------- | -------------------------------------------------------------------------------- |
| `no_phone_number`      | La conversación no tiene canal asignado (DB anomaly)                             |
| `no_inbound_to_anchor` | No hay mensaje inbound reciente con `waMessageId` (Meta requiere uno como ancla) |
| `phone_not_found`      | El canal asignado no existe en este tenant                                       |
| `meta_rejected`        | Meta devolvió error (ventana de servicio cerrada, número bloqueado, etc)         |
| `meta_unreachable`     | Network error al llamar Graph API                                                |
| `typing_off_noop`      | Acepté el `status: "off"` pero Meta no lo soporta — auto-clarea solo             |

Si la conversationId no existe, devuelve **`404`** (no un 200 silencioso).
