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.
https://api.clipi.video/apiAll 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.
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"}'Fetch metadata, available formats, and thumbnails for a video URL.
/video/infoReturns video metadata including available download formats.
{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ"
}{
"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)"
}
]
}
}Queue a video download job. Returns a job ID to track progress.
/video/downloadStarts a download job. Use the returned jobId to track progress via SSE.
{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"formatId": "137",
"format": "mp4",
"quality": "1080p",
"trimStart": 0,
"trimEnd": 60,
"noWatermark": true
}{
"success": true,
"jobId": "abc-123",
"downloadId": "def-456"
}Subscribe to real-time progress via Server-Sent Events (SSE).
/jobs/:jobIdSSE stream. Each event contains job status, progress %, speed, and ETA.
// 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"}Retrieve the processed file once the job is complete.
/download/:downloadIdReturns the video/audio file. Link expires after 24 hours.
// Binary file response
// Content-Type: video/mp4
// Content-Disposition: attachment; filename="video.mp4"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.
jobId + toolJobId → track via GET /tools/jobs/:jobId (SSE) → download via GET /tools/download/:toolJobId# Generic tool response
{
"success": true,
"jobId": "123", // BullMQ job ID — use for SSE progress
"toolJobId": "uuid-456" // Tool job UUID — use for download
}| endpoint | description | params (besides file) |
|---|---|---|
| POST /tools/convert | Convert video/audio format | outputFormat: mp4|webm|mkv|mp3|m4a|wav|ogg|flac |
| POST /tools/compress | Compress video | quality: low|medium|high (default: medium) |
| POST /tools/extract-audio | Extract audio from video | audioFormat: mp3|m4a|wav|ogg|flac (default: mp3) |
| POST /tools/gif | Video to animated GIF | startTime, duration (0.5-15), width? (120-800), fps? (5-30, default: 15) |
| POST /tools/thumbnail | Generate thumbnail from video | timestamp?, width? (50-3840), height? (50-2160), format: jpg|png|webp, cropX?, cropY?, cropW?, cropH? |
| POST /tools/trim-video | Trim video segment | startTime, endTime |
| POST /tools/resize-video | Resize video dimensions | width (16-7680), height (16-4320) |
| POST /tools/rotate-video | Rotate video | rotation: 90|180|270 |
| POST /tools/remove-audio | Remove audio track | (no extra params) |
| POST /tools/video-speed | Change playback speed | speed (0.25-4) |
| POST /tools/audio-converter | Convert audio format | outputFormat: mp3|m4a|wav|ogg|flac |
| POST /tools/trim-audio | Trim audio segment | startTime, endTime |
| POST /tools/image-converter | Convert image format | outputFormat: jpg|png|webp |
| POST /tools/resize-image | Resize image | width (1-7680), height (1-4320) |
| POST /tools/compress-image | Compress image | quality (1-100, default: 75) |
Subscribe to real-time progress for a tool job.
/tools/jobs/:jobIdSSE stream. Polls every 1s with status, percent, and queue position. Stream ends on completed/failed.
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"}Retrieve the processed file. Add ?preview=1 for inline display instead of download.
/tools/download/:toolJobIdReturns the processed file with correct MIME type. Expires after cleanup.
// Binary file response
// Content-Type: video/mp4 | image/jpeg | audio/mpeg | ...
// Content-Disposition: attachment; filename="result.mp4"
// Add ?preview=1 for Content-Disposition: inline# 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-uuidEach API key has two independent rate limit tiers:
Max requests per rolling hour. Default: 100 (admin keys), 50 (user keys)
Max requests per rolling 24h. Default: 1000 (admin keys), 500 (user keys)
// 429 response when rate limited
{
"error": "Hourly rate limit exceeded (100/hr)",
"retryAfter": 1800
}All errors return a JSON object with an error field.
| code | description |
|---|---|
| 400 | Bad request — malformed body or invalid parameters |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — account banned or key disabled |
| 404 | Not found — resource does not exist |
| 422 | Unprocessable — video unavailable, private, or unsupported |
| 429 | Rate limit exceeded — wait before retrying |
| 500 | Internal server error |
# 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_IDconst 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();
}
};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