Captioning
Short-form ASR tuned on compressed audio, fast talkers, and music beds. 98%+ word accuracy with production-ready transcripts.
Doomersion Video API
Word-level timing. Speaker ID. Dialect. 90+ languages.
Submit a URL, poll for completion, and pull clean structured transcripts into your own bucket.
Capabilities
Captioning and localization ship on every request. Timestamping and speaker tags come with the transcript. Dialect detection and video screenshots are production-ready in our pipeline and can be enabled on your API key on request.
Short-form ASR tuned on compressed audio, fast talkers, and music beds. 98%+ word accuracy with production-ready transcripts.
Detect language on every clip as an ISO 639-3 code. Route captions, translation, and catalog workflows without a separate detect step.
Word-level start_ms / end_ms on every token. Sync captions, scrubbers, and highlight reels to the frame.
Diarization with real names and roles when metadata allows. Not just speaker_0: Host, Guest, Lecturer, Narrator.
Timed frame grabs aligned to speech. Use them for moderation, thumbnails, scene search, or multimodal context.
Classify spoken variety beyond language code: Arabic dialects, Mandarin/Cantonese, Brazilian vs European Portuguese, and more.
Live demo
Three @doomlingo TikToks from our pipeline. Toggle the tabs or watch them auto-rotate: word-level timing, bilingual localization, and a live talker indicator for diarization.
Benchmark
Tuned on millions of social clips: compressed audio, fast talkers, music beds, and rapid cuts. 98%+ caption accuracy with word-level timing and speaker ID out of the box.
Competitor figures are approximate published word-accuracy ranges on clean / general audio. Doomersion's 98%+ is measured on short-form social video in production.
Coverage
Detected language lands in every transcript as an ISO 639-3 code. Use it to route captions, translations, and downstream localization without a separate detect step.
Showing 74 of 90+ languages in production. Same stack powers Creator Studio and the Video API.
Bucket keys are used only for that job's upload and are never stored after the job finishes.
Output lands in your S3-compatible bucket. Doomersion does not store transcripts or video files on our side.
AWS S3, Cloudflare R2, MinIO. Up to 10,000 URLs per job with parallel workers.
API reference
Complete flow. You need an API key plus your own S3-compatible bucket credentials. Results are written to your bucket.
01
POST /jobs with YouTube URLs and your bucket object. Replace bucket credentials with yours.
02
GET /jobs/{id} every 10โ30 seconds until status is "completed".
03
GET /jobs/{id}/results for S3 paths, then download .mp4 and .json from your bucket.
# 1. Submit a video (replace bucket credentials with yours)
curl -X POST https://api.doomlingo.ai/jobs \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "video",
"urls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],
"bucket": {
"name": "your-bucket",
"endpoint": "https://ACCOUNT_ID.r2.cloudflarestorage.com",
"access_key": "YOUR_ACCESS_KEY",
"secret_key": "YOUR_SECRET_KEY",
"region": "auto"
}
}'
# โ {"job_id": "550e8400-...", "status": "queued", "video_count": 1}
# 2. Poll until completed (repeat every 15s)
curl https://api.doomlingo.ai/jobs/550e8400-... \
-H "X-API-Key: YOUR_KEY"
# โ {"status": "completed", "total": 1, "completed": 1, ...}
# 3. Get results
curl https://api.doomlingo.ai/jobs/550e8400-.../results \
-H "X-API-Key: YOUR_KEY"
# โ {"results": [{"status": "done", "result_path": "s3://bucket/...", ...}]}
Average processing time: 30โ90 seconds per video. If a job hasn't completed after 5 minutes, check the health endpoint or contact support.
Check if the API is running and how many workers are active. No authentication required.
curl https://api.doomlingo.ai/health
{"status": "ok", "workers": 4}
Include your API key in every request header:
X-API-Key: your_api_key_here
Contact mostafa@doomlingo.ai to get an API key.
Submit YouTube URLs for processing. Each URL will be downloaded, transcribed with speaker diarization and word-level timing, and uploaded to your bucket.
| Field | Type | Description | |
|---|---|---|---|
type |
string | required | "video" for individual videos, "channel" for channel listing |
urls |
string[] | required | YouTube URLs (max 10,000 per job) |
bucket |
object | required | Your S3-compatible output bucket. Object with name, endpoint, access_key, secret_key, and region. The token must allow PutObject (upload). Works with AWS S3, Cloudflare R2, MinIO, etc. |
| Field | Required | Description |
|---|---|---|
name | yes | Bucket name |
endpoint | yes | S3 API endpoint URL (e.g. https://<account>.r2.cloudflarestorage.com or https://s3.us-east-1.amazonaws.com) |
access_key | yes | Access key ID |
secret_key | yes | Secret access key |
region | yes | Region string (auto for Cloudflare R2; e.g. us-east-1 for AWS) |
Each job writes {job_id}/{video_id}.mp4 and {job_id}/{video_id}.json into this bucket.
# Submit 3 videos for processing
curl -X POST https://api.doomlingo.ai/jobs \
-H "X-API-Key: your_key" \
-H "Content-Type: application/json" \
-d '{
"type": "video",
"urls": [
"https://www.youtube.com/shorts/abc123def45",
"https://www.youtube.com/watch?v=xyz789ghi01",
"https://youtu.be/mno456pqr78"
],
"bucket": {
"name": "your-bucket",
"endpoint": "https://ACCOUNT_ID.r2.cloudflarestorage.com",
"access_key": "YOUR_ACCESS_KEY",
"secret_key": "YOUR_SECRET_KEY",
"region": "auto"
}
}'
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"video_count": 3
}
Poll the status of a submitted job. A job moves through: queued โ processing โ completed.
curl https://api.doomlingo.ai/jobs/550e8400-... \
-H "X-API-Key: your_key"
{
"job_id": "550e8400-...",
"type": "video",
"status": "processing",
"total": 3,
"completed": 1,
"failed": 0,
"created_at": 1780000000.0,
"completed_at": null
}
Poll every 10โ30 seconds until status is "completed".
Get per-video results. Works at any stage. You can check individual video status even while the job is still processing. Each completed video includes the S3 path where the video and transcript were uploaded. The transcript includes speaker identification (real names inferred from video metadata).
{
"job_id": "550e8400-...",
"status": "completed",
"results": [
{
"video_url": "https://www.youtube.com/shorts/abc123def45",
"status": "done",
"result_path": "s3://bucket/550e8400-.../abc123def45",
"error": null
},
{
"video_url": "https://www.youtube.com/watch?v=xyz789ghi01",
"status": "done",
"result_path": "s3://bucket/550e8400-.../xyz789ghi01",
"error": null
}
]
}
For each video, two files are uploaded to your bucket:
| File | Description |
|---|---|
{job_id}/{video_id}.mp4 | The downloaded video file |
{job_id}/{video_id}.json | Transcript with timing & speaker data |
{
"video_url": "https://www.youtube.com/shorts/abc123def45",
"video_id": "abc123def45",
"duration_s": 28.4,
"language": "eng",
"transcript": "How do you say good morning in Japanese?",
"metadata": {
"channel_name": "Doomlingo",
"channel_id": "UCxxxxxxxx",
"channel_url": "https://www.youtube.com/@doomlingo",
"title": "How to say good morning in Japanese",
"description": "...",
"upload_date": "2026-05-15",
"view_count": 125000,
"like_count": 8500
},
"speakers": [
{"id": "speaker_0", "name": "Maya", "role": "Host"}
],
"segments": [
{
"text": "How do you say good morning in Japanese?",
"speaker": "Maya",
"start_ms": 420,
"end_ms": 2840,
"words": [
{"word": "How", "start_ms": 420, "end_ms": 610},
{"word": "do", "start_ms": 630, "end_ms": 720},
{"word": "you", "start_ms": 740, "end_ms": 860},
{"word": "say", "start_ms": 880, "end_ms": 1040}
]
}
]
}
| Field | Type | Description |
|---|---|---|
video_id | string | Platform video ID (YouTube 11-character ID, or the source ID for other supported URLs) |
duration_s | number | Video duration in seconds |
language | string | Detected language (ISO 639-3 code: eng, ara, jpn, etc.) |
transcript | string | Full transcript as plain text |
metadata | object | Source video metadata (channel name, title, description, view/like counts) |
speakers | array | Identified speakers with real names and roles (e.g. host, guest, lecturer) |
speakers[].name | string | Real name of the speaker, inferred from video metadata and transcript |
speakers[].role | string | Speaker's role (e.g. Lecturer, Host, Guest, Narrator) |
segments | array | Speech segments, split by speaker turn |
segments[].speaker | string | Real name of the speaker (resolved from speakers list) |
segments[].start_ms | number | Segment start time in milliseconds |
segments[].end_ms | number | Segment end time in milliseconds |
segments[].words | array | Word-level timestamps within the segment |
segments[].words[].word | string | Spoken token |
segments[].words[].start_ms | number | Word start time in milliseconds |
segments[].words[].end_ms | number | Word end time in milliseconds |
Before processing a video with the full pipeline, you can preview YouTube's auto-generated transcript for free. Run this from your machine. No API credits, no API key needed.
pip install youtube-transcript-api
# Python - get transcript for any YouTube video
from youtube_transcript_api import YouTubeTranscriptApi
ytt = YouTubeTranscriptApi()
for t in ytt.list("VIDEO_ID"):
entries = t.fetch()
print(f"Language: {t.language_code}, Segments: {len(entries)}")
for e in entries:
print(f" [{e.start:.1f}s] {e.text}")
break
Language: en, Segments: 12
[0.0s] How do you say good morning
[2.1s] in Japanese?
[3.4s] Ohayou gozaimasu.
...
1. Fetch free transcript locally โ preview content, filter videos
2. Pick the videos you want โ check language, speaker, topic
3. POST /jobs with URLs + your bucket โ full processing with speaker ID + word timing
The free transcript gives you YouTube's auto-captions. POST /jobs gives you production-grade transcription with word-level millisecond timing, real speaker names, and higher accuracy.
1. POST /jobs with URLs + bucket credentials โ get job_id
2. Poll GET /jobs/{id} every 10-30 seconds โ wait for "completed"
3. GET /jobs/{id}/results โ get S3 paths
4. Download .mp4 and .json from your bucket โ done
Average processing time: 30โ90 seconds per video (download + transcription).
Production POST /jobs accepts YouTube URLs today:
https://www.youtube.com/shorts/VIDEO_IDhttps://www.youtube.com/watch?v=VIDEO_IDhttps://youtu.be/VIDEO_IDhttps://www.youtube.com/embed/VIDEO_IDhttps://www.youtube.com/@channelname (channel jobs only)The live demo above uses real @doomlingo TikTok clips to showcase caption timing, localization, and speakers. Contact mostafa@doomlingo.ai if you need TikTok or other sources on the API.
| Limit | Value |
|---|---|
| Max URLs per job | 10,000 |
| Parallel processing | 4 videos at a time (configurable) |
| Concurrent jobs | Unlimited |
| Status | Meaning |
|---|---|
200 | Success |
400 | Bad request - invalid type, empty URLs, missing/incomplete bucket object, or bucket name only without credentials |
401 | Invalid or missing API key |
404 | Job not found |
500 | Server error |
| Symptom | Cause | Fix |
|---|---|---|
Job stays "queued" for >2 min |
Workers may be busy or restarting | Check GET /health. If workers: 0, contact support. |
400 "No bucket configured" |
bucket missing from the request body |
Include a full bucket object (name, endpoint, access_key, secret_key, region) in every POST /jobs call. |
400 "bucket requires name, endpoint..." |
bucket object is incomplete |
All five bucket fields are required. A bucket name string alone is not enough unless support has pre-configured server-side credentials for your account. |
Video status "failed" |
Video unavailable, private, age-restricted, region-locked, or upload to your bucket failed | Check the error field in results. Try a different video. Confirm your bucket token allows PutObject and the endpoint/region match your provider. |
422 response |
Missing required header or malformed request body | Ensure X-API-Key header is present and body is valid JSON with type, urls, and bucket. |
| Job not completed after 5 min | Long video or download retry in progress | Keep polling. If still not done after 10 min, contact support. |
API & Enterprise
API keys are issued by email. Bring your own S3-compatible bucket: results land in your storage and we don't keep copies on our side.
Request API accessResults delivered to your S3/R2 bucket. We never store your content.