
# API de Análise e Relatórios

Estes endpoints de leitura apenas permitem-lhe extrair a atividade da sua conta para os seus próprios dashboards e relatórios: contagens de eventos de mensagens, consumo de créditos, gastos com IA e os mesmos gráficos e informações que o dashboard na aplicação apresenta. Este guia abrange:

- **Resumo** — contadores de volume de mensagens (enviadas, entregues, lidas, respondidas, agendadas, contactos criados, créditos).
- **Créditos** — um registo detalhado e paginado da utilização de créditos com totais e detalhamentos.
- **Custo de IA** — um resumo diário dos gastos com IA.
- **Séries de métricas** — uma série temporal pronta a usar em gráficos para uma ou mais métricas, agrupadas por campanha, canal, Agente de IA ou número.
- **Resultados das conversas** — como as conversas terminaram, por etiqueta de resultado atribuída pela IA.
- **Informações do Dashboard** e **Informações de IA do Dashboard** — todos os dados por detrás do dashboard na aplicação, incluindo resumos escritos pela IA.
- **Atividade da entidade** — a cronologia de um único contacto, negócio ou tarefa.
- **Contagens de eventos agregados** — uma forma legada, em camelCase, do Resumo, mantida para integrações existentes.

Cada endpoint nesta página necessita de um âmbito exato, não de ambos: passe no máximo um de `campaign_id` (legado) ou `agent_id` onde o endpoint o aceite. Enviar ambos devolve `400`, e um id que não pertença à sua conta devolve `404` em vez de `403`, para que os ids de outras contas permaneçam impossíveis de adivinhar.

Todos os caminhos abaixo são relativos ao URL base da API:

```
https://api.youraiconnector.com/v1
```

Todos os pedidos devem ser autenticados. Consulte [Autenticação](authentication.md) para os quatro métodos aceites. Os exemplos aqui utilizam o cabeçalho `X-API-Key` (e uma forma de parâmetro de consulta para cURL).

---

## Intervalo de datas

Todos os três endpoints aceitam os mesmos filtros de data opcionais:

| Parâmetro | Descrição |
|---|---|
| `from` | Início do intervalo, `YYYY-MM-DD`, inclusivo. O padrão é há 30 dias. |
| `to` | Fim do intervalo, `YYYY-MM-DD`, inclusivo. O padrão é hoje. |

As datas são interpretadas em UTC. O intervalo tem como padrão os **últimos 30 dias** e está limitado a **366 dias** — um intervalo mais amplo devolve `400`. `from` não deve ser posterior a `to`.

### O sinalizador `truncated`

Os endpoints de **Resumo** e **Créditos** limitam quantos registos um único pedido analisa. Se o seu intervalo for suficientemente movimentado para atingir esse limite, a resposta inclui `"truncated": true`. Quando o vir, os números baseiam-se numa análise parcial — reduza o seu intervalo de datas (ou navegue pelas páginas com uma janela mais pequena) para obter números completos.

::: note
**Nota:** Os valores de custo e de tokens apenas são incluídos para chamadas de IA faturadas através das suas próprias chaves de API de fornecedor. Quando os valores de custo estão ocultos para a sua conta, a resposta define `"costs_redacted": true` e os campos de custo são devolvidos como zero.
:::


---

## Resumo do volume de mensagens

Devolve contadores agregados de eventos de mensagens para a sua conta, tanto como totais do intervalo como como uma série diária. Todos os dias no intervalo aparecem em `by_date` — os dias sem atividade são preenchidos com zero. Opcionalmente, filtre para uma única campanha com `campaign_id`.

`GET /analytics/summary`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `from` | Não | Início do intervalo, `YYYY-MM-DD`. |
| `to` | Não | Fim do intervalo, `YYYY-MM-DD`. |
| `campaign_id` | Não | Contar apenas eventos pertencentes a esta campanha. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/summary?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/summary?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/summary",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total": 1240,
    "sent": 800,
    "delivered": 760,
    "read": 540,
    "replied": 210,
    "booked": 35,
    "contact_created": 120,
    "credits_spent": 412.5,
    "credits_recharged": 500
  },
  "by_date": [
    {
      "date": "2026-05-01",
      "total": 40,
      "sent": 25,
      "delivered": 24,
      "read": 18,
      "replied": 7,
      "booked": 1,
      "contact_created": 4,
      "credits_spent": 13.5,
      "credits_recharged": 0
    }
  ],
  "truncated": false
}
```

Cada entrada em `by_date` tem os mesmos campos de contador que `totals`, mais um `date`.

Se passar um `campaign_id` que não pertence à sua conta, a resposta será `404` com `{ "success": false, "error": "Campaign not found" }`.

---

## Utilização de créditos

Devolve a utilização de créditos durante o intervalo: uma lista paginada de registos individuais, além de totais do intervalo e detalhamentos por motivo e por campanha.

`GET /analytics/credits`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `from` | Não | Início do intervalo, `YYYY-MM-DD`. |
| `to` | Não | Fim do intervalo, `YYYY-MM-DD`. |
| `campaign_id` | Não | Incluir apenas a utilização atribuída a esta campanha. |
| `limit` | Não | Tamanho da página para `records`, 1–100. O padrão é 50. |
| `cursor` | Não | Passe o `next_cursor` da página anterior para obter a página seguinte. |

> **Ajustes vs. consumo:** Alterações de saldo, tais como bónus, renovações de planos e correções, são **excluídas** de `totals` e dos detalhamentos — não constituem consumo real. Ainda aparecem na lista `records`, assinaladas com `"is_adjustment": true`.

**Os totais e detalhamentos aparecem apenas na primeira página** (quando não é fornecido nenhum `cursor`). Nas páginas seguintes, `totals`, `by_reason`, `by_reason_cost` e `by_campaign` são devolvidos como `null` — apenas a matriz `records` continua. Isto evita voltar a analisar todo o intervalo para cada página.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/credits?from=2026-05-01&to=2026-05-31&limit=50&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  limit: "50",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/credits?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

// To page: pass data.next_cursor as ?cursor on the next request, until it is null.
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/credits",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31", "limit": 50},
)
data = res.json()

# To page: pass data["next_cursor"] as cursor on the next request, until it is None.
```

**Resposta** (primeira página)

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "credits_used": 412.5,
    "cost_usd": 1.284512,
    "records": 318
  },
  "by_reason": {
    "AI Message": 380.0,
    "Campaign Message": 32.5
  },
  "by_reason_cost": {
    "AI Message": 1.284512,
    "Campaign Message": 0
  },
  "by_campaign": {
    "Spring Promo": 250.0,
    "Reactivation": 162.5
  },
  "records": [
    {
      "id": "rec_abc123",
      "amount": 1,
      "timestamp": "2026-05-31T14:02:11.000Z",
      "reason": "AI Message",
      "is_adjustment": false,
      "campaign_id": "campaign123",
      "campaign_name": "Spring Promo",
      "contact_id": "contact456",
      "contact_name": "Jane Smith",
      "credit_type": "ai",
      "custom_keys_used": false,
      "description": null,
      "cost_usd": 0,
      "input_tokens": 0,
      "output_tokens": 0,
      "cache_read_tokens": 0,
      "cache_creation_tokens": 0,
      "ai_model": null,
      "request_id": null,
      "is_test": false
    }
  ],
  "next_cursor": "rec_abc123",
  "costs_redacted": false,
  "truncated": false
}
```

**Notas de campo:**

- `amount` — créditos cobrados pelo registo. Zero para registos faturados na sua própria chave de API de fornecedor.
- `is_adjustment` — `true` para alterações de saldo (excluídas dos totais/detalhamentos).
- `cost_usd`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_creation_tokens`, `ai_model`, `request_id` — preenchidos apenas em registos faturados na sua própria chave de API de fornecedor; zero ou `null` caso contrário.
- `is_test` — `true` para execuções de teste/playground, que nunca são faturadas.
- `next_cursor` — o cursor para a página seguinte, ou `null` quando não existem mais registos.

---

## Resumo de custos de IA

Devolve o resumo diário de gastos com IA da sua conta. Isto lê totais diários pré-agregados, pelo que é rápido mesmo em intervalos longos. Todos os dias no intervalo aparecem em `days` — os dias sem atividade são preenchidos com zero.

