Skip to content

Quickstart

Get started with the SubX API in minutes! This guide will walk you through your first API requests.

Prerequisites

Before you begin, make sure you have:

  • ✅ Created a SubX account and generated an API key (see Authentication Guide)
  • ✅ Your favorite HTTP client or programming language ready

Your First Request

Let's start by checking the API health status - this is the only endpoint that doesn't require authentication:

=== "cURL"

curl https://subx-api.duckdns.org/api/health
import requests

response = requests.get("https://subx-api.duckdns.org/api/health")
print(response.json())
const response = await fetch('https://subx-api.duckdns.org/api/health');
const data = await response.json();
console.log(data);

Expected Response:

{
  "status": "ok",
  "version": "1.0.0",
  "commit": "aaceda5"
}

Search for Subtitles

Now let's search for subtitles! Replace {YOUR_API_KEY_HERE} with your actual API key.

Search by Title

=== "cURL"

curl -X GET "https://subx-api.duckdns.org/api/subtitles/search?title=Dexter&limit=10" \
  -H "Authorization: Bearer {YOUR_API_KEY_HERE}"
import requests

headers = {"Authorization": "Bearer {YOUR_API_KEY_HERE}"}
params = {
    "title": "Dexter",
    "limit": 10
}

response = requests.get(
    "https://subx-api.duckdns.org/api/subtitles/search",
    headers=headers,
    params=params
)

data = response.json()
print(f"Found {data['total']} subtitles")
for subtitle in data['items']:
    print(f"- {subtitle['title']} ({subtitle['video_type']})")
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
)

func main() {
    apiKey := "{YOUR_API_KEY_HERE}"
    baseURL := "https://subx-api.duckdns.org/api/subtitles/search"

    // Build query parameters
    params := url.Values{}
    params.Add("title", "Dexter")
    params.Add("limit", "10")

    // Create request
    req, _ := http.NewRequest("GET", baseURL+"?"+params.Encode(), nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)

    // Send request
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // Parse response
    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    fmt.Printf("Found %v subtitles\n", result["total"])
}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Text.Json;

class Program
{
    static async Task Main()
    {
        var apiKey = "{YOUR_API_KEY_HERE}";
        var client = new HttpClient();

        client.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", apiKey);

        var url = "https://subx-api.duckdns.org/api/subtitles/search?title=Dexter&limit=10";
        var response = await client.GetAsync(url);
        var json = await response.Content.ReadAsStringAsync();

        var data = JsonSerializer.Deserialize<JsonElement>(json);
        Console.WriteLine($"Found {data.GetProperty("total")} subtitles");
    }
}

Expected Response:

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "video_type": "episode",
      "title": "Dexter",
      "season": 1,
      "episode": 1,
      "imdb_id": "tt0773262",
      "description": "Dexter S01E01 - Dexter",
      "uploader_name": "user123",
      "posted_at": "2024-01-15T10:30:00Z",
      "downloads": 1250
    }
  ],
  "total": 1
}

Search by IMDb ID

If you know the IMDb ID, you can search directly:

=== "cURL"

curl -X GET "https://subx-api.duckdns.org/api/subtitles/search?imdb_id=tt0773262&limit=20" \
  -H "Authorization: Bearer {YOUR_API_KEY_HERE}"
import requests

headers = {"Authorization": "Bearer {YOUR_API_KEY_HERE}"}
params = {
    "imdb_id": "tt0773262",  # Dexter series
    "limit": 20
}

response = requests.get(
    "https://subx-api.duckdns.org/api/subtitles/search",
    headers=headers,
    params=params
)

data = response.json()
print(f"Found {data['total']} subtitles for IMDb ID tt0773262")

Download a Subtitle

Once you've found a subtitle, download it using its ID:

=== "cURL"

# Download and save to file
curl -X GET "https://subx-api.duckdns.org/api/subtitles/550e8400-e29b-41d4-a716-446655440000/download" \
  -H "Authorization: Bearer {YOUR_API_KEY_HERE}" \
  -o subtitle.srt
import requests

headers = {"Authorization": "Bearer {YOUR_API_KEY_HERE}"}
subtitle_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.get(
    f"https://subx-api.duckdns.org/api/subtitles/{subtitle_id}/download",
    headers=headers
)

# Save to file
with open("subtitle.srt", "wb") as f:
    f.write(response.content)

