Subly REST API Documentation

Last updated: February 26, 2026

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

  1. Open the Subly mini app in Telegram
  2. Tap ⚙️ Settings
  3. 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]

↑