API Quickstart guide

KickAssSubtitles API lets users access various site features like searching/converting/uploading subtitles from withing any programming language/environment capable of performing HTTP requests. This guide demonstrates how to consume the API using Python language. All demonstrated code samples are also available in our GitHub repository.

Before continuing make sure you have at least Python 3.x. You will also need requests module installed:

pip install requests # or `apt-get install python3-requests` on Debian-based Linux distros

Obtaining API key

You can obtain YOUR_API_KEY from account information screen. Click Generate API key button to generate new key. After generation the key will be displayed on screen for short period of time - you should copy it and store in safe place. For this guide lets assume this is our generated key: 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69

Testing connection

In order to test API connection lets send GET query to /api/user endpoint which returns various information about user's account:

import requests

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
response = requests.request("GET", "https://kickasssubtitles.com/api/user", headers=headers)
print(response.text) # should return JSON string: `{"username":"admin","email":"[email protected]", ...}`

Uploading subtitle

Suppose we have movie file Some.Movie.2006.1080p.BluRay.x264.mp4 along with matching subtitle file Some.Movie.2006.1080p.BluRay.x264.srt

In order to upload subtitle, we must first calculate hash (fingerprint) of movie file. Most popular way to do it is to use OpenSubtitles hashing function. Here is Python implementation:

import struct
import os

def hash_opensubtitles(video_path):
    """Compute a hash using OpenSubtitles' algorithm.

    :param str video_path: path of the video.
    :return: the hash.
    :rtype: str

    """
    bytesize = struct.calcsize(b'<q')
    with open(video_path, 'rb') as f:
        filesize = os.path.getsize(video_path)
        filehash = filesize
        if filesize < 65536 * 2:
            return
        for _ in range(65536 // bytesize):
            filebuffer = f.read(bytesize)
            (l_value,) = struct.unpack(b'<q', filebuffer)
            filehash += l_value
            filehash &= 0xFFFFFFFFFFFFFFFF  # to remain as 64bit number
        f.seek(max(0, filesize - 65536), 0)
        for _ in range(65536 // bytesize):
            filebuffer = f.read(bytesize)
            (l_value,) = struct.unpack(b'<q', filebuffer)
            filehash += l_value
            filehash &= 0xFFFFFFFFFFFFFFFF
    returnedhash = '%016x' % filehash

    return returnedhash

With hashing function in place we can proceed to uploading subtitle by sending POST query to /api/upload endpoint. Note that we also need to pass movie IMDb URL (imdb_url) and subtitle language code:

import os
import requests

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
payload = {
    "filename": "Some.Movie.2006.1080p.BluRay.x264.mp4",
    "filesize": os.path.getsize("Some.Movie.2006.1080p.BluRay.x264.mp4"),
    "hashes[opensubtitles]": hash_opensubtitles("Some.Movie.2006.1080p.BluRay.x264.mp4"),
    "imdb_url": "https://www.imdb.com/title/tt0000000/",
    "language": "en"
}
files = [
    ("subtitle",("Some.Movie.2006.1080p.BluRay.x264.srt", open("Some.Movie.2006.1080p.BluRay.x264.srt", "rb"), "application/octet-stream"))
]
response = requests.request("POST", "https://kickasssubtitles.com/api/upload", headers=headers, data=payload, files=files)
print(response.text) # should return JSON string: `{"id":"dcszd","created_at":"2024-07-10T21:00:29.000000Z", ...}`

Searching subtitle

Suppose we have movie file Some.Movie.2006.1080p.BluRay.x264.mp4 but this time we want to search for subtitles matching this file. In order to do that we need to send POST query to /api/search endpoint:

import requests
import os

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
payload = {
    "filename": "Some.Movie.2006.1080p.BluRay.x264.mp4",
    "filesize": os.path.getsize("Some.Movie.2006.1080p.BluRay.x264.mp4"),
    "hashes[opensubtitles]": hash_opensubtitles("Some.Movie.2006.1080p.BluRay.x264.mp4"),
    "language": "pl", # optional - defaults to "en"
    "encoding": "UTF-8", # optional - defaults to "UTF-8"
    "format": "subrip" # optional - defaults to "subrip"
}
response = requests.request("POST", "https://kickasssubtitles.com/api/search", headers=headers, data=payload)
task = response.json()
print(task["id"]) # should return task identifier - for instance: `01j2pfmd5sth39v4kdrvtbwan2`

Note that /api/search endpoint works in asynchronous fashion. So first search "task" is created with some id and later we will need to query the API for this task by its id to see if it has been processed. Usually it takes few seconds to process a task depending on current site load.

import requests
import base64

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
response = requests.request("GET", "https://kickasssubtitles.com/api/tasks/01j2pfmd5sth39v4kdrvtbwan2", headers=headers)
task = response.json()
if task["status"] != "completed":
    raise Exception("Something went wrong.")
subtitle_file = "subtitle." + task["result"]["subtitles"][0]["extension"]
with open(subtitle_file, "wb") as f:
    f.write(base64.b64decode(task["result"]["subtitles"][0]["contents_base64"]))
print(f"Subtitle written to {subtitle_file}")

Subtitles are base64-encoded in the response. You can find more about task response structure in the docs.

Converting subtitle

To convert our example subtitle Some.Movie.2006.1080p.BluRay.x264.srt to different format we can send POST query to /api/convert endpoint:

import requests
import os

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
payload = {
    "language": "pl", # optional
    "input_encoding": "UTF-8", # optional
    "encoding": "UTF-8", # optional - defaults to "UTF-8"
    "format": "webvtt", # optional - defaults to "subrip"
    "fps": None # optional
}
files = [
    ("subtitle",("Some.Movie.2006.1080p.BluRay.x264.srt", open("Some.Movie.2006.1080p.BluRay.x264.srt", "rb"), "application/octet-stream"))
]
response = requests.request("POST", "https://kickasssubtitles.com/api/convert", headers=headers, data=payload)
task = response.json()
print(task["id"]) # should return task identifier - for instance: `01j2pfmd5sth39v4kdrvtbwan2`

Similarily to previous example /api/convert also works in async fashion - we get task id which we use to query task status:

import requests
import base64

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer 1VS3lrNBp8UBB3eBBMWAWynHWh7KtiyuMKVJ4HiQ377c1d69"
}
response = requests.request("GET", "https://kickasssubtitles.com/api/tasks/01j2pfmd5sth39v4kdrvtbwan2", headers=headers)
task = response.json()
if task["status"] != "completed":
    raise Exception("Something went wrong.")
subtitle_file = "subtitle." + task["result"]["subtitles"][0]["extension"]
with open(subtitle_file, "wb") as f:
    f.write(base64.b64decode(task["result"]["subtitles"][0]["contents_base64"]))
print(f"Subtitle written to {subtitle_file}")

Subtitles are base64-encoded in the response. You can find more about task response structure in the docs.