Minvo API and MCP Guide: Edit Video Clips with AI Agents and Code

Minvo API and MCP Guide: Edit Video Clips with AI Agents and Code

Minvo's API and MCP server let your own tools and AI agents upload videos, turn them into captioned clips and edit those clips with plain-language prompts, without opening Minvo Studio.

How it fits together

MCP and REST are two doors to the same services, as the diagram above shows. An edit made by your agent behaves exactly like the same edit made by your script, costs the same tokens, and shows up in Studio.

Get access

API and MCP access comes with every monthly or annual Pro and Pro+ plan. Lifetime (LTD) Pro and Pro+ accounts unlock it with a one-time $199.99 add-on.

Plan API and MCP Monthly tokens
Pro, monthly or annual Included 500
Pro+, monthly or annual Included 1,500
LTD Pro $199.99 one-time add-on 500
LTD Pro+ $199.99 one-time add-on 1,500
Free, Creator, LTD Creator Not available —

Create an API key

  1. In Minvo Studio, open Settings → API keys. On an LTD plan, click Unlock API and MCP: $199.99 first.
  2. Click Create key, give it a name (for example "Claude Code") and choose its scope: read (look only) or write (upload, edit, render).
  3. Copy the key now. It starts with mnv_ and is shown only once; Minvo stores only a hash of it.
  4. Keep it secret, like a password. An organization has one active key at a time: to replace it (or if it leaks), revoke it on the same page and create a new one. Only organization admins can create or revoke keys.

A key acts only inside your organization and stops working if its creator leaves the organization or deletes their account.

Connect over MCP

Minvo's MCP server is at https://be.minvo.pro/api/mcp (Streamable HTTP). Your agent sends your key in an Authorization: Bearer mnv_… header, and from then on you just ask it for what you want.

Claude Code

claude mcp add --transport http minvo https://be.minvo.pro/api/mcp \
  --header "Authorization: Bearer mnv_YOUR_KEY"

Run /mcp inside Claude Code to check that minvo shows as connected.

Cursor (.cursor/mcp.json in your project, or ~/.cursor/mcp.json for all projects)

{
  "mcpServers": {
    "minvo": {
      "url": "https://be.minvo.pro/api/mcp",
      "headers": { "Authorization": "Bearer mnv_YOUR_KEY" }
    }
  }
}

Your own agent (TypeScript, @modelcontextprotocol/sdk)

import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"

const transport = new StreamableHTTPClientTransport(new URL("https://be.minvo.pro/api/mcp"), {
  requestInit: { headers: { Authorization: `Bearer ${process.env.MINVO_API_KEY}` } },
})
const client = new Client({ name: "my-agent", version: "1.0.0" })
await client.connect(transport)

const brands = await client.callTool({ name: "list_brands", arguments: {} })

Hosted connectors (claude.ai, ChatGPT) aren't supported yet; use Claude Code, Cursor or your own agent.

The 21 tools your agent gets

Tool Access What it does
list_brands read The brands (shows) you can upload to
import_video write Import a YouTube or Vimeo link
create_video_upload write Get an upload target for a local file
refresh_video_upload write A fresh upload target for a video still awaiting its file
process_video write Transcribe a video and make clips
list_videos read A brand's videos, newest first
get_video_status read One video and where it is in processing
get_transcript read The transcript as JSON, SRT or plain text
list_clips read A video's clips
create_clip write A clip over a time range you choose
get_clip read A clip's current edits, words, jobs and revision
edit_clip write Apply edit operations to a clip
reset_clip write Undo edits, like Studio's Reset moment
get_edit_options read Every operation, font, layout, language and token price
get_token_balance read Tokens left this month and from packs
search_media read Stock images, videos, GIFs, stickers and sound effects
save_template write Save a clip's style as a brand template
preview_clip write A quick 360p preview render
render_clip write A full-quality render (1080p, or 4K on Pro+)
get_render read Render status and its download link
get_job read Status of an async job (audio enhancement, dubbing)

A read-only key can use only the read tools.

Uploading a file from your computer. If your agent can't send files itself, open the uploadHandoffUrl that create_video_upload returns: a Studio page that uploads your file into the video the agent reserved. If an upload broke off or its target expired, refresh_video_upload continues the same video rather than creating a second one.