`GET /analytics/ai-cost`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `from` | Não | Início do intervalo, `YYYY-MM-DD`. |
| `to` | Não | Fim do intervalo, `YYYY-MM-DD`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/ai-cost?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/ai-cost?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/ai-cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total_usd": 12.4821,
    "byok_usd": 12.4821,
    "platform_usd": 0,
    "calls": 4210
  },
  "days": [
    {
      "date": "2026-05-01",
      "total_usd": 0.4012,
      "byok_usd": 0.4012,
      "platform_usd": 0,
      "input_usd": 0.18,
      "output_usd": 0.19,
      "cache_creation_usd": 0.02,
      "cache_read_usd": 0.0112,
      "calls": 140,
      "by_provider": { "anthropic": 0.4012 }
    }
  ],
  "costs_redacted": false
}
```

**Notas de campo:**

- `byok_usd` — despesas cobradas através das suas próprias chaves de API de fornecedor.
- `platform_usd` — a parte das despesas que foi executada na plataforma em vez de na sua própria chave.
- `input_usd`, `output_usd`, `cache_creation_usd`, `cache_read_usd` — as componentes de custo que constituem `total_usd`.
- `by_provider` — despesas em USD organizadas pelo nome do fornecedor de IA.
- Os valores em USD só são devolvidos a contas que utilizam a sua própria chave de fornecedor. Para contas que pagam com crédito, todos os campos em USD são zero e `costs_redacted` é `true` (as contagens de chamadas permanecem visíveis).

---

## Séries de métricas

Devolve uma ou mais séries temporais de métricas numa única chamada, opcionalmente agrupadas por até duas dimensões — o endpoint para vincular a um gráfico. Um único pedido pode responder a "enviadas e respondidas por dia, por canal, para esta campanha" sem ser necessária uma chamada por campanha.

`GET /analytics/series`

Cada resposta contém uma matriz `labels` (o eixo temporal, preenchido com zeros em todo o intervalo) e uma entrada em `series` por grupo, cada uma contendo uma matriz por métrica solicitada alinhada com `labels`. As séries após `limit` não são descartadas — colapsam em `other_bucket`, calculado como o total do intervalo menos as séries devolvidas, para que um gráfico renderizado some sempre os seus números reais; `truncated` é `true` sempre que isso acontece.

De onde vêm os números: `sent`, `delivered`, `read` e `replied` provêm de registos de mensagens, que contêm o canal e o número de envio. `booked`, `contact_created` e `credits_spent` provêm do fluxo de eventos, que não contém número de envio, pelo que essas métricas caem no balde de número `null` quando agrupa por `number`.

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `from` | Não | Início do intervalo, `YYYY-MM-DD`. O padrão é há 30 dias. |
| `to` | Não | Fim do intervalo, `YYYY-MM-DD`. O padrão é hoje. |
| `metrics` | Não | Lista separada por vírgulas de `sent`, `ai_sent`, `human_sent`, `delivered`, `read`, `replied`, `booked`, `contact_created`, `credits_spent`. O padrão é `sent,replied`. Uma métrica desconhecida devolve `400`. |
| `group_by` | Não | Lista separada por vírgulas de até duas dimensões de `date`, `campaign`, `channel`, `agent`, `number`. `date` é aceite, mas não tem efeito — cada resposta já contém o eixo temporal. Omitir para uma única série de toda a conta. |
| `granularity` | Não | `day` (padrão), `week` ou `month`. Os baldes semanais começam à segunda-feira, os baldes mensais no dia 1. |
| `limit` | Não | Quantas séries devolver antes que o resto colapse em `other_bucket`, 1–50. O padrão é 12. |
| `campaign_id` | Não | Contar apenas a atividade pertencente a esta campanha. Legado; prefira `agent_id`. |
| `agent_id` | Não | Contar apenas a atividade pertencente a este Agente de IA. |
| `channel` | Não | Contar apenas a atividade neste canal, por exemplo `whatsapp`. |

O intervalo de datas deste endpoint está limitado a **92 dias** (mais restrito do que o limite de 366 dias usado noutros locais desta página).

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/series?from=2026-05-01&to=2026-05-31&metrics=sent,replied,booked&group_by=campaign,channel&limit=10&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  metrics: "sent,replied,booked",
  group_by: "campaign,channel",
  limit: "10",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/series?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/series",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={
        "from": "2026-05-01",
        "to": "2026-05-31",
        "metrics": "sent,replied,booked",
        "group_by": "campaign,channel",
        "limit": 10,
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "granularity": "day",
  "labels": ["2026-05-01", "2026-05-02"],
  "group_by": ["campaign", "channel"],
  "metrics": ["sent", "replied", "booked"],
  "series": [
    {
      "key": {
        "campaign_id": "campaign123",
        "campaign_name": "Spring Promo",
        "channel": "whatsapp"
      },
      "total": 812,
      "metrics": {
        "sent": [40, 35],
        "replied": [12, 9],
        "booked": [2, 1]
      }
    }
  ],
  "other_bucket": {
    "series_count": 6,
    "total": 340,
    "metrics": {
      "sent": [18, 20],
      "replied": [5, 6],
      "booked": [0, 1]
    }
  },
  "truncated": true
}
```

