Transcription

Asynchronous audio/video transcription with optional automatic speaker diarization.

Billing: 4 API credits per started minute, based on the actual audio duration. Credits are reserved after the duration is confirmed, before transcription starts, and refunded automatically if transcription fails. No credits are charged while the file is being processed and its duration is still unknown.

Before creating a job, the server checks that at least 4 API credits are available. A lower balance returns HTTP 402 with code: "insufficient_credits", without creating a job or charging credits. Passing this minimum check does not guarantee that the balance will cover the full transcription cost.

Endpoints: POST/transcriptions GET/transcriptions/{id}

Submit a job

Pass a publicly accessible audio or video file URL from SnapAny's extraction API or one you provide:

curl -X POST https://api.snapany.com/openapi/v1/transcriptions \
  -H "Authorization: Bearer sk_snapany_xxx" \
  -H "Content-Type: application/json" \
  -d '{"fileUrl": "https://example.com/audio.mp3", "speakerLabels": true}'

Or upload a local file (max 512 MiB):

curl -X POST https://api.snapany.com/openapi/v1/transcriptions \
  -H "Authorization: Bearer sk_snapany_xxx" \
  -F "file=@meeting.mp3" -F "speakerLabels=true"

A successful submission immediately returns { "id": "...", "status": "processing" }. Use this id to poll for the result while the file is processed and transcribed.

language — an English language name or ISO-639-1 code (e.g. english, en). Omit the field to auto-detect; there is no "auto" value. Region subtags like zh-CN are rejected with unsupported_language — use the base language instead.

File URLs and download headers

Both audio URLs and video file URLs are supported, including public HTTP/HTTPS domains and public IP addresses. Loopback, private and other special addresses are rejected. If you have a separate audio URL, you can submit it directly. The file limit is 512 MiB, with no duration limit.

JSON URL requests also accept:

ParameterRequiredDescription
fileHeadersNoHeaders needed to download the file, such as Referer or User-Agent
{
  "fileUrl": "https://example.com/video.mp4",
  "fileHeaders": { "Referer": "https://example.com/" },
  "speakerLabels": true
}

Each submission creates a separate job, even for the same file URL, and each job is billed separately. To check an existing job, query its id rather than submitting it again.

Speaker diarization

Set speakerLabels: true to detect speakers and their count automatically. No speaker count is required.

Parameter change: maxSpeakers is deprecated. Existing JSON, multipart and MCP requests may still include it, but its value is ignored and no longer limits the speaker count. Validation of other parameters is unchanged.

Poll for the result

curl https://api.snapany.com/openapi/v1/transcriptions/{id} \
  -H "Authorization: Bearer sk_snapany_xxx"

Poll every 3–5 seconds (polling is free). While the file is being processed, status is processing and duration is null:

{
  "id": "...",
  "status": "processing",
  "duration": null,
  "errorCode": null,
  "error": null
}

Once the actual audio duration is confirmed, duration is a number in seconds. A file without audio or a failed download makes the job failed without charging credits. If the job passed the initial minimum balance check but the balance is insufficient for the full cost once the duration is confirmed, it also becomes failed with errorCode: "insufficient_credits", without charging credits. Read the machine-readable errorCode and human-readable error from the same query:

{
  "id": "...",
  "status": "failed",
  "duration": null,
  "errorCode": "audio_track_missing",
  "error": "The video has no audio track"
}

Common error codes include audio_track_missing, download_failed, download_timeout and insufficient_credits. If transcription fails after credits have been reserved, they are refunded automatically.

A polling loop:

import time
import requests

headers = {"Authorization": f"Bearer {API_KEY}"}
url = f"https://api.snapany.com/openapi/v1/transcriptions/{job_id}"

while True:
    job = requests.get(url, headers=headers).json()
    if job["status"] == "completed":
        print(job["result"]["text"])
        break
    if job["status"] == "failed":
        print("failed:", job["errorCode"], job["error"])
        break
    time.sleep(5)

When status is completed, result contains transcription output compatible with verbose_json: full text, detected language, and segments with start/end timestamps — each segment carries a speaker label when diarization is enabled.