Knowledge Base · Tech Console · Dialpad Platform

Dialpad Tech Console

A personal call companion for support engineers. Three states: idle, on call, and wrap-up. Surfaces AI-generated call scripts, live floor health, per-call CSAT, and an end-of-shift call log with AI recaps and note review.

File dashboard-dialpad-tech-console.html
Role Support Technician
Status Demo Mode
Live Data Proxy Required
Scripts SharePoint (read-only)

What This Tool Is

The tech console is the personal call companion for each engineer on shift. It is intentionally narrow in scope: show the tech their own data, guide them through the current call, and let them review their shift at the end of the day. It does not expose the live queue, other techs' stats, or any administrative controls.

What Techs Can Do
See their own shift stats (calls, AHT, FCR, abandoned)
Get live floor health at a glance
Follow AI-surfaced call scripts during calls
Record wrap-up notes and disposition
Review their own call history at end of shift
Read AI recaps for past calls
Edit notes after a call is closed
What Techs Cannot Do
See the live queue or waiting callers
View other techs' stats or call logs
Edit call scripts or KB steps
Publish to SharePoint
Change call routing or Dialpad settings
Access the manager dashboard
Select or pick calls from a queue
Queue is deliberately hidden. Techs do not see the live queue. This prevents cherry-picking — they cannot choose easier calls or avoid difficult queues. Queue management and call distribution are the manager's responsibility via the OPS Console.

Architecture

State Machine

The entire left panel is a state machine with three mutually exclusive states. Only one is visible at a time. Transitions are driven by WebSocket call events in live mode, or by the sim bar buttons in demo mode.

idle
Greeting with tech name, 4 personal stat cards, expandable call log. Shown between calls.
oncall
Caller ID, queue, live timer (yellow >5min, red >8min), issue type, checkable runbook steps.
wrapup
Disposition buttons (Resolved/Transferred/Escalated/Voicemail), notes textarea, Save or Skip.
State transitions in live mode: connected WebSocket event → oncall. hangup event → wrapup. Save wrap-up → idle. The sim buttons at the bottom of the left panel simulate these transitions in demo mode.
Data Sources
Four Live Data Sources
Dialpad REST API (via proxy)GET /users/me to resolve identity, GET /calls for call log, POST /stats for shift metrics, GET /callcenters/{id}/status for floor health.

Dialpad WebSocket — Real-time call events drive the state machine. Connected to wss://platform-websockets-6kqb5ajsla-uc.a.run.app/events/{token}. Reconnects every 55 minutes before Dialpad's 60-minute disconnect.

SharePoint REST APIscripts.json loaded read-only at startup. Tech console never writes to SharePoint.

sessionStorage — Per-call notes, dispositions, and AI recap cache stored locally via _callNoteStore. Survives page reload within a shift. Cleared when browser closes.

UI Panels

KTC Nav Bar — #ktc-bar
Fixed Navigation Strip — 36px, top of viewport
OPS Console link — navigates to dashboard-dialpad-console.html.
My Console link — active page, green style.
Tech selector dropdown#tech-sel — In demo mode allows switching between simulated techs to test the console. In live mode this dropdown is informational only — the tech identity is resolved from GET /api/v2/users/me using the API key. Known Limitation The selector is not hidden in live mode. It does not affect live data queries, which always use the resolved user ID. A future update will hide or disable the selector once a key is saved.
API key input + SET button — Saves key to localStorage, sets MODE='live', triggers resolveUser() then data load and WebSocket connect.
Mode dot — Yellow (DEMO) or green (LIVE).
Live clock — Updated every second.
Floor Ambient Bar — #floor-bar

A single 40px horizontal strip. The tech's only view of the floor. Three health states drive the entire bar's background color and message.

StateCSS classDotMessage patternTrigger
Nominal.fl-okGreen"Queue clear — focus on quality."Pressure <1 AND SLA ≥80%
Elevated.fl-warnOrange"Queue building. Stay efficient."Pressure ≥1 OR SLA <80%
Critical.fl-critRed (pulsing)"Floor under pressure. End calls fast."Pressure ≥2 OR SLA <70%

