Admin
← Dashboard

Agents

Add and manage the agents whose calls are fetched from Hunar and evaluated. Only admins can add or rename agents. Fetch pulls the agent's calls; Run further evaluations? runs the LLM scoring pipeline (signals + verbatim) — turn it off for an agent that shouldn't be scored, and it won't need an evaluation prompt configured either. Generate transcript is separate: it fetches/transcribes the call recording (via ElevenLabs) once a call comes back "completed", whether or not the agent is also being evaluated. Transcript only marks an agent that relies on Hunar's own voice-API outputs instead of our scoring — its Evals/Campaigns/Test tables hide every signal toggle column and show only the transcript. Can trigger campaigns decides which agents the “New campaign” / “New test call” launcher offers inside that agent's category — untick it for an agent nobody should be dialling new calls on (retired, experimental, kept only for its history); its past calls stay visible and keep syncing either way, and it still appears in Evaluation config / Re-evaluation by default (tick "Show all agents" there for the rest). An agent with Run further evaluations? off never appears in Evaluation config or Re-evaluation at all, and its Campaigns/Test screens show a "Fetch transcript" button (ElevenLabs only) instead of "Run evals + transcripts". Backfill pulls an agent's older history from Hunar on demand and evaluates the new calls.

Agent IDNameCategoryCan trigger campaigns FetchRun further evaluations? Generate transcriptTranscript only Backfill

Data cleanup

Calls store custom_data keys exactly as the source CSV had them, so the same field uploaded with different casing across campaigns (e.g. "Branch" vs "branch") used to create separate, mostly-blank columns in Evals. New calls now collapse these automatically. This re-keys calls stored before that fix, in place — no re-fetch from Hunar, just rewrites what's already in the DB. Safe to re-run any time.

Separately: Hunar's voice agent produces its own post-call result fields (e.g. reported issue / issue description) that ride alongside the transcript but weren't being pulled out before. New calls pick these up automatically now — this backfills calls fetched earlier, straight from their already-stored raw data (no Hunar re-fetch).

Separately: the dashboard's "hide the team's test-dial numbers" filter now matches against a new indexed column instead of scanning every call's phone number on every page load (this was the biggest reason the Evals table felt slow). Run this once after deploy so calls fetched before this change get that column filled in too — new calls get it automatically going forward. Safe to re-run any time.

Separately: some calls (usually from a CSV import) ended up with the same piece of data split across two columns — e.g. duration, callee name, mobile number, status, or call_ended_by each showing up both as a standard column AND as a near-identical custom field — so an export shows the same value twice under two different headers (or blank on one side depending on the row). This copies the value into the standard column wherever it's missing, then deletes the custom_data duplicate — so each of those ends up as ONE column, not two. A value already sitting on the standard column is never overwritten, and nothing is ever deleted if there's no usable value to promote first — this only removes a copy once it's redundant.

Separately: some custom_data columns are blank on every single call — left behind by an old import, a merge, or a campaign whose agent never actually fills that field — but they still show up as empty columns in Evals, Campaigns, and CSV export because those show the union of every custom_data key across all calls. This deletes only the keys that are blank everywhere in scope; a key with a real value on even one call is left completely alone.

Separately: a few custom_data fields are the SAME metric your evaluation pipeline also scores on its own (e.g. "team_culture_health_score" appears both as a raw custom_data.* field Hunar's agent reported live, and as a signal column your own scoring rubric computes independently) — so an export shows it twice under near-identical headers. This keeps the evaluation pipeline's column as the source of truth: the custom_data copy is deleted only for calls where the evaluation pipeline already has a real value for that field; if it doesn't (not yet evaluated, or the pipeline didn't extract it), the custom_data value is left completely untouched — it stays the only copy of that data. Taxonomy is resolved per agent, same as the Evals table.

