
# API Analitik & Laporan

Endpoint read-only ini memungkinkan Anda menarik aktivitas akun ke dasbor dan laporan Anda sendiri: jumlah peristiwa pesan, konsumsi kredit, pengeluaran AI, serta grafik dan wawasan yang sama seperti yang ditampilkan di dasbor dalam aplikasi. Panduan ini mencakup:

- **Ringkasan** — penghitung volume pesan (terkirim, terkirim ke tujuan, dibaca, dibalas, dipesan, kontak dibuat, kredit).
- **Kredit** — buku besar penggunaan kredit yang terperinci dan berhalaman dengan total dan perincian.
- **Biaya AI** — akumulasi pengeluaran AI per hari.
- **Seri metrik** — deret waktu siap-grafik untuk satu atau beberapa metrik, dikelompokkan berdasarkan kampanye, saluran, Agen AI, atau nomor.
- **Hasil percakapan** — bagaimana percakapan berakhir, berdasarkan tag hasil yang ditetapkan AI.
- **Wawasan dasbor** dan **Wawasan AI dasbor** — data lengkap di balik dasbor dalam aplikasi, termasuk ringkasan yang ditulis AI.
- **Aktivitas entitas** — linimasa satu kontak, kesepakatan, atau tugas.
- **Jumlah peristiwa gabungan** — bentuk camelCase lama dari Ringkasan yang dipertahankan untuk integrasi yang sudah ada.

Setiap endpoint di halaman ini memerlukan cakupan yang tepat, bukan keduanya: berikan paling banyak satu dari `campaign_id` (lama) atau `agent_id` di mana endpoint menerimanya. Mengirim keduanya akan mengembalikan `400`, dan id yang tidak ada di akun Anda akan mengembalikan `404` alih-alih `403`, sehingga id akun lain tetap tidak dapat ditebak.

Semua jalur di bawah ini bersifat relatif terhadap URL dasar API:

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

Setiap permintaan harus diautentikasi. Lihat [Autentikasi](authentication.md) untuk empat metode yang diterima. Contoh di sini menggunakan header `X-API-Key` (dan satu bentuk parameter kueri untuk cURL).

---

## Rentang tanggal

Ketiga endpoint menerima filter tanggal opsional yang sama:

| Parameter | Deskripsi |
|---|---|
| `from` | Awal rentang, `YYYY-MM-DD`, inklusif. Default-nya adalah 30 hari yang lalu. |
| `to` | Akhir rentang, `YYYY-MM-DD`, inklusif. Default-nya adalah hari ini. |

Tanggal diinterpretasikan dalam UTC. Rentang default adalah **30 hari terakhir** dan dibatasi hingga **366 hari** — rentang yang lebih luas akan mengembalikan `400`. `from` tidak boleh setelah `to`.

### Flag `truncated`

Endpoint **Ringkasan** dan **Kredit** membatasi berapa banyak catatan yang dipindai oleh satu permintaan. Jika rentang Anda cukup sibuk hingga mencapai batas tersebut, respons akan menyertakan `"truncated": true`. Saat Anda melihatnya, angka-angka tersebut didasarkan pada pemindaian parsial — persempit rentang tanggal Anda (atau buka halaman dengan jendela yang lebih kecil) untuk mendapatkan angka lengkap.

::: note
**Catatan:** Angka biaya dan token hanya disertakan untuk panggilan AI yang ditagihkan ke kunci API penyedia Anda sendiri. Saat angka biaya disembunyikan untuk akun Anda, respons akan mengatur `"costs_redacted": true` dan kolom biaya dikembalikan sebagai nol.
:::


---

## Ringkasan volume pesan

Mengembalikan penghitung peristiwa pesan yang diagregasi untuk akun Anda, baik sebagai total rentang maupun sebagai seri per hari. Setiap hari dalam rentang muncul di `by_date` — hari yang sepi diisi dengan nol. Secara opsional, filter ke satu kampanye dengan `campaign_id`.

`GET /analytics/summary`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `from` | Tidak | Awal rentang, `YYYY-MM-DD`. |
| `to` | Tidak | Akhir rentang, `YYYY-MM-DD`. |
| `campaign_id` | Tidak | Hanya hitung peristiwa yang termasuk dalam kampanye ini. |

