CallLens

Call analytics platform · powered by APIs

Every sales call — transcribed and scored automatically.

Connect your call source once. From then on, the system transcribes conversations on its own, separates the rep from the customer, scores performance against your checklist, and rolls everything up into reports.

call → webhook → transcription → scoring → dashboard

Getting started

Up and running in four steps

Connect your source once — everything after that runs without you.

  1. 01

    Sign up

    Create a workspace for your team and invite your sales managers.

  2. 02

    Connect a source

    Generate a webhook URL and secret, then drop them into your phone system or CRM. Recordings start flowing in automatically.

  3. 03

    Set up your checklist

    Define your scoring criteria: greeting, needs discovery, objection handling, agreeing on the next step.

  4. 04

    Done

    Every new call is transcribed, scored, and shows up in the dashboard with per-rep reports.

Demo

See how it works

Our demo of CallLens recognising a real call — and the example recording it ran on.

Screen recording: CallLens transcribes and scores a real call inside the cabinet.

Architecture

A call's journey through the system

Five processing zones. Synchronous intake on Symfony returns a response in milliseconds, while all the heavy lifting runs asynchronously in workers that call external APIs . No GPU of your own required.

  1. A
    Zone · Customer
    outside your perimeter

    Call source

    • Source Twilio · Binotel · Ringostat · Bitrix24
    • Event call completed
    • Data mp3/wav recording, ideally dual-channel (rep/customer on separate tracks)
  2. B
    Zone · Symfony (synchronous)
    < 50 ms

    Webhook intake

    • Endpoint POST /v1/calls/webhook
    • Security HMAC-SHA256 signature verification
    • Dedupe idempotency by call_id
    • Action store audio in Hetzner S3 → dispatch to Messenger
    • Response 202 Accepted immediately, without waiting for processing
  3. C
    Zone · Workers (asynchronous)
    Messenger

    Call processing

    • Transport Redis / Doctrine · retries with backoff · dead-letter
    • Calls via Symfony HttpClient behind a single interface
    Pipeline · external APIs
    paid/min
    1 · STTDeepgram / AssemblyAI → transcript + diarization + word timestamps
    2 · LLMGPT-4o-mini / Gemini → JSON scoring per criterion + quotes (structured output)
    3 · EMBOpenAI / Voyage → utterance vectors for search
  4. D
    Zone · Data
    Doctrine ORM

    PostgreSQL + pgvector

    • Entities Call · Transcript · Utterance(+vector) · Score · Tenant
    • Isolation data partitioned by tenant_id (multi-tenancy)
    • Search semantic vector search (pgvector, HNSW index)
  5. E
    Zone · Interface
    REST

    Delivery and dashboard

    • API Symfony REST (JSON), authenticated by token and tenant
    • Analytics Cube — a semantic layer with pre-aggregations over PostgreSQL for fast reports
    • UI Next.js (React) — scores, transcript, reports, call search

The amber zone C is the only one that depends on external paid APIs. Everything sits behind an interface, so you can swap providers and, down the line, move transcription onto your own GPU without touching zones A, B, D, or E.

Infrastructure decision

Why APIs instead of your own GPU

At launch and through early growth, paid APIs cost 3–4× less than running your own GPU — and they're far simpler to operate. A dedicated GPU only pays off at high volume.

chosen at launch

Paid APIs

$310–520 / mo

for 50,000 min/mo (≈ 10,000 calls)

  • ✓Zero DevOps for inference
  • ✓Pay only for what you actually use
  • ✓Instant scaling under load
  • ✓Launch in weeks, with no capital outlay

Your own GPU

$1,300–2,040 / mo

for the same 50,000 min/mo volume

  • ✕GPU sits idle ~96% of the time at low volume
  • ✕Requires DevOps: vLLM, monitoring, model updates
  • ✕Fixed cost regardless of load
  • →Only breaks even from ~215,000 min/mo
Monthly cost at launch (50,000 min)
Paid APIs≈ $415
Your own GPU≈ $1,670

Everything sits behind a single interface, so once volume crosses ~215,000 min/mo, we move transcription onto our own GPU with no system rewrite — architecture zones A, B, D, and E stay unchanged.

From sound to analytics

How a conversation becomes a number

Four transformations: raw call audio turns, step by step, into a structured rep score and aggregated analytics.

01 · Sound

Raw call audio recording

