for developers · REST + MCP

Open-source agentic pipelines for audio intelligence

The models are open source and you can run them yourself. If you'd rather not own GPUs, this is the hosted path: submit a file or a URL, poll the job, pull transcript JSON with speaker labels and word timings, hand the segments to your agent.

Read the API docs → Connect the MCP server

async batch · faster-whisper + WhisperX · diarization · txt/json/srt/vtt/docx

Be clear about what you're buying

Whisper, faster-whisper, WhisperX and whisper.cpp are open source. Nothing here is locked behind a proprietary model — we run the same open weights on our own GPUs. What you're buying is the operations: the queue, the retries, the diarization pass, the storage, and the pager at 3am.

Self-host when…

audio can't leave your network; you already run GPUs and someone owns them; you need to patch the decoding path or fine-tune; or volume is steady enough that a reserved GPU beats per-minute credit.

faster-whisper · WhisperXyou own scaling + model ops

Use the hosted API when…

volume is bursty, you want a transcript today rather than a CUDA afternoon, or transcription is one node in a bigger pipeline and the week is better spent on the agent than the GPU box.

POST /api/v1/transcribewe own scaling + model ops

Neither, if you need real-time

This is asynchronous batch. No streaming socket, no on-device mode, no bot that joins a live call. If you need partial hypotheses while someone is still talking, use a streaming stack instead.

async onlysubmit → poll → fetch

Still picking an engine?

We keep a neutral comparison of the open-source Whisper family — what each implementation is actually best at, with no fabricated benchmarks.

8 implementations compared →then benchmark on your audio

The pipeline, end to end

Four calls. Every path, field and header below is in the API reference — nothing on this page is aspirational.

  1. 01

    Submit — a URL or a multipart upload

    POST /api/v1/transcribe/url takes JSON; POST /api/v1/transcribe takes multipart/form-data with a file field. Both accept language, diarize, word_timestamps and source. Send an Idempotency-Key so a retried submit returns the original job instead of a duplicate.

    curl https://whipscribe.com/api/v1/transcribe/url \
      -H "X-API-Key: $WHIPSCRIBE_KEY" \
      -H "Idempotency-Key: ep-412-v1" \
      -H "Content-Type: application/json" \
      -d '{"url":"https://example.com/ep-412.mp3","diarize":true,"word_timestamps":true,"source":"api"}'
    
    # 202 Accepted
    { "job_id": "35f4be54-…", "status": "queued", "tier": 2 }
  2. 02

    Poll the job

    GET /api/v1/jobs/{job_id} every ~3 seconds while status is queued or processing. It also returns progress, audio_duration_seconds, language, source, speech_detected, speech_ratio and error.

    # 200 OK
    { "job_id": "35f4be54-…", "status": "processing", "progress": 0.42,
      "audio_duration_seconds": 967, "speech_detected": true,
      "speech_ratio": 0.78, "error": null }

    Branch on speech_detected === false: a VAD pre-flight catches music and near-silence and finishes the job with an empty transcript rather than letting Whisper hallucinate over it.

  3. 03

    Pull the transcript in the shape you need

    GET /api/v1/jobs/{job_id}/result?format=json is the pipeline format — text, language, and a segments array of start / end / speaker / text, each with a words array. format also takes txt, srt, vtt and docx.

    { "text": "Welcome back to the show…", "language": "en",
      "segments": [
        { "start": 0.0, "end": 16.3, "speaker": "SPEAKER_00",
          "text": "Welcome back to the show…",
          "words": [ { "start": 0.0, "end": 0.4, "text": "Welcome" } ] } ] }
  4. 04

    Hand the segments to the agent

    Group segments by speaker, or window them by start, and pass the windows as tool results. Every segment carries a timestamp, so whatever the agent asserts traces back to a moment in the audio — and GET /api/v1/jobs/{job_id}/audio/url returns a short-lived playback url (with storage and expires_in) so a human can hear it.

    import httpx, time
    h = {"X-API-Key": KEY}
    job = httpx.post("https://whipscribe.com/api/v1/transcribe/url",
                     headers=h, json={"url": SRC, "diarize": True}).json()
    while True:
        s = httpx.get(f"https://whipscribe.com/api/v1/jobs/{job['job_id']}", headers=h).json()
        if s["status"] in ("done", "failed"): break
        time.sleep(3)
    r = httpx.get(f"https://whipscribe.com/api/v1/jobs/{job['job_id']}/result",
                  params={"format": "json"}, headers=h).json()
    turns = [{"t": seg["start"], "who": seg.get("speaker"), "say": seg["text"]}
             for seg in r["segments"]]     # → your agent's context

