Go to file
Yashas 0612626491 feat: play the call recording on My calls
Same treatment as the BA operator console: the audio sits with the conversation
it belongs to, so "did the AI capture what the customer actually said" is
answerable by pressing play rather than by trusting the summary above it.

Reads the new /api/agent-sessions/:id/call, which is scoped to the human who
took the call — the recording lives on the voice session, owned by the telephony
leg, and is unreachable through the ordinary session API.

preload="none" so opening the screen doesn't pull a WAV of a whole phone call
before anyone asked to hear one. A 404 is a normal answer and renders nothing:
recordings are written at call END, so a live call shows its duration and end
reason with a note instead of a dead player.

tsc -b and vite build clean.
2026-08-27 11:28:04 +05:30
src feat: play the call recording on My calls 2026-08-27 11:28:04 +05:30
.env.example feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
.gitignore feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
index.html feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
package-lock.json feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
package.json feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
postcss.config.js feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
README.md feat: rebrand to Mahindra, and ground the models in the real line-up 2026-08-26 23:36:19 +05:30
tailwind.config.js feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
tsconfig.app.json feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
tsconfig.json feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
tsconfig.node.json feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30
vite.config.ts feat: EV Sales Desk console — place a transferring call, watch it live 2026-08-26 22:58:25 +05:30

Mahindra EV Sales Desk Console

Two-screen operator console for the live call-transfer demo: place an outbound Mahindra EV sales call, and watch it transfer to a human colleague mid-call.

Backs onto Zino app 583 (org 900000104, dev). Line-up: BE 6, XEV 9e, XEV 9S. Built on the frontgen React scaffold — Vite + Tailwind + React Router + TanStack Query + src/zino-sdk.

The two screens

Place a call — lead name, model, and the two numbers: the customer Meera dials, and the colleague the transfer bridges to. Submitting starts a Lead Outreach workflow instance; its trigger places the call server-side.

Live monitor — polls the leads record view every 3s. Transferred to human is the transfer having fired.

Running locally

npm install
echo 'VITE_ZINO_API_URL=https://dev-apps.getzino.in' >> .env
npm run dev

Sign in with an app user of app 583 (e.g. salesops@mahindra-ev.demo / Mahindra@2026 (prefilled on the login screen)).

VITE_ZINO_API_URL is only read from .env in dev. A production build requires the config.js the server writes at placement time, and throws if it is absent — a promoted artifact must never fall back to the build machine's value and quietly call the wrong backend.

API notes worth keeping

The base URL is the root (https://dev-apps.getzino.in), not an app-scoped path, because login and the app APIs live at different depths:

Call Path
Login POST /usr/login
Start a lead POST /app/583/start
Leads list POST /app/583/view/recordview

src/api.ts bypasses two SDK methods on purpose — both are SDK bugs, not preferences:

  • workflows.startWorkflow() posts workflow_id, but core's StartRequest reads workflow_uuid and rejects the call outright.
  • views.getTabularView() issues GET /view/recordview — the legacy unscoped route. The app-scoped one is POST /app/{id}/view/recordview with the paging/filters in the body.

Auth still goes through the SDK, so there is one token and one session.

Why the browser holds no API key

Screen 1 submits a workflow activity as the signed-in user. The workflow's own trigger then places the call using the agent key held in its server-side config. The zvk_ key never reaches the browser.

The per-call transfer number

handover_number rides on the lead into the call's context, and agents-backend prefers it over anything configured on the agent — the agent's numbers are the fallback for calls that don't name one. Requires an agents-backend carrying the per-call override; without it the field is sent, silently ignored, and the call transfers to the agent's default number instead.

Known gap

The live transcript and the co-pilot's suggestions live in agents-backend, which the app-user token does not reach — the SDK talks to the renderer's workflow/view services. So the monitor shows call status live, but not the turn-by-turn feed. Closing that needs either a new endpoint or the trigger writing transcript lines onto the instance.