KonvrtKonvrt

Developer

API Documentation

Compress and convert media files programmatically. Upload a file, get a job ID, poll for status, and download the result.

Quick Start

cURL example
# 1. Compress a video
curl -X POST https://your-domain.com/api/v1/compress \
  -H "Authorization: Bearer kvrt_your_api_key" \
  -F "file=@video.mp4" \
  -F "codec=h264" \
  -F "quality=23"

# Response: { "job_id": "j_abc123", "status": "pending", "status_url": "/api/v1/status/j_abc123" }

# 2. Check status
curl https://your-domain.com/api/v1/status/j_abc123 \
  -H "Authorization: Bearer kvrt_your_api_key"

# 3. Download when complete
curl -O https://your-domain.com/api/v1/download/j_abc123 \
  -H "Authorization: Bearer kvrt_your_api_key"

Authentication

All API requests require an API key in the Authorization header. Create your API key in the dashboard. API access requires a Pro or Team plan.

Header format
Authorization: Bearer kvrt_your_api_key_here
Key format: kvrt_ followed by 32 alphanumeric characters. Keys start with kvrt_ prefix.

Endpoints

POST/api/v1/compress

Upload and compress a video file. Returns a job ID for tracking.

Request (multipart/form-data)

FieldTypeDescription
filebinaryVideo file (required, max 2GB)
codecstringh264, h265, av1 (default: h264)
qualitynumberCRF value 18-51 (default: 23)
methodstringcrf, bitrate, size (default: crf)
resolutionstringe.g. 1920x1080, 1280x720
webhook_urlstringURL to POST when job completes

Response (202 Accepted)

{
  "success": true,
  "job_id": "j_abc123def456",
  "status": "pending",
  "status_url": "/api/v1/status/j_abc123def456",
  "credits_charged": 5
}
GET/api/v1/status/:jobId

Check the status of a processing job.

Response (200)

{
  "job_id": "j_abc123def456",
  "status": "completed",
  "progress": 100,
  "input": {
    "filename": "video.mp4",
    "size_bytes": 104857600
  },
  "output": {
    "filename": "video-compressed.mp4",
    "size_bytes": 31457280,
    "compression_ratio": 70,
    "download_url": "/api/v1/download/j_abc123def456",
    "expires_at": "2026-04-13T12:00:00Z"
  }
}
Status values: pending | processing | completed | failed
GET/api/v1/download/:jobId

Download the processed file. Returns the file binary.

Returns the processed file with appropriate Content-Type header. Download links expire 24 hours after job completion.
GET/api/v1/usage

Get your current plan and credit balance.

Response (200)

{
  "plan": "pro",
  "credits": {
    "balance": 420,
    "total_purchased": 500
  }
}
POST/api/v1/convert

Convert an image between formats using server-side Sharp.

Request (multipart/form-data)

FieldTypeDescription
filebinaryImage file (required, max 50MB)
formatstringOutput format: jpg, png, webp, avif, gif, tiff
qualitynumber1-100 (default: 80)
widthnumberResize width in pixels
heightnumberResize height in pixels
Returns the converted image binary directly (not a job). Response headers include X-Original-Size, X-Output-Size, and X-Output-Format.

Rate Limits

PlanRequests/minMax file size
Pro602GB
Team602GB

When rate limited you'll receive a 429 Too Many Requests response with a Retry-After header.

Credits

API usage is billed per-job based on input file size. Credits are deducted when a job is submitted.

PackCreditsPrice
Starter1,000$5
Growth5,000$20
Scale20,000$60

Pro plans include 500 credits. Team plans include 2,000 credits. Purchase additional credits from the pricing page.

Webhooks

Pass a webhook_url when creating a job to receive a POST notification when the job completes or fails.

Webhook payload (job.completed)
{
  "event": "job.completed",
  "job_id": "j_abc123def456",
  "status": "completed",
  "output": {
    "download_url": "/api/v1/download/j_abc123def456",
    "size_bytes": 31457280,
    "expires_at": "2026-04-13T12:00:00Z"
  },
  "timestamp": "2026-04-12T12:00:00Z"
}
Webhook payload (job.failed)
{
  "event": "job.failed",
  "job_id": "j_abc123def456",
  "status": "failed",
  "error": "FFmpeg exited with code 1",
  "timestamp": "2026-04-12T12:00:00Z"
}

Error Codes

CodeMeaning
400Bad request (missing fields)
401Invalid or missing API key
404Job not found
410Download link expired (24h)
413File too large (max 2GB)
429Rate limit exceeded

Code Examples

Node.js

compress.js
const fs = require("fs");
const FormData = require("form-data");

const form = new FormData();
form.append("file", fs.createReadStream("input.mp4"));
form.append("codec", "h264");
form.append("quality", "23");

const res = await fetch("https://your-domain.com/api/v1/compress", {
  method: "POST",
  headers: { Authorization: "Bearer kvrt_your_key" },
  body: form,
});

const { job_id } = await res.json();

// Poll for completion
let status = "pending";
while (status === "pending" || status === "processing") {
  await new Promise((r) => setTimeout(r, 3000));
  const check = await fetch(`https://your-domain.com/api/v1/status/${job_id}`, {
    headers: { Authorization: "Bearer kvrt_your_key" },
  });
  const data = await check.json();
  status = data.status;
  console.log(`Progress: ${data.progress}%`);
}

console.log("Done! Download from:", `/api/v1/download/${job_id}`);

Python

compress.py
import requests
import time

# Upload and compress
with open("input.mp4", "rb") as f:
    res = requests.post(
        "https://your-domain.com/api/v1/compress",
        headers={"Authorization": "Bearer kvrt_your_key"},
        files={"file": f},
        data={"codec": "h264", "quality": "23"},
    )

job_id = res.json()["job_id"]

# Poll for completion
while True:
    check = requests.get(
        f"https://your-domain.com/api/v1/status/{job_id}",
        headers={"Authorization": "Bearer kvrt_your_key"},
    )
    data = check.json()
    print(f"Status: {data['status']} ({data['progress']}%)")
    if data["status"] in ("completed", "failed"):
        break
    time.sleep(3)

# Download result
if data["status"] == "completed":
    dl = requests.get(
        f"https://your-domain.com/api/v1/download/{job_id}",
        headers={"Authorization": "Bearer kvrt_your_key"},
    )
    with open("output.mp4", "wb") as f:
        f.write(dl.content)