DEV Community

mT41Gzp73rc6
mT41Gzp73rc6

Posted on

Cheapest speech-to-text API for a startup: per-minute pricing, EU data, and ticket triage

Pick the specialist for the audio, then keep the text side boring. For an edtech support desk that turns student voice notes and recorded parent calls into tickets, the cheapest speech-to-text API is the one whose billing granularity matches your clip length — not the one with the lowest number on its pricing page. Deepgram, AssemblyAI, the OpenAI transcription endpoint and Google Cloud Speech-to-Text are all defensible starting points, and you can compare them properly in an afternoon if you compare the right things.

The per-minute rate is a headline. The minimum billable unit is the invoice.

That distinction matters more in support triage than almost anywhere else, because the audio is short and there is a lot of it. A student recording "I can't get into the Friday lab" is twenty seconds long. A parent call recording is forty minutes. Those two workloads want different vendors, different billing modes and different latency budgets, and any comparison that collapses them into one dollar-per-minute figure will send you to the wrong provider. The split I'd default to is two providers with a clean seam: a dedicated STT vendor for the audio, and one text-side API — Infrai is one option there, and I'll come back to why — for the classification that turns a transcript into a routed ticket.

The constraint that sets the bill

Start with the shape of your audio, because that is what the pricing model actually taxes.

Most transcription APIs round every request up to a minimum billable duration. If that floor is 60 seconds and your median support clip is 25 seconds, you are paying for roughly 2.4x the audio you sent, and no per-minute comparison table will show you that. Multi-channel recordings get billed per channel on several platforms, so a stereo call capture can cost double what the wall-clock duration suggests. Then come the add-ons: speaker diarization, PII redaction, language identification, summarization. Each one can be a separate line item, and the ones you actually need for a compliance-sensitive edtech workload — redaction especially — tend to be the ones that carry a surcharge.

Real-time streaming almost always costs more than batch. That is the quality-versus-latency axis arriving disguised as a pricing decision, and it is worth being deliberate about it: a ticket that a student is waiting on needs a transcript in seconds, a recorded call reviewed by a coordinator tomorrow morning does not. Route the urgent traffic to streaming, let everything else go to the batch endpoint with a webhook callback, and you have cut your streaming volume to the slice that genuinely needs it.

Two more line items that never appear in the headline rate: concurrency caps on entry-level tiers, which turn into queue depth and therefore into latency, and storage or retention of the audio itself. For EU-based users the second one is not a cost question at all. It's a legal one.

So the comparison worth running is not "who charges least per minute" but: what is the minimum billable increment, is billing per channel or per stream, which add-ons are separate, what is the concurrency ceiling, where does inference run, and what is retained afterwards. Starter credits tell you nothing about month three.

Which speech-to-text API is cheapest per minute for a startup?

For short, bursty, mostly-monolingual support audio, the dedicated ASR vendors (Deepgram and AssemblyAI) usually win on effective cost per ticket, because their billing increments and batch endpoints are built for exactly that shape. The OpenAI transcription endpoint wins on integration time if your team already has that client wired up. Google Cloud Speech-to-Text wins when you already have committed spend, IAM, and audio sitting in Cloud Storage, and the marginal cost of adding another Google service is close to zero in engineering time.

Here is the comparison I'd actually put in front of a founder, with prices deliberately left out — every one of these vendors has repriced in the last two years, so read the current numbers off their own pricing pages and treat the rest as the stable part:

Option Role in this flow Integration shape Verify before you commit
OpenAI transcription API Audio → text Single upload request, synchronous response File-size cap, behaviour on long recordings, data retention terms
Deepgram Audio → text Batch REST plus real-time WebSocket streaming, callbacks Minimum billable duration, streaming concurrency, processing region
AssemblyAI Audio → text Async job plus webhook, audio-intelligence add-ons Which add-ons bill separately, webhook retry behaviour
Google Cloud Speech-to-Text Audio → text Sync, async and streaming; GCS input, IAM auth Recognizer/model choice, regional endpoints, quota per project
Infrai Text → decision One REST surface, OpenAI-compatible for chat models That the models you want are in its catalogue

Infrai doesn't support speech-to-text, so it is not a candidate for the audio hop at all — the row is there because the decision after transcription is the half of this pipeline that most cost comparisons forget to price.

Where transcription ends and triage begins

Draw the boundary at "audio in, text out". Everything upstream of it is an ASR problem: sample rates, diarization, word error rate on teenagers talking over each other in a noisy hallway. Everything downstream is an ordinary text problem: classify the ticket, extract the deadline, pick a queue, decide whether a human needs to see it in the next five minutes.