Four floor metrics shown as numbers (Queue, Free, SL%, Abn%) plus four personal stats on the right strip (Calls, Avg Handle, FCR, Abandoned). Color-coded by threshold. Updates every 30 seconds via liveTick() calling GET /api/v2/callcenters/{id}/status.

The floor bar is intentionally minimal. A tech during a call should be able to assess floor health in under a second without reading numbers. The background color and the plain-English action message do that work. Numbers are for between-call reference only.
Idle State — #st-idle
Between Calls — Shift Summary View
Greeting — "Ready, {TechName}" with shift duration and call count in the subtitle. Tech name sourced from GET /api/v2/users/me in live mode; from #tech-sel in demo mode.

4 stat cards — Calls Today, First-Call Resolution %, Avg Handle Time, Abandoned on Me. Each card has a color-coded top border (green good / yellow watch / orange warn) and a sub-label (target or status).

Call log — Every call this shift as an expandable row. Click any row to expand it. See the Call Log section for full detail.
On-Call State — #st-oncall
During a Call
Header row — Green pulsing live dot, "On Call" label, queue pill, caller number on the right.

Timer block — Large duration counter. Green → yellow at 5 minutes (>300s) → red blinking at 8 minutes (>480s). Progress bar below scales from green to red at 10 minutes. In live mode, timer starts from date_connected timestamp in the WebSocket event (catches any elapsed time if the event arrives late).

Caller info — Caller number (external_number from call event), queue name (group_id), issue type, contextual tags (PRIOR TICKET, VIP).

Runbook checklist — Steps from scripts.json for the matched issue type, rendered as checkable items. Click a step to check it off. Steps marked as done show strikethrough. Checks are session-only — not persisted. The checklist is for cognitive support during the call, not for tracking compliance.
Wrap-Up State — #st-wrapup
After Call Ends — Before Returning to Idle
Disposition buttons — Resolved, Transferred, Escalated, Voicemail. One must be selected before saving. Active selection highlighted with matching color.

Notes textarea — Pre-filled placeholder names the issue type from the call. Tech types their notes here.

Save & Return button — Calls saveWrapup(). Stores notes immediately to sessionStorage then calls PUT /api/v2/calls/{id}/labels and PATCH dutystatus to set tech back to available in all their call centers.

Skip — Returns to idle without saving. Notes are lost. Disposition is not written to Dialpad.

Clear — Resets disposition selection and clears notes textarea without leaving wrap-up state.
KB / Script Panel — #kb-panel
Right Column Top — 50% height
Shows scripts for the current call's issue type. Always visible on the right side regardless of state machine state.

Idle: Shows a "Scripts load when a call connects" placeholder.

On-call / wrap-up: Shows script cards for the active issue type. Content depends on the source field in scripts.json:
  • custom — renders your runbook cards
  • dialpad — shows a purple notice to follow the Dialpad AI Playbook in the app
  • both — Dialpad notice at the top, then your custom cards below

Fallback: If scripts.json is not loaded or the issue type has no match, falls back to the hardcoded KB object in the console JS, then to KB_DEFAULT (identity verification, documentation, escalation rule).
Sentiment Panel — #sent-panel
Right Column Middle — Between KB and Events
Shows CSAT scores for the last 5 calls as horizontal bars with a 5-call average and trend indicator.

Live source: pcsat_score field in the Dialpad WebSocket hangup event payload. Dialpad returns this on a 0–10 scale. The console normalizes to 0–5 for display.

Demo mode: Scores are randomly generated in genState().

Source label below the chart reads demo in demo mode, pcsat_score · live in live mode.

Color thresholds: ≥4/5 green · ≥3/5 yellow · <3/5 red.
Floor Events Feed — #ev-panel
Right Column Bottom — Always Visible
Translated floor alerts written in tech-action language — not manager-monitoring language. Every event tells the tech what to do, not just what is happening.

Four severity levels: 🔴 Critical (red left border), 🟠 Warning (orange), 🟡 Info (yellow), 🟢 OK (green).

Events are generated by buildEvents(floor, my) every time floor data updates. They are not fetched from an API — they are derived locally from the same floor metrics that feed the ambient bar.

