Batch transcription API: transcribe many audio files
Batch transcription by API is a loop: one speech-to-text job per file, keyed by the file's id, collected by webhook or polling. How it works on Sume.

With a job-based speech-to-text API, batch transcription is a loop: submit one job per audio file with an idempotency key derived from that file, let the service queue what it can't start yet, and save each transcript when its job finishes. Sume STT 1.0 works this way. Every file is its own POST /v1/stt-1.0/transcribe job, and jobs past your workspace's concurrency limit wait as queued while queue capacity remains.
STT 1.0 is specified in the OpenAPI document behind the Sume API reference, which the API reference docs page names as the source for exact request and response shapes. Queueing and polling follow Generation admission and Jobs and results. All were read on 2026-09-27. For a single file, see Speech-to-text API with word timestamps.
Is there a batch endpoint for many files?
No. An STT 1.0 request takes one audio_url string and rejects fields its schema doesn't define, so there is no list of files to send. The batch is a loop on your server, one request per file:
audio_url: a public HTTPS URL for the file. The request has no upload field, so each file must already be reachable at a URL.duration_seconds: the file's length, 1–600. It sizes the usage reservation; omit it and Sume reserves 1 minute. Files over 10 minutes need splitting into parts first.segmentation: { "mode": "sentence" }adds sentence timestamps to each result.webhook_url: a public HTTPS callback for when each job ends. Leave it out to poll instead.Idempotency-Key: built from the file's own id, so a resend with the same body returns the original job instead of a second one.
// Server-side Node 18+. files: [{ id, url, seconds }] from your own storage.
const jobIds = new Map(); // your file id -> Sume job id; persist it
for (const file of files) {
const res = await fetch("https://api.sume.com/v1/stt-1.0/transcribe", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.SUME_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": "stt-" + file.id, // same key, same body on every retry
},
body: JSON.stringify({
audio_url: file.url,
duration_seconds: file.seconds,
segmentation: { mode: "sentence" },
webhook_url: "https://example.com/webhooks/sume",
}),
});
if (res.status === 429) break; // queue full or rate limited: wait, then resume
if (!res.ok) throw new Error(await res.text());
const { data } = await res.json();
jobIds.set(file.id, data.request_id); // request_id is the job id
}What happens when I submit more files than can run at once?
The extra jobs wait. Sume admits paid jobs queue-first: a valid job starts at once or waits in queued until a workspace concurrency slot opens. In current code, speech_to_text is one of the job types that take such a slot.
Your plan sets the concurrency limit, and queue capacity defaults to max(3, concurrency_limit × 5). Submit responses carry a generation_limits snapshot when Sume can compute one; video job concurrency and queueing shows how to size each wave from it. Your loop should handle these responses:
| Response | What it means | What the loop does |
|---|---|---|
2xx | The job exists and paid work is in flight; that doesn't mean it finished. | Store the job id and move to the next file. |
429 queue_full | The workspace has no accepted generation capacity left. | Stop, wait for jobs to finish, then retry the same file with the same key. |
429 rate_limited | Request volume passed an abuse-protection limit. | Back off, using retry-after when present, and retry with the same key. |
402 insufficient_credits | The balance can't cover the estimate. Nothing starts. | Stop the batch until the balance can cover it. |
409 idempotency_conflict | The key was already used with a different payload. | Fix how you build keys; reuse a key only for exact retries. |
How do I collect the transcripts?
Take webhooks, poll, or both. The docs call a webhook a delivery optimization, not your only recovery path, so keep polling available.
- Webhook: Sume sends a signed
job.completed,job.failed, orjob.canceledevent when each job ends, with no progress callbacks. Verify its signature, then fetch that job's result. - Polling: call
GET /v1/jobs/{id}/statuswith backoff, honoringnext_poll_after_seconds, untilterminalis true.GET /v1/jobs/{id}/resultanswers409 job_not_completeduntil the job has completed. - Recovery:
GET /v1/jobs?type=speech_to_textlists jobs newest first, up to 100 per page. Each row carries theidempotency_keyit was created with, so join results to your files on that key, not on position. - A completed result has
text,words[]with each word'sstartandendin seconds,segments[]if you asked for sentences, andlanguage_codewhen available. - A resend under the same key returns the original job, so to try a failed file again, send it under a new key, such as the file id plus an attempt number.
How much does batch transcription cost?
The same as transcribing the files one by one: $0.01 per audio minute on API pricing, plus a 5.5% agent fee by default. A backlog of 100 recordings of 5 minutes each is 500 audio minutes, or $5.00 before the fee.
Sume reserves each job's estimate when it accepts the submit, captures it when the job completes, and releases or refunds it, where applicable, when a job fails. Cancel queued jobs you no longer need with POST /v1/jobs/{id}/cancel. Once a job has started, cancel answers 409 job_generation_already_started and the job runs to the end.
What are the limits?
- One file per request, up to 10 minutes of audio:
duration_secondsstops at 600. webhook_urlmust be public HTTPS and at most 2,048 characters. Localhost and private-network URLs are rejected.mode: "sync"holds a request for at most 30 seconds, so useasyncorwebhookfor a batch.- Accepted jobs per workspace stop at the concurrency limit plus queue capacity; past that, submits answer
429 queue_full.
Sources
Related posts
More in Developers
- Bulk image generation: script hundreds of AI images via API
Send one image request per row, each with its own Idempotency-Key, async mode, and up to four images per call. Your plan's concurrency sets the pace.
- Can multiple people use the same API key?
They can, but they then share its rate limit, usage record, and revocation. Give each person or service its own key, and know what stays shared.
- Create a talking avatar using Python with the Sume API
Create a talking avatar in Python with Requests: generate the avatar, poll its job, send it a script to speak, then read the finished video's URL.
- Do AI-generated video URLs expire? How Sume stores outputs
Not for Format runs and Agent Completions: Sume returns their media on media.sume.com URLs that do not expire, and anyone holding a link can open it.
Written by Sume