print("Subtitle downloaded successfully!")
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    apiKey := "{YOUR_API_KEY_HERE}"
    subtitleID := "550e8400-e29b-41d4-a716-446655440000"
    url := fmt.Sprintf("https://subx-api.duckdns.org/api/subtitles/%s/download", subtitleID)

    // Create request
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)

    // Send request
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // Save to file
    file, _ := os.Create("subtitle.srt")
    defer file.Close()

    io.Copy(file, resp.Body)
    fmt.Println("Subtitle downloaded successfully!")
}
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var apiKey = "{YOUR_API_KEY_HERE}";
        var subtitleId = "550e8400-e29b-41d4-a716-446655440000";
        var client = new HttpClient();

        client.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", apiKey);

        var url = $"https://subx-api.duckdns.org/api/subtitles/{subtitleId}/download";
        var response = await client.GetAsync(url);

        var content = await response.Content.ReadAsByteArrayAsync();
        await File.WriteAllBytesAsync("subtitle.srt", content);

        Console.WriteLine("Subtitle downloaded successfully!");
    }
}

Complete Example: Search and Download

Here's a complete example that searches for subtitles and downloads the first result:

=== "Python"

import requests
import os

# Configuration
API_KEY = os.getenv("SUBX_API_KEY")  # Use environment variable
BASE_URL = "https://subx-api.duckdns.org"
headers = {"Authorization": f"Bearer {API_KEY}"}

def search_subtitles(title, limit=10):
    """Search for subtitles by title."""
    response = requests.get(
        f"{BASE_URL}/api/subtitles/search",
        headers=headers,
        params={"title": title, "limit": limit}
    )
    response.raise_for_status()
    return response.json()

def download_subtitle(subtitle_id, output_path):
    """Download a subtitle file."""
    response = requests.get(
        f"{BASE_URL}/api/subtitles/{subtitle_id}/download",
        headers=headers
    )
    response.raise_for_status()

    with open(output_path, "wb") as f:
        f.write(response.content)

    return output_path

# Main workflow
if __name__ == "__main__":
    # Search for "Dexter" subtitles
    print("Searching for Dexter subtitles...")
    results = search_subtitles("Dexter", limit=5)

    print(f"Found {results['total']} subtitles")

    if results['items']:
        # Download the first result
        first_subtitle = results['items'][0]
        print(f"\nDownloading: {first_subtitle['title']}")

        subtitle_id = first_subtitle['id']
        output_file = f"{first_subtitle['title']}.srt"

        download_subtitle(subtitle_id, output_file)
        print(f"✓ Saved to: {output_file}")
    else:
        print("No subtitles found")
const API_KEY = process.env.SUBX_API_KEY;
const BASE_URL = 'https://subx-api.duckdns.org';

async function searchSubtitles(title, limit = 10) {
  const response = await fetch(
    `${BASE_URL}/api/subtitles/search?title=${encodeURIComponent(title)}&limit=${limit}`,
    {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    }
  );

  if (!response.ok) throw new Error('Search failed');
  return await response.json();
}

async function downloadSubtitle(subtitleId, outputPath) {
  const response = await fetch(
    `${BASE_URL}/api/subtitles/${subtitleId}/download`,
    {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    }
  );

  if (!response.ok) throw new Error('Download failed');

  const buffer = await response.arrayBuffer();
  const fs = require('fs').promises;
  await fs.writeFile(outputPath, Buffer.from(buffer));

  return outputPath;
}

// Main workflow
async function main() {
  console.log('Searching for Dexter subtitles...');
  const results = await searchSubtitles('Dexter', 5);

  console.log(`Found ${results.total} subtitles`);

  if (results.items.length > 0) {
    const firstSubtitle = results.items[0];
    console.log(`\nDownloading: ${firstSubtitle.title}`);

    const outputFile = `${firstSubtitle.title}.srt`;
    await downloadSubtitle(firstSubtitle.id, outputFile);
    console.log(`✓ Saved to: ${outputFile}`);
  } else {
    console.log('No subtitles found');
  }
}

main().catch(console.error);

Error Handling

Always handle errors gracefully in production code:

=== "Python"

import requests

headers = {"Authorization": f"Bearer {API_KEY}"}

try:
    response = requests.get(
        "https://subx-api.duckdns.org/api/subtitles/search",
        headers=headers,
        params={"title": "Dexter"}
    )
    response.raise_for_status()  # Raise exception for 4xx/5xx status codes
    data = response.json()

except requests.exceptions.HTTPError as e:
    if e.response.status_code == 401:
        print("❌ Invalid API key")
    elif e.response.status_code == 429:
        print("❌ Rate limit exceeded")
    else:
        print(f"❌ HTTP error: {e}")

except requests.exceptions.RequestException as e:
    print(f"❌ Request failed: {e}")

Common Response Codes

Code Meaning Description
200 OK Request successful
400 Bad Request Invalid parameters
401 Unauthorized Missing or invalid API key
404 Not Found Resource not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error

Next Steps

Now that you've made your first requests, explore the full API capabilities: