Skip to main content
By the end of this guide you’ll have a pipeline that takes a recorded call, transcribes it with PyAI Hear batch jobs (diarized, with SRT/VTT subtitles), and turns the result into the metrics every revenue team wants: who talked how much, which keywords came up, and an LLM-written summary with action items. It’s the “mine your calls” recipe, and every step here runs on the shipped async jobs API, so it’s concrete and runnable today.
Run the complete example. Scaffold this guide’s full pipeline in one command, no clone:
Or browse it: recap-call-intelligence.

How it fits together

Batch transcription is asynchronous: you submit a job, it returns 202 immediately, and the result arrives either via a signed webhook or by polling. Because batch is latency-tolerant, Hear batch is billed at a discounted rate versus realtime, the right tool for processing call archives at scale. (See the pricing page for current rates.)
This guide is fully grounded in the shipped jobs API (/v1/transcription/jobs). The only deliberately provider-agnostic piece is the summarization step, it calls your LLM (any OpenAI-compatible chat endpoint), clearly marked, because PyAI doesn’t prescribe one.

Prerequisites

1

A key with the jobs scopes

Create a key in the console with the hear:transcribe and transcribe:jobs scopes. A pyai_test_ sandbox key works instantly for building against, hard daily caps, no billing.
2

Call recordings you can reach

Either an https URL we can fetch (privacy-cleanest, the input is never stored), or a local file you’ll upload as multipart. Stereo telephony recordings (one party per channel) give the most accurate speaker split.
3

An LLM endpoint (for the summary step)

Any OpenAI-compatible chat completions endpoint and its key. This is the one “bring your own” piece of the pipeline.

Choose your diarization mode

Speaker separation is what turns a transcript into conversation intelligence. Pick the mode that matches how the call was recorded:
Don’t set both. Use channel: true for stereo and diarize: true for mono. If your telephony provider can record dual-channel, turn that on, it’s strictly better than guessing speakers from a mixed track.

Build it

1

Submit the transcription job

Send the recording, choose your diarization mode, ask for srt/vtt alongside json if you want subtitles, and register a webhook_url for the completion callback. Pass an Idempotency-Key so a retried submit can’t create a duplicate job.
For a mono recording, swap channel: true for diarize: true. To upload a local file instead of a URL, post multipart/form-data with an audio part and the same fields as form fields.
2

Receive the result, webhook (recommended) or polling

When the job finishes, PyAI POSTs a signed callback to your webhook_url. Verify the X-PyAI-Signature header before trusting the body, then fetch the full job.
Node, webhook handler
No public URL? Poll instead, equally valid for batch jobs and back-end pipelines:
The pyai CLI does the submit-and-poll loop in one line, handy for backfilling an archive:
3

Read the diarized result

A completed job carries a result with the full text, a speakers count, audio_seconds, diarized segments (each with start, end, text, and a speaker and/or channel), per-word timings, and a formats map of signed URLs for the SRT/VTT you requested. Large results are offloaded to a signed result_url instead of being inlined, handle both.
Python, normalize inline vs offloaded
4

Compute talk-ratio and track keywords

The diarized segments are all you need. Sum each speaker’s segment durations for talk-ratio, and scan segment text for the phrases you care about (competitors, pricing, objections) for keyword tracking. Use channel as the speaker key when you transcribed stereo, speaker otherwise.
Python, metrics from segments
A rep talking 80% of a discovery call is a coaching signal; a spike in “pricing” near the end is a buying signal. These two functions are the core of a Gong-style scorecard.
5

Summarize with your LLM of choice

Hand the transcript to any OpenAI-compatible chat endpoint for a summary, next steps, and sentiment. PyAI doesn’t run this step, point it at whichever model you’ve standardized on.
Python, provider-agnostic summary (YOUR LLM)

Run it

Wire the steps into one analyzeCall(job) (or run the CLI for a one-off), point it at a real recording, and you’ll get back a structured record per call:
Backfill an archive by listing past jobs, the list is cursor-paginated, newest first:
Python, page through jobs

Cost & scale notes

  • Batch is cheaper than realtime. Routing call processing through /v1/transcription/jobs (rather than realtime transcription) is billed at the discounted batch rate, see the pricing page for current figures. The result.audio_seconds field is the exact billed quantity, reconcile against the x-pyai-units header on your own ledger.
  • Prefer audio_url over upload when you can, the input is fetched and never stored, which is the cleanest posture for customer-call data.
  • Idempotency keys are per logical job. Reuse the same key only when retrying the exact same submit after a network blip; a new recording gets a new key.

Troubleshooting

Next steps

Streaming speech-to-text

Live transcription when you need partials in real time, not after the call.

Voice cloning

Give your agents and voicemail a branded, custom voice.

Pricing & metering

How batch usage is measured and the discounted batch tier.

Errors & limits

Idempotency, pagination, and the full code catalog.