Quickstart

Transcribe audio with /v1/transcribe.

Send a file as multipart form data, or provide a url to have the API download and transcribe it. Files under 10 minutes and 30 MB return the transcript directly in the HTTP response. Larger files or URLs pointing to longer audio are automatically routed to async jobs. Add a webhook when you want the request to return immediately and deliver a signed result URL later.

First request
curl -X POST https://api.transcribeapi.com/v1/transcribe \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@audio.mp3" \
  -F "language=en"

SDKs

Use the SDK when you want uploads, polling, and batches handled for you.

The SDK chooses direct multipart or async upload flow from the file count, file size, duration estimate, remote URL, and webhook option. Set polling when the SDK should wait for terminal job status. Set showLogs when you want upload and polling progress printed by the SDK.

Node.js

Install with npm install @transcribe-api/sdk.

Node SDK
import { TranscribeAPI } from "@transcribe-api/sdk";

const client = new TranscribeAPI({
  apiKey: "YOUR_API_KEY",
  autoReload: { amount: 10, ifBalanceBelow: 20 },
  polling: { interval: 10, timeout: 15 * 60 },
  showLogs: true,
});

const result = await client.transcribe({
  files: [
    { reference_id: "customer_123_meeting_1", file: "meeting.mp3" },
  ],
  language: "en",
  exclude: ["metadata"],
});

console.log(result);

Python

Install with pip install transcribe-api.

Python SDK
from transcribe_api import TranscribeAPI

client = TranscribeAPI(
    apiKey="YOUR_API_KEY",
    autoReload={"amount": 10, "if_balance_below": 20},
    polling={"interval": 10, "timeout": 15 * 60},
    showLogs=True,
)

result = client.transcribe(
    files=[
        {"reference_id": "customer_123_meeting_1", "file": "meeting.mp3"},
    ],
    language="en",
    exclude=["metadata"],
)

print(result)

Cloudflare Workers

Use @transcribe-api/sdk/worker in Cloudflare Workers and other web-standard runtimes. The Worker entrypoint accepts remote URLs, Blob, File, Uint8Array, and ArrayBuffer. It does not accept local file path strings.

Worker SDK
import { TranscribeAPI } from "@transcribe-api/sdk/worker";

export default {
  async fetch(request, env) {
    const client = new TranscribeAPI({
      apiKey: env.TRANSCRIBE_API_KEY,
      autoReload: { amount: 10, ifBalanceBelow: 20 },
      polling: { interval: 10, timeout: 15 * 60 },
      showLogs: true,
    });

    const result = await client.transcribe({
      files: [
        { reference_id: "customer_123_episode_1", url: "https://example.com/audio-1.mp3" },
        { reference_id: "customer_456_episode_2", url: "https://example.com/audio-2.wav" },
      ],
      exclude: ["metadata"],
    });

    return Response.json(result);
  },
};

Auto reload

Set autoReload when creating a client to automatically top up your account after every transcription result. The SDK checks remaining_balance and calls POST /v1/add-funds when it drops below your threshold.

Node.js auto reload
const client = new TranscribeAPI({
  apiKey: process.env.TRANSCRIBE_API_KEY,
  autoReload: { amount: 10, ifBalanceBelow: 20 },
  polling: { interval: 10, timeout: 15 * 60 },
});

const result = await client.transcribe({
  files: [
    { reference_id: "episode_1", file: "./episode.mp3" },
  ],
});

// addFunds called automatically if remaining_balance < 20
console.log(result);
Python auto reload
client = TranscribeAPI(
    apiKey=os.environ["TRANSCRIBE_API_KEY"],
    autoReload={"amount": 10, "if_balance_below": 20},
    polling={"interval": 10, "timeout": 15 * 60},
)

result = client.transcribe(
    files=[
        {"reference_id": "episode_1", "file": "./episode.mp3"},
    ],
)

# add_funds called automatically if remaining_balance < 20
print(result)

Auto reload runs when the SDK receives the result directly (polling path). When using a webhook, the result goes to your server instead of the SDK. Use the standalone addFunds method inside your webhook handler:

