Create transcript
Starts a transcription and returns it right away with `status: "processing"`. **Audio**: `url` (any public http(s) address) **or** `uploadId` (from `POST /v1/uploads`), exactly one of the two. **Result**: poll `GET /v1/transcripts/{id}` until `status` is `done` or `failed`, or pass `webhookUrl` to be called when it finishes. **Billing**: charged on completion, from the real audio duration (max 10 hours). Failed transcripts are never charged. `reuseIfIdentical` (on an upload created with `sha256`) returns the transcript the account already has for that exact audio instead of charging twice. **Retries**: send an `Idempotency-Key` header (up to 64 chars); the same key returns the same transcript instead of creating and charging a second one. The same key with a different body is a `409`. An `uploadId` changes on every retry, so key the request by your first `uploadId`, never by your own media id. **Trial limit**: until the first top-up, at most 2 transcriptions run at once; a third gets `429 concurrency_limit`.
Starts a transcription and returns it right away with status: "processing".
Audio: url (any public http(s) address) or uploadId (from POST /v1/uploads), exactly one of the two.
Result: poll GET /v1/transcripts/{id} until status is done or failed, or pass webhookUrl to be called when it finishes.
Billing: charged on completion, from the real audio duration (max 10 hours). Failed transcripts are never charged. reuseIfIdentical (on an upload created with sha256) returns the transcript the account already has for that exact audio instead of charging twice.
Retries: send an Idempotency-Key header (up to 64 chars); the same key returns the same transcript instead of creating and charging a second one. The same key with a different body is a 409. An uploadId changes on every retry, so key the request by your first uploadId, never by your own media id.
Trial limit: until the first top-up, at most 2 transcriptions run at once; a third gets 429 concurrency_limit.
Authorization
bearerAuth API key (tk_...)
In: header
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/transcripts" \ -H "Content-Type: application/json" \ -d '{}'{ "data": { "id": "string", "status": "processing", "text": "string", "words": [ { "start": 0, "end": 0, "text": "string", "speaker": "string" } ], "utterances": [ { "start": 0, "end": 0, "text": "string", "speaker": "string", "overlap": true } ], "diarizationSegments": [ { "start": 0, "end": 0, "speakers": [ "string" ] } ], "error": { "code": "audio_too_long", "message": "string" }, "language": "string", "durationSeconds": 0, "speakerCount": 0, "cost": 0, "currency": "USD", "model": "string", "url": "string", "retentionDays": 0, "externalId": "string", "metadata": {}, "createdAt": "string" }}List transcripts GET
Transcripts on the account, newest first. Items omit `text` and `words`; fetch a single transcript to get those. `since` and `until` cut by creation date in the database, so closing out one day of cost does not mean paging through the whole account: `?since=2026-08-27T00:00:00Z&until=2026-08-28T00:00:00Z`.
Get transcript GET
Read this until `status` becomes `done` (text in `text`, word timings in `words`, cost in `cost`), `failed` (reason in `error`) or `canceled`. **Prefer `?wait=30` over a polling loop**: the response is held until the transcript finishes, and comes back immediately when it does. While it is still `processing`, the response carries `Retry-After` with the interval worth waiting before asking again. For many transcripts at once, `webhookUrl` on creation is still the cheaper path: one delivery per job instead of one connection per job.