**Notas de campo:**

- `key` — a identidade de uma série. Apenas as chaves para as dimensões `group_by` solicitadas estão presentes; uma dimensão cujo valor é desconhecido para uma linha (uma mensagem sem campanha, um evento sem canal) volta como `null` em vez de ser descartada, para que as séries continuem a somar os totais.
- `other_bucket` — `null` quando nada foi colapsado.
- Este endpoint devolve `503` com `"error_code": "analytics_unavailable"` quando a base de dados de relatórios não consegue responder pela sua conta, em vez de um `200` cheio de zeros — um gráfico a zeros seria lido como um facto.

---

## Resultados das conversas

Devolve como as conversas terminaram durante um intervalo de datas: uma contagem diária para cada etiqueta de resultado que a IA atribuiu, mais totais de intervalo para respostas, agendamentos, transferências para um humano e conversas que a IA nunca classificou.

`GET /analytics/outcomes`

Passe `group_by=tag` para colapsar o eixo temporal e obter apenas totais de intervalo por etiqueta — nesse modo, `labels` está vazio e a matriz `counts` de cada etiqueta está vazia, enquanto `total` continua preenchido.

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `from` | Não | Início do intervalo, `YYYY-MM-DD`. Predefinição: há 30 dias. |
| `to` | Não | Fim do intervalo, `YYYY-MM-DD`. Predefinição: hoje. |
| `campaign_id` | Não | Contar apenas conversas com contactos atualmente nesta campanha. Legado; prefira `agent_id`. |
| `agent_id` | Não | Contar apenas resultados pertencentes a este Agente de IA. |
| `group_by` | Não | `date` (predefinição) mantém as contagens diárias; `tag` agrupa em totais de intervalo. |

O intervalo de datas deste endpoint está limitado a **92 dias**.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/outcomes?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/outcomes?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/outcomes",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "group_by": "date",
  "labels": ["2026-05-01", "2026-05-02"],
  "by_tag": [
    { "tag": "interested", "total": 84, "counts": [3, 5] },
    { "tag": "not_interested", "total": 40, "counts": [1, 2] },
    { "tag": null, "total": 12, "counts": [0, 1] }
  ],
  "totals": {
    "sessions": 260,
    "replied": 210,
    "booked": 35,
    "human_alerted": 18,
    "unresolved": 12
  }
}
```

**Notas de campo:**

- `by_tag[].tag` — `null` para conversas às quais a IA nunca atribuiu uma etiqueta de resultado.
- `totals.human_alerted` — conversas transferidas para um humano; isto é registado em cada transferência e não era anteriormente apresentado por nenhum endpoint.
- Mesma postura `503`/`analytics_unavailable` que a série de Métricas quando a base de dados de relatórios não consegue responder.

---

## Informações do dashboard

Devolve o payload completo do dashboard para um intervalo de datas numa única chamada: um mapa de calor da taxa de resposta por dia da semana e hora, a tabela de classificação de campanhas, volume por canal, totais exatos por ligação, detalhe de métricas por dia (a nível de conta, por canal e por número), origem dos contactos, tempo de resposta da caixa de entrada e um feed de atividade recente. Este é o payload de relatórios mais rico da API — alimenta diretamente o dashboard na aplicação.

`GET /analytics/dashboard-insights`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `startDate` | Sim | Início do intervalo, `YYYY-MM-DD`. |
| `endDate` | Sim | Fim do intervalo, `YYYY-MM-DD`. |
| `campaignId` | Não | Incluir apenas atividade pertencente a esta campanha (`campaign_id` também aceite). Legado; prefira `agent_id`. |
| `agent_id` | Não | Incluir apenas atividade pertencente a este Agente de IA (`agentId` também aceite). Sob o âmbito de um agente, a tabela de classificação de campanhas é construída apenas a partir da atividade desse agente. |

Este endpoint utiliza `startDate`/`endDate` (não `from`/`to`) porque partilha a sua implementação com o dashboard na aplicação. O intervalo está limitado a 92 dias e é **ajustado, não rejeitado**, quando é superior.

> **Nulo significa indisponível, não zero.** Vários blocos (`numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`) são calculados a partir da base de dados de relatórios e devolvem `null` quando esta não consegue responder pela sua conta. Não apresente um bloco `null` como um gráfico vazio.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/dashboard-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()
```

