v1stable

REST API

Integrate Clipi into your apps and bots. Use your API key to download videos from YouTube, TikTok, Instagram, Twitter, and more — plus 15 media processing tools for converting, trimming, compressing, and editing files.

base_url=https://api.clipi.video/api

authentication

All API requests require an API key sent via the X-Api-Key header. Generate your key from the My Key page or contact an admin for a custom key.

bash
curl -X POST https://api.clipi.video/api/video/info \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: clp_your_api_key_here" \
  -d '{"url": "https://youtube.com/watch?v=dQw4w9WgXcQ"}'
Security note: Keep your keys secure and never expose them in frontend code. Each key has independent rate limits configurable from the admin panel.

endpoints

get video info

Fetch metadata, available formats, and thumbnails for a video URL.

POST/video/info

Returns video metadata including available download formats.

request body
json
{
  "url": "https://youtube.com/watch?v=dQw4w9WgXcQ"
}
response
json
{
  "success": true,
  "data": {
    "url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
    "title": "Rick Astley - Never Gonna Give You Up",
    "thumbnail": "https://i.ytimg.com/vi/.../maxresdefault.jpg",
    "duration": 212,
    "platform": "youtube",
    "uploader": "Rick Astley",
    "formats": [
      {
        "id": "137",
        "ext": "mp4",
        "quality": "1080p",
        "resolution": "1920x1080",
        "filesize": 52428800,
        "fps": 30,
        "label": "1080p (mp4)"
      }
    ]
  }
}

start download

Queue a video download job. Returns a job ID to track progress.

POST/video/download

Starts a download job. Use the returned jobId to track progress via SSE.

request body
json
{
  "url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
  "formatId": "137",
  "format": "mp4",
  "quality": "1080p",
  "trimStart": 0,
  "trimEnd": 60,
  "noWatermark": true
}
response
json
{
  "success": true,
  "jobId": "abc-123",
  "downloadId": "def-456"
}

track job progress

Subscribe to real-time progress via Server-Sent Events (SSE).

GET/jobs/:jobId

SSE stream. Each event contains job status, progress %, speed, and ETA.

response
json
// SSE event stream
data: {"jobId":"abc-123","status":"processing","percent":45,"speed":"2.5MB/s","eta":12}
data: {"jobId":"abc-123","status":"completed","percent":100,"downloadUrl":"/api/download/def-456"}

download file

Retrieve the processed file once the job is complete.

GET/download/:downloadId

Returns the video/audio file. Link expires after 24 hours.

response
json
// Binary file response
// Content-Type: video/mp4
// Content-Disposition: attachment; filename="video.mp4"

media tools

All tool endpoints accept a multipart/form-data upload with a file field and tool-specific parameters. Returns a job ID for tracking progress via SSE.

Flow: Upload file → get jobId + toolJobId → track via GET /tools/jobs/:jobId (SSE) → download via GET /tools/download/:toolJobId
bash
# Generic tool response
{
  "success": true,
  "jobId": "123",          // BullMQ job ID — use for SSE progress
  "toolJobId": "uuid-456"  // Tool job UUID — use for download
}
endpointdescriptionparams (besides file)
POST /tools/convertConvert video/audio formatoutputFormat: mp4|webm|mkv|mp3|m4a|wav|ogg|flac
POST /tools/compressCompress videoquality: low|medium|high (default: medium)
POST /tools/extract-audioExtract audio from videoaudioFormat: mp3|m4a|wav|ogg|flac (default: mp3)
POST /tools/gifVideo to animated GIFstartTime, duration (0.5-15), width? (120-800), fps? (5-30, default: 15)
POST /tools/thumbnailGenerate thumbnail from videotimestamp?, width? (50-3840), height? (50-2160), format: jpg|png|webp, cropX?, cropY?, cropW?, cropH?
POST /tools/trim-videoTrim video segmentstartTime, endTime
POST /tools/resize-videoResize video dimensionswidth (16-7680), height (16-4320)
POST /tools/rotate-videoRotate videorotation: 90|180|270
POST /tools/remove-audioRemove audio track(no extra params)
POST /tools/video-speedChange playback speedspeed (0.25-4)
POST /tools/audio-converterConvert audio formatoutputFormat: mp3|m4a|wav|ogg|flac
POST /tools/trim-audioTrim audio segmentstartTime, endTime
POST /tools/image-converterConvert image formatoutputFormat: jpg|png|webp
POST /tools/resize-imageResize imagewidth (1-7680), height (1-4320)
POST /tools/compress-imageCompress imagequality (1-100, default: 75)

track tool job (SSE)

Subscribe to real-time progress for a tool job.