REST quick start

The REST API lives at https://be.minvo.pro/api/v1, uses camelCase JSON, and has interactive docs at https://be.minvo.pro/api/v1/docs. Every call carries Authorization: Bearer mnv_…. The walk-through below takes one video from link to downloaded clip.

export MINVO=https://be.minvo.pro/api/v1
export KEY="Authorization: Bearer mnv_YOUR_KEY"

1. Check your key and pick a brand.

curl -H "$KEY" $MINVO/me
curl -H "$KEY" $MINVO/brands
# {"brands":[{"id":42,"name":"My Podcast","imageUrl":null}]}

2. Add a video. Import a YouTube or Vimeo link:

curl -X POST -H "$KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: import-ep-118" \
  -d '{"brandId":42,"url":"https://www.youtube.com/watch?v=VIDEO_ID"}' \
  $MINVO/videos/import
# {"video":{"id":9001,"status":"uploaded",...},"deduplicated":false}

Or upload a local file in one request (.mp4, .m4v, .mov or .webm; the form fields go before file):

curl -X POST -H "$KEY" \
  -F brandId=42 -F title="Episode 118" -F file=@episode-118.mp4 \
  $MINVO/videos/upload-file

For very large files, POST /videos/uploads returns a resumable (TUS) upload target instead, and POST /videos/{id}/upload gives a fresh one for the same video if it expired or the upload broke off.

3. Process it into clips. auto makes suggested clips for long videos and one full-length captioned clip for videos under 2 minutes. clipDefaults are edits applied to every clip as it's built.

curl -X POST -H "$KEY" -H "Content-Type: application/json" \
  -d '{"mode":"auto","clipDefaults":[
        {"op":"set_aspect_ratio","ratio":"9:16"},
        {"op":"remove_silences","minSilenceMs":700}]}' \
  $MINVO/videos/9001/process

Use "mode":"captions_only" to always get one full-length clip, or "clips" to ask for suggestions.

4. Wait until it's ready, then list the clips. Poll every 15–30 seconds until status is ready, then list clips. Each clip's draftStatus turns ready once its edits are built.

curl -H "$KEY" $MINVO/videos/9001
curl -H "$KEY" $MINVO/videos/9001/clips

5. Edit a clip. Read it first to get its revision, then send operations with that revision:

curl -H "$KEY" $MINVO/clips/555          # "revision": 3

curl -X POST -H "$KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: clip555-captions-v1" \
  -d '{"expectedRevision":3,"ops":[
        {"op":"set_captions","textColor":"#FFFF00","y":1500},
        {"op":"magic_emojis","position":"above"}]}' \
  $MINVO/clips/555/edits

All operations in one call apply together or not at all. If someone changed the clip since you read it, you get 409 with the current revision: read again and resend.

6. Render and download. Start a preview (360p) or a full render, poll it, then download:

curl -X POST -H "$KEY" -H "Content-Type: application/json" \
  -d '{"quality":1080}' $MINVO/clips/555/renders
# {"id":31,"status":"queued",...}

curl -H "$KEY" $MINVO/renders/31
# {"status":"complete","downloadUrl":"https://be.minvo.pro/api/v1/renders/31/download?expires=...&signature=..."}

curl -L -o clip-555.mp4 "DOWNLOAD_URL"

The download link needs no key and works for one hour; ask GET /renders/{id} again for a fresh one.

Other useful endpoints

Method and path What it does
GET /videos?brandId=42 A brand's videos, newest first (page, pageSize up to 100)
GET /videos/{id}/transcript?format=srt The transcript as json, srt or txt
POST /videos/{id}/clips A custom clip: {"startMs":60000,"endMs":95000}
POST /clips/{id}/reset Undo edits back to the clip's original state, then re-apply the video's defaults
POST /clips/{id}/previews A 360p preview render
GET /jobs/{id} An async job (audio enhancement, dubbing)
GET /edit-options?brandId=42 Everything you can pass to edits: ops, fonts, layouts, music, languages, token prices
GET /media/search?type=gif&query=wow Stock images, videos, GIFs, stickers and sound effects
GET or POST /brands/{id}/templates List templates, or save a clip's style as one: {"clipId":555,"name":"Yellow bold"}
GET /tokens Your token balance