Node.js webhook addFunds
// Inside your webhook handler
app.post("/webhook", async (req, res) => {
  const { remaining_balance } = req.body;

  if (remaining_balance < 20) {
    const client = new TranscribeAPI({ apiKey: process.env.TRANSCRIBE_API_KEY });
    await client.addFunds(10, { ifBalanceBelow: 20 });
  }

  res.sendStatus(200);
});
Python webhook add_funds
# Inside your webhook handler
@app.route("/webhook", methods=["POST"])
def webhook():
    payload = request.get_json()
    remaining_balance = payload.get("remaining_balance", 0)

    if remaining_balance < 20:
        client = TranscribeAPI(apiKey=os.environ["TRANSCRIBE_API_KEY"])
        client.add_funds(10, if_balance_below=20)

    return "", 200

addFunds(amount, { ifBalanceBelow }) / add_funds(amount, if_balance_below=N) calls POST /v1/add-funds. The ifBalanceBelow guard is enforced server-side, making it safe against duplicate webhook deliveries. See Billing for the full auto-reload and concurrency protection details.

Transcribe

POST /v1/transcribe handles single files, URLs, async jobs, and batch jobs.

Send multipart/form-data with a file or url field for single transcriptions—the API will return the text directly or route to async automatically. Send JSON with a files array when you want async upload URLs, remote URL import, or batch processing.

Field Required Meaning
file No* The audio file to transcribe (multipart only). Required unless url is provided.
url No* An HTTPS URL to an audio file. Required unless file is provided.
language No Two-letter language code such as en or fr. Omit it for auto-detect.
size_bytes No File size in bytes. For JSON batch jobs only. Files at or above 128 MB receive multipart upload URLs instead of a single put URL. The SDK includes this automatically.
webhook_url No HTTPS URL to receive the completed job payload.
exclude No Comma-separated response fields to omit.
reference_id No Your own ID for the file, for example a user ID, customer ID, or media ID. Use 1-150 safe characters: letters, numbers, dot, underscore, or hyphen.

Without a webhook

The request waits for transcription and returns the transcript JSON directly. Use this for short files from regular server environments.

Direct response
{
  "job_id": "job_2u7v8...",
  "user_id": "usr_abc123",
  "job_status": "completed",
  "billed_seconds": 42,
  "price_per_hour": 0.15,
  "cost": 0.00175,
  "remaining_balance": 18.47291,
  "files": [
    {
      "reference_id": "customer_123_meeting_1",
      "billed_seconds": 42,
      "text": "The full transcript...",
      "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:04.120\n...",
      "segments": [
        {
          "id": 0,
          "start_seconds": 0,
          "end_seconds": 4.12,
          "text": "The first sentence."
        }
      ],
      "detected_language": "en"
    }
  ]
}

With a webhook

The transcription takes the same amount of time as the direct response path, but the HTTP request returns as soon as the job is accepted. The completed result is delivered by webhook with a signed result_url. This is useful for serverless backends with short execution limits.

Accepted response
{
  "job_id": "job_2u7v8...",
  "job_status": "processing"
}

exclude

exclude controls which fields are omitted from the response or downloaded result JSON. It can contain text, vtt, segments, metadata, billing, and detected_language. At least one transcript field must remain, so do not exclude text, vtt, and segments together.

Examples: exclude=metadata,billing returns only transcript data. exclude=segments removes word or sentence segment arrays when you only need text and vtt.

For single-file outputs, if exclude leaves only one transcript field and removes metadata, billing, and detected language, the API returns that remaining value directly instead of a JSON object. Text-only responses return a plain string, VTT-only responses return a plain string, and segments-only responses return an array. Multi-file outputs still return JSON so each result stays associated with its reference_id.

url

Pass a url instead of file in the multipart form. If the audio is within the 30 MB and 10-minute sync limits, the transcript is returned directly in the response. Otherwise a batch job is created and the response includes job_id and job_status so you can poll for the result.

language