**Resposta** (abreviada — este payload é grande; consulte a [Referência da API](reference.md) para o esquema completo)

```json
{
  "success": true,
  "data": {
    "heatmap": {
      "buckets": [
        { "weekday": 1, "hour": 9, "sent": 12, "replied": 5, "replyRate": 0.42 }
      ]
    },
    "topCampaigns": [
      { "campaignId": "campaign123", "name": "Spring Promo", "sent": 420, "replied": 180, "booked": 22, "replyRate": 0.43, "creditsSpent": 210.5 }
    ],
    "channelVolume": [
      { "channel": "whatsapp", "sent": 800, "received": 540, "lastMessageAt": "2026-05-31T14:02:11.000Z" }
    ],
    "inboxSla": { "medianFirstResponseMs": 92000, "sampleSize": 140 },
    "activityFeed": [
      { "id": "evt_1", "kind": "booked", "at": "2026-05-31T14:02:11.000Z", "contactId": "contact456", "contactName": "Jane Smith", "campaignId": "campaign123", "campaignName": "Spring Promo", "label": "Jane Smith booked an appointment" }
    ],
    "numberStats": null,
    "channelDailySeries": null,
    "metricDailyBreakdown": null,
    "contactsByCountry": null,
    "ai_human_split": null
  }
}
```

**Notas de campo:**

- `heatmap.buckets[].weekday` — `0` é domingo até `6` é sábado.
- `numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`, `ai_human_split` — cada um independentemente `null` quando a base de dados de relatórios está indisponível para a sua conta; todos os outros blocos continuam a devolver resultados.

---

## Informações de IA do dashboard

Devolve três breves informações escritas por IA sobre as mensagens da conta durante um intervalo de datas: uma vitória, um ponto de atenção e uma dica — frases que pode colar diretamente num relatório em vez de números que ainda teria de interpretar. Gerado apenas a partir das métricas de mensagens da própria conta.

`GET /analytics/dashboard-ai-insights`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `startDate` | Sim | Início do intervalo, `YYYY-MM-DD`. |
| `endDate` | Sim | Fim do intervalo, `YYYY-MM-DD`. |

Este endpoint é aplicável a toda a conta — não requer âmbito de campanha ou de agente.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "insights": [
      { "tone": "win", "title": "Reply rate is up", "detail": "Your reply rate climbed to 43% this period, up from 36% the period before." },
      { "tone": "watch", "title": "Bookings slowed midweek", "detail": "Wednesday bookings dropped to a third of Monday's, worth a look at your Wednesday follow-up timing." },
      { "tone": "tip", "title": "Re-send to non-repliers", "detail": "212 contacts received a message but never replied — a short follow-up template often recovers 10-15% of them." }
    ]
  }
}
```

A falta de `startDate` ou `endDate` devolve `400`.

---

## Cronologia de atividade da entidade

Devolve a atividade de um único contacto, negócio ou tarefa como uma cronologia única, da mais recente para a mais antiga: o que aconteceu e quando, através de mensagens, marcações, notas e alterações de estado. Utilize-o para responder a "o que aconteceu com esta pessoa" sem ter de combinar vários endpoints de lista.

`GET /analytics/entity-activity`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `entityType` | Sim | `contact`, `deal` ou `task`. |
| `entityId` | Sim | ID do registo cuja cronologia pretende obter. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/entity-activity?entityType=contact&entityId=contact456&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ entityType: "contact", entityId: "contact456" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/entity-activity?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/entity-activity",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"entityType": "contact", "entityId": "contact456"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "evt_9",
        "kind": "appointment_booked",
        "at": "2026-05-31T14:02:11.000Z",
        "label": "Booked an appointment for June 3",
        "detail": "Consultation call, 30 minutes"
      },
      {
        "id": "evt_8",
        "kind": "message_replied",
        "at": "2026-05-31T13:58:02.000Z",
        "label": "Replied: \"Yes, that time works\""
      }
    ]
  }
}
```

