KINOPIPE DOCS

Give your agent video editing in one request.

Create an API key, send a public URL or upload a file, then receive a job you can poll or follow with a webhook.

QUICKSTART

Your first edit in five minutes

The fastest path is a prebuilt tool. It gives your agent a narrow, stable contract for one common media task.

01
Create a key
Sign in and create a server-side API key. Copy it once.
02
Name your inputs
Use a public URL or a signed KinoPipe upload. The first input is named main.
03
Run the tool
Send JSON, then poll the returned status URL or receive a webhook.
API key
Create a key for your server or agent runtime.
curl -X POST https://kinopipe.com/api/v1/tools/resize-video \
  -H "Authorization: Bearer $KINOPIPE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: resize-demo-001" \
  -d '{
    "inputs": [{ "id": "main", "url": "https://example.com/source.mp4" }],
    "options": {
      "aspect_ratio": "9:16",
      "fit": "cover"
    }
  }'
AUTHENTICATION

Bearer keys for server-side requests

KinoPipe API keys begin with kp_live_. Keep them on your server and never expose them in browser code or public agent prompts.

Every API request
Authorization: Bearer kp_live_••••••••••••
Copy each key immediately

The raw key is returned only once. KinoPipe stores a SHA-256 hash, so a lost key cannot be recovered.

Key prefixkp_live_
TransportHTTPS only
DIRECT UPLOADS

Send files without hosting them first

Ask KinoPipe for a signed storage policy, submit its fields with the file, then pass the returned mediaUrl to a job or tool.

POST/api/v1/uploads
Maximum file300 MB
Upload window15 minutes
Input URL24 hours
const file = document.querySelector("input[type=file]").files[0]

const signed = await fetch("https://kinopipe.com/api/v1/uploads", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.KINOPIPE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    filename: "source.mp4",
    contentType: "video/mp4",
    byteSize: file.size,
  }),
}).then((response) => response.json())

const body = new FormData()
for (const [name, value] of Object.entries(signed.upload.fields)) {
  body.append(name, value)
}
body.append("file", file)

await fetch(signed.upload.uploadUrl, { method: "POST", body })

// Use this URL in inputs[].url within 24 hours.
console.log(signed.upload.mediaUrl)
Files go straight to storage

Your browser or server sends the file to the signed storage URL. KinoPipe deletes direct uploads after one day.

REMOTE MCP

Give an agent every video tool at once

Connect the KinoPipe remote MCP server once. Your agent discovers focused, typed video tools and can queue edits, poll jobs and retrieve downloadable results without generating FFmpeg commands.

MCPhttps://kinopipe.com/mcp
TransportStreamable HTTP
AuthenticationOAuth 2.1 or API key
ExecutionAsync jobs

Agent configuration

Add the URL to an OAuth-capable MCP client. KinoPipe opens a secure sign-in and consent screen automatically—no API key to paste. Bearer API keys remain supported for clients that need manual headers.

Connect to ChatGPT, Claude or Codex
{
  "mcpServers": {
    "kinopipe": {
      "url": "https://kinopipe.com/mcp"
    }
  }
}
Designed for reliable agent loops

Editing tools return immediately with a jobId. The agent calls get_job until the edit succeeds, then receives the real temporary download URL.

CapabilityExamplesResult
Focused toolstrim_video · resize_video · add_music_to_videoTyped arguments and useful defaults for common edits.
Custom recipescreate_video_jobComposable bounded operations for advanced jobs.
Job retrievalget_jobProgress, errors, credits and downloadable outputs.
JOBS API

Compose several edits in one job

Use the Jobs API when an agent needs a pipeline. KinoPipe accepts the job immediately with HTTP 202, then processes the operations in order on a media worker.

POST/api/v1/jobs
{
  "name": "social-cut",
  "inputs": [{
    "id": "main",
    "url": "https://example.com/source.mp4",
    "filename": "source.mp4"
  }],
  "operations": [
    { "type": "trim", "start": 2, "end": 17 },
    {
      "type": "resize",
      "width": 1080,
      "height": 1920,
      "fit": "cover"
    }
  ],
  "output": { "format": "mp4", "quality": "balanced" }
}

Read job status

Poll the returned statusUrl with the same API key until the status is succeeded or failed.

GET/api/v1/jobs/{jobId}
{
  "ok": true,
  "job": {
    "id": "f7541d5e-…",
    "status": "succeeded",
    "progress": 100,
    "consumedCredits": 3
  },
  "result": {
    "output": {
      "downloadUrl": "https://cdn.kinopipe.com/…",
      "contentType": "video/mp4",
      "byteSize": 437021,
      "filename": "output.mp4"
    },
    "outputs": [{
      "downloadUrl": "https://cdn.kinopipe.com/…",
      "contentType": "video/mp4",
      "byteSize": 437021,
      "filename": "output.mp4"
    }],
    "runtimeMs": 2501
  }
}

Supported operations

TypeFieldsPurpose
trimstart, end?Cut a time range in seconds.
resizewidth, height, fit?Scale and cover or contain the output frame.
thumbnail—Return one JPG or WebP frame.
subtitlesurl or inputBurn a public SRT or WebVTT file into the video.
cropaspectRatio, focusRemove edges to match a social aspect ratio.
giffps, width, maxColorsGenerate a palette-optimized animated GIF.
remove_audio—Remove every audio stream from a video output.
add_audioinput, mode, volumes, loopMix or replace the soundtrack with a named audio input.
concatinputs, width, heightNormalize and join two to six clips.
watermarkinput, position, width, opacityOverlay a named image input.
picture_in_pictureinput, position, widthOverlay a named video input.
splitsegmentDuration, maxSegmentsReturn up to 50 independently playable MP4 files.
Safe retries with idempotency