Set language to a two-letter ISO 639-1 code to specify the audio language. Omit or use auto to enable automatic language detection. Supported languages:

  • af Afrikaans
  • am Amharic
  • ar Arabic
  • as Assamese
  • az Azerbaijani
  • ba Bashkir
  • be Belarusian
  • bg Bulgarian
  • bn Bengali
  • bo Tibetan
  • br Breton
  • bs Bosnian
  • ca Catalan
  • cs Czech
  • cy Welsh
  • da Danish
  • de German
  • el Greek
  • en English
  • es Spanish
  • et Estonian
  • eu Basque
  • fa Persian
  • fi Finnish
  • fo Faroese
  • fr French
  • gl Galician
  • gu Gujarati
  • ha Hausa
  • haw Hawaiian
  • he Hebrew
  • hi Hindi
  • hr Croatian
  • ht Haitian Creole
  • hu Hungarian
  • hy Armenian
  • id Indonesian
  • is Icelandic
  • it Italian
  • ja Japanese
  • jw Javanese
  • ka Georgian
  • kk Kazakh
  • km Khmer
  • kn Kannada
  • ko Korean
  • la Latin
  • lb Luxembourgish
  • ln Lingala
  • lo Lao
  • lt Lithuanian
  • lv Latvian
  • mg Malagasy
  • mi Maori
  • mk Macedonian
  • ml Malayalam
  • mn Mongolian
  • mr Marathi
  • ms Malay
  • mt Maltese
  • my Myanmar
  • ne Nepali
  • nl Dutch
  • nn Norwegian Nynorsk
  • no Norwegian
  • oc Occitan
  • pa Punjabi
  • pl Polish
  • ps Pashto
  • pt Portuguese
  • ro Romanian
  • ru Russian
  • sa Sanskrit
  • sd Sindhi
  • si Sinhala
  • sk Slovak
  • sl Slovenian
  • sn Shona
  • so Somali
  • sq Albanian
  • sr Serbian
  • su Sundanese
  • sv Swedish
  • sw Swahili
  • ta Tamil
  • te Telugu
  • tg Tajik
  • th Thai
  • tk Turkmen
  • tl Tagalog
  • tr Turkish
  • tt Tatar
  • uk Ukrainian
  • ur Urdu
  • uz Uzbek
  • vi Vietnamese
  • yi Yiddish
  • yo Yoruba
  • zh Chinese
  • yue Cantonese

Batch

Use JSON on POST /v1/transcribe for async and batch jobs.

A batch can use local uploads, remote URLs, or both. Top-level language, webhook_url, and exclude apply to the job. A file can override language. Every multi-file batch must provide unique reference_id values so you can map each result back to your users.

Create a batch without the SDK
curl -X POST https://api.transcribeapi.com/v1/transcribe \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "language": "en",
    "webhook_url": "https://example.com/transcribe-webhook",
    "exclude": "metadata",
    "files": [
      { "reference_id": "customer_123_episode_1", "size_bytes": 5242880 },
      { "reference_id": "customer_456_episode_2", "url": "https://example.com/audio-2.wav", "language": "fr" }
    ]
  }'

Create response

Upload URLs are returned in the create response, so no separate upload URL request is needed.

Upload instructions
{
  "job_id": "job_8k3...",
  "job_status": "uploading",
  "uploads": [
    {
      "reference_id": "customer_123_episode_1",
      "upload": {
        "type": "put",
        "url": "https://...",
        "headers": {}
      }
    }
  ]
}

Remote URL jobs

If every file entry has a url, the API does not return upload instructions. The job moves directly into verification and processing. URLs must be reachable by Transcribe API while the job starts.

Remote only response
{
  "job_id": "job_8k3...",
  "job_status": "verifying"
}

Requesting upload URLs

When you create a job with local files, include size_bytes on each file entry so the API can return the correct upload instructions. Files under 128 MB receive a single type: "put" signed URL—PUT the entire file to that URL. Files at or above 128 MB receive type: "multipart" instructions with multiple part URLs and a complete_url. The SDK includes size_bytes automatically; when calling the REST API directly you must supply it.

Upload local files manually

For type: "put", upload the exact file bytes with PUT. For type: "multipart", upload each byte range to its part URL, collect the returned ETag, then POST the completion XML to complete_url. After all local files are uploaded, call POST /v1/transcribe/{job_id}/upload-completed.

PUT upload
curl -X PUT "SIGNED_UPLOAD_URL" \
  --upload-file "episode-1.mp3"
Mark upload complete
curl -X POST https://api.transcribeapi.com/v1/transcribe/job_8k3.../upload-completed \
  -H "Authorization: Bearer YOUR_API_KEY"
Multipart completion XML
<CompleteMultipartUpload>
  <Part>
    <PartNumber>1</PartNumber>
    <ETag>"etag-from-part-1"</ETag>
  </Part>
  <Part>
    <PartNumber>2</PartNumber>
    <ETag>"etag-from-part-2"</ETag>
  </Part>
</CompleteMultipartUpload>

Polling and Result Files

Poll GET /v1/transcribe/{job_id} until a terminal status.

Polling is useful when you do not use webhooks or when webhook delivery fails. A completed job includes a signed result_url. Download that URL to read result.json.