Examples of translated language: instead of "SLA breach — 67%", the event reads: "SLA breach — escalate anything you can't resolve in 8 min."

Critical count badge shown in the panel header. If >0, the panel header border turns red.
Expandable Call Log — #idle-log
End-of-Day Review — Inside Idle State
Every call this shift appears as a row with a expand chevron. A cyan dot on the row indicates the call has notes attached.

Click to expand — Reveals a full detail panel below the row. Expand is handled by event delegation on #idle-log using data-key attributes (no inline onclick). Multiple rows can be expanded simultaneously.

Detail panel contents:
  • Caller, queue, duration (color-coded), disposition
  • AI Predicted CSAT (from pcsat_score, if available)
  • Notes block — what the tech typed during wrap-up
  • Edit Notes button — turns notes block into an editable textarea inline
  • AI Recap section — Dialpad's AI-generated call summary

AI Recap behavior: In live mode, fires GET /api/v2/calls/{id}/ai_recap on first expand only (lazy load). Result cached in _callNoteStore. Never re-fetches. In demo mode, uses pre-written realistic recaps from the DEMO_RECAPS template bank, keyed by issue type.

Edit Notes: Saves to sessionStorage immediately, then calls PUT /api/v2/calls/{id}/labels in live mode.

API Reference

All live API calls go through a proxy at PROXY_BASE. Auth header Bearer {API_KEY} is set on every call by apiFetch(). The proxy forwards to https://dialpad.com/api/v2 with the stored credentials.

Initialization — On Key Save
EndpointMethodPurposeResponse Used
/dialpad/users/meGETResolve tech identity from the API key. Fired immediately on SET.id → stored as MY_USER_ID. name → updates tech name display.
My Stats — Today's Shift Metrics
EndpointMethodPurposeNotes
/dialpad/statsPOSTInitiate today's call stats for this userBody: {stat_type: 'calls', is_today: true, target_type: 'user', target_id: MY_USER_ID, timezone}
/dialpad/stats/{id}GETRetrieve CSV result. Called 20 seconds after POST (Dialpad minimum).Fields used: answered, abandoned, duration_avg_seconds. Cached 30 min by Dialpad.
Call Log — This Shift
EndpointMethodPurposeNotes
/dialpad/calls?target_id={MY_USER_ID}&limit=20GETLoad recent call history for the idle state logResponse: items[]. Fields: external_number, direction, date_started, duration (ms), group_id, disposition.
/dialpad/calls/{id}/ai_recapGETFetch AI-generated recap for a specific call. Lazy-loaded on first row expand.Response fields: summary, transcript_summary, text. First non-null used. Cached in _callNoteStore.
/dialpad/calls/{id}/labelsPUTSave wrap-up disposition and notes to the call recordBody: {label: 'Resolved', notes: '...'}. Called on wrap-up Save and Edit Notes Save.
Floor Status — Ambient Bar Data
EndpointMethodPurposeNotes
/dialpad/callcenters/{id}/statusGETReal-time floor metrics. Polled every 30 seconds for all of the tech's call centers (MY_CC_IDS).Fields: agents_available, queue_depth, service_level, abandon_rate, agents_on_call, agents_in_wrapup, agents_total. Aggregated across all CCs.
Wrap-Up Actions
EndpointMethodPurposeNotes
/dialpad/callcenters/{cc_id}/operators/{user_id}/dutystatusPATCHSet tech back to 'available' in all their call centers after wrap-up SaveBody: {on_duty_status: 'available'}. Called once per CC in MY_CC_IDS after saveCallLabel() resolves.
WebSocket — Real-Time Call Events Live Only
Production WebSocket URL
wss://platform-websockets-6kqb5ajsla-uc.a.run.app/events/{token}

