Analytics API
Conversation, AI, ticket and team numbers, the same data that powers your dashboard.
All analytics endpoints use your API key and return the same data, from the same cache, as the Kerabie dashboard. Results are cached briefly (summary and agents: 5 minutes; tickets and setup: 1 minute), so a number can lag live activity slightly.
import { KerAbieClient } from '@kerabie/sdk';
const kerabie = new KerAbieClient({ apiKey: process.env.KERABIE_API_KEY });Summary
GET /v1/analytics/summary| Query param | Description |
|---|---|
days | Window length in days. Default 30, maximum 365. |
period | Alternative to days, e.g. 7d or 30d. Wins if both are sent. |
const summary = await kerabie.analytics.getSummary({ days: 7 });Response
{
"period": { "days": 7, "since": "2026-09-28T00:00:00.000Z" },
"openConversations": 14,
"resolvedToday": 9,
"avgResponseTime": 144,
"satisfactionScore": 96,
"activeVisitors": 23,
"totals": { "conversations": 186, "resolved": 120, "closed": 20, "messages": 900, "visitors": 40, "aiChats": 310, "tickets": 22, "contacts": 35, "siteVisitors": 1290 },
"rates": { "resolution": 75 },
"satisfaction": { "avgRating": 4.8, "totalRatings": 30 },
"deltas": { "conversations": 12, "resolved": 9, "responseTime": -8, "satisfaction": 4, "aiChats": 31 },
"ai": { "resolvedAlone": 130, "resolvedAlonePct": 70, "handedOffPct": 18, "agentHoursSaved": 41 },
"channels": [{ "channel": "WHATSAPP", "count": 54 }, { "channel": "WEBSITE", "count": 38 }],
"aiEscalations": [{ "reason": "kb_gap", "count": 33 }],
"trend": [
{ "date": "2026-10-04", "count": 28, "ai": 17, "human": 11 },
{ "date": "2026-10-05", "count": 24, "ai": 15, "human": 9 }
]
}Field notes
avgResponseTimeis the average first-response time in seconds (0when there is no data yet).satisfactionScoreis the average rating × 20, so0–100.deltasare the percentage change versus the previous period of the same length. A value isnullwhen there is nothing to compare against. ForresponseTime, a negative number is an improvement.ai.resolvedAlonecounts conversations the AI handled without a human ever replying.ai.handedOffPctis the share handed off to a person.ai.agentHoursSavedis an estimate: AI-only conversations × the average time your agents spent on the human-handled ones in the same window (each clamped to 1–120 minutes; 8 minutes is assumed when there are no human-handled conversations yet).trendhas one entry per day, oldest first, capped at the last 30 days, with empty days included.ai + human = count.
Insights
GET /v1/analytics/insightsTakes the same days / period parameters as the summary. This is what powers the Agents, Channels, AI and questions, Customers and Pages tabs of the dashboard's Analytics page.
const insights = await kerabie.analytics.getInsights({ days: 30 });{
"period": { "days": 30, "since": "2026-09-06T00:00:00.000Z" },
"firstResponse": { "medianSeconds": 144, "deltaPct": -8, "sample": 240 },
"agents": [
{ "agentId": 1, "name": "Amara Osei", "availability": "online", "messages": 900, "assigned": 142, "resolved": 134, "resolutionRate": 94, "avgRating": 4.8, "firstResponseSeconds": 126 }
],
"channels": [
{ "channel": "WHATSAPP", "count": 108, "pct": 38, "firstResponseSeconds": 132, "avgRating": 4.7 }
],
"ai": {
"csatOnAiChats": { "avg": 4.4, "count": 61 },
"questions": [
{ "question": "Where is my order?", "asked": 128, "aiResolvedPct": 74, "avgRating": 4.1, "page": "/orders", "trendPct": 6 }
],
"unanswered": [{ "question": "Do you support SSO with Okta?", "count": 23 }],
"outcomes": { "resolvedByAi": 198, "handedOff": 51, "other": 35 }
},
"customers": {
"active": 1230, "new": 412, "returning": 818, "perCustomer": 2.3,
"deltas": { "active": 23, "new": 14, "returning": 27 },
"csat": [{ "stars": 5, "count": 111, "pct": 68 }, { "stars": 4, "count": 33, "pct": 20 }],
"csatResponses": 163,
"countries": [{ "country": "NG", "count": 412 }],
"newPct": 34, "returningPct": 66,
"top": [{ "id": 1, "name": "Chidi Okafor", "company": "Palmex", "conversations": 14, "lastSeenAt": "2026-10-06T10:30:00.000Z", "avgRating": 4.2 }],
"heatmap": { "days": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], "cells": [[0, 1, 0, 2, 5, 9, 14, 12, 8, 4, 2, 0]], "timezone": "Africa/Lagos" }
},
"pages": [
{ "page": "/pricing", "views": 4210, "questions": 412, "askRate": 9.8, "topQuestion": "Can I get a refund after 30 days?" }
]
}Field notes
firstResponse.medianSecondsis the median time from a customer's first message to a person's first reply (AI replies don't count).deltaPctcompares with the previous period; negative is faster.- Questions are grouped by their first customer message, ignoring case and punctuation. Greetings ("hi", "thanks") are left out. Only the top 20 are returned, most asked first.
aiResolvedPctis the share of those conversations where no person ever replied and the AI didn't hand off.avgRatingis the customers' own 1–5 rating of those conversations.unansweredare the questions behind AI handoffs with the reason no matching knowledge base article: good candidates for new articles.heatmap.cellshas one row per weekday (Monday first) and 12 columns, each a two-hour block starting at 0, 2, … 22, counted in the organisation's own timezone.pages:viewsare the widget page views we recorded (kept for 90 days) andquestionsthe conversations that started on that page.askRate= questions ÷ views, and isnullwhile a page has no recorded views. A conversation's page is the one the visitor was on when they wrote in; conversations before this was tracked have none.- Computed from up to the 20,000 most recent conversations in the window and cached for up to 5 minutes.
Agent performance
GET /v1/analytics/agentsAccepts the same days / period parameters as the summary.
const { agents } = await kerabie.analytics.getAgentStats({ period: '7d' });{
"agents": [
{
"agentId": 7,
"name": "Amara Osei",
"avatar": "https://cdn.kerabie.com/avatars/7.jpg",
"availability": "online",
"messages": 200,
"assigned": 12,
"resolved": 10,
"resolutionRate": 83,
"avgRating": 4.9
}
]
}name falls back to the part of the email before the @ for agents who haven't set a name. Agents are sorted by resolved, highest first.
Open tickets and SLA
GET /v1/analytics/tickets-slaconst sla = await kerabie.analytics.getTicketSla();{
"total": 32,
"withinSlaPct": 94,
"byPriority": [
{ "priority": "URGENT", "count": 3, "oldestMinutes": 14 },
{ "priority": "HIGH", "count": 8, "oldestMinutes": 60 },
{ "priority": "NORMAL", "count": 21, "oldestMinutes": 180 },
{ "priority": "LOW", "count": 0, "oldestMinutes": null }
]
}Only open tickets (new or active) are counted. withinSlaPct is the share that has not passed its SLA due time, and is 100 when there are no open tickets. oldestMinutes is the age of the oldest ticket at that priority, or null if there are none.
Setup status
GET /v1/analytics/setup-statusconst status = await kerabie.analytics.getSetupStatus();
// { channel: true, ai: false, automation: false }| Field | true when |
|---|---|
channel | WhatsApp or Instagram is connected and active, or an email mailbox is connected. |
ai | At least one published knowledge-base item exists. |
automation | At least one automation exists. |