Processing
{
  "job_id": "job_8k3...",
  "user_id": "usr_abc123",
  "job_status": "queued",
  "billed_seconds": 3600,
  "price_per_hour": 0.15,
  "cost": 0.15,
  "remaining_balance": 18.32291,
  "total_files": 2
}
Completed
{
  "job_id": "job_8k3...",
  "user_id": "usr_abc123",
  "job_status": "completed",
  "billed_seconds": 3600,
  "price_per_hour": 0.15,
  "cost": 0.15,
  "remaining_balance": 18.32291,
  "total_files": 2,
  "result_url": "https://..."
}

result.json

result_url points to the completed transcript file. The URL is signed for 7 days from the transcription completion time. It contains transcript data, not the latest account balance. Use polling, webhook payloads, or GET /v1/billing/summary for current balance.

Downloaded result
{
  "job_id": "job_8k3...",
  "user_id": "usr_abc123",
  "billed_seconds": 3600,
  "files": [
    {
      "reference_id": "customer_123_episode_1",
      "billed_seconds": 1800,
      "text": "Transcript for file one...",
      "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:04.120\n...",
      "segments": [
        {
          "id": 0,
          "start_seconds": 0,
          "end_seconds": 4.12,
          "text": "Transcript for file one."
        }
      ],
      "detected_language": "en"
    }
  ]
}

Job Status Lifecycle

Understand what each job status means.

A job moves through several stages from creation to completion.

Status Meaning
uploading Upload URLs have been issued. Local files are being uploaded to Cloudflare R2. Remote URL files are being imported. The job will not proceed until all uploads are complete and POST /v1/transcribe/{job_id}/upload-completed is called.
verifying Uploads are confirmed. The backend validates audio formats, enforces file size and duration limits, and calculates billing for every file. No transcript data is available at this stage—the response includes only job_id and job_status.
queued Verification passed. The job is waiting in queue.
processing Used for direct single-file jobs. Transcription is in progress and the HTTP response will return the result when complete, or a webhook will be sent.
completed Transcription finished successfully. A signed result_url is available in the polling response or delivered by webhook.
failed Audio did not parse, corrupt or failed the verification process.
insufficient_funds The job passed verification but the account balance was too low to cover the transcription cost. Add funds and create a new job.

Webhooks

Receive completed transcription results at your server.

Pass webhook_url in REST or webhookUrl in the SDK. The HTTP request returns immediately once the job is accepted—transcription runs in the background. When complete, a signed POST is sent to your URL with the result payload. Your endpoint should return a 2xx response within 10 seconds. If a webhook is missed, poll GET /v1/transcribe/{job_id}.

Audio under 10 minutes can take up to 25 seconds to transcribe. If you run on a serverless backend with short execution limits, use a webhook even for single files—the result will be delivered with a signed result_url just like an async job.

Completed webhook
{
  "job_id": "job_8k3...",
  "user_id": "usr_abc123",
  "job_status": "completed",
  "billed_seconds": 3600,
  "price_per_hour": 0.15,
  "cost": 0.15,
  "remaining_balance": 18.32291,
  "result_url": "https://..."
}
Insufficient funds webhook
{
  "job_id": "job_8k3...",
  "job_status": "insufficient_funds",
  "required_balance": 0.42,
  "current_balance": 0.18
}

Signature verification

Each webhook includes X-TranscribeAPI-Timestamp, X-TranscribeAPI-Signature, and X-TranscribeAPI-Key-Id. Verify the signature against the raw request body. The signing keys are available at GET /.well-known/transcribeapi-webhook-keys.json.

Verification input
${timestamp}.${raw_request_body}

Reject old timestamps, for example anything older than 5 minutes. Webhook handlers should be idempotent because delivery can be retried or a user can also poll the same job.

Billing

Read balance from responses or from /v1/billing/summary.

Transcription responses, webhook payloads, and polling responses include remaining_balance. This is the current balance when that response was created. Use it to decide when to top up—for example, trigger /v1/add-funds when it drops below a threshold. It is a snapshot, not a live-updating value, so multiple concurrent responses can show the same balance. GET /v1/billing/summary also returns the account's configured auto-reload settings.

Billing summary request
curl https://api.transcribeapi.com/v1/billing/summary \
  -H "Authorization: Bearer YOUR_API_KEY"
Billing summary response
{
  "seconds_remaining": 439750,
  "remaining_balance": 18.32291,
  "auto_reload": {
    "amount": 10,
    "if_balance_below": 20
  }
}

Add funds with a saved card