GET/tools/jobs/:jobId

SSE stream. Polls every 1s with status, percent, and queue position. Stream ends on completed/failed.

response
json
data: {"jobId":"123","status":"pending","percent":0,"queuePosition":2,"queueTotal":5}
data: {"jobId":"123","status":"processing","percent":45}
data: {"jobId":"123","status":"completed","percent":100,"downloadUrl":"/api/tools/download/uuid-456"}

download tool result

Retrieve the processed file. Add ?preview=1 for inline display instead of download.

GET/tools/download/:toolJobId

Returns the processed file with correct MIME type. Expires after cleanup.

response
json
// Binary file response
// Content-Type: video/mp4 | image/jpeg | audio/mpeg | ...
// Content-Disposition: attachment; filename="result.mp4"
// Add ?preview=1 for Content-Disposition: inline

example: trim a video

bash
# 1. Upload and start tool job
curl -X POST https://api.clipi.video/api/tools/trim-video \
  -H "X-Api-Key: clp_your_key" \
  -F "file=@video.mp4" \
  -F "startTime=10" \
  -F "endTime=30"

# Response: {"success":true,"jobId":"123","toolJobId":"abc-uuid"}

# 2. Track progress (SSE)
curl -N https://api.clipi.video/api/tools/jobs/123

# 3. Download result
curl -O -J https://api.clipi.video/api/tools/download/abc-uuid

rate limits

Each API key has two independent rate limit tiers:

hourly limit

Max requests per rolling hour. Default: 100 (admin keys), 50 (user keys)

daily limit

Max requests per rolling 24h. Default: 1000 (admin keys), 500 (user keys)

json
// 429 response when rate limited
{
  "error": "Hourly rate limit exceeded (100/hr)",
  "retryAfter": 1800
}

errors

All errors return a JSON object with an error field.

codedescription
400Bad request — malformed body or invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — account banned or key disabled
404Not found — resource does not exist
422Unprocessable — video unavailable, private, or unsupported
429Rate limit exceeded — wait before retrying
500Internal server error

examples

curl

bash
# 1. Get video info
curl -X POST https://api.clipi.video/api/video/info \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: clp_your_key" \
  -d '{"url": "https://youtube.com/watch?v=dQw4w9WgXcQ"}'

# 2. Start download
curl -X POST https://api.clipi.video/api/video/download \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: clp_your_key" \
  -d '{"url": "https://youtube.com/watch?v=dQw4w9WgXcQ", "format": "mp4"}'

# 3. Track progress (SSE)
curl -N https://api.clipi.video/api/jobs/JOB_ID

# 4. Download file
curl -O -J https://api.clipi.video/api/download/DOWNLOAD_ID

javascript / node.js

javascript
const API_KEY = "clp_your_key";
const BASE = "https://api.clipi.video/api";

// Get video info
const info = await fetch(`${BASE}/video/info`, {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-Api-Key": API_KEY },
  body: JSON.stringify({ url: "https://youtube.com/watch?v=dQw4w9WgXcQ" }),
}).then(r => r.json());

console.log(info.data.title, info.data.formats);

// Start download
const job = await fetch(`${BASE}/video/download`, {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-Api-Key": API_KEY },
  body: JSON.stringify({
    url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
    format: "mp4",
    formatId: info.data.formats[0].id,
  }),
}).then(r => r.json());

// Track progress via SSE
const es = new EventSource(`${BASE}/jobs/${job.jobId}`);
es.onmessage = (e) => {
  const data = JSON.parse(e.data);
  console.log(`${data.percent}% - ${data.speed}`);
  if (data.status === "completed") {
    console.log(`${BASE}/download/${job.downloadId}`);
    es.close();
  }
};

python

python
import requests, sseclient, json

API_KEY = "clp_your_key"
BASE = "https://api.clipi.video/api"
headers = {"Content-Type": "application/json", "X-Api-Key": API_KEY}

# Get video info
info = requests.post(f"{BASE}/video/info",
    json={"url": "https://youtube.com/watch?v=dQw4w9WgXcQ"},
    headers=headers).json()

# Start download
job = requests.post(f"{BASE}/video/download",
    json={"url": "https://youtube.com/watch?v=dQw4w9WgXcQ", "format": "mp4"},
    headers=headers).json()

# Track progress
response = requests.get(f"{BASE}/jobs/{job['jobId']}", stream=True)
for event in sseclient.SSEClient(response).events():
    data = json.loads(event.data)
    print(f"{data.get('percent', 0)}%")
    if data["status"] == "completed":
        r = requests.get(f"{BASE}/download/{job['downloadId']}")
        open("video.mp4", "wb").write(r.content)
        break