Developer API

Ship media workflowswithout building the pipeline yourself.

Upload a file, start a hosted job, poll or receive a webhook, and download the result. The API complements Konvrt's local-first tools when you need automation, larger files, or backend integration.

Simple job model

Create a job, check status, then download the output when it completes.

Credit-based usage

Only pay for hosted compute when you actually use API or cloud video workloads.

Webhook-ready

Attach a callback URL when polling is not the right fit for your system.

Before you start

API access requires a Pro or Team plan.

Create an API key in the dashboard before making requests.

Use credit packs when your hosted usage grows beyond the included balance.

Core flow

1. `POST /api/v1/compress` or `POST /api/v1/convert`
2. Poll `GET /api/v1/status/:jobId` when applicable
3. Download from `GET /api/v1/download/:jobId`

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 requests require an API key in the `Authorization` header. Create a key in the dashboard.

Header format
Authorization: Bearer kvrt_your_api_key_here

Keys start with `kvrt_` and are intended for server-side use in your own app or backend.

Limits and credits

Rate limit

Pro and Team plans support 60 requests per minute.

Hosted file size

Video jobs support files up to 2GB.

Included credits

Pro includes 500 credits. Team includes 2,000.

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.

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)

Media jobs

Use hosted processing when browser-only flows are not enough for your app or customer workflow.

Status and downloads

Track progress, inspect output metadata, and download results from expiring URLs.

Plan-aware billing

Included credits on paid plans with optional packs when your volume expands.

Built for fast file workflows

Convert, optimize, and ship files without sending them away first.

Konvrt keeps the experience simple: local-first processing when possible, clear pricing, strong privacy defaults, and focused tools for repetitive file work.

Local-first

Files stay on your device for supported browser workflows.

Fast answers

Use FAQ, docs, and contact paths without hunting around the site.

Clear upgrades

Move from free workflows to paid access without confusing plan language.