POST /v1/add-funds charges the saved card on the account. The amount must be a whole dollar value from 5 to 100. You can also send optional if_balance_below to make the top-up conditional on the current account balance.

For auto reload flows, send if_balance_below even if your client already checks remaining_balance. That gives the backend the same threshold and prevents stale later requests from adding funds after another request has already recharged the account.

Add funds request
curl -X POST https://api.transcribeapi.com/v1/add-funds \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{ "amount": 10, "if_balance_below": 20 }'

Top-up response

If Stripe confirms the charge and the billing ledger has updated, the API returns the new account balance. If the optional threshold is already no longer met, the API returns a skipped response instead of charging. If ledger settlement is still catching up, the response can say funds will update soon.

Add funds response
{
  "transaction": "completed",
  "funds_added": 10,
  "account_balance": 28.32291
}
Conditional no-op response
{
  "transaction": "skipped",
  "reason": "balance_threshold_not_met",
  "account_balance": 29.99832
}

Auto reload

Auto reload on this API is account-level backend behavior. Once you save the configured auto-reload settings in the dashboard billing UI or by calling POST /v1/dashboard/billing/auto-reload/settings, the backend automatically checks the saved threshold after balance deductions and charges the saved card when the account falls below it. The user does not need to send /v1/add-funds on every request.

The settings endpoint works with both dashboard JWT auth and API keys. Read the configured values back at any time from GET /v1/billing/summary.

Update auto reload settings
curl -X POST https://api.transcribeapi.com/v1/dashboard/billing/auto-reload/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{ "amount": 10, "if_balance_below": 20 }'
Settings response
{
  "ok": true,
  "autoReload": {
    "amount": 10,
    "if_balance_below": 20
  },
  "updatedAt": "2026-06-22T07:19:01.505Z"
}
Disable account-level auto reload
curl -X POST https://api.transcribeapi.com/v1/dashboard/billing/auto-reload/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{ "amount": 0, "if_balance_below": 0 }'

POST /v1/add-funds is still available as a manual top-up endpoint. Use it when you want an explicit one-off recharge from your own backend logic. For example, a webhook consumer can still decide to top up based on remaining_balance. The backend uses a per-account pending recharge lock and Stripe idempotency, so if two add-funds attempts happen at the same time, only one proceeds while the recharge is in progress. The other request returns 409 funds_recharge_in_progress. If you send if_balance_below, stale later requests are skipped when the balance is already back above the threshold.

This protection is designed for concurrent recharge attempts caused by the same low-balance state. It is not a rate limit or a permanent duplicate-payment block: once a recharge finishes, a later /v1/add-funds request may succeed if your backend calls it again.

Manual add-funds fallback
if (result.remaining_balance < 20) {
  const response = await fetch("https://api.transcribeapi.com/v1/add-funds", {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ amount: 10, if_balance_below: 20 }),
  });

  if (response.status !== 409) {
    console.log(await response.json());
  }
}
Concurrent top-up response
{
  "message": "Another transaction to add funds is already in progress.",
  "code": "funds_recharge_in_progress",
  "transaction": "failed",
  "reason": "Another transaction to add funds in progress"
}

Pricing

$0.15 per hour of audio transcription.

Pricing is based on billable audio seconds, rounded up to the next second—for example, 1.2 seconds of audio is billed as 2 seconds. In batch transcription, each file has a minimum billable duration of 1 second per file. This means 1,000 files of 0.5 seconds each are billed as 1,000 seconds.

  • 10 minutes: 600 seconds costs $0.025.
  • 1 hour: 3,600 seconds costs $0.15.
  • 10 hours: 36,000 seconds costs $1.50.

Free Transcription

Every account receives 60 minutes of free transcription.

When you save a credit card, we automatically add 60 minutes of free transcription credit to your account. There is no charge to your card; it is only used to prevent abuse.

You do not need to add funds to use your free transcription credit. Simply save a credit card, create an API key, and start sending requests. The free credit is applied automatically. After the 60 free minutes are used, transcription requests are denied until funds are added manually.

Limits

Rate Limits

/v1/transcribe and related endpoints

  • Free: 10 RPM
  • Pay as You Go: 300 RPM

Applies to POST /v1/transcribe (multipart and JSON), GET /v1/transcribe/{job_id} (polling), POST /v1/transcribe/{job_id}/upload-completed, and POST /v1/transcribe/{job_id}/delete.

Billing endpoints

  • All plans: 50 RPM

