PPactDocs
CRM

Calls

Upload sales-call recordings, pass the consent gate, and get AI transcripts, deal insights, and proposed CRM updates.

Calls

Calls is Pact's conversation-intelligence surface. A recording is uploaded (or captured from a live voice session), passes a SQL-enforced recording-consent gate, then flows through a pending → transcribing → extracting → ready pipeline that produces a diarized transcript, structured deal insights, and proposed CRM updates a rep can approve one click at a time.

The list lives at /calls; every recording is backed by the call_recordings table and served by the /v1/calls API (api/routes/conversation_intel.py). Access requires the sales module (require_module("sales")).

This is a live, enforced surface

Upload, the consent gate, transcription, AI extraction, and the approve/reject proposal loop are all real backend code. The one external dependency is a speech-to-text key — see the note below.

The recording lifecycle

Every row carries a status that the list renders as a colored chip:

StatusMeaning
pendingUploaded and queued; the pipeline has not started.
transcribingAudio is at the STT provider.
extractingTranscript is back; the LLM is pulling insights.
readyTranscript, insights, and proposals are all available.
failedA phase errored (often a missing STT key).
consent_blockedThe consent gate refused this contact — audio was preserved for audit but never transcribed.

The list polls every few seconds, so a freshly uploaded call visibly walks through the phases without a manual refresh. Filter chips at the top of /calls narrow the list to any single status.

Uploading a recording

  1. 1

    Open the upload dialog

    Click Upload recording on /calls. Accepts mp3, wav, m4a, and other audio/* or video/* files. The filename extension and the multipart Content-Type are both validated server-side, and empty or oversized files are rejected.

  2. 2

    Identify the contact for the consent gate

    Provide the contact email (and optionally an opportunity ID). The email is how the gate resolves a consent subject — without a resolvable email or phone the upload cannot be cleared.

  3. 3

    Consent gate runs at ingest

    check_recording_consent looks for a granted call-channel consent record for that contact. No record means default-deny: the upload returns HTTP 409, the row is written in consent_blocked state for audit, and no transcript is ever generated.

  4. 4

    Pipeline is enqueued

    On a granted contact the audio is stored, the row goes pending, and (with auto-process on) the transcription job is queued immediately.

The gate is deliberately strict because sales-call recording is a two-party-consent primitive. Grant or inspect call consent in the consent ledger.

Speech-to-text requires a provider key

Transcription uses AssemblyAI, keyed by the ASSEMBLYAI_API_KEY secret. When it is unset, /calls shows a banner and uploads still succeed but stay in failed until an operator sets the secret (flyctl secrets set ASSEMBLYAI_API_KEY=… -a pact-demo). The GET /v1/calls/_meta/stt-status endpoint reports whether the key is configured. Seed data still renders regardless.

What the pipeline produces

Once a call reaches ready, the call detail view exposes three things:

  • Transcript — speaker-diarized segments with timestamps and rep/prospect roles.
  • AI insights — extractions typed as pain, objection, competitor, criterion, next step, buying signal, and sentiment, each with an evidence quote and a click-to-jump citation into the transcript.
  • Proposed CRM updates — AI-drafted field changes on the linked opportunity that a rep approves or rejects. Nothing is written to the opportunity until a human approves it.

Reprocessing

Any call except a consent_blocked one can be re-run via Reprocess (POST /v1/calls/{id}/process). This resets the row to pending and re-queues the pipeline — useful after an STT key is added or extraction logic improves. Reprocessing a consent_blocked row is refused with a 409.

Coaching

Beyond per-call insights, the pipeline computes coaching metrics (talk ratio, questions asked, longest monologue, filler density) that roll up per rep and per management subtree. Managers see their team via /v1/calls/coaching/team/{user_id}, scoped by the org hierarchy. See the coaching page for the full breakdown.