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.
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", "clips": [ { "url": "...", "captions_url": "..." } ] }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.
GET /api/v1/jobs/{id} — poll until status is completed.
{
"id": "JOB_ID",
"status": "completed",
"progress": { "step": "done", "pct": 100 },
"clips": [
{ "url": "https://.../clip_0.mp4", "captions_url": "https://.../clip_0.srt" },
{ "url": "https://.../clip_1.mp4", "captions_url": "https://.../clip_1.srt" }
],
"error": null
}Statuses: queued → processing → scoring → completed (or failed). Typical time ~5–7 min.
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",
"clips": [ { "url": "...", "captions_url": "..." } ],
"timestamp": "..."
}Verify: HMAC-SHA256(secret, timestamp + "." + rawBody) compared to X-Katto-Signature. 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 |
katto-mcp is a local MCP server that wraps this API, so agents can clip videos as a tool call. It runs over npx with your key — nothing to host.
{
"mcpServers": {
"katto": {
"command": "npx",
"args": ["-y", "katto-mcp"],
"env": { "KATTO_API_KEY": "sk_live_..." }
}
}
}Tools: katto_create_clip_job(url, config?) and katto_get_job(id). Then just ask your agent: “Clip the best moments from this podcast.”