Subly REST API Documentation
Subly REST API
The Subly REST API lets you submit video translation jobs and retrieve results programmatically. It is available to Business plan subscribers. Check the current price in the app before purchasing.
Quick Start
1. Get your API key — open the Subly mini app → Settings → copy your sk-sub_... key.
2. Submit a job:
curl -X POST https://app.subly.xyz/api/v1/translate \
-H "Authorization: Bearer sk-sub_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"target_language": "ru",
"source_language": "auto"
}'
Response:
{
"job_id": 4821,
"status": "queued",
"message": "Job submitted. Poll GET /api/v1/jobs/4821 for status.",
"poll_url": "/api/v1/jobs/4821"
}
3. Poll for completion:
curl https://app.subly.xyz/api/v1/jobs/4821 \
-H "Authorization: Bearer sk-sub_YOUR_KEY"
Completed response:
{
"job_id": 4821,
"status": "completed",
"source_language": "tr",
"target_language": "ru",
"video_url": "https://media.subly.xyz/jobs/4821/video.mp4",
"srt_url": "https://media.subly.xyz/jobs/4821/subtitle.srt",
"vtt_url": "https://media.subly.xyz/jobs/4821/subtitle.vtt",
"audio_url": null,
"created_at": "2026-02-26T10:00:00",
"completed_at": "2026-02-26T10:04:23",
"error": null
}
Authentication
All API endpoints require a Bearer token in the Authorization header:
Authorization: Bearer sk-sub_<your_api_key>
API keys are scoped to your account. An active Business plan subscription is required. Keys do not expire but can be regenerated from the Settings screen.
Base URL
https://app.subly.xyz
Endpoints
POST /api/v1/translate
Submit a video or audio URL for translation.
Request body (JSON):
| Field | Type | Required | Description |
|---|---|---|---|
video_url |
string | ✅ | URL of the video to translate. Supports YouTube, TikTok, Instagram, direct MP4/MP3 links. |
target_language |
string | ✅ | Target language code (e.g. ru, vi, ar, fa, en). See supported languages. |
source_language |
string | — | Source language code, or "auto" for automatic detection. Default: "auto". |
output_format |
string | — | "video" (default), "srt", or "both". |
webhook_url |
string | — | Optional HTTPS URL. Subly will POST the completed result here (same schema as GET /api/v1/jobs/{id}) — up to 3 retries with exponential backoff. |
Response (202 Accepted):
{
"job_id": 4821,
"status": "queued",
"message": "Job submitted. Poll GET /api/v1/jobs/4821 for status.",
"poll_url": "/api/v1/jobs/4821"
}
GET /api/v1/jobs/{job_id}
Get the current status and results of a job.
Response fields:
| Field | Type | Description |
|---|---|---|
job_id |
int | Job identifier |
status |
string | queued, processing, completed, or failed |
source_language |
string | Detected or specified source language |
target_language |
string | Target language |
video_url |
string / null | CDN URL of the translated video (when completed) |
srt_url |
string / null | CDN URL of the SRT subtitle file |
vtt_url |
string / null | CDN URL of the WebVTT subtitle file |
audio_url |
string / null | CDN URL of audio-only output (if applicable) |
created_at |
string | ISO 8601 timestamp |
completed_at |
string / null | ISO 8601 timestamp (null if not yet complete) |
error |
string / null | Error message if status == "failed" |
Job Status Flow
queued → processing → completed
↘ failed
Typical processing time: 2–8 minutes depending on video length. Poll every 15–30 seconds.
Rate Limits & Quotas
Business plan limits:
| Resource | Limit |
|---|---|
| Video minutes per day | 1,800 min (30 hours) |
| Max video duration | 360 min (6 hours) |
| Concurrent jobs | 5 |
Exceeding daily limits returns HTTP 429 with a Retry-After header.
Supported Languages
Subly supports 100+ languages. Common codes:
| Language | Code |
|---|---|
| Russian | ru |
| Vietnamese | vi |
| Arabic | ar |
| Farsi/Persian | fa |
| English | en |
| Spanish | es |
| French | fr |
| German | de |
| Japanese | ja |
| Korean | ko |
| Chinese (Simplified) | zh |
| Turkish | tr |
| Portuguese | pt |
| Ukrainian | uk |
Full list available at /api/miniapp/languages.
Code Examples
Python
import requests
import time
API_KEY = "sk-sub_your_key_here"
BASE_URL = "https://app.subly.xyz"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# Submit job
response = requests.post(f"{BASE_URL}/api/v1/translate", headers=HEADERS, json={
"video_url": "https://www.youtube.com/watch?v=example",
"target_language": "ru",
"source_language": "auto",
})
response.raise_for_status()
job_id = response.json()["job_id"]
print(f"Job {job_id} submitted")
# Poll until complete
while True:
result = requests.get(f"{BASE_URL}/api/v1/jobs/{job_id}", headers=HEADERS)
result.raise_for_status()
data = result.json()
print(f"Status: {data['status']}")
if data["status"] == "completed":
print(f"Video URL: {data['video_url']}")
print(f"SRT URL: {data['srt_url']}")
break
elif data["status"] == "failed":
print(f"Error: {data['error']}")
break
time.sleep(20)
Node.js
const API_KEY = 'sk-sub_your_key_here';
const BASE_URL = 'https://app.subly.xyz';
const headers = { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' };
async function translateVideo(videoUrl, targetLang) {
// Submit
const res = await fetch(`${BASE_URL}/api/v1/translate`, {
method: 'POST', headers,
body: JSON.stringify({ video_url: videoUrl, target_language: targetLang }),
});
const { job_id } = await res.json();
console.log(`Job ${job_id} submitted`);
// Poll
while (true) {
await new Promise(r => setTimeout(r, 20000));
const status = await fetch(`${BASE_URL}/api/v1/jobs/${job_id}`, { headers });
const data = await status.json();
console.log('Status:', data.status);
if (data.status === 'completed') return data;
if (data.status === 'failed') throw new Error(data.error);
}
}
translateVideo('https://www.youtube.com/watch?v=example', 'ru')
.then(r => console.log('Video:', r.video_url))
.catch(console.error);
curl
# Submit a job
JOB=$(curl -s -X POST https://app.subly.xyz/api/v1/translate \
-H "Authorization: Bearer sk-sub_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"video_url":"https://youtube.com/watch?v=example","target_language":"ru"}')
JOB_ID=$(echo $JOB | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo "Job ID: $JOB_ID"
# Poll status
curl https://app.subly.xyz/api/v1/jobs/$JOB_ID \
-H "Authorization: Bearer sk-sub_YOUR_KEY"
Error Codes
| HTTP Status | Meaning |
|---|---|
401 |
Invalid or missing API key |
403 |
Business plan required |
422 |
Invalid request (bad URL, missing fields) |
429 |
Daily quota exceeded |
500 |
Internal server error — please retry |
Getting Your API Key
- Open the Subly mini app in Telegram
- Tap ⚙️ Settings
- Your API key is shown under REST API Access (visible to Business plan subscribers)
To upgrade to Business plan: tap Upgrade in the Settings screen.
Support
Questions or integration help: @sublyadmin on Telegram or [email protected]