Turn long videos into scored, reframed, captioned 9:16 clips from your own code — the same pipeline as the dashboard. Available as a REST API and as an MCP server, so any backend, workflow tool, or AI agent (Claude, Cursor, …) can clip a video with one call. Usage draws from your plan’s monthly video quota — no per-minute surcharges, no enterprise-only gating.
Katto is an AI video clipping tool that turns long videos into scored, captioned 9:16 clips. It exposes a public REST API, a CLI (npm katto-cli) and an official hosted MCP server (mcp.katto.tech, 16 tools, OAuth 2.1). All three are available on every plan, including free, and draw from the same monthly video quota as the dashboard.
New to the API? See what the video clipping API is for.
Submit a video, then poll until the clips are ready.
# 1. submit
curl -X POST https://katto.tech/api/v1/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
# -> { "id": "JOB_ID", "status": "queued", "status_url": "..." }
# 2. poll (every few seconds)
curl https://katto.tech/api/v1/jobs/JOB_ID \
-H "Authorization: Bearer sk_live_..."
# -> { "status": "completed", "hd_ready": true,
# "clips": [ { "url": "...", "captions_url": "...", "title": "...", "score": 88, "clip_index": 0, "hd": true } ] }Three common flows, end to end.
Podcast → short clips
curl -X POST https://katto.tech/api/v1/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=...","config":{"genre":"podcast","clipLength":"30_60"}}'
# poll GET /api/v1/jobs/JOB_ID until status "completed", then read clips[]Twitch VOD → clips
curl -X POST https://katto.tech/api/v1/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://www.twitch.tv/videos/123456789","config":{"genre":"gaming"}}'Re-render or dub a finished clip
Re-rendering a finished clip with a new layout or caption style, and dubbing it into another language, run as MCP tools (katto_rerender_clip, katto_dub_clip) — free, no quota. See the tools reference.
Create a key in Dashboard → API and pass it as a bearer token. A key is shown once; we store only a hash. Revoke anytime.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
POST /api/v1/jobs— accepts YouTube, Twitch, Vimeo, Rumble, Zoom and Dailymotion links.
// Node (fetch)
const r = await fetch("https://katto.tech/api/v1/jobs", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
config: { genre: "podcast", clipLength: "30_60" },
}),
});
const { id, status_url } = await r.json();# Python (requests)
import requests
r = requests.post(
"https://katto.tech/api/v1/jobs",
headers={"Authorization": "Bearer sk_live_..."},
json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
)
job = r.json() # { "id": ..., "status": "queued", "status_url": ... }config is optional: genre, clipLength (lt30 / 30_60 / 60_90 / 90_180), customPrompt, topics.
Pass an Idempotency-Key header on POST /api/v1/jobs to make retries safe. A repeat with the same key returns the original job (200, with idempotent_replay: true) instead of creating — and quota-charging — a second one. While the first request is still in flight, a duplicate returns 409; retry shortly.
curl -X POST https://katto.tech/api/v1/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: 8f3a1c-your-unique-id" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'Use a fresh unique key per distinct submission (a UUID works well), and reuse it when retrying that same submission.
GET /api/v1/jobs/{id} — poll until status is completed.
{
"id": "JOB_ID",
"status": "completed",
"progress": { "step": "done", "pct": 100 },
"hd_ready": true,
"clips": [
{ "url": "https://.../hq_0.mp4", "captions_url": "https://.../clip_0.srt", "title": "The hook that stops the scroll", "score": 88, "clip_index": 0, "hd": true },
{ "url": "https://.../hq_1.mp4", "captions_url": "https://.../clip_1.srt", "title": "Second-best moment", "score": 83, "clip_index": 1, "hd": true }
],
"error": null
}Clips are ranked by virality score (highest first; ties break on clip_index). hd is true once a clip's 1080p render has landed; the job-level hd_ready turns true once every clip is hd, i.e. the URLs are final. status reaches completed a little before that, so wait for hd_ready before caching a clip URL.
Statuses: queued → processing → scoring → completed (or failed). Clips finish asynchronously — a 20-minute source measured about 5 minutes end to end; longer sources take longer.
GET /api/v1/jobs— your jobs, newest first. Keyset pagination: pass the previous next_cursor as ?cursor=. Optional ?limit= (1–100, default 20) and ?status=.
curl "https://katto.tech/api/v1/jobs?limit=20&status=completed" \
-H "Authorization: Bearer sk_live_..."
# -> { "jobs": [ { "id": "...", "status": "completed", "source": "youtube",
# "created_at": "...", "completed_at": "..." } ], "next_cursor": "..." }GET /api/v1/jobs/{id}/transcript — the completed job’s timestamped transcript. Returns 404 while still processing.
curl https://katto.tech/api/v1/jobs/JOB_ID/transcript \
-H "Authorization: Bearer sk_live_..."
# -> { "job_id": "...", "lang": "en",
# "segments": [ { "start": 26.78, "end": 27.16, "text": "Good morning." } ] }GET /api/v1/usage— your plan and monthly video quota.
curl https://katto.tech/api/v1/usage \
-H "Authorization: Bearer sk_live_..."
# -> { "plan": "pro", "videos_used": 6, "videos_limit": 25, "videos_remaining": 19 }Add webhook_url to a job to get a signed POST on completion instead of polling. It must be a public https URL.
curl -X POST https://katto.tech/api/v1/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.youtube.com/watch?v=...",
"webhook_url": "https://your-app.com/hooks/katto"
}'On completion Katto POSTs:
POST https://your-app.com/hooks/katto
X-Katto-Timestamp: 1786943456
X-Katto-Signature: sha256=<hmac>
{
"event": "job.completed",
"job_id": "...",
"status": "completed",
"hd_ready": true,
"clips": [ { "url": "...", "captions_url": "...", "title": "...", "score": 88, "clip_index": 0, "hd": true } ],
"timestamp": "..."
}Verify: HMAC-SHA256(secret, timestamp + "." + rawBody) compared to X-Katto-Signature (use a constant-time comparison). The timestamp is part of the signed payload, so to stop replays, also reject any request whose X-Katto-Timestamp is more than ~5 minutes old. Your signing secret is in Dashboard → API.
Over-limit responses return 429 with Retry-After and X-RateLimit-* headers.
| Scope | Limit |
|---|---|
| Per IP | 60 / min |
| Create job (per key) | 20 / min |
| Get job (per key) | 60 / min |
All errors are JSON: { "error": "message" }.
| 400 | Invalid or missing URL / oversized input |
| 401 | Invalid or missing API key |
| 403 | Monthly video quota reached |
| 404 | Job not found (or not yours) |
| 405 | Wrong method |
| 413 | Request body too large |
| 429 | Rate limit exceeded |
| 500 | Server error |
The full machine-readable contract is published as OpenAPI 3.1 at /openapi.json— import it into Postman, an SDK generator, or an agent.
curl https://katto.tech/openapi.json
katto-mcp exposes this API as MCP tools, so agents (Claude, Cursor, ChatGPT, VS Code, Windsurf) can clip videos as a tool call. Connect it two ways.
Hosted (recommended) — nothing to install
{
"mcpServers": {
"katto": { "url": "https://mcp.katto.tech/mcp" }
}
}Streamable HTTP at https://mcp.katto.tech/mcp. Sign in with your Katto account via OAuth 2.1(dynamic client registration) — the key never touches the browser. Scripts can instead send Authorization: Bearer sk_live_… to the same URL (dual auth).
Local — run it yourself
{
"mcpServers": {
"katto": {
"command": "npx",
"args": ["-y", "katto-mcp"],
"env": { "KATTO_API_KEY": "sk_live_..." }
}
}
}16 tools, each carrying MCP annotations (read-only vs quota-spending vs destructive): katto_create_clip_job, katto_get_job, katto_list_jobs, katto_get_clips, katto_get_transcript, katto_get_usage, katto_get_account, katto_cancel_job, katto_list_sources, katto_list_clip_lengths, katto_rerender_clip, katto_dub_clip, katto_get_rerender, katto_get_brand_kit and katto_get_webhook_secret. Then just ask your agent: “Clip the best moments from this podcast.”
Per-client setup: Claude, Cursor / VS Code / Windsurf, ChatGPT. Full tool reference with input schemas: /mcp/tools. Published on npm and the official MCP registry.