02 · Text + roles
Rep
Hi there! What's most important to you right now?
Customer
We want to cut our logistics costs.

Transcript with diarization

03 · Score
Greeting9/10
Needs discovery8/10
Objection handling5/10

"…I'll send over the proposal today" — supporting quote

Scored against your checklist

04 · Analytics
R1R2R3R4R5

Average scores across the team

Reports and analytics

Metrics on top of PostgreSQL with Cube

Cube is a semantic layer over the database: metrics are defined once, then served through an API with pre-aggregations and caching. Reports stay fast on plain PostgreSQL — no separate query engine needed.

Source

PostgreSQL

Call · Score · Utterance

Semantic layer

Cube

pre-aggregations + cache

Access

API

REST / GraphQL / SQL

Interface

Next.js

dashboards and reports

cube · metrics model
cubes:
  - name: calls
    sql_table: calls
    measures:
      - name: avg_score
        sql: score
        type: avg
      - name: count
        type: count
    dimensions:
      - name: manager
        sql: manager_id
        type: string
      - name: week
        sql: created_at
        type: time
    pre_aggregations:
      - name: by_manager_week
        measures: [avg_score, count]
        dimensions: [manager]
        granularity: week

Average score by rep

avg_score
R1R2R3R4R5

Quality trend by week

granularity: week

Top customer objections

count
Price42
Implementation timeline28
Already with a competitor19
Complex integration11

Connecting a source

What "registering a webhook" means

After signing up, head to Settings → Integrations and you'll get your own webhook URL and secret key. You paste this URL into your phone system or CRM.

When a call ends, your system sends a message to that URL with a link to the recording. Symfony verifies the signature, stores the audio, and queues the call for processing. One setup at the start — automatic from there on.

  • ✓An HMAC-SHA256 signature guards against forged requests.
  • ✓Dual-channel recordings put the rep and customer on separate tracks, with no diarization errors.
  • ✓No webhook? You can upload recordings manually or via the REST API.
call webhook
POST https://api.calllens.app/v1/calls/webhook
X-CallLens-Signature: sha256=9f3a…

{
  "call_id": "c_8421",
  "recording_url": "https://…/rec.mp3",
  "agent_id": "mgr_17",
  "channels": "dual",
  "started_at": "2026-06-17T09:14:02Z",
  "duration_sec": 312
}
Symfony — intake
#[Route]('/v1/calls/webhook', methods:['POST'])
public function handle(Request $r): Response
{
    $this->verifySignature($r);        // HMAC
    $bus->dispatch(new ProcessCall($payload));
    return new Response(status: 202);
}

Infrastructure · hardware

One dedicated server is enough

All the heavy processing — transcription, scoring, embeddings — runs on external APIs, so the server needs no GPU. It only hosts the app, the workers, the database, and the queue — comfortably handled by a single Hetzner dedicated server.

Dedicated server

Hetzner AX-line

  • AMD Ryzen · 8 cores / 16 threads
  • 64 GB DDR5 ECC
  • 2 × 512 GB NVMe (RAID 1)
  • 1 Gbit/s, unmetered traffic
from €46 / mo

+ ~€39 one-time (setup)

Audio storage

Hetzner Object Storage

  • S3-compatible (works with the same code)
  • EU data centers · GDPR (instead of Cloudflare)
  • 1 TB storage + 1 TB traffic included
  • beyond that — pay-as-you-go
€4.99 / mo per 1 TB

S3 API calls and inbound traffic — free

Total infrastructure
≈ €50–65 / mo

server + storage

Why one server is enough

  • ✓No GPU — just web, workers, database, queue
  • ✓Workers wait on API responses (I/O), they don't tax the CPU
  • ✓PostgreSQL + Redis run comfortably on 64 GB and NVMe
  • →To scale: a bigger server, or add a dedicated worker

What's installed on the server

The full project stack on a single node (click for details):

aaPanel — server management and analytics

A free web panel for server administration: web server, databases, domains, SSL, cron, and backups — all in a graphical interface, no manual console required. It also provides real-time server analytics.

•CPU / RAM / disk / traffic monitoring
•SSL certificates in a few clicks
•Scheduled backups
•Firewall and security logs

Hetzner prices are shown excluding VAT and are approximate — check current configurations and pricing on the Hetzner website before ordering.

Ready to connect your sales team?

Sign up, webhook, checklist — and your first scores land today.

Get started →