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

# API de analíticas

> Consulta las analíticas de tus conversaciones: métricas agregadas por agente y canal, y el detalle de cada conversación

La API de analíticas es un endpoint de solo lectura que devuelve los datos de las conversaciones de tu empresa. Tiene dos modos:

* **`type=metrics`**: cifras agregadas por agente y canal (conversaciones, transferencias a humano, contención de la IA, duración de las llamadas, notificaciones de WhatsApp, recontactos y series por día y por hora). Para informes y cuadros de mando.
* **`type=chats`**: una fila por conversación con todos sus parámetros, paginada. Para exportar o cuadrar los datos en bruto.

## 🔑 Autenticación

Cada petición necesita una API key con el permiso **`analytics_api`**. Pídesela al equipo de Lovi; no es la misma key que usa el widget web.

Envía la key en la cabecera `x-api-key` (recomendado) o en el parámetro `access_key` de la URL.

```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" \
  "https://cloud.lovi.ai/functions/v1/analytics?type=metrics&date_from=2026-10-01&date_to=2026-10-31"
```

> [!NOTE]
>
> La empresa sale siempre de la key. Una key solo puede leer los datos de su propia empresa y no hay ningún parámetro para elegir otra.

## Endpoint

```
GET https://cloud.lovi.ai/functions/v1/analytics
```

### Parámetros de la URL

| Parámetro | Obligatorio | Descripción |
| - | - | - |
| `type` | Sí | `metrics` o `chats`. |
| `date_from` | Sí | Primer día, `YYYY-MM-DD`, incluido. |
| `date_to` | Sí | Último día, `YYYY-MM-DD`, incluido. El rango puede abarcar hasta **31 días**. |
| `tz` | No | Zona horaria IANA con la que se interpretan los días y se construyen las series diaria y horaria. Por defecto `Europe/Madrid`. Ejemplos: `UTC`, `America/Bogota`. |
| `channels` | No | Canales separados por comas: `voice`, `whatsapp`, `web`, `instagram`, `facebook`… |
| `agents` | No | Ids de agente (UUID) separados por comas. |
| `languages` | No | Códigos de idioma del usuario separados por comas, p. ej. `es,pt`. |
| `limit` | No | Solo `chats`. Conversaciones por página, de 1 a 100. Por defecto 100. |
| `cursor` | No | Solo `chats`. El `next_cursor` que devolvió la página anterior. |

Los días se interpretan en `tz`: `date_from=2026-10-01&date_to=2026-10-31` con `tz=Europe/Madrid` cubre del 1 de octubre a las 00:00 al 1 de noviembre a las 00:00, hora de Madrid. Los cambios de hora están contemplados.

Todas las fechas de las respuestas van en **UTC** (ISO 8601 terminado en `Z`).

## Métricas (`type=metrics`)

Devuelve una entrada por agente y canal, ordenadas por número de conversaciones.

```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" \
  "https://cloud.lovi.ai/functions/v1/analytics?type=metrics&date_from=2026-10-01&date_to=2026-10-31&channels=voice"
```

```json theme={null}
{
  "tz": "Europe/Madrid",
  "from": "2026-09-30T22:00:00.000Z",
  "to": "2026-10-31T23:00:00.000Z",
  "data": [
    {
      "agent": { "id": "2fef9696-0662-4e49-bb83-7564ff25c7ef", "name": "Voice assistant" },
      "channel": "voice",
      "conversations": 12480,
      "escalated": 4120,
      "contained_pct": 67.0,
      "avg_duration_s": { "all": 109, "without_transfer": 120, "with_transfer": 86 },
      "whatsapp_notifications": 1210,
      "unique_users": 7950,
      "recontacts": 2480,
      "daily": [
        { "date": "2026-10-01", "conversations": 410, "escalated": 151 }
      ],
      "hourly": [
        { "hour": 9, "conversations": 1320 },
        { "hour": 10, "conversations": 1544 }
      ]
    }
  ]
}
```

| Campo | Descripción |
| - | - |
| `agent` | Agente de IA que atendió las conversaciones (`id`, `name`). `null` si la conversación no tiene agente. |
| `channel` | Canal de la conversación. `n/a` si no quedó registrado. |
| `conversations` | Conversaciones iniciadas en el rango (en voz, llamadas). |
| `escalated` | Conversaciones transferidas a un humano (tienen un evento `chat_escalated`). |
| `contained_pct` | `(conversations − escalated) / conversations × 100`. Parte que gestiona la IA sin transferir. **No es una tasa de resolución.** |
| `avg_duration_s` | Duración media de la llamada en segundos: global, sin transferencia y con transferencia. `null` en canales sin duración (solo voz la registra). |
| `whatsapp_notifications` | Notificaciones de WhatsApp enviadas desde esas conversaciones (eventos `notification_sent`). |
| `unique_users` | Usuarios distintos (en voz, números de teléfono distintos). |
| `recontacts` | Usuarios con 2 o más conversaciones en el rango. Tasa de recontacto = `recontacts / unique_users`. |
| `daily` | Conversaciones y transferencias por día, en `tz`. Los días sin conversaciones no aparecen. |
| `hourly` | Conversaciones por hora del día (0–23), en `tz`. Las horas sin conversaciones no aparecen. |

