Kerabie
API Reference

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 paramDescription
daysWindow length in days. Default 30, maximum 365.
periodAlternative 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

  • avgResponseTime is the average first-response time in seconds (0 when there is no data yet).
  • satisfactionScore is the average rating × 20, so 0–100.
  • deltas are the percentage change versus the previous period of the same length. A value is null when there is nothing to compare against. For responseTime, a negative number is an improvement.
  • ai.resolvedAlone counts conversations the AI handled without a human ever replying. ai.handedOffPct is the share handed off to a person.
  • ai.agentHoursSaved is 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).
  • trend has one entry per day, oldest first, capped at the last 30 days, with empty days included. ai + human = count.

Insights

GET /v1/analytics/insights

Takes 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.medianSeconds is the median time from a customer's first message to a person's first reply (AI replies don't count). deltaPct compares 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.
  • aiResolvedPct is the share of those conversations where no person ever replied and the AI didn't hand off. avgRating is the customers' own 1–5 rating of those conversations.
  • unanswered are the questions behind AI handoffs with the reason no matching knowledge base article: good candidates for new articles.
  • heatmap.cells has 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: views are the widget page views we recorded (kept for 90 days) and questions the conversations that started on that page. askRate = questions ÷ views, and is null while 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/agents

Accepts 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-sla
const 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-status
const status = await kerabie.analytics.getSetupStatus();
// { channel: true, ai: false, automation: false }
Fieldtrue when
channelWhatsApp or Instagram is connected and active, or an email mailbox is connected.
aiAt least one published knowledge-base item exists.
automationAt least one automation exists.