Edit operations

Every edit Studio offers is an operation (op) you send to POST /clips/{id}/edits or the edit_clip tool, up to 50 per call. Times are in milliseconds on the original video's timeline, colours are #RRGGBB (or #RRGGBBAA), and media is given as {"url":"https://…"}.

Area Operations
Format and style set_aspect_ratio (9:16, 1:1, 16:9), apply_template, set_background, set_border, set_footer
Captions set_captions, set_caption_animation, edit_words, set_line_breaks
Title set_title, regenerate_title (AI)
Framing and camera set_framing (contain, center, split), set_camera_layout, set_camera_filter, set_camera_animation, set_main_media
Cuts trim, remove_silences, remove_fillers, remove_repetitions, add_jump_cut, undo_cuts
Hooks and energy super_hook_intro, video_pulse (and their revert_ ops)
Overlays add_overlay (text, emoji, image, video, GIF or sound), update_overlay, remove_overlay
Branding set_logo, set_intro, set_outro
Audio set_background_music, auto_music, set_main_volume, set_audio_track, enhance_audio (async)
Language translate_captions (AI), select_translation, dub (async)
AI magic magic_emphasis, magic_emojis, emoji_for_text, magic_broll, magic_sounds, ai_image

GET /edit-options (or get_edit_options) lists every op with its allowed values, the fonts, camera layouts, music library and languages, and which ops your plan can use.

Examples

Yellow, bold, upper-case captions near the bottom of a 9:16 clip, with the active word highlighted (pick a bold font name from get_edit_options):

[
  {"op": "set_aspect_ratio", "ratio": "9:16"},
  {"op": "set_captions", "fontFamily": "<a bold font from get_edit_options>", "textColor": "#FFFF00",
   "strokeWidth": 4, "strokeColor": "#000000", "textCase": "uppercase", "y": 1500, "lines": 2},
  {"op": "set_caption_animation", "wordAnimation": "biggerFontWhenActive", "activeTextColor": "#FFFFFF"}
]

Tighten the pacing:

[
  {"op": "remove_silences", "minSilenceMs": 500},
  {"op": "remove_fillers"},
  {"op": "super_hook_intro", "zoomType": "short", "soundEffect": "swoosh_hit"}
]

Split-screen for an interview section, picture-in-picture elsewhere:

[
  {"op": "set_camera_layout", "startMs": 12500, "endMs": 17500, "camera": {"layout": "split"}},
  {"op": "set_camera_layout", "startMs": 17500, "endMs": 20000,
   "camera": {"layout": "PiP", "pipPosition": "bottomRight"}}
]

Branding, a text callout and music:

[
  {"op": "set_logo", "slot": 1, "media": {"url": "https://example.com/logo.png"}, "x": 820, "y": 80, "zoom": 0.5},
  {"op": "add_overlay", "startMs": 3000, "endMs": 6000,
   "content": {"type": "text", "text": "Link in bio", "textColor": "#FFFFFF", "backgroundColor": "#7C3AED"}},
  {"op": "auto_music", "genre": "upbeat"},
  {"op": "set_outro", "key": "ContinueOnYouTube"}
]

AI edits (these use tokens):

[
  {"op": "magic_emphasis"},
  {"op": "magic_emojis", "position": "above"},
  {"op": "magic_broll", "format": "gif", "position": "above"},
  {"op": "regenerate_title", "style": "question"},
  {"op": "translate_captions", "language": "de-DE"}
]

Rules worth knowing

  • Plans: ai_image, magic_broll with ai_img, dub and 4K renders need Pro+. enhance_audio needs the studio-audio feature.
  • AI limit: at most 5 AI operations per call.
  • Async ops: enhance_audio and dub start a job and the call returns 202. Follow it with GET /jobs/{id} or get_job. If you change the audio track while it runs, the result is kept but not selected (applied: false); pick it later with set_audio_track.
  • trim: it changes the clip's range and resets its translations, dubs and enhanced audio.
  • AI framing: set_framing with "mode":"ai" currently returns 422 framing_unavailable; use center, contain or split.
  • Media: media by uploaded asset (assetId) and named caption or title presets aren't available yet (501). Pass a media url and explicit style fields instead.