**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()
```

**Respons**

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

Setiap entri dalam `by_date` memiliki kolom penghitung yang sama dengan `totals`, ditambah `date`.

Jika Anda memberikan `campaign_id` yang bukan milik akun Anda, responsnya adalah `404` dengan `{ "success": false, "error": "Campaign not found" }`.

---

## Penggunaan kredit

Mengembalikan penggunaan kredit selama rentang waktu: daftar catatan individual yang dipaginasi, ditambah total rentang dan rincian berdasarkan alasan serta kampanye.

`GET /analytics/credits`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `from` | Tidak | Awal rentang, `YYYY-MM-DD`. |
| `to` | Tidak | Akhir rentang, `YYYY-MM-DD`. |
| `campaign_id` | Tidak | Hanya sertakan penggunaan yang diatribusikan ke kampanye ini. |
| `limit` | Tidak | Ukuran halaman untuk `records`, 1–100. Defaultnya adalah 50. |
| `cursor` | Tidak | Berikan `next_cursor` halaman sebelumnya untuk mengambil halaman berikutnya. |

> **Penyesuaian vs. konsumsi:** Perubahan saldo seperti bonus, pembaruan paket, dan koreksi **dikecualikan** dari `totals` dan rinciannya — ini bukan konsumsi nyata. Hal tersebut tetap muncul dalam daftar `records`, ditandai dengan `"is_adjustment": true`.

**Total dan rincian hanya muncul di halaman pertama** (saat tidak ada `cursor` yang diberikan). Pada halaman berikutnya, `totals`, `by_reason`, `by_reason_cost`, dan `by_campaign` dikembalikan sebagai `null` — hanya array `records` yang berlanjut. Ini menghindari pemindaian ulang seluruh rentang untuk setiap halaman.

**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.
```

**Respons** (halaman pertama)

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

**Catatan kolom:**

