# Audio Transcriber - Speech-to-Text API (`automa-flow/audio-transcriber`) Actor

Transcribe MP3/WAV/FLAC/OGG/WEBM/M4A audio into text with speaker diarization, timestamps, context-aware terminology, and SRT/VTT. No external transcription API key required. Built for batch/API/MCP workflows.

- **URL**: https://apify.com/automa-flow/audio-transcriber.md
- **Developed by:** [Vadim Bezrukov](https://apify.com/automa-flow) (community)
- **Categories:** AI, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 audio minutes

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Audio Transcriber - Speech-to-Text API

You already have a public link to an audio file. Paste that HTTPS URL, run the Actor, and read one Dataset row with the transcript, speaker labels, timestamps, and SRT/VTT. You do not need your own speech-to-text API key. If you prefer to use your own Mistral account, you can [bring your own key](#use-your-own-mistral-api-key-optional).

The Console prefill is a 24-second public-domain NASA recording of Neil Armstrong stepping onto the Moon (Wikimedia Commons `Armstrong Small Step.ogg`). It bills one started audio minute, and the transcript should contain "one small step". Keep it for a first look, or replace `audioUrls` with your own MP3, WAV, FLAC, OGG, or WEBM links. One bad URL does not cancel the rest of the batch.

After the run, open Key-Value Store `RUN_SUMMARY` for the overall status, billed minutes, and the next action. Then open the Dataset. The next useful run is another file or batch, from the API, MCP, a schedule, n8n, or Make.

### Latest updates

19 October 2026: the first version accepts direct audio URLs and returns one status per file. [Full update history](https://apify.com/automa-flow/audio-transcriber/changelog).

### 30-second quickstart

1. Open the Actor and keep the default sample URL, or replace `audioUrls` with your public HTTPS audio links.
2. Leave diarization and subtitles on unless you only need plain text.
3. Run. Expect one Dataset row per URL with `status`, `text`, timed `segments` with speaker labels, and `srt` / `vtt` when enabled.

Example input:

```json
{
  "audioUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/d/dd/Armstrong_Small_Step.ogg"
  ],
  "diarize": true,
  "contextBias": ["Armstrong", "Apollo"],
  "includeSrt": true,
  "includeVtt": true,
  "maxDurationSeconds": 3600
}
```

### What data you get

| Field | Meaning |
| --- | --- |
| `status` | `SUCCESS`, `NO_SPEECH`, `FAILED`, or `SKIPPED` |
| `text` | Full transcript |
| `speaker_transcript` | Speaker-labelled plain text when diarization is on |
| `segments` | Timed sentence-level cues with a `speaker` label (`speaker_1`, `speaker_2`, ...) when diarization is on |
| `srt` / `vtt` | Deterministic subtitles from segments |
| `duration_seconds` / `billed_minutes` | Provider duration and started-minute billing |
| `error_code` | Explicit failure code when not successful |

`NO_SPEECH` is not a transport failure. Invalid media, unreachable URLs, oversize or over-duration files, and budget stops never look like empty success.

### Pricing

Primary event: **`audio-minute` at $0.007** per started provider-observed audio minute (`ceil(seconds / 60)`). With [your own Mistral key](#use-your-own-mistral-api-key-optional) the event is **`audio-minute-byok` at $0.004** instead, and Mistral bills your account for the transcription.

| Workload | Approx. buyer charge (PPE only) |
| --- | --- |
| 10-minute file | $0.07 |
| 60-minute file | $0.42 |

Also charged: synthetic `apify-actor-start` ($0.00005 per GB of run memory; one event at the default 1 GB). Platform usage (compute, transfer, storage) is included in these prices: nothing else is billed for the run. Failed items, duration-probe failures, over-duration rejects, and verified no-speech results are not charged. Free Apify plans cannot run this Actor, with or without your own key.

Set `maxTotalChargeUsd` on API or agent runs to bound the bill. The lowest accepted limit is `$0.008`: it covers the start events at any memory size plus one audio minute.

### Use your own Mistral API key (optional)

You do not need a key: by default the Actor uses its included transcription. If your team already works with Mistral, or needs its own retention and training settings, you can run the Actor with your own key instead.

**Set it up (about two minutes)**

1. Sign in at [console.mistral.ai](https://console.mistral.ai). Free mode gives API access without a card. Add billing there if you need higher limits.
2. Open **API Keys** in the left sidebar and click **Create new key**. Give it a name and, ideally, an expiry date. Copy the key right away: Mistral shows it only once.
3. In this Actor's input, open **Use your own Mistral key (optional)** and paste the key into **Your Mistral API key**. For API, MCP, or scheduled runs, send it as `mistralApiKey`:

```json
{
  "audioUrls": ["https://example.com/interview.mp3"],
  "mistralApiKey": "YOUR_MISTRAL_API_KEY"
}
```

4. Run. `RUN_SUMMARY` shows `"transcriptionKey": "own"` and `"billingEvent": "audio-minute-byok"`, so you can confirm which key was used.

**What changes**

| | Included (default) | Your own key |
| --- | --- | --- |
| Setup | None | A Mistral API key |
| This Actor charges | `audio-minute`, $0.007 per started minute | `audio-minute-byok`, $0.004 per started minute |
| Mistral bills you | Nothing | The transcription itself, at your plan's rate ([Mistral pricing](https://mistral.ai/pricing)) |
| Rate limits, retention, training settings | The publisher's Mistral account | Your Mistral account |

**If something goes wrong**

- The key is checked with Mistral before any audio is downloaded. If Mistral does not recognize it (HTTP 401), the run stops as FAILED right away and `RUN_SUMMARY.nextAction` says so. If your account runs out of credit during the run (HTTP 402), the run stops the same way. No audio minutes are charged for the failed files, and files that already finished stay in the Dataset.
- The Actor never falls back to the included key when your key fails, so the price never changes silently.
- Rate limits on your account (HTTP 429) are retried with backoff. Free Mistral mode has low limits, so a large batch may be slow or end with `UPSTREAM_RATE_LIMITED` rows.
- Free Apify plans cannot run this Actor, with or without your own key.

**Your key stays private.** It is an Apify secret input: stored encrypted, sent only to `api.mistral.ai`, never logged, and never written to the Dataset, `RUN_SUMMARY`, or the billing ledger. Audio you send is processed under your Mistral account's terms, so check its privacy settings before sending sensitive recordings.

### Diarization and context bias

Turn on `diarize` for interviews and meetings. Pass product names, people, or jargon in `contextBias` (up to 100 single words; the transcription API refuses entries with spaces or commas, so enter `Neil` and `Armstrong` as two entries). Context biasing is optimized for English. Other languages are experimental.

### API / MCP / schedule

Direct MCP endpoint (authenticated execution):

`https://mcp.apify.com?tools=automa-flow/audio-transcriber`

Example agent ask: "Transcribe these public HTTPS audio URLs with diarization and return SRT."

#### When an agent should call it

- You already have direct public HTTPS audio file URLs
- You need a bounded transcript with status and spend limits
- You will set `maxTotalChargeUsd` and read `RUN_SUMMARY`, then Dataset rows

#### When not to call it

- You only have YouTube, TikTok, Spotify, or page URLs (not supported)
- You need real-time streaming, translation, summaries, or 90+ languages
- You cannot estimate audio length and spend before the call

Anonymous MCP discovery uses `search-actors` and `fetch-actor-details` only. Running this Actor always requires the caller's own Apify authentication and budget.

Schedule example: a nightly batch of new interview files with the same input shape. Use Apify webhooks on the run for downstream delivery. This Actor does not add its own webhook product.

### Batch input

Send up to 100 URLs. Exact duplicate URLs are transcribed and charged once, then copied to every matching `input_index`; the copies show `duplicate_of` and `billed_minutes` 0. One bad URL does not cancel the rest of a valid batch.

### Output schema

Dataset views: **Transcripts**, **Subtitles** (SRT and WebVTT per file), **Errors**, and **All**. Agents should read Key-Value Store `RUN_SUMMARY` first for overall status, counts, billed minutes, and `nextAction`, then fetch Dataset items.

### Failure semantics

| Code | Meaning |
| --- | --- |
| `INVALID_URL` | Non-HTTPS, SSRF-unsafe, or malformed URL |
| `UNSUPPORTED_FORMAT` | Not readable audio, no audio track, or a video file |
| `DECODE_FAILED` | The audio could not be decoded for transcription |
| `URL_NOT_REACHABLE` | Download failed |
| `DURATION_PROBE_FAILED` | Could not measure duration safely |
| `MEDIA_TOO_LONG` / `MEDIA_TOO_LARGE` | Over `maxDurationSeconds` or 500 MiB |
| `BUDGET_INSUFFICIENT` | Remaining charge limit too low |
| `NO_SPEECH` | Verified empty speech |
| `UPSTREAM_*` | Provider timeout, rate limit, or failure |
| `DEADLINE_EXCEEDED` | The run timeout arrived before this file finished; not charged |
| `CANCELLED` | Not started because the spending limit or a provider stop ended the run; not charged |
| `BILLING_UNCERTAIN` | The charge for this file could not be confirmed; its transcript is kept in `BILLING_RECEIPT` and the run is not replayed |
| `PROCESSING_ERROR` | Unexpected error for this file only; not charged, the rest of the batch continues |
| `FREE_PLAN_REQUIRES_UPGRADE` | Free Apify plans cannot run this Actor |
| `PLAN_CHECK_FAILED` (run status) | The platform's paid-plan signal could not be read; nothing was transcribed or charged |

Each finished file is written to the Dataset right away, so a timeout or abort never loses a row you were charged for. Files the run timeout cut off are `SKIPPED` with `DEADLINE_EXCEEDED`, and `RUN_SUMMARY.deadlineReached` is true.

`RUN_SUMMARY.chargeLimitReached` is true when the spending limit stops further minutes. A restarted run reconciles the billing ledger with charged events and Dataset indexes. An unresolved charge is `BILLING_UNCERTAIN` and is not replayed.

### Supported formats, languages and limits

- Formats: MP3, WAV, FLAC, OGG, WEBM (including browser recordings without a stored length), M4A, AAC. Audio-only files are accepted even when the server labels them `video/webm` or `application/octet-stream`. Video files are refused.
- Languages: 13 (en, zh, hi, es, ar, fr, pt, ru, de, ja, ko, it, nl) via the upstream transcription model
- Max duration: 60 minutes per file
- Max size: 500 MB
- Max URLs per run: 100

A language hint input is deferred. Current provider docs mark `language` as incompatible with the timestamp detail required for SRT and VTT.

### Privacy

Audio is sent to Mistral for transcription through their official audio API. You are responsible for the rights and consents to process that audio. Do not use this Actor for covert recording or unlawful interception.

- The included publisher key is never exposed to users and is never logged. If you bring your own `mistralApiKey`, it is handled as described in [Use your own Mistral API key](#use-your-own-mistral-api-key-optional).
- Raw audio is not kept in the Dataset or Key-Value Store. Temporary files are deleted after processing.
- Default Mistral retention is not zero retention. Zero Data Retention is specific to the publisher account and is not confirmed here. Training opt-out is a separate control.
- Transcript text is not written to normal INFO logs.

### Limitations

- No YouTube, social, or webpage resolution. No browser and no proxies.
- No local Whisper, Batch API, translation, summaries, or chapters.
- No word-level timestamps: with speaker labels on, the transcription provider returns sentence-level segments only.
- Not a lowest-price claim, a highest-accuracy claim, or a HIPAA or GDPR certification.
- Audio URLs must be reachable from Apify's cloud without a login, cookie, or IP allow-list.

### Technical notes

Implementation uses HTTP only against `POST /v1/audio/transcriptions`. Media duration is probed locally with `ffprobe` before spend. Compact MP3, OGG, WEBM, FLAC, and WAV files are uploaded as they are. M4A/AAC, files without a stored length, and heavy files (above about 256 kbps, such as CD-quality WAV) are first converted to 16 kHz mono FLAC, the rate the speech model works at, which also makes the upload several times smaller. Billing always uses the provider-measured duration. Billing charges exact started minutes from `usage.prompt_audio_seconds` after a verified non-empty transcript.

# Changelog

This Actor's version history is a separate document: https://apify.com/automa-flow/audio-transcriber/changelog.md

# Actor input Schema

## `audioUrls` (type: `array`):

1-100 public HTTPS direct audio file URLs (MP3, WAV, FLAC, OGG, WEBM, M4A, AAC). Exact duplicate URLs are transcribed once and mirrored into every matching Dataset row. Webpage and social-media page URLs are not supported.

## `diarize` (type: `boolean`):

Label different speakers in the transcript when possible.

## `contextBias` (type: `array`):

Up to 100 single words that guide the spelling of names and domain terms, for example Armstrong, Voxtral or co-op. No spaces or commas inside an entry: enter a two-word name as two entries. Optimized for English; other languages are experimental.

## `includeSrt` (type: `boolean`):

Generate an SRT subtitle track from segment timestamps.

## `includeVtt` (type: `boolean`):

Generate a WebVTT subtitle track from segment timestamps.

## `maxDurationSeconds` (type: `integer`):

Reject files longer than this before calling the transcription provider. Default and maximum are 3600 seconds (60 minutes) until a longer limit is live-verified.

## `mistralApiKey` (type: `string`):

Leave empty to use the included transcription: nothing to set up, $0.007 per started audio minute. Or paste your own Mistral API key: this Actor then charges $0.004 per started audio minute and Mistral bills your account directly for the transcription. Create a key at console.mistral.ai > API Keys > Create new key. Apify stores it encrypted; it is sent only to api.mistral.ai and never logged or written to the output.

## `payload` (type: `object`):

Added by an Apify Actor-to-Actor integration. It is accepted so the run can start and is not read or stored. Put the audio links in audioUrls of the integration input.

## Actor input object example

```json
{
  "audioUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/d/dd/Armstrong_Small_Step.ogg"
  ],
  "diarize": true,
  "contextBias": [],
  "includeSrt": true,
  "includeVtt": true,
  "maxDurationSeconds": 3600
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

## `billingReceipt` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "audioUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/d/dd/Armstrong_Small_Step.ogg"
    ],
    "diarize": true,
    "contextBias": [],
    "includeSrt": true,
    "includeVtt": true,
    "maxDurationSeconds": 3600
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/audio-transcriber").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "audioUrls": ["https://upload.wikimedia.org/wikipedia/commons/d/dd/Armstrong_Small_Step.ogg"],
    "diarize": True,
    "contextBias": [],
    "includeSrt": True,
    "includeVtt": True,
    "maxDurationSeconds": 3600,
}

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/audio-transcriber").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "audioUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/d/dd/Armstrong_Small_Step.ogg"
  ],
  "diarize": true,
  "contextBias": [],
  "includeSrt": true,
  "includeVtt": true,
  "maxDurationSeconds": 3600
}' |
apify call automa-flow/audio-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/audio-transcriber"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/XSMkVsF6IxsO3DYow/builds/cHylTK5NovCXEiSf5/openapi.json