Token obtained by calling POST /api/v2/websockets. Token expires after 60 minutes. Console reconnects at 55 minutes to stay ahead of Dialpad's forced disconnect.
Event TypeState TriggerKey Fields Used
Call event state='connected'Flip to oncall stateexternal_number (caller), group_id (queue), date_connected (compute elapsed time), call_id, target.id (for identity check)
Call event state='hangup'Flip to wrapup stateduration (ms → divide by 1000), pcsat_score (normalize 0–10 to 0–5), csat_score fallback
Call event state='queued'Increment floor queue countUsed to update ambient bar in real time without a full status poll
Call event state='abandoned'Increment abandon counterAdjusts floor abn value locally
Agent status eventUpdate MY_CC_IDS, trigger floor status pollon_duty_status, call_center_ids[], target.id
Call events are filtered by target.id === MY_USER_ID. Events for other techs' calls are used only to update floor pressure (queue count, abandon rate) — never surfaced to the tech directly.
AI Recap — Lazy Loaded on Log Expand
GET /api/v2/calls/{id}/ai_recap
Fires when the tech clicks to expand a call row in the idle state log for the first time. Never re-fetches. Result cached in _callNoteStore[callKey].aiRecap in sessionStorage.

Loading state: the AI Recap section shows "Loading AI recap…" with a blink animation while the request is in flight.

Response fields checked in order: summary, transcript_summary, text. First non-null value used.

If no real call ID available (demo mode, or call connected before user resolved): shows "AI recap not available — call ID not resolved."

Config Fields

Proxy Config
ConstantDefaultDescription
PROXY_BASE'http://localhost:3001'Base URL of the proxy server. Change to deployed URL before going live. Used as the base for all apiFetch() calls.
API_KEYFrom localStorageDialpad API key. Base64-encoded in storage under dp_api_key. Auto-restored on page load. Set via the KTC bar input.
MY_USER_IDnullResolved from GET /users/me on key save. Scopes all stats, call log, and duty status calls to this user.
MY_CC_IDS[]Call center IDs resolved from WebSocket agent status events. Used for floor status polling and duty status updates.
SharePoint Config — Read-Only
ConstantDefaultDescription
SP_SITE''SharePoint site path. Must match exactly the value in the manager console. Set together or scripts will load from different paths.
SP_DATA_FOLDER'{SP_SITE}/pages/config/current'Folder path. Scripts.json is loaded from here on DOMContentLoaded via loadScriptsJson().
The tech console loads scripts.json on every page load. It never caches between sessions. If a manager publishes new scripts, the tech gets them the next time they load the console — no manual refresh needed.
Note Store — _callNoteStore
sessionStorage key: dp_call_notes
Stores per-call data keyed by callId (or demo-{n} for demo calls). Each entry:

notes — wrap-up notes text
disp — disposition label
dur — duration in seconds
caller — external number
queue — queue name
pcsat — raw Dialpad CSAT score (0–10)
aiRecap — cached AI recap text (null until first expand)
callId — real Dialpad call ID (null in demo)

Persistence: Survives page reload within the same browser tab. Cleared automatically when the browser or tab closes. Never persists between shifts.

Proxy Activation Checklist

Complete in order. The console runs in demo mode until all steps are done. Sim buttons and all panels work in demo mode for training and testing.

