Sales teams that live on the phone often run two telephony systems at once — SIM-based call tracking on field phones and a cloud dialer in the office. The numbers never agree, and managers reconcile them in spreadsheets. BillGill ingests both feeds, detects when they report the same physical call, and turns 90 days of raw call logs into leaderboards, scorecards and payroll-grade cost analysis.
Recorded against a locally running instance seeded with 11,000+ fictional calls replayed through the real webhook receivers — every number on screen was computed by the production pipeline, not mocked.
All employees, phone numbers and amounts are fictional demo data. Click any screenshot to enlarge it.
Click through the six screens managers actually live in — every number computed by the real pipeline from the seeded demo dataset. Click a screenshot to enlarge it.
The two providers report the same physical call with different client numbers. Matching on employee, date and a 10-second timestamp window flags duplicates, and every analytics query excludes them — so totals never double-count.
A rep exists twice — once per provider, under different names. A dedicated Data Management screen links, merges and scores the mapping, with orphan-name detection and a data-quality percentage.
Pollers run every 5–10 minutes; a nightly reconciler compares local counts against the provider's own summary and automatically backfills whenever drift exceeds 5%. Backfills are checkpointed and resumable.
Call recordings run through on-device Whisper, Hindi/Kannada→English translation and sentiment/topic analysis — offloaded to worker threads after inline inference was found blocking the event loop on a 1-vCPU box.
The CBO scorecard composites effort (calls, connects, active days) and outcomes (registrations, fees, loans) normalised against the team's p95 into A–D grades — so a manager reads one letter, then argues with the detail.
External consumers get a separate read-only API with per-consumer static keys, constant-time comparison, per-resource field allowlists — and it fails closed with 503 when unconfigured.