API
Send a file, get a transcript back.
The API draws on the same hours as the app - plan hours first, then top-up credits. A file costs exactly its audio length and failed jobs refund automatically.
Create a key in Settings → API keys and get hours on the pricing page.
Authentication
Pass your key as a bearer token on every request. Keys start with fs_live_ and can be revoked in Settings at any time.
Authorization: Bearer fs_live_...
Create a transcription
POST /api/v1/transcriptions - the file is the raw request body (not multipart), with the name in X-Filename. Audio and video both work; files can be up to 10 hours. The response returns immediately while transcription runs in the background - it also shows the hours you have left. If you know the spoken language, pass its ISO code in X-Language (e.g. de, es) - it skips auto-detection, which helps on short or noisy audio. Unknown codes are rejected with a 400.
curl -X POST https://flashscribe.ai/api/v1/transcriptions \ -H "Authorization: Bearer $FLASHSCRIBE_API_KEY" \ -H "X-Filename: interview.mp3" \ -H "X-Language: de" \ --data-binary @interview.mp3
{
"id": "1f0f9a4e-...",
"status": "pending",
"original_name": "interview.mp3",
"duration_sec": 1847.3,
"credits_charged_sec": 1847.3,
"credits_remaining_sec": 16152.7,
"created_at": "2026-08-26T14:03:07.512Z"
}Fetch the result
GET /api/v1/transcriptions/{id} - poll until status is completed (roughly a minute per audio-hour). Completed responses include the full text, word-level timestamps, and sentence-shaped subtitle cues. Transcriptions paid from plan hours or credits also label speakers: words and cues carry a speaker field ("A", "B", …) whenever more than one voice was heard.
curl https://flashscribe.ai/api/v1/transcriptions/1f0f9a4e-... \ -H "Authorization: Bearer $FLASHSCRIBE_API_KEY"
{
"id": "1f0f9a4e-...",
"status": "completed",
"language": "english",
"duration_sec": 1847.3,
"text": "Welcome back to the show - today we're talking about...",
"words": [{ "word": "Welcome", "start": 1.24, "end": 1.61, "speaker": "A" }, ...],
"cues": [{ "start": 1.24, "end": 3.81, "text": "Welcome back to the show -", "speaker": "A" }, ...],
"speaker_names": { "A": "Dana" }
}Add ?format=srt, ?format=vtt or ?format=txt to the same URL to get a ready-made file instead of JSON - subtitles carry the speaker name on every change of voice. Documents have no timestamps, so they offer txt only. Asking before the transcript is ready answers 409.
curl -o interview.srt \ "https://flashscribe.ai/api/v1/transcriptions/1f0f9a4e-...?format=srt" \ -H "Authorization: Bearer $FLASHSCRIBE_API_KEY"
Rate limits
Two limits, both answering 429 with a Retry-After header saying how many seconds to wait. Rejected keys are capped at 10 a minute per IP address, so a key that works is never held up by one that doesn't. Uploads are capped at 30 a minute per key - far past any real batch, and it only counts the two calls that create a transcription. Reading results is not limited.
Sources
Watch a podcast, a YouTube channel, a blog or a page; new entries are scored 0-100 against your topics and, for articles, get facts with verbatim quotes checked against the text. Nothing is transcribed until you approve it. POST /api/v1/sources takes any link - the feed behind it is discovered for you - and an optional topics list. Plans watch 2 sources (Free) or 25 (paid).
curl -X POST https://flashscribe.ai/api/v1/sources \
-H "Authorization: Bearer $FLASHSCRIBE_API_KEY" \
-H "content-type: application/json" \
-d '{"url": "https://feed.syntax.fm/", "topics": ["JavaScript", "web tooling"]}'{
"source": {
"id": "cmf...",
"kind": "podcast",
"url": "https://feed.syntax.fm/",
"title": "Syntax - Tasty Web Development Treats",
"topics": ["JavaScript", "web tooling"],
"paused": false,
"item_count": 0,
"new_count": 0
}
}GET /api/v1/sources lists what you watch; GET /api/v1/sources/{id}/items returns the entries best score first (?status=new by default, or dismissed, done, all) with their facts; DELETE /api/v1/sources/{id} stops watching.
{
"items": [{
"id": "cmf...",
"title": "1037: WebMCP is here (and you should care)",
"link": "https://syntax.fm/1037",
"published_at": "2026-09-09T11:00:00.000Z",
"duration_sec": 3390,
"media_url": "https://traffic.megaphone.fm/FSI4063165063.mp3",
"score": 88,
"score_reason": "A primary-source walkthrough of the new W3C standard you follow.",
"facts": [{ "text": "...", "quote": "...", "start": 1204, "end": 1290, "match": "exact" }],
"status": "new",
"transcription_id": null
}]
}POST /api/v1/items/{id}/approve transcribes an episode or video - priced like any link, by its length - or saves an article's text as a finished document at no charge. Either way you get a transcription_id to poll with the endpoint above. Optional language hint in the body.
curl -X POST https://flashscribe.ai/api/v1/items/cmf.../approve \
-H "Authorization: Bearer $FLASHSCRIBE_API_KEY"
{ "transcription_id": "1f0f9a4e-...", "status": "pending" }Errors
Errors are JSON with an error message and a meaningful status code:
- 401 - missing, invalid, or revoked key
- 400 - unreadable file (can't be priced or transcribed)
- 402 - not enough hours for this file's length
- 413 - file over the size cap or the 10-hour length cap
- 415 - multipart upload (send the raw body instead)
- 429 - rate limited; wait the seconds in Retry-After
- 409 - asked for a file before the transcript was ready
- 403 - source limit for the plan reached · 409 - already watching that URL · 422 - no feed or media at that link
Hours are charged when the upload is accepted and refunded in full if transcription fails. API usage always draws on your paid hours - the free daily allowance applies only in the app.