Home → Blog → Speech-to-text pricing: what you actually pay for
Speech-to-text pricing: what you actually pay for
Transcription pricing looks simple — a rate per minute — and then the first invoice does not match the estimate. The gap is almost never the rate. It is the minutes you did not realise you were sending: silence, duplicates, retries and files nobody ever reads.
The unit is a minute of audio, not a word
Start here, because it explains most surprises. You are billed for the duration of the audio you upload, not for the amount of text that comes back.
Consequences worth internalising:
- A minute of silence costs the same as a minute of dense speech.
- A recording where nobody spoke still costs its full length, even though the response is empty.
- Ten seconds of speech inside a five-minute file costs five minutes.
- Speaking faster does not make it cheaper. Trimming the file does.
Almost every optimisation below is a variation on one idea: send less audio, not less speech.
Where the unexpected minutes come from
| Source | Typical waste | Fix |
|---|---|---|
| Leading and trailing silence in call recordings | 10–30% | Trim with ffmpeg before sending |
| Hold music and IVR menus | 5–20% | Cut the segment before the answer |
| The same file sent twice after a crash | up to 100% | Idempotent pipeline, skip finished files |
| Test runs left in production code | varies | Separate key, watch the client area |
| Recordings nobody ever opens | often the majority | Transcribe on demand, not everything |
The last row is usually the biggest one and the least technical. Teams often transcribe an entire archive because it is easy, then use two per cent of it.
Estimating your own spend
Do not extrapolate from a price page — measure your own audio. The whole calculation is two numbers:
ffprobe -v error -show_entries format=duration -of csv=p=0 sample.mp3
import pathlib, subprocess
def minutes(p):
out = subprocess.run(["ffprobe", "-v", "error", "-show_entries",
"format=duration", "-of", "csv=p=0", str(p)],
capture_output=True, text=True).stdout
return float(out) / 60
month = sum(minutes(p) for p in pathlib.Path("recordings").glob("*.mp3"))
print(f"{month:.0f} min per month")
Multiply by your rate and you have the monthly figure. Sanity anchors that hold in practice: a support line with 200 calls a day at four minutes each is roughly 16 000 minutes a month; a weekly podcast is about 4 hours; a team of ten on daily half-hour meetings is around 600 minutes.
Package plus overage, and why it exists
Most plans combine a monthly fee that includes a package of minutes with a per-minute rate above it. The arithmetic is worth doing once:
bill = monthly_fee + max(0, used_minutes - included_minutes) * rate
Two failure modes to avoid. Buying a package far above your volume means paying for minutes you never use — the included minutes do not roll over. Staying on pure pay-per-minute at high volume means missing the discount the package represents. Look at three months of actual usage before committing to either.
A hard limit on the package is a safety feature, not a restriction: it stops a runaway loop from generating an invoice nobody approved. Turn it on while you are still developing.
API or your own GPU
The honest comparison is not “rate per minute versus zero”. Self-hosting moves cost from a line item to a set of things that are easy to forget:
| Cost | API | Own GPU |
|---|---|---|
| Per minute of audio | rate | 0 |
| Hardware | 0 | card + machine, amortised |
| Electricity and hosting | 0 | continuous, whether idle or not |
| Setup and maintenance | 0 | engineer time, ongoing |
| Idle time | free | full price |
The break-even is about utilisation, not volume. A GPU that runs a few hours a day loses to an API, because you pay for the twenty idle hours too. A GPU saturated around the clock wins. In between, the deciding factor is usually whether you want to be responsible for a machine at 3 a.m.
There is a third reason that has nothing to do with money: some data is not allowed to leave your perimeter. That is a requirement, not an optimisation, and it settles the question on its own.
Cutting the bill without losing quality
- Trim silence. The cheapest single change on call recordings — often 10–30% off, with zero quality impact.
- Do not transcribe what nobody reads. Transcribe on request, or only calls above a duration threshold, and watch what people actually open.
- Make the pipeline idempotent. Repeating finished work after a crash is pure waste; skipping finished files removes it.
- Use a separate key for development. Test traffic mixed into production numbers hides both problems.
- Check usage weekly, not monthly. A loop that sends the same file in a cycle is obvious on day one and expensive by day thirty.
# trim the silence at both ends
ffmpeg -i call.mp3 -af silenceremove=start_periods=1:start_threshold=-45dB:stop_periods=-1:stop_threshold=-45dB:stop_duration=2 short.mp3
Try it on your own recordings. Sign-up takes a minute, and the free minutes are enough to judge the quality.
Get a free API keyFrequently asked questions
Am I billed per minute of audio or per word of text?
Per minute of audio you upload. The length of the resulting text changes nothing, which is why silence and hold music cost exactly as much as speech.
Do I pay for a recording that turned out to be silent?
Yes — the audio was still processed, even though the response is empty. Trimming silence before sending is the direct fix.
Are failed requests charged?
A request that returns an error is not billed for audio minutes. What does cost money is repeating a successful transcription, which is why a resumable pipeline matters.
Is running Whisper on my own GPU cheaper?
Only at high utilisation. A card that idles most of the day loses to per-minute billing once you count hardware, power and maintenance. Round-the-clock load is where self-hosting wins.
How do I avoid an unexpected invoice?
Estimate the volume with ffprobe before the first batch, keep the hard package limit on during development, and check the usage numbers in the client area weekly rather than at the end of the month.
Related reading
- How to build a batch transcription pipeline for an audio archive — Transcribing thousands of recordings without losing any: a work queue, concurrency, retries, resuming after a crash and keeping the bill under control.
- How to migrate from the OpenAI Whisper API to another service — A migration guide for the OpenAI Whisper API: what to change in code, how responses and errors compare, and how to test quality before switching production traffic.
- How to transcribe a call recording to text — A step-by-step guide to turning phone call recordings into text through an API in minutes: Python and C# samples, response formats and the errors you will meet.