- `amount` — kredit yang dibebankan untuk catatan tersebut. Nol untuk catatan yang ditagihkan ke kunci API penyedia Anda sendiri.
- `is_adjustment` — `true` untuk perubahan saldo (dikecualikan dari total/rincian).
- `cost_usd`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_creation_tokens`, `ai_model`, `request_id` — diisi hanya pada catatan yang ditagihkan ke kunci API penyedia Anda sendiri; nol atau `null` jika tidak.
- `is_test` — `true` untuk uji coba/playground, yang tidak pernah ditagihkan.
- `next_cursor` — kursor untuk halaman berikutnya, atau `null` jika tidak ada lagi catatan.

---

## Ringkasan biaya AI

Mengembalikan ringkasan pengeluaran AI per hari untuk akun Anda. Ini membaca total harian yang telah diagregasi sebelumnya, sehingga cepat bahkan dalam rentang waktu yang lama. Setiap hari dalam rentang tersebut muncul di `days` — hari yang tenang diisi dengan nol.

`GET /analytics/ai-cost`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `from` | Tidak | Awal rentang, `YYYY-MM-DD`. |
| `to` | Tidak | Akhir rentang, `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()
```

**Respons**

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

**Catatan kolom:**

- `byok_usd` — pengeluaran yang ditagihkan ke kunci API penyedia Anda sendiri.
- `platform_usd` — porsi pengeluaran yang berjalan di platform, bukan menggunakan kunci Anda sendiri.
- `input_usd`, `output_usd`, `cache_creation_usd`, `cache_read_usd` — komponen biaya yang membentuk `total_usd`.
- `by_provider` — pengeluaran dalam USD berdasarkan nama penyedia AI.
- Angka USD hanya dikembalikan ke akun yang menggunakan kunci penyedia mereka sendiri. Untuk akun yang membayar dengan kredit, setiap kolom USD bernilai nol dan `costs_redacted` adalah `true` (jumlah panggilan tetap terlihat).

---

## Seri metrik

Mengembalikan satu atau beberapa deret waktu metrik dalam satu panggilan, secara opsional dikelompokkan hingga dua dimensi — endpoint untuk mengikat grafik. Satu permintaan dapat menjawab "pesan terkirim dan dibalas per hari, per saluran, untuk kampanye ini" tanpa perlu satu panggilan per kampanye.

`GET /analytics/series`

Setiap respons membawa array `labels` (sumbu waktu, diisi nol di seluruh rentang) dan satu entri di `series` per grup, masing-masing menampung satu array per metrik yang diminta yang diselaraskan dengan `labels`. Seri setelah `limit` tidak dibuang — seri tersebut digabungkan ke dalam `other_bucket`, dihitung sebagai total rentang dikurangi seri yang dikembalikan, sehingga grafik yang dirender selalu berjumlah sesuai dengan angka asli Anda; `truncated` adalah `true` kapan pun itu terjadi.

Dari mana angka-angka tersebut berasal: `sent`, `delivered`, `read`, dan `replied` berasal dari catatan pesan, yang membawa saluran dan nomor pengirim. `booked`, `contact_created`, dan `credits_spent` berasal dari aliran peristiwa, yang tidak membawa nomor pengirim, sehingga metrik tersebut masuk ke bucket nomor `null` saat Anda mengelompokkan berdasarkan `number`.

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `from` | Tidak | Awal rentang, `YYYY-MM-DD`. Default-nya adalah 30 hari yang lalu. |
| `to` | Tidak | Akhir rentang, `YYYY-MM-DD`. Default-nya adalah hari ini. |
| `metrics` | Tidak | Daftar yang dipisahkan koma dari `sent`, `ai_sent`, `human_sent`, `delivered`, `read`, `replied`, `booked`, `contact_created`, `credits_spent`. Default-nya adalah `sent,replied`. Metrik yang tidak dikenal mengembalikan `400`. |
| `group_by` | Tidak | Daftar yang dipisahkan koma hingga dua dimensi dari `date`, `campaign`, `channel`, `agent`, `number`. `date` diterima tetapi tidak berpengaruh — setiap respons sudah membawa sumbu waktu. Abaikan untuk satu seri di seluruh akun. |
| `granularity` | Tidak | `day` (default), `week`, atau `month`. Bucket minggu dimulai pada hari Senin, bucket bulan pada tanggal 1. |
| `limit` | Tidak | Berapa banyak seri yang akan dikembalikan sebelum sisanya digabungkan ke dalam `other_bucket`, 1–50. Default-nya adalah 12. |
| `campaign_id` | Tidak | Hanya hitung aktivitas milik kampanye ini. Lama; lebih disukai `agent_id`. |
| `agent_id` | Tidak | Hanya hitung aktivitas milik Agen AI ini. |
| `channel` | Tidak | Hanya hitung aktivitas pada saluran ini, contohnya `whatsapp`. |

Rentang tanggal endpoint ini dibatasi hingga **92 hari** (lebih ketat daripada batas 366 hari yang digunakan di tempat lain di halaman ini).

**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()
```

**Respons**

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

**Catatan kolom:**

- `key` — identitas satu seri. Hanya kunci untuk dimensi `group_by` yang diminta yang ada; dimensi yang nilainya tidak diketahui untuk baris (pesan tanpa kampanye, peristiwa tanpa saluran) akan kembali sebagai `null` alih-alih dibuang, sehingga seri tetap berjumlah sesuai dengan totalnya.
- `other_bucket` — `null` saat tidak ada yang digabungkan.
- Endpoint ini mengembalikan `503` dengan `"error_code": "analytics_unavailable"` saat basis data pelaporan tidak dapat menjawab untuk akun Anda, alih-alih `200` yang penuh dengan angka nol — grafik yang dinolkan akan dibaca sebagai fakta.

---

## Hasil percakapan

Mengembalikan bagaimana percakapan berakhir selama rentang tanggal: jumlah per hari untuk setiap tag hasil yang ditetapkan AI, ditambah total rentang untuk balasan, pemesanan, serah terima ke manusia, dan percakapan yang tidak pernah diklasifikasikan oleh AI.

`GET /analytics/outcomes`