Prompt examples

With the MCP server connected, you talk to your agent in plain language. It reads the clip (get_clip) and the options (get_edit_options), picks the operations and applies them with edit_clip. Being specific about colours, positions and times gets you closer on the first try.

From a link to finished clips

Import https://www.youtube.com/watch?v=VIDEO_ID into my "My Podcast" brand, process it into clips, and when they're ready list the five clips with the strongest hooks.

Tools: list_brands → import_video → process_video → get_video_status (polled) → list_clips.

Process video 9001 so every clip is 9:16 with silences removed and yellow captions.

Tools: process_video with clipDefaults: set_aspect_ratio, remove_silences, set_captions.

Style and captions

Prompt What the agent sends
"Make clip 555 vertical with yellow bold captions at the bottom." set_aspect_ratio 9:16, set_captions with a bold font from the options, textColor #FFFF00, y near the bottom
"Captions in upper case, two lines max, and make the spoken word pop." set_captions textCase uppercase, lines 2; set_caption_animation wordAnimation biggerFontWhenActive
"Highlight the important words in our brand purple." magic_emphasis with colors ["#7C3AED"] (1 token)
"Fix the caption at 0:42: it should say 'Kubernetes', not 'Cuban eighties'." edit_words over that time range
"Apply my 'Yellow bold' template." apply_template with the template's id

Pacing and structure

Prompt What the agent sends
"Remove silences and filler words." remove_silences, remove_fillers
"Cut it down to 0:10–0:55 of the video." trim startMs 10000, endMs 55000
"Open with a hook: quick zoom and a swoosh." super_hook_intro zoomType short, soundEffect swoosh_hit
"Add some energy, punch-in on short sentences." video_pulse frequency shortSentences, intensity energetic

Layout and framing

Prompt What the agent sends
"Split layout for the interview part, picture-in-picture for the rest." Several set_camera_layout ops with split and PiP over the matching time ranges
"Keep both speakers in frame." set_framing split
"Show the whole frame with a blurred background." set_framing contain, set_background videoBlur

Overlays, B-roll and branding

Prompt What the agent sends
"Add emojis and B-roll." magic_emojis, magic_broll (1 token each)
"Put a 'mind blown' GIF over the moment he says 'wow'." get_clip to find the word's time, search_media gif, then add_overlay with that GIF
"Add my logo top-right: https://example.com/logo.png" set_logo slot 1, that media url, x, y, zoom
"Show 'Link in bio' for the last 3 seconds." add_overlay with text content over the clip's last 3 s
"Generate an image of a rocket launching for 0:05–0:08." ai_image with that prompt and range (Pro+, 8 tokens)
"Add upbeat background music, quiet." auto_music upbeat, then set_background_music volume 20
"End with the 'Continue on YouTube' outro." set_outro key ContinueOnYouTube

Language and audio

Prompt What the agent sends
"Translate the captions to German and dub it." translate_captions de-DE (4 tokens a minute), dub de-DE (async; the agent follows it with get_job)
"Clean up the audio, it's noisy." enhance_audio (async, 1 token a minute)
"Switch back to the original audio." set_audio_track original
"Give it a catchier title, as a question." regenerate_title style question

Finishing

Render a quick preview of clip 555, and if it looks fine render it in 1080p and give me the download link.

Tools: preview_clip → get_render (polled) → render_clip → get_render → the downloadUrl.

Save clip 555's style as a template called "Yellow bold" and apply it to every other clip from this video.

Tools: save_template → list_clips → edit_clip with apply_template for each clip.

How many tokens do I have left, and what would adding emojis and B-roll to all 8 clips cost?

Tools: get_token_balance and get_edit_options (token prices). The answer: 2 tokens per clip, 16 in total.

Tips for better results

  • Name the clip: say which clip you mean (by number, title or "the one about pricing"); the agent can find it with list_clips.
  • Use the timeline: give times as they appear in the video ("at 2:15"). Agents convert them to milliseconds.
  • Ask for a preview first: a 360p preview is quick and doesn't count against your exports.
  • Batch related changes: one prompt with several changes becomes one edit_clip call that applies all or nothing.