Um `entityType`/`entityId` em falta ou inválido devolve `400`. Uma entidade que não existe na sua conta devolve `404`, para que os IDs de outras contas permaneçam impossíveis de adivinhar.

---

## Contagens de eventos agregadas (legado)

Devolve as mesmas contagens de eventos agregadas que o [Resumo do volume de mensagens](#message-volume-summary), mas no formato camelCase (`contactCreated` em vez de `contact_created`, `byDate` em vez de `by_date`) para o qual algumas integrações mais antigas foram criadas. Prefira `/analytics/summary` para novas integrações — este endpoint existe apenas para que o dashboard da aplicação e a API partilhem a mesma implementação.

`GET /analytics/aggregate`

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `startDate` | Não | Início do intervalo, data ou data-hora ISO. Predefinição para a mesma janela que `/analytics/summary` utiliza. |
| `endDate` | Não | Fim do intervalo, data ou data-hora ISO. |
| `campaignId` | Não | Contar apenas eventos pertencentes a esta campanha (`campaign_id` também aceite). Legado; prefira `agent_id`. |
| `agent_id` | Não | Contar apenas eventos pertencentes a este Agente de IA (`agentId` também aceite). |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/aggregate?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "from": "2026-05-01",
    "to": "2026-05-31",
    "total": 1240,
    "byAnalyticType": {
      "total": 1240,
      "sent": 800,
      "delivered": 760,
      "read": 540,
      "replied": 210,
      "booked": 35,
      "contactCreated": 120,
      "creditsSpent": 412.5,
      "creditsRecharged": 500
    },
    "byDate": [
      { "date": "2026-05-01", "byAnalyticType": { "total": 40, "sent": 25, "delivered": 24, "read": 18, "replied": 7, "booked": 1, "contactCreated": 4, "creditsSpent": 13.5, "creditsRecharged": 0 } }
    ]
  }
}
```

---

## Agrupamento de subcontas de agência


---

## Erros da API de Analytics

Os endpoints de Analytics devolvem o envelope de erro padrão:

```json
{
  "success": false,
  "error": "Date range too large. Maximum is 366 days."
}
```

Num endpoint de análise, um formato de data inválido ou uma janela fora do intervalo devolve `400`, e um `campaign_id` ou `agent_id` desconhecido devolve `404`. Enviar tanto `campaign_id` como `agent_id` num endpoint que aceite qualquer um deles é também um `400` — envie no máximo um. Os endpoints de relatórios exclusivos de PG (Série de métricas, Resultados de conversação, Agrupamento de agência) devolvem `503` com `"error_code": "analytics_unavailable"` em vez de um `200` cheio de zeros quando a base de dados de relatórios não consegue responder pela sua conta — tente novamente em breve. Os códigos partilhados que qualquer endpoint pode devolver — `401`, `403` (o seu plano não inclui acesso à API ou, no agrupamento de agência, a sua conta não é Agência/Dev), `429` (limite de taxa) e `500` — estão listados com orientações de repetição em [Erros e Paginação](errors-and-pagination.md).

---

## Próximos passos

- [Autenticação](authentication.md) — as quatro formas de autenticar um pedido.
- [Erros e Limites de Taxa](errors-and-pagination.md) — códigos de estado e o limite de 300 pedidos/min.
- [API de Campanhas](campaigns.md) — as campanhas pelas quais estes números podem ser filtrados.