Berikan `group_by=tag` untuk menggabungkan sumbu waktu dan mendapatkan total rentang per tag saja — dalam mode tersebut `labels` kosong dan setiap array `counts` tag kosong, sementara `total` masih terisi.

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `from` | Tidak | Awal rentang, `YYYY-MM-DD`. Defaultnya adalah 30 hari yang lalu. |
| `to` | Tidak | Akhir rentang, `YYYY-MM-DD`. Defaultnya adalah hari ini. |
| `campaign_id` | Tidak | Hanya hitung percakapan dengan kontak yang saat ini ada di kampanye ini. Warisan; lebih disarankan `agent_id`. |
| `agent_id` | Tidak | Hanya hitung hasil yang dimiliki oleh Agen AI ini. |
| `group_by` | Tidak | `date` (default) mempertahankan jumlah per hari; `tag` menggabungkan menjadi total rentang. |

Rentang tanggal titik akhir ini dibatasi hingga **92 hari**.

**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()
```

**Respons**

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

**Catatan kolom:**

- `by_tag[].tag` — `null` untuk percakapan yang tidak pernah diberi label hasil oleh AI.
- `totals.human_alerted` — percakapan yang diserahkan kepada manusia; ini ditulis pada setiap penyerahan dan sebelumnya tidak dimunculkan oleh titik akhir mana pun.
- Postur `503`/`analytics_unavailable` yang sama seperti seri Metrik saat basis data pelaporan tidak dapat menjawab.

---

## Wawasan dasbor

Mengembalikan payload dasbor lengkap untuk rentang tanggal dalam satu panggilan: peta panas tingkat balasan berdasarkan hari dalam seminggu dan jam, papan peringkat kampanye, volume per saluran, total per koneksi yang tepat, perincian metrik per hari (seluruh akun, per saluran, dan per nomor), asal kontak, waktu respons kotak masuk, dan umpan aktivitas terkini. Ini adalah payload pelaporan terkaya di API — yang menggerakkan dasbor dalam aplikasi secara langsung.

`GET /analytics/dashboard-insights`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `startDate` | Ya | Awal rentang, `YYYY-MM-DD`. |
| `endDate` | Ya | Akhir rentang, `YYYY-MM-DD`. |
| `campaignId` | Tidak | Hanya sertakan aktivitas yang dimiliki oleh kampanye ini (`campaign_id` juga diterima). Warisan; lebih disarankan `agent_id`. |
| `agent_id` | Tidak | Hanya sertakan aktivitas yang dimiliki oleh Agen AI ini (`agentId` juga diterima). Di bawah cakupan agen, papan peringkat kampanye dibangun hanya dari aktivitas agen tersebut. |

Titik akhir ini menggunakan `startDate`/`endDate` (bukan `from`/`to`) karena berbagi implementasi dengan dasbor dalam aplikasi. Rentang dibatasi hingga 92 hari dan **dijepit (clamped), bukan ditolak**, jika rentang tersebut lebih lebar.

> **Null berarti tidak tersedia, bukan nol.** Beberapa blok (`numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`) dihitung dari basis data pelaporan dan kembali sebagai `null` jika basis data tersebut tidak dapat menjawab untuk akun Anda. Jangan merender blok `null` sebagai bagan kosong.

**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()
```

**Respons** (disingkat — payload ini besar; lihat [Referensi API](reference.md) untuk skema lengkapnya)

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

**Catatan kolom:**

- `heatmap.buckets[].weekday` — `0` adalah Minggu hingga `6` adalah Sabtu.
- `numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`, `ai_human_split` — masing-masing secara independen `null` saat basis data pelaporan tidak tersedia untuk akun Anda; setiap blok lainnya tetap mengembalikan data.

---

## Wawasan AI dasbor

Mengembalikan tiga wawasan singkat yang ditulis oleh AI tentang pesan akun selama rentang tanggal: satu kemenangan, satu hal yang perlu diperhatikan, dan satu kiat — kalimat yang dapat Anda tempel langsung ke dalam laporan alih-alih angka yang masih harus Anda interpretasikan. Dihasilkan hanya dari metrik pesan akun itu sendiri.

