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

> Consultez les analyses de vos conversations : métriques agrégées par agent et par canal, et le détail de chaque conversation

L'API Analytics est un endpoint en lecture seule qui renvoie les données de conversations de votre entreprise. Elle propose deux modes :

* **`type=metrics`** : chiffres agrégés par agent et par canal (conversations, transferts vers un humain, taux de containment de l'IA, durée des appels, notifications WhatsApp, recontacts, et séries quotidiennes et horaires). Utilisez-le pour vos rapports et tableaux de bord.
* **`type=chats`** : une ligne par conversation avec tous ses paramètres, paginée. Utilisez-le pour exporter ou rapprocher les données brutes.

## 🔑 Authentification

Chaque requête nécessite une clé API disposant de la permission **`analytics_api`**. Demandez-la à l'équipe Lovi ; elle est différente de la clé utilisée par le widget web.

Envoyez la clé dans l'en-tête `x-api-key` (recommandé) ou via le paramètre de requête `access_key`.

```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]
>
> L'entreprise est toujours déterminée à partir de la clé. Une clé ne peut lire que les données de sa propre entreprise, et il n'existe aucun paramètre pour en choisir une autre.

## Endpoint

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

### Paramètres de requête

| Paramètre | Requis | Description |
| - | - | - |
| `type` | Oui | `metrics` ou `chats`. |
| `date_from` | Oui | Premier jour, `YYYY-MM-DD`, inclus. |
| `date_to` | Oui | Dernier jour, `YYYY-MM-DD`, inclus. La plage peut couvrir jusqu'à **31 jours**. |
| `tz` | Non | Fuseau horaire IANA utilisé pour interpréter les jours et construire les séries quotidiennes et horaires. Par défaut `Europe/Madrid`. Exemples : `UTC`, `America/Bogota`. |
| `channels` | Non | Canaux séparés par des virgules : `voice`, `whatsapp`, `web`, `instagram`, `facebook`… |
| `agents` | Non | Identifiants d'agents (UUID) séparés par des virgules. |
| `languages` | Non | Codes de langue de l'utilisateur séparés par des virgules, p. ex. `es,pt`. |
| `limit` | Non | `chats` uniquement. Conversations par page, 1–100. Par défaut 100. |
| `cursor` | Non | `chats` uniquement. Le `next_cursor` renvoyé par la page précédente. |

Les jours sont interprétés dans `tz` : `date_from=2026-10-01&date_to=2026-10-31` avec `tz=Europe/Madrid` couvre du 1er octobre à 00h00 au 1er novembre à 00h00, heure de Madrid. Les changements d'heure (heure d'été) sont gérés automatiquement.

Tous les horodatages des réponses sont en **UTC** (ISO 8601 se terminant par `Z`).

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

Renvoie une entrée par agent et par canal, triée par nombre de conversations.

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

| Champ | Description |
| - | - |
| `agent` | Agent IA qui a pris en charge les conversations (`id`, `name`). `null` si la conversation n'a pas d'agent. |
| `channel` | Canal de la conversation. `n/a` s'il n'a pas été enregistré. |
| `conversations` | Conversations démarrées dans la plage (pour la voix, appels). |
| `escalated` | Conversations transférées vers un humain (elles ont un événement `chat_escalated`). |
| `contained_pct` | `(conversations − escalated) / conversations × 100`. Part traitée par l'IA sans transfert. **Ce n'est pas un taux de résolution.** |
| `avg_duration_s` | Durée moyenne des appels en secondes : globale, sans transfert et avec transfert. `null` sur les canaux sans durée (seule la voix l'enregistre). |
| `whatsapp_notifications` | Notifications WhatsApp envoyées depuis ces conversations (événements `notification_sent`). |
| `unique_users` | Utilisateurs distincts (pour la voix, numéros de téléphone distincts). |
| `recontacts` | Utilisateurs ayant 2 conversations ou plus dans la plage. Taux de recontact = `recontacts / unique_users`. |
| `daily` | Conversations et transferts par jour, dans `tz`. Les jours sans conversation sont omis. |
| `hourly` | Conversations par heure de la journée (0–23), dans `tz`. Les heures sans conversation sont omises. |

> [!TIP]
>
> **Comparaisons avec le mois précédent** : appelez l'endpoint deux fois, une par mois, et calculez la différence.
> **Containment sur les jours avec présence humaine uniquement** : utilisez `daily` et conservez les jours où `escalated > 0`.

## Conversations (`type=chats`)

Renvoie les conversations de la plage une par une, des plus anciennes aux plus récentes, 100 par page par défaut.

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

| Champ | Description |
| - | - |
| `id` | Identifiant de la conversation. |
| `created_at`, `ended_at`, `last_message_at` | Début, fin et dernier message, en UTC. |
| `status` | Avec qui est la conversation : `aiagent`, `human`, `queue` (en attente d'un humain) ou `push` (initiée par une notification). |
| `channel`, `language` | Copiés depuis `parameters.channel` et `parameters.lang_user` par commodité. |
| `agent` | Agent IA de la conversation (`id`, `name`). |
| `escalated_to_human`, `escalated_at` | Indique si elle a été transférée vers un humain, et quand (premier transfert). |
| `attended_by_human` | Indique si un agent humain a écrit au moins un message. |
| `human_agents` | Agents humains qui ont écrit dans la conversation (`id`, `name`). Peut être vide même lorsque `attended_by_human` vaut `true` : les messages envoyés depuis un CRM externe ne sont pas attribués à une personne. |
| `whatsapp_notifications` | Notifications WhatsApp envoyées depuis la conversation. |
| `parameters` | **Tous** les paramètres enregistrés pour la conversation, sans filtre. Les clés dépendent du canal et de la configuration de votre agent (pour la voix : `call_length`, `phone_call`, `voice_inbound`, `session_call_id`, `conversation_recording_url`… ; ainsi que tout paramètre personnalisé que votre agent enregistre). |

### Pagination

Tant que `next_cursor` n'est pas `null`, demandez la page suivante avec les mêmes paramètres plus `cursor=<next_cursor>`. Les conversations sont triées par `created_at` et `id`, ce qui garantit qu'aucune conversation n'est répétée ni omise entre les pages.

```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), "conversations")
```

## Erreurs

Les erreurs renvoient un corps JSON `{ "success": false, "message": "…" }`.

| Code | Quand |
| - | - |
| `400` | Clé manquante (`Missing access_key parameter`), `type` invalide, dates invalides, plage supérieure à 31 jours, `tz`, `limit`, `agents`, `channels` ou `cursor` invalides. |
| `403` | La clé existe mais ne dispose pas de la permission `analytics_api`. |
| `404` | Clé invalide ou révoquée. |
| `405` | Méthode autre que `GET`. |
| `500` | Erreur interne. Réessayez après quelques secondes ; si le problème persiste, contactez le support en indiquant l'heure de la requête. |

## Limites et bonnes pratiques

* Jusqu'à **31 jours** par requête et **100 conversations** par page.
* Une requête `metrics` sur un mois complet prend quelques secondes. Pour un rapport mensuel ou quotidien, un seul appel par période suffit : inutile de faire du polling.
* Pour exporter un mois entier de conversations, parcourez les pages l'une après l'autre plutôt qu'en parallèle.
* Gardez la clé secrète et côté serveur. Ne l'utilisez pas dans un navigateur ni dans une application mobile.


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