API Reference
Authentication
All API requests require an API key passed in the apikey header (lowercase):
curl -H "apikey: YOUR_API_KEY" \
https://dublab.app/api/v1/me
Note: The header name is
apikey, notAuthorization: Bearer. Keep this in mind when integrating.
Creating an API Key
- Log into your DubLab account
- Go to Account Settings
- Scroll to the API Keys section
- Click Create API Key
- Copy and save your key — it won't be shown again
Endpoints
GET /api/v1/me
Returns your user profile, credits, and subscription info.
Request:
curl -H "apikey: YOUR_API_KEY" \
https://dublab.app/api/v1/me
Response (200):
{
"id": "bc6276da-fb68-40a2-...",
"email": "you@example.com",
"name": "Your Name",
"username": "you@example.com",
"firstName": null,
"lastName": null,
"seconds": 32955,
"defaultDubLang": "de",
"subscriptionStatus": "active",
"subscriptionPlan": "hobby",
"createdAt": "2025-04-28T01:10:53.359Z"
}
The seconds field is your available credit balance (one credit = one second of
output). subscriptionStatus and subscriptionPlan are null for users without
an active subscription. firstName/lastName may be null.
GET /api/v1/dubs
Returns all your dubbed files with status and metadata.
Request:
curl -H "apikey: YOUR_API_KEY" \
https://dublab.app/api/v1/dubs
Response (200):
[
{
"id": "ec2a9095-6f35-...",
"name": "my-video.mp4",
"type": "video/mp4",
"sourceLang": "auto",
"destLang": "tr",
"externalStatusId": 5,
"progressPercentage": 100,
"externalErrorMessage": null,
"duration": 143,
"measuredDuration": 142,
"isStudioQuality": false,
"source": "web",
"createdAt": "2026-04-12T17:20:40.611Z"
}
]
duration is the value you supplied at init-dub; measuredDuration is the
server-measured length (seconds) and is what your credits are billed on. It is
null until the dub completes.
Status IDs (externalStatusId):
| externalStatusId | Meaning |
|---|---|
| 1 | Uploading |
| 2 | In Queue |
| 3 | Processing |
| 4 | Failed |
| 5 | Completed |
The public status surface is
1–5. The pipeline also tracks a separate internal status that is not returned by the API.
POST /api/v1/init-dub
Creates a file record and returns a presigned S3 upload URL. You upload your video to this URL before starting the dub.
Request:
curl -X POST https://dublab.app/api/v1/init-dub \
-H "apikey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileType": "video/mp4",
"name": "my-video.mp4",
"source_lang": "auto",
"dest_lang": "tr",
"duration": 67,
"isStudioQuality": false
}'
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| fileType | string | Yes | MIME type: video/mp4, video/quicktime, audio/mpeg, etc. |
| name | string | Yes | Original filename |
| source_lang | string | Yes | Source language code or "auto" for auto-detection |
| dest_lang | string | Yes | Target language code (tr, de, es, fr, ja, etc.) |
| duration | number | No | Video duration in seconds |
| isStudioQuality | boolean | No | true for ElevenLabs studio quality (2x credits) |
Response (200):
{
"file": {
"id": "ce14fea7-9c5b-...",
"name": "my-video.mp4",
"source": "api",
"externalStatusId": 1,
"internalStatusId": 1
},
"uploadUrl": "https://s3.eu-central-1.amazonaws.com/dublab-app-1/...?X-Amz-Algorithm=..."
}
Upload your file to the presigned URL:
curl -X PUT \
-H "Content-Type: video/mp4" \
--data-binary @my-video.mp4 \
"PRESIGNED_UPLOAD_URL"
POST /api/v1/start-dub
Starts the AI dubbing pipeline for an uploaded file. The file must already be uploaded to S3.
Request:
curl -X POST https://dublab.app/api/v1/start-dub \
-H "apikey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fileId": "ce14fea7-9c5b-..."}'
Response (200):
{
"success": true,
"fileId": "ce14fea7-9c5b-..."
}
After this, the file enters the processing queue. Poll GET /api/v1/dubs to check the progressPercentage and externalStatusId.
Possible errors: 402 (no credits), 404 (file not found), 403 (not your file), 409 (already in progress or completed), 412 (file not uploaded to S3 yet), 502 (dispatch failed).
Billing: credits are charged once, when the dub completes, against the server-measured duration (
measuredDuration) — not thedurationyou sent.start-dubonly checks that your balance is above zero.
Full Workflow Example
Here's a complete example dubbing a video from English to Turkish using curl:
# 1. Create file record and get upload URL
RESPONSE=$(curl -s -X POST https://dublab.app/api/v1/init-dub \
-H "apikey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileType": "video/mp4",
"name": "presentation.mp4",
"source_lang": "en",
"dest_lang": "tr",
"duration": 120
}')
FILE_ID=$(echo $RESPONSE | jq -r '.file.id')
UPLOAD_URL=$(echo $RESPONSE | jq -r '.uploadUrl')
# 2. Upload the video to S3
curl -X PUT \
-H "Content-Type: video/mp4" \
--data-binary @presentation.mp4 \
"$UPLOAD_URL"
# 3. Start dubbing
curl -X POST https://dublab.app/api/v1/start-dub \
-H "apikey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"fileId\": \"$FILE_ID\"}"
# 4. Check status (poll until externalStatusId = 5)
curl -H "apikey: YOUR_API_KEY" \
https://dublab.app/api/v1/dubs
Error Responses
All errors return JSON with an error field:
{ "error": "Invalid API key" }
| Status | Meaning |
|---|---|
| 400 | Bad request — missing or invalid parameters |
| 401 | Unauthorized — missing or invalid API key |
| 402 | Payment required — insufficient credit balance |
| 403 | Forbidden — file belongs to another user |
| 404 | Not found — file or user doesn't exist |
| 409 | Conflict — dub already in progress or completed |
| 412 | Precondition failed — source file not uploaded yet |
| 502 | Bad gateway — processing backend unavailable |
| 500 | Internal server error |
Supported Languages
dest_lang accepts any of the 90+ supported codes below (powered by the OmniVoice
engine). source_lang accepts the same codes or "auto" (auto-detect) —
auto is a source-only option, not a dub target.
The authoritative, always-current list is served by GET /api/langs. Current set:
English (en), Spanish (es), French (fr), German (de), Chinese (zh), Japanese (ja), Russian (ru), Portuguese (pt), Arabic (ar), Hindi (hi), Bengali (bn), Punjabi (pa), Vietnamese (vi), Korean (ko), Italian (it), Persian (fa), Turkish (tr), Dutch (nl), Hebrew (he), Indonesian (id), Polish (pl), Ukrainian (uk), Romanian (ro), Greek (el), Hungarian (hu), Thai (th), Swedish (sv), Czech (cs), Danish (da), Finnish (fi), Norwegian (no), Bulgarian (bg), Slovak (sk), Croatian (hr), Serbian (sr), Malay (ms), Tamil (ta), Urdu (ur), Telugu (te), Marathi (mr), Gujarati (gu), Malayalam (ml), Afrikaans (af), Basque (eu), Catalan (ca), Esperanto (eo), Galician (gl), Georgian (ka), Haitian Creole (ht), Icelandic (is), Irish (ga), Kannada (kn), Latin (la), Latvian (lv), Lithuanian (lt), Luxembourgish (lb), Macedonian (mk), Maltese (mt), Mongolian (mn), Nepali (ne), Northern Sami (se), Sinhala (si), Estonian (et), Tagalog (tl), Burmese (my), Kazakh (kk), Bosnian (bs), Swahili (sw), Amharic (am), Azerbaijani (az), Belarusian (be), Uzbek (uz), Khmer (km), Lao (lo), Sindhi (sd), Welsh (cy), Frisian (fy), Yoruba (yo), Hausa (ha), Igbo (ig), Zulu (zu), Xhosa (xh), Shona (sn), Faroese (fo), Chichewa (ny), Kinyarwanda (rw), Southern Sotho (st), Tswana (tn), Tsonga (ts), Swati (ss), Venda (ve), Twi (tw)