> [!TIP]
>
> **Comparar con el mes anterior**: llama al endpoint dos veces, una por mes, y calcula la diferencia.
> **Contención solo en días con agentes humanos**: usa `daily` y quédate con los días con `escalated > 0`.

## Conversaciones (`type=chats`)

Devuelve las conversaciones del rango una a una, de la más antigua a la más reciente, 100 por página por defecto.

```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" \
  "https://cloud.lovi.ai/functions/v1/analytics?type=chats&date_from=2026-10-01&date_to=2026-10-01&channels=voice&limit=100"
```

```json theme={null}
{
  "data": [
    {
      "id": "29d67962-119b-406c-b172-d66cf179975e",
      "created_at": "2026-10-01T05:58:40.4431Z",
      "ended_at": "2026-10-01T05:58:48Z",
      "last_message_at": null,
      "status": "aiagent",
      "channel": "voice",
      "language": "es",
      "agent": { "id": "2fef9696-0662-4e49-bb83-7564ff25c7ef", "name": "Voice assistant" },
      "escalated_to_human": true,
      "escalated_at": "2026-10-01T05:58:45.12Z",
      "attended_by_human": false,
      "human_agents": [],
      "whatsapp_notifications": 0,
      "parameters": {
        "channel": "voice",
        "call_length": 8,
        "phone_call": "+34600000000",
        "voice_inbound": true,
        "conversation_recording_url": "https://…"
      }
    }
  ],
  "next_cursor": "MjAyNi0xMC0wMVQwNjowMjoxMS4xMjM0NTZ8…"
}
```

| Campo | Descripción |
| - | - |
| `id` | Id de la conversación. |
| `created_at`, `ended_at`, `last_message_at` | Inicio, fin y último mensaje, en UTC. |
| `status` | Con quién está la conversación: `aiagent`, `human`, `queue` (esperando a un humano) o `push` (iniciada por una notificación). |
| `channel`, `language` | Copiados de `parameters.channel` y `parameters.lang_user` por comodidad. |
| `agent` | Agente de IA de la conversación (`id`, `name`). |
| `escalated_to_human`, `escalated_at` | Si se transfirió a un humano y cuándo (primera transferencia). |
| `attended_by_human` | Si un agente humano escribió al menos un mensaje. |
| `human_agents` | Agentes humanos que escribieron en la conversación (`id`, `name`). Puede ir vacío aunque `attended_by_human` sea `true`: los mensajes enviados desde un CRM externo no se atribuyen a una persona. |
| `whatsapp_notifications` | Notificaciones de WhatsApp enviadas desde la conversación. |
| `parameters` | **Todos** los parámetros guardados de la conversación, sin filtrar. Las claves dependen del canal y de la configuración de tu agente (en voz: `call_length`, `phone_call`, `voice_inbound`, `session_call_id`, `conversation_recording_url`…; además de cualquier parámetro propio que guarde tu agente). |

### Paginación

Mientras `next_cursor` no sea `null`, pide la página siguiente con los mismos parámetros más `cursor=<next_cursor>`. Las conversaciones van ordenadas por `created_at` e `id`, así que ninguna se repite ni se salta entre páginas.

```python theme={null}
import requests

URL = "https://cloud.lovi.ai/functions/v1/analytics"
HEADERS = {"x-api-key": "YOUR_API_KEY"}
params = {"type": "chats", "date_from": "2026-10-01", "date_to": "2026-10-31", "channels": "voice"}

chats = []
while True:
    page = requests.get(URL, headers=HEADERS, params=params, timeout=60).json()
    chats.extend(page["data"])
    if not page["next_cursor"]:
        break
    params["cursor"] = page["next_cursor"]

print(len(chats), "conversaciones")
```

## Errores

Los errores devuelven un JSON `{ "success": false, "message": "…" }`.

| Código | Cuándo |
| - | - |
| `400` | Falta la key (`Missing access_key parameter`), `type` no válido, fechas no válidas, rango de más de 31 días, o `tz`, `limit`, `agents`, `channels` o `cursor` no válidos. |
| `403` | La key existe pero no tiene el permiso `analytics_api`. |
| `404` | Key no válida o revocada. |
| `405` | Método distinto de `GET`. |
| `500` | Error interno. Reintenta pasados unos segundos; si persiste, contacta con soporte indicando la hora de la petición. |

## Límites y buenas prácticas

* Hasta **31 días** por petición y **100 conversaciones** por página.
* Una petición de `metrics` de un mes completo tarda unos segundos. Para un informe mensual o diario basta con una llamada por periodo: no hace falta consultar en bucle.
* Para exportar un mes entero de conversaciones, recorre las páginas una tras otra, no en paralelo.
* Guarda la key en secreto y en tu servidor. No la uses en un navegador ni en una app móvil.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.