MeowLoad Docs
On this page

Audio and video transcription API

Create an asynchronous transcription from an uploaded audio file or an audio/video file URL. Automatic language detection is the default; choose a language code or enable speakerLabels when needed. The model determines the speaker count.

This REST-only feature has no MCP tool or developer callback. It uses your existing API key and API credits, separate from website and desktop AI credits. Prices are listed in the Developer Console.

Endpoints and workflow

EndpointPurpose
POST /openapi/v1/uploadsRequest a reusable file upload ID and optional single PUT URL
POST /openapi/v1/transcriptionsSubmit an uploaded audio ID or media URL and receive a task ID
GET /openapi/v1/transcriptions/{id}Query task status and results for free

The API host is https://api.meowload.net. Authenticate with Authorization: Bearer <your API key>. Only API requests receive your key; storage PUT uses the returned upload headers instead.

  1. For local audio, follow the file upload guide: request an upload with mediaType: "audio", send one complete PUT, then submit its upload ID. Skip PUT only when the response explicitly contains upload: null. A direct media URL needs no upload request.
  2. POST /transcriptions with one of the JSON inputs below. HTTP 200 with an ID means the task is durably accepted. Confirmation, media validation and preparation continue in the background before charging and execution.
  3. Save the ID and GET every 3 seconds. Stop at completed or failed. A failed task still returns HTTP 200; inspect error. Stopping polling does not cancel the task.

Each task POST creates an independent task and is billed separately, including repeated uses of the same upload ID or URL. No public requestId or Idempotency-Key is supported. Do not automatically retry POST after a lost response: the task may already exist, so resubmitting may duplicate tasks and charges. Save a received task ID and retry only its free GET.

Inputs

Both inputs use Content-Type: application/json, limited to 64 KiB. The two source modes are mutually exclusive. Multipart file bodies are not accepted by this endpoint.

FieldRules
uploadIdRequired for uploaded audio; a 24-character ID from /uploads, owned by this user. Cannot be combined with fileUrl or fileHeaders
fileUrlRequired for URL input; HTTP(S) audio/video file URL, at most 4096 characters
fileHeadersOptional for URL input only; at most 32 headers, 8192 UTF-8 bytes per value and 16384 bytes total for names and values
languageOptional, defaults to auto; supported codes such as en or zh, case-insensitive
speakerLabelsOptional boolean, defaults to false; speaker counts cannot be supplied

Original files and prepared audio are each limited to 1 GiB (1,073,741,824 bytes) in both source modes. File size does not guarantee that audio of any duration can be processed successfully.

Uploaded input must be real audio. A pure-audio M4A/MP4 container or audio with attached cover art is accepted as audio; a real video track is not. For a local video, extract its audio first or provide an audio/video file URL. Generic video upload IDs cannot be used for transcription.

URL input accepts audio or video with an audio track. Web pages, live streams and playlists are not supported; use post extraction to obtain a media URL first. Prefer a separate audio URL when available, and keep it valid until the background download finishes.

Source headers apply only to the media download. Restricted headers are rejected and credentials are stripped on cross-origin redirects. Do not include your MeowLoad API key or internal service credentials. Language names, region codes such as en-US, unsupported language codes and unknown fields return 422; the full code list is in the API reference.

Duration, prices, models, speaker counts and internal asset IDs are not client inputs. Billing uses verified audio duration; there is no model-selection option.

Submit uploaded audio

Complete the single PUT described in the file upload guide, then:

curl https://api.meowload.net/openapi/v1/transcriptions \
  -H 'Authorization: Bearer <your API key>' \
  -H 'Content-Type: application/json' \
  -d '{"uploadId":"0123456789abcdefghijklmn","language":"auto","speakerLabels":false}'

No public complete or upload-status query is needed. The task confirms and validates the file internally. The same valid upload ID may be used by multiple independent tasks, subject to current ownership and source availability; there is no extra fixed 24-hour business cutoff or permanent storage guarantee.

Submit a media URL

curl https://api.meowload.net/openapi/v1/transcriptions \
  -H 'Authorization: Bearer <your API key>' \
  -H 'Content-Type: application/json' \
  -d '{"fileUrl":"https://media.example.com/meeting.mp4","language":"auto","speakerLabels":false}'

