{
  "openapi": "3.0.3",
  "info": {
    "title": "TrimTake API",
    "version": "1.0.0",
    "description": "Clean a talking-head recording (filler words and dead air removed) and get back a clean video, a clean MP3 and captioned 9:16 clips. Available on every plan, including Free. Keys: https://trimtake.com/account/api. Docs: https://trimtake.com/developers. MCP server: https://trimtake.com/api/mcp",
    "contact": { "email": "support@trimtake.com", "url": "https://trimtake.com/developers" }
  },
  "servers": [{ "url": "https://trimtake.com/api/v1" }],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "videos", "description": "Cleanup jobs" },
    { "name": "clips", "description": "Captioned 9:16 clips cut from the cleaned video" },
    { "name": "usage", "description": "Plan and footage allowance" }
  ],
  "paths": {
    "/videos": {
      "post": {
        "tags": ["videos"],
        "summary": "Create a cleanup job",
        "description": "Send either `url` (a direct https link to an mp4/mov/webm file; YouTube/TikTok pages are rejected) or `filename` + `duration_seconds` to receive a signed upload URL. Jobs count against the account's monthly footage allowance.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  { "$ref": "#/components/schemas/CreateFromUrl" },
                  { "$ref": "#/components/schemas/CreateUpload" }
                ]
              },
              "examples": {
                "fromUrl": { "value": { "url": "https://example.com/episode.mp4", "options": { "mode": "medium", "clips": true, "noise_removal": true } } },
                "upload": { "value": { "filename": "call.mp4", "duration_seconds": 420, "size_bytes": 83000000, "options": { "mode": "medium" } } }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job created",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/CreatedFromUrl" },
                    { "$ref": "#/components/schemas/CreatedUpload" }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "description": "Pay Per Video accounts cannot start API jobs", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "403": { "description": "Plan limit reached (monthly footage or per-video length)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "413": { "description": "File too large to fetch", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "429": { "$ref": "#/components/responses/Error" }
        }
      },
      "get": {
        "tags": ["videos"],
        "summary": "List recent jobs",
        "parameters": [{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } }],
        "responses": {
          "200": { "description": "Recent jobs", "content": { "application/json": { "schema": { "type": "object", "properties": { "videos": { "type": "array", "items": { "$ref": "#/components/schemas/JobSummary" } } } } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/videos/{job_id}": {
      "get": {
        "tags": ["videos"],
        "summary": "Get job status and outputs",
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "responses": {
          "200": { "description": "Job", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Job" } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/videos/{job_id}/start": {
      "post": {
        "tags": ["videos"],
        "summary": "Start processing after a signed-URL upload",
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "responses": {
          "202": { "description": "Started (idempotent)", "content": { "application/json": { "schema": { "type": "object", "properties": { "job_id": { "type": "string" }, "status": { "$ref": "#/components/schemas/Status" } } } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/videos/{job_id}/clips": {
      "get": {
        "tags": ["clips"],
        "summary": "List clips",
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "responses": {
          "200": { "description": "Clips", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClipsResponse" } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      },
      "post": {
        "tags": ["clips"],
        "summary": "Generate or regenerate clips",
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "type": "object", "properties": { "force": { "type": "boolean", "default": true, "description": "Re-render even if clips already exist" } } } } } },
        "responses": {
          "202": { "description": "Accepted; poll GET /videos/{job_id}/clips", "content": { "application/json": { "schema": { "type": "object", "properties": { "job_id": { "type": "string" }, "status": { "type": "string", "enum": ["processing", "ready"] } } } } } },
          "409": { "description": "Job not finished yet", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "503": { "description": "Clips temporarily unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } }
        }
      }
    },
    "/videos/{job_id}/transcript": {
      "get": {
        "tags": ["videos"],
        "summary": "Word-level transcript and cut list",
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "responses": {
          "200": { "description": "Transcript", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Transcript" } } } },
          "409": { "description": "Job not ready", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": ["usage"],
        "summary": "Plan and footage used this month",
        "responses": {
          "200": { "description": "Usage", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Usage" } } } }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "tt_live_<32 hex chars>" }
    },
    "parameters": {
      "JobId": { "name": "job_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
    },
    "responses": {
      "Error": { "description": "Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } }
    },
    "schemas": {
      "ErrorEnvelope": {
        "type": "object",
        "properties": { "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["code", "message"] } }
      },
      "Status": { "type": "string", "enum": ["queued", "processing", "ready", "failed", "rejected"] },
      "Options": {
        "type": "object",
        "properties": {
          "mode": { "type": "string", "enum": ["light", "medium", "aggressive"], "default": "medium", "description": "light = fillers only; medium = fillers + long pauses; aggressive = tightest cut" },
          "clips": { "type": "boolean", "default": true, "description": "Generate captioned 9:16 clips when the cleanup finishes" },
          "noise_removal": { "type": "boolean", "default": true }
        }
      },
      "CreateFromUrl": {
        "type": "object",
        "required": ["url"],
        "properties": { "url": { "type": "string", "format": "uri", "description": "Direct https link to an mp4/mov/webm file" }, "options": { "$ref": "#/components/schemas/Options" } }
      },
      "CreateUpload": {
        "type": "object",
        "required": ["filename", "duration_seconds"],
        "properties": {
          "filename": { "type": "string", "example": "call.mp4" },
          "duration_seconds": { "type": "number", "description": "Length of the video; checked against plan limits before upload" },
          "size_bytes": { "type": "integer" },
          "options": { "$ref": "#/components/schemas/Options" }
        }
      },
      "CreatedFromUrl": {
        "type": "object",
        "properties": { "job_id": { "type": "string" }, "status": { "type": "string", "enum": ["queued"] }, "duration_seconds": { "type": "number", "nullable": true } }
      },
      "CreatedUpload": {
        "type": "object",
        "properties": {
          "job_id": { "type": "string" },
          "status": { "type": "string", "enum": ["awaiting_upload"] },
          "upload_url": { "type": "string", "description": "PUT the file bytes here, then POST /videos/{job_id}/start" },
          "upload_method": { "type": "string", "enum": ["PUT"] },
          "next": { "type": "string" }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "job_id": { "type": "string" },
          "status": { "$ref": "#/components/schemas/Status" },
          "clips_status": { "type": "string", "enum": ["none", "processing", "ready", "failed"] },
          "cleanup_mode": { "type": "string" },
          "duration_seconds": { "type": "number", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time", "nullable": true },
          "error": { "type": "string", "nullable": true },
          "outputs": {
            "type": "object",
            "description": "Signed URLs valid for 24 hours; null until the job is ready",
            "properties": {
              "video_url": { "type": "string", "nullable": true },
              "audio_url": { "type": "string", "nullable": true, "description": "Clean MP3" },
              "thumbnail_url": { "type": "string", "nullable": true },
              "transcript_url": { "type": "string", "nullable": true },
              "clips_url": { "type": "string" }
            }
          }
        }
      },
      "JobSummary": {
        "type": "object",
        "properties": {
          "job_id": { "type": "string" },
          "status": { "$ref": "#/components/schemas/Status" },
          "filename": { "type": "string", "nullable": true },
          "duration_seconds": { "type": "number", "nullable": true },
          "cleanup_mode": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Clip": {
        "type": "object",
        "properties": {
          "clip_id": { "type": "string" },
          "index": { "type": "integer", "description": "0-based" },
          "status": { "type": "string", "enum": ["pending", "processing", "ready", "failed"] },
          "start_seconds": { "type": "number", "description": "On the cleaned timeline" },
          "end_seconds": { "type": "number" },
          "duration_seconds": { "type": "number" },
          "hook_score": { "type": "number", "nullable": true, "minimum": 0, "maximum": 1, "description": "How strong the opening is; sort descending to post the best first" },
          "title": { "type": "string", "nullable": true },
          "language": { "type": "string", "nullable": true },
          "video_url": { "type": "string", "nullable": true, "description": "1080×1920 MP4 with burned-in captions; signed, 24 h" },
          "poster_url": { "type": "string", "nullable": true },
          "error": { "type": "string", "nullable": true }
        }
      },
      "ClipsResponse": {
        "type": "object",
        "properties": {
          "job_id": { "type": "string" },
          "status": { "type": "string", "enum": ["none", "processing", "ready", "failed", "unavailable"] },
          "available": { "type": "boolean" },
          "clips": { "type": "array", "items": { "$ref": "#/components/schemas/Clip" } }
        }
      },
      "Transcript": {
        "type": "object",
        "properties": {
          "job_id": { "type": "string" },
          "language": { "type": "string", "nullable": true },
          "text": { "type": "string", "nullable": true },
          "words": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "word": { "type": "string" },
                "start": { "type": "number", "description": "Seconds on the raw timeline" },
                "end": { "type": "number" },
                "removed": { "type": "string", "enum": ["filler", "silence"], "nullable": true }
              }
            }
          },
          "cuts": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "number" }, "end": { "type": "number" }, "reason": { "type": "string", "enum": ["filler", "silence"] } } } }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "plan": { "type": "string" },
          "period_start": { "type": "string", "format": "date-time" },
          "footage_used_seconds": { "type": "integer" },
          "footage_limit_seconds": { "type": "integer", "nullable": true },
          "footage_remaining_seconds": { "type": "integer", "nullable": true },
          "per_video_limit_seconds": { "type": "integer", "nullable": true },
          "jobs_this_period": { "type": "integer" }
        }
      }
    }
  }
}