Send a stable Idempotency-Key when retrying the same edit. A repeated key returns the existing job with HTTP 200 and does not run or bill it twice.

PREBUILT TOOLS

Focused endpoints with useful defaults

Every tool accepts named inputs, options and an optional webhook. The same presets can be tested by a human on their public tool pages.

POST/api/v1/tools/{slug}
ToolOptionsOpen
compress-videoCompress videoquality: fast | balanced | qualityTry
video-to-mp4Video to MP4No options requiredTry
resize-videoResize videoaspect_ratio: 9:16 | 1:1 | 16:9 · fit: cover | containTry
extract-audioExtract audioformat: mp3 | wavTry
video-thumbnail-generatorGenerate thumbnailstimestamp: number · format: jpg | webpTry
add-subtitles-to-videoBurn subtitlesinputs: main video + captions (SRT or WebVTT)Try
trim-videoTrim videostart: number · end: numberTry
optimize-video-for-webOptimize for webquality: fast | balanced | qualityTry
merge-videosMerge videosinputs: 2–6 videos · aspect_ratio: 9:16 | 1:1 | 16:9Try
add-watermark-to-videoAdd watermarkinputs: video + watermark · position · width · opacityTry
picture-in-picture-videoPicture in pictureinputs: main + pip video · position · widthTry
create-social-video-clipSocial video clipstart · end · aspect_ratio · fitTry
add-music-to-videoAdd musicinputs: main + music · mode · music_volume · source_volumeTry
convert-video-to-gifVideo to GIFstart · duration (max 30s) · fps · widthTry
crop-videoCrop videoaspect_ratio: 9:16 | 1:1 | 4:5 | 16:9 · focusTry
remove-audio-from-videoRemove audioNo options requiredTry
split-videoSplit videosegment_duration: 1–3600 seconds · max 50 outputsTry
WEBHOOKS

Receive signed terminal job events

Attach a webhook to any job or prebuilt tool request. KinoPipe sends a signed POST after the job reaches succeeded or failed.

Eventsjob.succeeded · job.failed
SignatureHMAC-SHA256
Timeout5 seconds

Add a webhook to the request

{
  "inputs": [{ "id": "main", "url": "https://example.com/source.mp4" }],
  "options": { "start": 0, "end": 12 },
  "webhook": {
    "url": "https://api.example.com/webhooks/kinopipe",
    "secret": "replace-with-at-least-16-characters",
    "events": ["job.succeeded", "job.failed"]
  }
}

Payload

{
  "id": "6f0462da-…",
  "event": "job.succeeded",
  "createdAt": "2026-08-24T14:42:18.000Z",
  "data": {
    "job": {
      "id": "f7541d5e-…",
      "status": "succeeded",
      "consumedCredits": 3
    },
    "result": {
      "output": { "downloadUrl": "https://cdn.kinopipe.com/…" },
      "runtimeMs": 2501
    }
  }
}

Verify the signature

Read the raw request body. Compute HMAC-SHA256 over timestamp.rawBody and compare it with the v1 value.

import { createHmac, timingSafeEqual } from "node:crypto"

export function verifyKinoPipeWebhook(rawBody, signatureHeader, secret) {
  const fields = Object.fromEntries(
    signatureHeader.split(",").map((part) => part.split("=")),
  )
  const expected = createHmac("sha256", secret)
    .update(`${fields.t}.${rawBody}`)
    .digest("hex")

  const received = Buffer.from(fields.v1 ?? "", "hex")
  const computed = Buffer.from(expected, "hex")

  return received.length === computed.length
    && timingSafeEqual(received, computed)
}
HeaderValue
X-KinoPipe-Eventjob.succeededThe event type.
X-KinoPipe-DeliveryUUIDUse it to deduplicate deliveries.
X-KinoPipe-Signaturet=…,v1=…Timestamp and HMAC signature.
Public HTTPS targets only

KinoPipe rejects credentials in URLs, non-standard ports, local hostnames and private network addresses. A failed callback never changes a successful media job into a failed one.

CREDITS

Pay for measured work

One credit covers one worker second or 6 MiB of output. Successful jobs use whichever rounded-up total is higher, with a one-credit minimum.

Free account100 credits once
Credit pack1,000 for $9, once
Starter1,500 / month
Developer5,000 / month
Pro25,000 / month
Hard stop at zero

KinoPipe checks the balance before processing and returns HTTP 402 with insufficient_credits. There are no automatic overages.

ERRORS

Stable HTTP status and error codes

Every error response includes an error code. Validation errors may also include a structured issues array.

StatusCodeMeaning
400invalid_recipe · invalid_tool_request · invalid_webhookThe request contract or webhook target is invalid.
401unauthorizedThe API key is missing, invalid or revoked.
402insufficient_creditsNo processing credits remain.
404tool_not_availableThe requested preset is not executable.
503queue_unavailableThe job could not be placed on the render queue.
{
  "error": "invalid_webhook",
  "message": "Webhook URL must resolve only to public addresses"
}
REFERENCE

Machine-readable API contract

Use the OpenAPI 3.1 document to generate clients, agent tools or validation schemas from the same public contract.

openapi.json
Canonical endpoints, schemas, response codes and webhook configuration.