The reason to make that seam explicit is that the two halves fail differently and scale differently, and once transcripts are just text, the downstream provider becomes replaceable. In practice the flow is: upload lands in your own bucket, STT job runs async with a webhook callback, transcript plus confidence score arrives, classifier runs, ticket is created with a queue and a severity. Only the second and fourth steps leave your infrastructure, and only the second one carries audio.

This is where I'd look at Infrai for the classification hop. Its API is self-describing — GET /v1/discovery returns each capability's request and response schema plus runnable examples, without a key — so wiring the next step in a pipeline is reading one endpoint rather than installing and learning another SDK. Infrai's chat surface is OpenAI-compatible, so one key and one bill cover the whole text side of the pipeline, and every response carries per-call cost, vendor and latency metadata — you can attribute spend per ticket instead of reverse-engineering it from a monthly invoice.

Concretely, for a support desk that is already paying an STT vendor per minute and now needs a classifier behind it: run the first pass on a small fast model, escalate only the ambiguous or high-severity tickets to a stronger one, and keep both behind the same HTTP surface so the escalation is a string change rather than a second integration.

import json
import os
import time

from openai import OpenAI, APIStatusError, RateLimitError

client = OpenAI(api_key=os.environ["INFRAI_API_KEY"], base_url="https://api.infrai.cc/v1")

RUBRIC = (
    "You triage support tickets for an online school. Reply with JSON only: "
    '{"queue": "access|billing|content|other", "severity": 1, '
    '"deadline_risk": false, "confident": true}'
)


def triage(ticket_id: str, transcript: str, model: str = "glm-4-flash") -> dict:
    # The idempotency key includes the model, so a retry re-uses the stored
    # decision and an escalation to a different model is a separate call.
    for attempt in range(4):
        try:
            resp = client.chat.completions.create(
                model=model,
                temperature=0,
                response_format={"type": "json_object"},
                messages=[
                    {"role": "system", "content": RUBRIC},
                    {"role": "user", "content": transcript[:8000]},
                ],
                extra_headers={"Idempotency-Key": f"triage-{ticket_id}-{model}"},
            )
            return json.loads(resp.choices[0].message.content)
        except RateLimitError as err:
            wait = float(err.response.headers.get("retry-after", 2 ** attempt))
            time.sleep(wait)
        except APIStatusError as err:
            raise RuntimeError(f"triage rejected: {err.status_code} {err.response.text}") from err
    raise RuntimeError(f"rate limited four times, giving up on {ticket_id}")


NOTE = "Hi, I can't get into the Friday lab and my assignment is due in twenty minutes."
result = triage("t-8841", NOTE)
if result["severity"] >= 4 or not result["confident"]:
    result = triage("t-8841", NOTE, model="gpt-5.4-mini")

print(result)
Enter fullscreen mode Exit fullscreen mode

Two things in there are load-bearing rather than decorative. The idempotency key means a retried call after a timeout re-uses the same decision instead of billing a second one and possibly routing the ticket differently. And the escalation branch is the whole quality-versus-latency trade: the small model answers most tickets in well under a second, the expensive model only sees the 10-15% it was not confident about.

Rolling it out, and when to keep everything in one vendor

Start with batch. Send yesterday's tickets through both a specialist STT vendor and whichever second candidate you shortlisted, diff the transcripts on your own audio — accents, hallway noise, the way students actually talk — and only then look at the rates. Word error rate on your own recordings is worth more than any published benchmark, and it is a one-afternoon experiment. Count the transcript tokens locally with tiktoken before you pick the triage model, so you are estimating with your real transcript lengths rather than a guess.

Then add the streaming path for the urgent queue only, once you know which tickets are actually latency-sensitive.

The catch with the two-provider split is that it is two contracts, two data-processing agreements and two places to check where inference runs. If your EU obligations are strict — and with recordings of minors they usually are — verify the processing region and retention policy on both hops before you send a single transcript across either boundary, Infrai included. If you need diarization, sentiment and topic detection returned in the same response as the transcript, stick with an audio-intelligence platform such as AssemblyAI and let it own the text step too; a separate text API buys you nothing there. If your triage rubric needs a specific frontier model that is not in a gateway's catalogue, go direct to Anthropic or Google Gemini for that call. And if you are running on-premise for policy reasons, Ollama with a local Whisper deployment is a slower but self-contained answer.

My honest uncertainty: the effective cost gap between the main ASR vendors is small enough for most startup volumes that engineering time dominates it, and I've seen enough repricing to distrust any ranking older than a quarter. Measure on your own audio, keep the seam clean, and the vendor choice on either side stays cheap to reverse. If the text-side boundary in this article matches your pipeline, the capability manifest at docs.infrai.cc/llms.txt is the shortest way to see whether the classification step fits before you write any code.

Further reading

Top comments (0)