Clipora — Custom AI Video Creation
API Reference · v1.0

Clipora API

Programmatically turn long videos into face-aware, captioned 9:16 reels. REST endpoints for upload, job status, and clip download.

Base URL: https://your-host/api JSON over HTTP Cookie auth

Quickstart

Three calls: generate a key → upload → fetch clips.

  1. STEP 1 · Generate an API key

    Sign in, then visit /keys to create a key. Format: ck_live_…. The plaintext is shown ONCE — store it as $CLIPORA_API_KEY.

    # Export the key into your shell so the examples below pick it up
    export CLIPORA_API_KEY="ck_live_AbCdEf...your-key-here"
  2. STEP 2 · Upload a video
    curl -X POST https://your-host/api/upload \
      -H "X-API-Key: $CLIPORA_API_KEY" \
      -F "video=@/path/to/video.mp4" \
      -F 'options={"numClips":3,"captionPreset":"mozi","aspectRatio":"9:16"}'
    
    # → {"jobId":"abc123…","wsUrl":"/ws?jobId=abc123…",...}
  3. STEP 3 · Wait for completion, then fetch clips
    # Poll job status, then fetch clips when status is completed
    curl https://your-host/api/jobs/abc123 \
      -H "X-API-Key: $CLIPORA_API_KEY"
    
    curl https://your-host/api/clips/abc123 \
      -H "X-API-Key: $CLIPORA_API_KEY"

Authentication

Protected API routes require authentication. Use an API key for server-to-server calls (Business plan), or the session cookie from the login pages for browser apps. Public routes: /api/billing/plans and auth signup/login.

API key (recommended for server-to-server)

Create a key at /keys. Pass it as either of:

X-API-Key: ck_live_AbCdEf...your-key-here
# or, equivalently:
Authorization: Bearer ck_live_AbCdEf...your-key-here
  • Keys are 256-bit random tokens, SHA-256 hashed at rest — the plaintext is shown once at creation
  • Up to 10 active keys per account; revoke unused ones from /keys
  • Revoked or wrong keys return 401 immediately (no fallback)
  • API keys cannot manage other keys, billing checkout, or billing portal — session only
  • Upload/jobs/clips/downloads are scoped to your account; clip files cannot be read without auth
  • /ws?jobId=… requires the same auth (cookie or X-API-Key) and job ownership
  • Keep keys secret — never commit them to git or expose them in frontend JavaScript

Cookie session (browser-side apps)

The login pages set a httpOnly cookie named reels_session, automatically sent by any browser on same-origin requests. Use this for in-browser apps and dashboards; use API keys for everything else.

Errors

All errors return JSON with an error field:

{ "error": "video file required" }
400 Bad request / missing field
401 Not authenticated
403 Forbidden (not your resource)
404 Resource not found
409 Conflict (e.g. email exists)
413 Upload too large
500 Internal server error
503 Pipeline unavailable

Upload API

POST /api/upload

Upload a video file (multipart/form-data). The response includes a jobId — poll GET /api/jobs/{jobId} until the job completes.

FieldTypeRequiredDescription
videofileRequiredVideo file. Up to 1 GB by default. MP4 / MOV / MKV / WEBM accepted.
optionsstring (JSON)OptionalJSON-encoded ProcessOptions (see table below).
ProcessOptions (all keys optional)
KeyTypeDefaultDescription
mode"ai" | "none""ai"ai = pick viral moments; none = one full-source clip.
numClipsinteger3Clips to generate. Range 1–10.
clipLength"short" | "medium" | "long""medium"3–15 s · 20–45 s · 45–90 s.
aspectRatio"9:16" | "1:1" | "4:5" | "16:9""9:16"Output dimensions.
captionPreset"none" | "beasty" | "karaoke" | "mozi""none"Burned-in caption style. See presets reference.
removeAiVoicebooleantrueSplice out AI-host/interviewer turns when the source is an interview.
autoHookbooleantrueLet Gemini write a punchy hook + title + hashtags.
promptstring""Free-form instruction, e.g. "Focus on moments about hiring."
genrestring"auto""podcast" | "interview" | "vlog" | "tutorial" | "auto".
trimStartnumber (seconds)0Cut the source before this timestamp before analyzing.
trimEndnumber (seconds)nullCut the source after this timestamp.
Response 200
{
  "jobId":        "K3pX9aB2mZ",
  "originalName": "interview.mp4",
  "sizeBytes":    82345677,
  "wsUrl":        "/ws?jobId=K3pX9aB2mZ",
  "options":      { /* what the server actually used */ }
}
POST /api/upload/url

Submit a video by URL. Direct media links (.mp4 / .mov) stream-download; site-hosted links (YouTube, TikTok, Instagram, Twitter, Twitch — ~1000 sites) are fetched via yt-dlp. Returns immediately with a jobId while the video downloads in the background — poll GET /api/jobs/{jobId} for status.

FieldTypeRequiredDescription
urlstringRequiredPublic HTTP/HTTPS URL to the video.
optionsobjectOptionalSame shape as /api/upload's options.
curl -X POST https://your-host/api/upload/url \
  -H "Content-Type: application/json" -H "X-API-Key: $CLIPORA_API_KEY" \
  -d '{"url":"https://youtube.com/watch?v=…","options":{"numClips":4}}'

Jobs API

GET /api/jobs

List all jobs for the current user, newest first.

Response
{
  "jobs": [
    {
      "id":           "K3pX9aB2mZ",
      "originalName": "interview.mp4",
      "status":       "completed",
      "createdAt":    1734567890000,
      "clipCount":    3,
      "posterUrl":    "/api/clips/K3pX9aB2mZ/clip_01.jpg"
    }
  ]
}
Status values: queued · downloading · processing · completed · failed
GET /api/jobs/{jobId}

Fetch a single job's status + metadata.

Clips API

GET /api/clips/{jobId}

Get the generated-clips manifest for a job. Returns 404 until the job is completed.

Response
{
  "jobId": "K3pX9aB2mZ",
  "duration": 312.4,
  "clipCount": 3,
  "clips": [
    {
      "index":        1,
      "start":        52.4,
      "end":          71.1,
      "duration":     18.7,
      "score":        9.1,
      "transcript":   "Here's the thing nobody tells you…",
      "downloadUrl":  "/api/clips/K3pX9aB2mZ/clip_01.mp4",
      "posterUrl":    "/api/clips/K3pX9aB2mZ/clip_01.jpg",
      "aspectRatio":  "9:16",
      "metadata": {
        "title":            "The hiring myth nobody talks about",
        "viral_hook":       "Stop interviewing for skills.",
        "key_insight":      "Hire for slope, not intercept.",
        "dominant_emotion": "excitement",
        "hashtags":         ["hiring", "startups", "interview"],
        "viral_score":      9.1
      }
    }
  ]
}
GET /api/clips/{jobId}/{filename}

Stream a generated artifact. Allowed filenames: clip_NN.mp4 (rendered clip), clip_NN.jpg (poster), clip_NN.ass (caption track), manifest.json (the manifest above). Served with long-lived cache headers.