Creating a recording
POST /transcriptions takes exactly one source: a file or a url. Sending neither is a 422. Both fields, and the optional language and title, can be sent as multipart form data or — for a URL — as JSON.
| Field | Type | Notes |
|---|---|---|
file | file | Audio or video, multipart only. Required without url. |
url | string | A public http(s) link. Required without file. |
language | string | An ISO code from GET /languages. Omit to auto-detect. |
title | string | Your own name for it, up to 255 characters. |
Always send an Idempotency-Key. A create is the one request here that costs money if it happens twice.
From a file
The upload is part of the request, so give your HTTP client a generous timeout — a large file over a slow link takes as long as it takes. We accept anything ffmpeg can read: m4a, mp3, wav, flac, ogg, aac, mp4, mov, mkv, webm and the rest.
curl https://heartotext.com/api/public/v1/transcriptions \
-H "Authorization: Bearer $H2T_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F file=@interview.wav \
-F title="Interview with Dr Yilmaz" \
--max-time 1800From a URL
Send a link and we fetch it ourselves — public video and audio hosts, podcast feeds’ episode files, and any plain http(s) file. Three things are refused:
- Playlists. Send one recording at a time; a playlist link is refused as a
422. - DRM-protected sites. We do not break content protection.
- Private addresses. Anything that resolves to a local or internal host is refused, both when you send it and again immediately before we fetch it.
A URL that turns out to be unfetchable produces a recording that reaches status: "failed" rather than an error on the create — we cannot know until we try.
Languages
Omit language and we detect it. Send an ISO code when you already know it: it is faster and it removes the one thing detection can get wrong, which is a recording that opens in a different language from the one it is mostly in. GET /languages lists every code we accept.
{ "data": [ { "code": "ar", "name": "Arabic" }, { "code": "de", "name": "German" }, { "code": "en", "name": "English" } ] }Limits
- 512 MB per upload. A larger file is refused as a
422, or as a413when the body is too large to reach the application at all. - 6 hours per recording on a paid plan.
GET /mereports the exact figure for your account. - A daily allowance across all recordings, and a ceiling on how many may run at once. Both are on the rate limits page.
Listing recordings
GET /transcriptions returns the recordings this key can see, newest first, with limit (up to 1000), cursor and an optional status filter.
curl "https://heartotext.com/api/public/v1/transcriptions?status=completed&limit=50" \
-H "Authorization: Bearer $H2T_API_KEY"Paging is by cursor everywhere, never by page number. next_cursor is opaque: pass it back unchanged and do not try to construct one.
Deleting a recording
DELETE /transcriptions/{id} removes the audio, the transcript and the embeddings, and answers 204. It is permanent and there is no undelete. A recording that has not finished — still queued or processing — answers 409 transcription_still_processing, so wait for it to complete or fail first.
