Skip to main content

Cutting long videos into clips

A long video (stream, podcast, webinar) → ready vertical clips with captions and a posting pack. The same pipeline as the bot and the web studio: the price is settled on actual duration, and on failure the estimate is fully refunded. All calls carry X-API-Key: pp_..., except file downloads (the signed link itself is the credential).

Base URL: https://api.piratepress.fun/public/v1.

Step 1. Probe a URL — POST /clips/probe​

curl -X POST https://api.piratepress.fun/public/v1/clips/probe \
-H "X-API-Key: pp_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://youtube.com/watch?v=..."}'
{ "duration_s": 3720.0, "title": "AI podcast", "estimated_cost": 240 }

This is an estimate: the order charges it up front, and after cutting the actual cost is settled (the difference is refunded or charged). A broken, private, or 18+ URL returns 422 invalid_params, not 500.

Step 2. Order the cut — POST /clips​

The Idempotency-Key header is mandatory (without it 400, someone else's key — 409 idempotency_conflict). Repeating with your own key returns the original order with no second charge (200 instead of 201).

curl -X POST https://api.piratepress.fun/public/v1/clips \
-H "X-API-Key: pp_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: clips-order-0001" \
-d '{
"source_url": "https://youtube.com/watch?v=...",
"estimated_seconds": 3720,
"lang": "en",
"top_n": 5,
"captions": true,
"split_layout": 50,
"split_bottom_preset": "lofi_game",
"banner_asset_id": "ast_...",
"banner_rules": "show twice in a row from the middle, with pause"
}'

Body (PublicClipOrderCreate):

FieldTypeDefaultMeaning
source_urlstring—Video URL (http/https, yt-dlp). Exactly one of source_url/source_asset_id is required
source_asset_idstring—Source from the media library (id from GET /assets)
estimated_secondsnumber0Duration hint for the price preview (see probe)
langstring"en"Language of captions and metadata
top_nint 1–50allHow many top clips to return
captionsbooltrueEmbedded captions
split_layout0/33/50/600Split view: % of the top slot (content + bottom filler)
split_bottom_presetstring—Preset for the split bottom (id from the generator catalog)
smart_cropboolfalseSmart 3-slot crop for streams; requires split_layout: 33
banner_asset_idstring—Ready offer banner (library asset) overlaid on the clips
banner_rulesstring—Show conditions as text: timings, loops, schedule
uniquifyoff/soft/strong/custom"off"Clip uniquifying (anti-shadowban): invisible frame/audio tweaks against platform dedupe. +30 🪙 for any mode ≠ off
uniquify_optsobject—Required with custom: toggles mirror/speed/pitch/zoom/hue/grain (bool)
variantsint 1–51Versions of each clip (clip_01.mp4, clip_01_v2.mp4…); +10 🪙 per extra version
resolutionstring"720x1280"Clip vertical resolution: 720x1280 or 1080x1920
caption_fontstring—Caption font: pool name (montserrat/inter/bebas/oswald/rubik/manrope/golos) or asset:<id> of an own font (font asset)
caption_colorstring—Main caption color, hex #RRGGBB
caption_hot_colorstring—Current-word color, hex
caption_highlight_colorstring—Karaoke highlight color, hex
caption_positionstring—top/center/bottom

If no caption fields are sent, the account caption style applies (the user's font/palette; new accounts get a random one, so clips from different users don't look stamped by one pipeline).

Response 201:

{ "id": "ord_a1b2c3", "status": "queued", "cost": 240, "eta_seconds": 900 }

Clip orders share the same quota as videos: 10 active tasks per key combined (see Error codes).

Step 3. Pick up the result — GET /clips/{id}​

curl https://api.piratepress.fun/public/v1/clips/ord_a1b2c3 \
-H "X-API-Key: pp_..."

While running, the response carries stage/stage_detail ("Cutting clips", "3/12"). When status: "done":

{
"id": "ord_a1b2c3",
"status": "done",
"title": "AI podcast",
"clips": [
{
"name": "clip_01.mp4",
"title": "Why AI won't replace editors",
"url": "https://api.piratepress.fun/public/v1/clips/files/eyJ...",
"description": "…",
"hashtags": ["ai", "podcast"]
}
],
"zip_url": "https://api.piratepress.fun/public/v1/clips/files/eyJ...",
"estimated_cost": 240,
"actual_cost": 236,
"created_at": "2026-10-19T12:00:00Z",
"finished_at": "2026-10-19T12:20:00Z"
}

Statuses: queued|running|done|error|refunded. On error/refunded the estimate is back on your balance. The url/zip_url links are signed (HMAC, 7-day TTL) and need no key to download:

curl -L -o clips.zip "<zip_url>"

Rather not poll? Subscribe to clip.done/clip.error: Webhooks.

List clip orders — GET /clips​

curl "https://api.piratepress.fun/public/v1/clips?limit=20&offset=0" \
-H "X-API-Key: pp_..."

Newest first; each row: id, status, title, source_url, is_file, clips_count, cost (actual after done, estimate before), created_at, error.

AI banner for clips​

POST /clips/banner generates a banner from a description (priced like the AI banner in video generation: trial/adveristor quota/doubloons):

curl -X POST https://api.piratepress.fun/public/v1/clips/banner \
-H "X-API-Key: pp_..." \
-H "Content-Type: application/json" \
-d '{"prompt": "headphone store banner, neon, dark background", "lang": "en"}'
# → { "job_id": "ban_...", "cost": 50 }

GET /clips/banner/{job_id} polls the job: on done the response has an asset_id (the asset lands in your media library — pass its id as banner_asset_id of the clip order); on error the doubloons are refunded automatically. The body may optionally carry source_asset_id — a source pack from the media library for the generator's VIP mode.

Where next​

  • Quickstart — the general order/status flow;
  • Webhooks — clip.done/clip.error instead of polling;
  • Error codes — the {error: {code, message}} envelope.