Applies to POST /v1/add-funds and GET /v1/billing/summary.

File and URL limits

  • Direct multipart response: 30 MB maximum file size and 10 minutes maximum duration.
  • Per file: up to 10 GB and up to 10 hours duration.
  • Batch jobs: up to 10,000 files, up to 10 GB total batch size, and up to 50 hours total batch duration.
  • Upload URLs are valid for 1 hour from creation.
  • Result URLs are valid for 7 days from transcription completion.
  • Supported audio formats: mp3, mpeg, mpga, m4a, wav, and webm.
  • Streaming transcription is not currently supported.
  • Video files are not supported. Use audio-only formats for transcription.
  • Each account can create up to 5 API keys.
429 response
{
  "message": "This Pay as You Go account is limited to 300 transcription requests per minute.",
  "code": "rate_limit_exceeded",
  "plan_name": "Pay as You Go",
  "requests_per_minute": 300
}

* Rate limits use a rolling window.

Errors

Every API error includes message and code.

Some errors include extra fields such as the active plan limit, required balance, current job status, or required transcription seconds.

Error shape
{
  "message": "Attach an audio file in the `file` field.",
  "code": "missing_file"
}
Status Common codes Meaning
400 invalid_form_data, invalid_request_options, invalid_json, invalid_job_request, invalid_audio_duration The request body, form data, upload metadata, language, webhook URL, reference ID, or exclude option is invalid.
400 file_too_large, audio_too_long, too_many_files, batch_too_large, batch_duration_too_long The request exceeds the direct, single-file, file count, batch size, or total batch duration limits.
401 missing_api_key, invalid_api_key The bearer token is missing or invalid.
402 insufficient_credit, card_charge_failed The account needs more credit or the saved card charge failed.
403 email_not_verified The account email must be verified before API use.
404 job_not_found, not_found The route or job ID was not found.
409 invalid_job_status, job_not_deletable, funds_recharge_in_progress The requested action conflicts with the current job or billing state.
429 rate_limit_exceeded The per-minute request limit was exceeded.
500, 502 internal_error, transcription_failed A server-side or provider-side failure occurred.

Models

Open-source models we use

Transcribe API uses Whisper large v3 turbo and Whisper large v3 for transcription.

Privacy

Audio files & transcription.

Audio files uploaded to Transcribe API are stored temporarily in Cloudflare R2 for the duration of the transcription job. For async and batch jobs, audio files are deleted immediately after transcription completes—they are never retained beyond the job lifetime.

Completed transcription results (result.json) are stored for 7 days from the completion date. During this window, you can download results via the signed result_url returned in polling and webhook responses. After 7 days, transcription is deleted automatically.

If you need to delete results before the 7-day automatic deletion, call POST /v1/transcribe/{job_id}/delete. This removes the stored transcription result immidiately.

Latency

These are the maximum expected completion times.

Times reflect transcription processing only—upload speed varies by your connection and is not included. Sync jobs with a webhook do not add latency; transcription takes the same time either way.

Audio duration Maximum completion target
Under 10 seconds 1-4 seconds
Under 10 minutes Up to 25 seconds
Single file under 1 hour Up to 5 minutes
Single file 1-5 hours Up to 15 minutes
Single file 5-10 hours Up to 30 minutes

Batch latency

Batch latency is the duration latency for the full batch plus about 100-300 ms per file. For example, one 1-hour file is up to 5 minutes. A batch of 3,600 one-second files is roughly 5 min + (3600 * 0.1-0.3 sec), which is about 11-23 minutes.

Endpoint reference

Transcription, billing, webhook keys, and job result endpoints.

Use API key auth with Authorization: Bearer YOUR_API_KEY unless noted.

Method Path Description
GET /.well-known/transcribeapi-webhook-keys.json Webhook signing keys. No API key required.
POST /v1/transcribe Multipart direct transcription, JSON async job creation, and JSON batch job creation.
GET /v1/transcribe/{job_id} Poll job status. Adds result_url when the job is completed and the result exists.
POST /v1/transcribe/{job_id}/upload-completed Mark local uploads complete and start verification/processing.
POST /v1/transcribe/{job_id}/delete Delete stored transcription result.
GET /v1/billing/summary Return seconds_remaining, current remaining_balance, and configured auto-reload settings.
POST /v1/dashboard/billing/auto-reload/settings Update configured auto-reload settings using dashboard JWT auth or an API key.
POST /v1/add-funds Charge the saved card and add funds to the account.