Tokens

AI and heavy-compute edits made through the API or MCP spend tokens. Everything else is free: uploads, transcription, clips, normal edits, renders and dubbing. Studio is never charged tokens.

Operation Tokens
ai_image (AI-generated image) 8 per image
magic_broll with AI images 8 per image
translate_captions 4 per started clip minute
enhance_audio 1 per started clip minute
set_framing with ai 1 per started clip minute, once AI framing is available
magic_broll (GIF, stock image or video search) 1
magic_emphasis, magic_emojis, emoji_for_text, magic_sounds, regenerate_title 1 each

A started minute is rounded up: a 61-second clip counts as 2 minutes.

Where tokens come from

  • Monthly tokens: 500 on Pro and 1,500 on Pro+ (LTD included). They reset on the 1st of each month, 00:00 UTC, and don't roll over.
  • Token packs: $10 for 1,000 tokens or $20 for 3,000 tokens, from Settings → API keys → Buy tokens. Pack tokens never expire.
  • Monthly tokens are spent first, then pack tokens.

How charging works

  • An edit that needs tokens reserves them before it runs. If you don't have enough, it's refused with 402 tokens_exhausted and nothing runs.
  • Instant AI edits are charged when the edit saves. Async jobs (audio enhancement, AI framing) are charged only if the job succeeds; a failed or cancelled job gives its tokens back.
  • A charge always uses the price at the moment you sent the request.

Check your balance with GET /api/v1/tokens or the MCP tool get_token_balance. The edit options (get_edit_options) list each operation's current price, so an agent can tell you the cost before it spends.

Errors, limits and retries

Every error has the same body; switch on code, not on the message. Over MCP, the tool result carries the same body with isError: true.

{"statusCode": 402, "error": "Payment Required", "code": "tokens_exhausted",
 "message": "...", "details": {"cost": 8, "monthlyLeft": 0, "purchasedLeft": 3, "monthlyResetsOn": "2026-11-01T00:00:00.000Z"}}
Status code What to do
401 missing_api_key, invalid_api_key Send Authorization: Bearer mnv_…; create a new key if it was revoked
402 plan_required Upgrade, or unlock the add-on on an LTD plan; also returned for Pro+-only ops
402 tokens_exhausted Buy a token pack or wait for the monthly reset (details shows the cost and what's left)
403 insufficient_scope The key is read-only; use a write key
404 not_found The id doesn't exist or isn't in your organization
409 conflict The clip changed: GET it again and resend with details.revision. Also returned while a video is still uploading or already processing
409 job_in_progress That clip already has the same async job running; wait for it
413 / 415 payload_too_large, unsupported_media_type File over your plan's size limit, or not .mp4, .m4v, .mov or .webm
422 validation_error A field is wrong; details lists each problem
422 idempotency_mismatch You reused an Idempotency-Key with a different request
422 framing_unavailable, op_unavailable That operation isn't available right now
429 rate_limited Too many calls this minute; wait for Retry-After seconds
429 concurrency_limit Your organization already has the maximum jobs running; retry when one finishes
501 not_implemented Not available yet (uploaded-asset media, named presets)

Limits

Limit Value
Reads per key 60 per minute
Writes per key 20 per minute (each AI op counts as one more)
MCP requests per key 120 per minute
Videos processing at once, per organization 3
Renders and previews at once, per organization 5
File uploads at once, per organization 3
Operations per edit call 50, of which at most 5 AI
Download link lifetime 1 hour

Retry safely with Idempotency-Key

Networks drop requests. Send an Idempotency-Key header (any unique string up to 128 characters, for example a UUID) on imports, uploads and edits; MCP tools take it as idempotencyKey.

  • Same key, same request: you get the first answer back, and nothing runs or is charged twice. Edit keys are kept for 24 hours.
  • Same key, different request: 422 idempotency_mismatch.
  • First request still running: 409. Wait a moment and retry.
  • First request failed: nothing was kept, so retrying with the same key runs it again.

Use a new key for each new change, and the same key only for retries of that change.

Paste a YouTube Link to Try Minvo