Dashboard Heatmap
Returns call distribution by day-of-week and hour-of-day to identify optimal calling times. Queries the raw calls table since hourly granularity is not available in the pre-aggregated table. Returns a sparse heatmap (only time slots with data) and the top 5 best-performing time slots.
Endpoint
| Property | Value |
|---|---|
| Function Name | dashboard-heatmap |
| HTTP Method | GET |
| Authentication | Supabase JWT (Bearer token) |
Request
Headers
Authorization: Bearer <supabase_jwt_token>
Content-Type: application/json
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period | string | No | 30d | 7d, 30d, or 90d only (no today or custom) |
metric | string | No | calls | calls, connected, or meetings_booked |
campaign_id | string (UUID) | No | -- | Filter to a specific campaign |
client_id | string (UUID) | No | -- | Filter to a specific client |
Response
Success (200)
{
"period": { "start_date": "2026-01-18", "end_date": "2026-02-16" },
"metric": "calls",
"heatmap": [
{ "day": 0, "hour": 9, "total_calls": 5, "connected_calls": 3, "meetings_booked": 0 },
{ "day": 0, "hour": 10, "total_calls": 8, "connected_calls": 4, "meetings_booked": 1 },
{ "day": 1, "hour": 9, "total_calls": 12, "connected_calls": 7, "meetings_booked": 2 }
// ... entries only for day/hour combos that had calls
],
"best_times": [
{ "day": 2, "hour": 10, "metric_value": 15, "label": "Tuesday 10:00" },
{ "day": 3, "hour": 14, "metric_value": 12, "label": "Wednesday 14:00" },
{ "day": 1, "hour": 11, "metric_value": 11, "label": "Monday 11:00" },
{ "day": 4, "hour": 9, "metric_value": 10, "label": "Thursday 09:00" },
{ "day": 2, "hour": 15, "metric_value": 9, "label": "Tuesday 15:00" }
]
}
Day Number Mapping
| Day | Label |
|---|---|
| 0 | Sunday |
| 1 | Monday |
| 2 | Tuesday |
| 3 | Wednesday |
| 4 | Thursday |
| 5 | Friday |
| 6 | Saturday |
note
Hours are in UTC. Convert to the user's timezone on the frontend before rendering.
Error Responses
| Status | Condition |
|---|---|
| 401 | Missing or invalid authorization header |
| 403 | User exists but has no agency_id |
| 405 | HTTP method is not GET |
| 500 | Failed to query calls table |
Behavior
- Authenticates the user via Supabase JWT and resolves their
agency_id. - Only accepts
7d,30d, or90dperiods. Other values return an error. - Queries the raw
callstable for ended calls within the date range. - Extracts UTC day-of-week and hour from
created_atfor each call. - Builds a heatmap by counting
total_calls,connected_calls(calls wherejoined_atis set andend_reasonis notunjoined), andmeetings_booked(fromanalysis.sdr.meeting_booked). - Sorts heatmap by day then hour. Identifies the top 5 time slots based on the requested
metric. - Uses the
idx_calls_agency_createdindex for efficient querying.
Database Tables
| Table | Operation | Description |
|---|---|---|
users | Read | Fetches user profile to determine agency_id |
calls | Read | Raw call records, queried for hourly distribution |
External APIs
None.
Related Functions
- Dashboard Quality -- Quality analytics (same page)
- Dashboard Objections -- Objection analysis (same page)
- Frontend API Guide -- Heatmap rendering guidance