`GET /analytics/dashboard-ai-insights`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `startDate` | Ya | Awal rentang, `YYYY-MM-DD`. |
| `endDate` | Ya | Akhir rentang, `YYYY-MM-DD`. |

Titik akhir ini berlaku untuk seluruh akun — tidak memerlukan cakupan kampanye atau agen.

**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()
```

**Respons**

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

`startDate` atau `endDate` yang hilang akan mengembalikan `400`.

---

## Linimasa aktivitas entitas

Mengembalikan aktivitas satu kontak, kesepakatan, atau tugas sebagai satu linimasa, diurutkan dari yang terbaru: apa yang terjadi dan kapan, mencakup pesan, janji temu, catatan, dan perubahan status. Gunakan ini untuk menjawab "apa yang telah terjadi dengan orang ini" tanpa harus menggabungkan beberapa titik akhir daftar.

`GET /analytics/entity-activity`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `entityType` | Ya | `contact`, `deal`, atau `task`. |
| `entityId` | Ya | ID catatan yang linimasanya ingin dikembalikan. |

**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()
```

**Respons**

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

`entityType`/`entityId` yang hilang atau tidak valid akan mengembalikan `400`. Entitas yang tidak ada di akun Anda akan mengembalikan `404`, sehingga ID akun lain tetap tidak dapat ditebak.

---

## Jumlah peristiwa gabungan (warisan)

Mengembalikan jumlah peristiwa gabungan yang sama seperti [Ringkasan volume pesan](#message-volume-summary), tetapi dalam bentuk camelCase (`contactCreated` alih-alih `contact_created`, `byDate` alih-alih `by_date`) yang digunakan oleh beberapa integrasi lama. Gunakan `/analytics/summary` untuk integrasi baru — titik akhir ini ada hanya agar dasbor dalam aplikasi dan API berbagi implementasi yang sama.

`GET /analytics/aggregate`

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `startDate` | Tidak | Awal rentang, tanggal atau tanggal-waktu ISO. Default ke jendela yang sama yang digunakan `/analytics/summary`. |
| `endDate` | Tidak | Akhir rentang, tanggal atau tanggal-waktu ISO. |
| `campaignId` | Tidak | Hanya hitung peristiwa milik kampanye ini (`campaign_id` juga diterima). Warisan; gunakan `agent_id`. |
| `agent_id` | Tidak | Hanya hitung peristiwa milik Agen AI ini (`agentId` juga diterima). |

**cURL**

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

**Respons**

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

---

## Penggabungan sub-akun agensi


---

## Kesalahan API Analytics

Endpoint Analytics mengembalikan amplop kesalahan standar:

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

Pada titik akhir analitik, format tanggal yang tidak valid atau jendela di luar rentang akan mengembalikan `400`, dan `campaign_id` atau `agent_id` yang tidak diketahui akan mengembalikan `404`. Mengirim `campaign_id` dan `agent_id` sekaligus pada titik akhir yang hanya menerima salah satunya juga merupakan `400` — kirimkan maksimal satu. Titik akhir pelaporan khusus PG (Seri metrik, Hasil percakapan, Penggabungan agensi) mengembalikan `503` dengan `"error_code": "analytics_unavailable"` alih-alih `200` yang penuh dengan angka nol ketika basis data pelaporan tidak dapat menjawab untuk akun Anda — coba lagi dalam waktu singkat. Kode bersama yang dapat dikembalikan oleh setiap titik akhir — `401`, `403` (paket Anda tidak menyertakan akses API, atau, pada penggabungan agensi, akun Anda bukan Agensi/Dev), `429` (batas kecepatan), dan `500` — tercantum dengan panduan percobaan ulang di [Kesalahan & Penomoran Halaman](errors-and-pagination.md).

---

## Langkah berikutnya

- [Autentikasi](authentication.md) — empat cara untuk mengautentikasi permintaan.
- [Error & Batas Kecepatan](errors-and-pagination.md) — kode status dan batas 300 permintaan/menit.
- [API Kampanye](campaigns.md) — kampanye yang dapat digunakan untuk memfilter angka-angka ini.