If the source requires headers, add "fileHeaders":{"Referer":"https://example.com/"} to the JSON.

Accepted response

{"id":"0123456789abcdefghijklmn","status":"processing"}

The ID is an opaque 24-character string. Preserve it exactly for subsequent queries.

Query and result

curl https://api.meowload.net/openapi/v1/transcriptions/0123456789abcdefghijklmn \
  -H 'Authorization: Bearer <your API key>'

Completed example with speaker labeling enabled:

{
  "id": "0123456789abcdefghijklmn",
  "status": "completed",
  "duration": 15.2,
  "language": "en",
  "apiCreditsCost": 3,
  "billingStatus": "settled",
  "result": {
    "text": "Hello everyone. Let's start our discussion.",
    "segments": [
      {"id": 0, "start": 0, "end": 3.2, "speaker": "speaker_0", "text": "Hello everyone. Let's start our discussion."}
    ]
  },
  "error": null
}
FieldMeaning
statusprocessing, completed or failed
durationVerified audio duration in seconds; null before preparation completes
languageDetected language at completion; null beforehand
apiCreditsCostInteger quote for this task; null until known. Preserved after a refund
billingStatusnot_charged: no debit; reserved: debited; settled: successful; refunded: original debit returned
resultNull before completion; otherwise original full text and segments. No source audio URL is returned
result.segmentsTimes are seconds; start/end may be null when unavailable. Speaker labels are not guaranteed when disabled
errorNull unless failed; then { "message": "…", "code": "snake_case" }

Valid audio with no recognized speech may succeed with empty text and null or empty segments; it is still billed by audio duration. You can generate SRT/VTT from the segments; there is no separate subtitle-download endpoint.

Any valid key owned by the same user can query their task, even after key rotation or with zero API credits. Other users' tasks and nonexistent IDs return 404. Web and desktop tasks are excluded. This release introduces no fixed expiry for task text and does not guarantee permanent retention; save the results you need.

Billing and errors

Verified audio duration is rounded up to whole minutes, and API credits are reserved before execution. Preparation failures cost nothing. If the full balance is insufficient after preparation, the task fails with insufficient_api_credits; top up and submit again. It does not automatically resume after a top-up. An explicitly failed execution refunds the original reservation. Network timeouts or unknown acceptance keep the task processing and do not trigger a refund by themselves.

Asynchronous failure, HTTP 200:

{
  "id": "0123456789abcdefghijklmn",
  "status": "failed",
  "duration": null,
  "language": null,
  "apiCreditsCost": null,
  "billingStatus": "not_charged",
  "result": null,
  "error": {"message":"The video has no audio track","code":"audio_track_missing"}
}

audio_track_missing means the video has no audio track; file_too_large means the size limit was exceeded. Download failures, preparation timeouts and transcription failures have their own reason codes. Branch on error.code, not the message text.

HTTP request failures use a non-200 response with {message, code?, detail?}: 401 for an invalid key, 402 for insufficient API credits, 422 for invalid parameters, 429 for per-key rate limits, and 503 when the service is unavailable before acceptance. See the API reference. Extraction's retryable field does not apply to transcription tasks.

JavaScript: submit once and poll

Node.js 18+ has built-in fetch. This example sends POST once, prints the ID, then queries for free. If a network request fails after receiving the ID, preserve it and resume GET separately.

const base = "https://api.meowload.net/openapi/v1"
const headers = { Authorization: "Bearer <your API key>" }
const response = await fetch(`${base}/transcriptions`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ fileUrl: "https://media.example.com/meeting.mp3" }),
})
if (!response.ok) throw new Error(`Create failed: ${response.status} ${await response.text()}`)
const { id } = await response.json()
console.log("Save this task ID:", id)
for (;;) {
  await new Promise(resolve => setTimeout(resolve, 3000))
  const query = await fetch(`${base}/transcriptions/${id}`, { headers })
  if (!query.ok) throw new Error(`Query failed: ${query.status} ${await query.text()}`)
  const task = await query.json()
  if (task.status === "processing") continue
  if (task.status === "failed") throw new Error(`${task.error.code}: ${task.error.message}`)
  console.log(task.result.text)
  break
}