Separately: before a CSV re-upload was matched to existing rows by phone number, re-uploading the same "Import completed" campaign (common when a campaign's export has no Call ID column) created a brand-new row every time instead of updating what was already there — so a campaign uploaded 3 times could have 3x the real rows, each showing slightly different data. New uploads no longer do this; this finds campaigns that already have that pile-up from before the fix, so you can review and clean each one up.

Excluded numbers (test calls)

Phone numbers the team dials for testing. Calls to these numbers are hidden from the dashboard and never run through the evaluation pipeline (no STT/LLM spend). Matching ignores country code and spacing (last 10 digits). Applies to existing and future calls.

NumberNoteAdded by

Remove a call

Permanently delete a single call (and its evaluation) from the dashboard — e.g. a mis-fired call whose stray custom-data fields add empty columns to the table. A later backfill of that date window could re-fetch it from Hunar.

Evaluation configuration

Per-agent scoring settings. Leave a field blank to use the bundled default. Changes apply on the next sync / re-evaluation. Signals, verbatims and summaries are one list now — the old separate “signal taxonomy” and “verbatim keys” boxes were two halves of the same thing.

Calls shorter than this are stamped "Not Found" without STT/LLM spend.
Shown when a verbatim topic wasn't raised.
One entry per column, in the order you want them. type is signal (a constrained value), verbatim (their exact words) or summary (a line of the model’s own prose) — omit it and it’s inferred from the _verbatim / _summary suffix. values pins a signal to its own set; leave it out and the signal is restricted to Yes/No/NA, and anything else the model answers is stored as NA. description is what the scorer tells the model to capture for that key. You can paste a bare { "key": "", … } sample output and press “Fill in types”.

Re-evaluation

Re-run scoring for an agent's calls. Re-score reuses each call's stored transcript (OpenAI only — cheap). Full re-run re-downloads and re-transcribes via ElevenLabs too (higher cost), processed on the next sync. Start with Count (spends nothing).

Cap how many calls to process (bounds token spend).

Eval queue

Live view of the evaluation backlog — every call currently "pending" or "error", and why. A row past the 15-minute sync window with no result is flagged stuck; the same agent + phone number queued more than once is flagged duplicate; a call whose Hunar status is still non-terminal (e.g. "SCHEDULED") is flagged stale status — that's usually why it has nothing to score yet, and is common right after uploading a completed-campaign CSV for calls the agent side hasn't marked finished. Refresh statuses re-fetches those from Hunar by call id (free — no eval spend) before you Run now.

Calls still in progress

Every call not yet Failed, Not connected, or Completed on Hunar's side — scheduled, queued, ringing, whatever it's called mid-flight — whether or not it has an eval row at all. "Fetch latest data" re-pulls each one's real status from Hunar by call id (free, no eval spend).

—
CallAgentCalleeMobileStatusSince

Per-agent breakdown

AgentPendingErrorOkSkipped

Queued items

Oldest first, capped at 100. Filter to one agent/status, then select rows to delete.

CallAgentCalleeMobile Eval statusCall statusReasonAge (h)Flags

30 / 60 / 90-day sequences

Map each follow-up stage to the agent that stage calls on. A campaign or test batch triggered on the 30-day agent will show a "Trigger 60 days" button (once it's finished); that button carries the same people + custom fields forward onto the 60-day agent, previews the mapping first, then triggers on confirm. Same again 60 → 90. Works from both the Campaigns and Test tabs.

A “(CONTEXT)” agent asks for variables the earlier stage never had — issues_description_hindi_sixty, say. Those describe what happened on the previous call, so they can’t come from the original upload. They are filled automatically: the same information sits on the previous call under that stage’s own name (issues_description_hindi_thirty), so each required variable is matched to it by name once the stage suffix is ignored — looking at the call’s eval fields first, then the custom data Hunar’s agent wrote back. Context mapping below is the override, for the cases where the two names genuinely don’t correspond: point a variable at any field on the previous call, with a default for recipients that have no value. Hunar rejects the whole batch if a variable it declares is absent, so anything neither matched nor mapped blocks the trigger here with the list of what’s missing, instead of failing upstream.

Reminder emails: give a sequence a list of addresses and, 30 days after any of its 30-day (or 60-day) campaigns is launched, those addresses get an email saying the next stage is due — once per campaign, and not if the next stage was already triggered. A super admin can also send it straight away with “Send reminder email” on the campaign page. No addresses = no reminders for that sequence.

Name30-day agent60-day agent90-day agent Context mappingReminder emails

Users & roles

Whitelisted logins. super-admin has full access (this tab, evaluation config, re-evaluation). admin gets agent setup, excluded numbers, and call deletion. viewer sees the dashboard only. Everyone signs in with an email code by default; they can optionally set a password from the dashboard for faster sign-in, without ever losing OTP as a fallback. Clear a user's password here if they leave or it may be compromised.

EmailRoleEnabledPassword