Failure modes worth handling before you ship

402 NO_CREDITS carries a credits snapshot and an upgrade_url. 429 RATE_LIMITED wants backoff. 502 BACKEND_ERROR and 502 BACKEND_UNREACHABLE are safe to retry. 410 AUDIO_EXPIRED means the audio retention window elapsed — the transcript is still readable, only playback is gone.

Every error is {"error": "…", "code": "…"}. Branch on code, never on the sentence. Only /api/v1/* is public and versioned; anything outside that prefix is internal and will move under you.

Or skip the glue: let the agent call the transcripts itself

The MCP server at https://whipscribe.com/mcp exposes the same capability as tools, so an MCP client — Claude, Claude Code, Cursor, or your own — submits and reads transcripts with no polling loop of yours. Setup is one connector →

ToolWhat it does
transcribe_urlTranscribe a direct media link, podcast episode, or Creative-Commons YouTube URL. Polls until done, then returns a preview plus a link to the full transcript.
transcribe_urls_batchUp to 20 URLs concurrently; a per-URL failure doesn't abort the batch. This is the playlist / backlog path.
get_job_statusPoll one job by job_id.
get_transcriptFetch a finished transcript as txt, json, srt, vtt or docx. Large transcripts are linked, not inlined.
list_my_transcriptsThe account's recent transcripts, including ones uploaded through the web app rather than by the agent.
clips_search_transcriptSearch one transcript's sentences; returns matches with start/end timestamps and speaker.
request_upload_urlMint a one-time presigned PUT URL, upload the bytes from the user's machine, then pass the returned public_url to transcribe_url. Audio never streams through the MCP transport.

One honest gap: transcribe_file exists in the toolset but is not supported over the remote transport — a local path doesn't exist on the server. Use request_upload_url then transcribe_url, or upload in the app.

Capture and identity, for the awkward cases

When the audio isn't a file yet

The Chrome extension records the current tab's audio or your microphone and submits it through the same API — useful when the source is a browser player.

Chrome Web Store →tab audio or mic

Filing jobs under a user

Pass X-User-Email alongside your key for server-to-server flows, or Authorization: Bearer with a Firebase ID token from a signed-in browser, and the transcript lands in that account's files.

X-API-Key + identity headerretention follows the user

Anonymous submits you claim later

A submit with no user identity returns a claim_token. Hold it client-side, then POST /api/v1/jobs/claim once the user signs in to attach every pending job.

POST /api/v1/jobs/claim{"claimed": 2}

Don't hardcode retention

GET /api/v1/me returns email, retention_days and signed_in — read it rather than baking a window into your client.

GET /api/v1/meauthoritative retention_days

What it costs to run a pipeline

Credit is metered in audio-hours: a 30-minute file spends 0.5h, and failed jobs don't consume credit. Credits don't expire.

PlanPriceMinutesPer audio-hour
Starter$4300$0.80
Pro$122,000$0.36
Team$245,000$0.29

Packs are one-time and the credits do not expire — there is no monthly commitment and no subscription to cancel. Worked example: a nightly job over 40 episodes averaging 50 minutes is 40 × 50 = 2,000 minutes — exactly one $12 Pro pack, which is 33 hours of audio at $0.36 an hour. Team's 5,000 minutes is 83 hours. Full pricing →

Get a key and put one file through it

Keys are self-serve: sign in, add credit, and create one at /apis/keys. The API has no free tier — a key needs a positive balance ($50 minimum, spendable on transcription). Then the whole pipeline above is four calls.

Create an API key →

Questions

Is this real-time or streaming?

No. It's asynchronous batch: submit, poll, fetch. No streaming socket, no on-device mode, no bot that joins a live call. If you need partial hypotheses mid-sentence, this is the wrong tool — better to know that here than after integration.

When is self-hosting the better call?

When audio can't leave your network, when you already run GPUs, when you need to modify the decoding path or fine-tune, or when steady volume makes a reserved GPU cheaper than per-minute credit. The engines are open source — start here if you're picking one.

How long can a single file be?

Up to 10 hours per file on the multipart endpoint, across mp3, m4a, wav, mp4, mov, ogg, webm and flac. Language is auto-detected when you omit language.

How do I make retries safe?

Send Idempotency-Key on submits. The same key from the same API key returns the original job with X-Idempotent-Replay: true instead of creating a duplicate. Keys are ≤255 chars, no whitespace.

Where does the audio actually run?

On our own GPUs, running open-source Whisper — your audio isn't handed to a third-party transcription vendor, and it is never used to train a model. Audio retention depends on plan; the transcript stays until you delete it. Details on /security.