Step 1 — Deploy Proxy Server
Same proxy as the manager console. The tech console uses the same /dialpad/* route structure. If the manager console proxy is already deployed, point PROXY_BASE to the same URL.
Step 2 — Set PROXY_BASE
Change var PROXY_BASE = 'http://localhost:3001' to your deployed proxy URL. Do not add a trailing slash.
Step 3 — Configure SharePoint (optional)
Set SP_SITE to match the manager console. If SharePoint is not configured, the console falls back to the hardcoded KB object — the console still works, techs just see the default scripts instead of manager-maintained ones.
Step 4 — Tech Enters Their API Key
Each tech enters their own Dialpad API key in the KTC bar and clicks SET. The console resolves their identity via GET /users/me, loads their call log and stats, and connects the WebSocket. Mode dot turns green.
Step 5 — Test State Machine with a Real Call
Make a test call to the tech's queue. Confirm: console flips to oncall state with real caller number, timer starts, KB scripts load. End the call. Confirm: console flips to wrapup, disposition saves to Dialpad, dutystatus returns to available.
Verify activation: Mode dot green. Idle state shows real call history. Floor bar shows real numbers. WebSocket connected toast appears on load. AI recaps available in call log after first real call.

Limitations

Limitation Tech Selector Not Hidden in Live Mode
The tech name dropdown in the KTC bar remains visible after an API key is saved and a real user is resolved. It does not affect live data — all API calls use MY_USER_ID from users/me. However it may be confusing to techs. A future update will replace it with a plain-text name display once a key is set.
Limitation Issue Type Not Auto-Detected from Call
The issue type displayed during an on-call session is set to "Inbound Call" by default in live mode. Dialpad's call event payload does not include a pre-classified issue type. The _queue_map in scripts.json maps queue names to issue types (e.g. "Tech" queue → "Network Issue" scripts), but this requires the queue name to match exactly. If no match is found, the KB panel shows the default verification/documentation scripts.
Limitation WebSocket Requires Token Refresh Every 55 Minutes
Dialpad disconnects WebSocket connections after 60 minutes. The console reconnects at 55 minutes automatically by calling POST /api/v2/websockets to get a new token. During the ~1 second reconnect window, call events may be missed. This is unlikely to cause issues in practice but is a known gap.
Not Yet Live FCR Is Derived, Not API-Sourced
First-Call Resolution percentage is computed locally from the call log (calls where disposition = Resolved divided by total calls). Dialpad's Stats API does not expose an FCR field directly. The local calculation is approximate and depends on disposition labels being set correctly in wrap-up.
Limitation Note Store Is Session-Only
Notes and AI recaps stored in sessionStorage are cleared when the browser closes. Techs who close their browser mid-shift lose any unsaved local context. Wrap-up notes that were saved via PUT /calls/{id}/labels are preserved in Dialpad. Notes edited after the fact via the call log Edit button are re-saved to Dialpad in live mode, but only persist locally in demo mode.
Limitation No Authentication Layer
No login or session management. Access is controlled by possession of the URL and an API key. Restrict to VPN or internal network in production. Each tech's key is stored in their own browser's localStorage and scoped entirely to their own Dialpad user ID.

Troubleshooting

Call connects in Dialpad but console does not flip to on-call
Cause: WebSocket not connected, or MY_USER_ID not resolved so the event is filtered out.
Fix: Confirm the API key was entered and SET was clicked. Check browser console for WebSocket connection errors. Confirm PROXY_BASE is correct and proxy is reachable. Check that the call event's target.id matches the resolved MY_USER_ID.
KB panel shows default steps instead of custom scripts
Cause: Either SP_SITE is not configured (SP not set up), or the queue name in the call event does not match any key in _queue_map in scripts.json.
Fix: Confirm SP_SITE is set and matches the manager console. Check the browser console for the scripts.json loaded message. If loaded, verify _queue_map contains an entry for the queue name coming in on calls.
Wrap-up Save does not change tech status back to available
Cause: MY_CC_IDS is empty — the call centers were not captured from WebSocket agent status events.
Fix: Confirm at least one agent status event has been received (the tech must have gone on-duty or had a status change since page load). The call_center_ids field in the agent status event populates MY_CC_IDS. Without it, the PATCH dutystatus call has no CC IDs to iterate over.
Call log rows do not expand when clicked
Cause: This was a known bug (inline onclick quote collision) that was fixed. Confirm you are running the latest version of the file. The rows now use data-key attributes and event delegation — no inline onclick. If expansion still fails, check browser console for JS errors on page load.
AI Recap shows "AI recap not available" for all calls
Cause 1: Demo mode — calls have no real Dialpad call ID so the API cannot be queried. The section should show demo recap text from DEMO_RECAPS.
Cause 2: Live mode with the call ID not resolving from the WebSocket event. Check that call_id is present in the WebSocket hangup event and being stored in _currentCall.callId.
Cause 3: AI recap not available for this call in Dialpad (not all calls generate recaps, depends on plan and call duration).
Floor bar stays on "Nominal" even when floor is busy
Cause: In demo mode this is expected — the demo drift is moderate by design. In live mode, confirm loadFloorStatus() is being called (requires proxy + MY_CC_IDS populated). Also confirm the 30-second poll interval is running by checking for the liveTick() setInterval in browser debugger.
KRAWCZYK.CITY · KB · DIALPAD TECH CONSOLE · COPILOT PLATFORM