Dashboard & Analytics
The Virsyn Voice AI dashboard system provides real-time and historical analytics across all call activity. Seven dedicated edge functions power KPI cards, trend charts, conversion funnels, campaign comparisons, call quality metrics, time-of-day heatmaps, and objection analysis.
Architecture
Raw Calls ──► process-enrichment-queue (AI analysis) ──► call_stats_daily (pre-aggregated)
│
┌──────────────────────────────────────────────┤
│ │ │ │
dashboard- dashboard- dashboard- dashboard-
overview timeseries funnel campaigns
│
┌──────────────────────────────────────────────┘
│ │ │
dashboard- dashboard- dashboard-
quality heatmap objections
(raw calls) (raw calls)
- 5 endpoints query the pre-aggregated
call_stats_dailytable for fast lookups. - 2 endpoints (heatmap, objections) query the raw
callstable for hour-level granularity and JSONB array unnesting.
Endpoints
| Function | Data Source | Description |
|---|---|---|
dashboard-overview | call_stats_daily | Summary KPIs, disposition breakdown, quality metrics, tool usage |
dashboard-timeseries | call_stats_daily | Daily aggregated metrics for trend charts |
dashboard-funnel | call_stats_daily | 5-stage conversion funnel with step-to-step rates |
dashboard-campaigns | call_stats_daily + v_call_batch_summary | Active batch progress and campaign-level stats |
dashboard-quality | call_stats_daily | Call quality analytics with daily trends |
dashboard-heatmap | calls | Best-times-to-call day/hour distribution |
dashboard-objections | calls | Top objections and buying signals analysis |
Authentication
All endpoints require a Supabase JWT Bearer token. The backend resolves the user's agency_id automatically -- you never pass it as a parameter.
const response = await fetch(`${SUPABASE_URL}/functions/v1/<function-name>?params`, {
headers: {
'Authorization': `Bearer ${session.access_token}`,
'Content-Type': 'application/json',
},
});
Common Query Parameters
All endpoints share these filters:
| Parameter | Type | Default | Description |
|---|---|---|---|
period | string | 7d | today, 7d, 30d, 90d, custom |
start_date | string | -- | ISO date YYYY-MM-DD (required when period=custom) |
end_date | string | -- | ISO date YYYY-MM-DD (required when period=custom) |
campaign_id | UUID | -- | Filter to a specific campaign |
client_id | UUID | -- | Filter to a specific client |
note
The heatmap endpoint only supports 7d, 30d, 90d periods (no today or custom). The campaigns endpoint defaults to 30d instead of 7d.
Error Handling
All endpoints return errors in a consistent format:
{
"error": "Human-readable error message",
"details": "Technical detail (only in 500s)"
}
| Status | Meaning |
|---|---|
| 401 | Missing or invalid Bearer token |
| 403 | User exists but has no agency_id |
| 405 | Wrong HTTP method (must be GET) |
| 500 | Server error (check details) |
Data Freshness
| Source | Freshness |
|---|---|
call_stats_daily | Updated by trigger when call analysis completes + cron every 6h for last 7 days |
v_call_batch_summary | Real-time view (queries on read) |
Raw calls table | Real-time (used by heatmap and objections endpoints) |
Next Steps
- Frontend API Guide -- TypeScript helpers, page layout mapping, and code examples