{
  "openapi": "3.1.0",
  "info": {
    "title": "FetchMedia API",
    "version": "1.0.0",
    "summary": "Cloud video transcoding and media processing API",
    "description": "FetchMedia provides a managed video processing API for transcoding, format conversion, audio normalization, transcription, and FFmpeg pipelines. Fetch videos from social media sources (YouTube, TikTok, Instagram, Twitter, LinkedIn) and process them with parallel segment splitting for high-speed output across H.264, H.265, VP9, and AV1 codecs.",
    "termsOfService": "https://fetchmedia.io/terms-of-use",
    "contact": {
      "name": "FetchMedia Support",
      "url": "https://fetchmedia.io/contact",
      "email": "support@fetchmedia.io"
    },
    "license": {
      "name": "Commercial",
      "url": "https://fetchmedia.io/terms-of-use"
    }
  },
  "servers": [
    {
      "url": "https://api.fetchmedia.io/v1",
      "description": "Production API"
    }
  ],
  "externalDocs": {
    "description": "Full API documentation",
    "url": "https://docs.fetchmedia.io"
  },
  "security": [
    { "ApiKeyAuth": [] }
  ],
  "tags": [
    { "name": "Transcoding", "description": "Video transcoding and format conversion" },
    { "name": "Fetcher", "description": "Fetch videos from social media platforms" },
    { "name": "Media Tools", "description": "FFmpeg pipelines, transcription, audio normalization" },
    { "name": "Jobs", "description": "Job status and management" }
  ],
  "paths": {
    "/transcode": {
      "post": {
        "tags": ["Transcoding"],
        "summary": "Submit a transcoding job",
        "description": "Transcode a source video to one or more output renditions using parallel segment splitting.",
        "operationId": "createTranscodeJob",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TranscodeRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Job" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/fetch": {
      "post": {
        "tags": ["Fetcher"],
        "summary": "Fetch a video from a social media URL",
        "operationId": "fetchSocialVideo",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/FetchRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Fetch job accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Job" }
              }
            }
          }
        }
      }
    },
    "/transcribe": {
      "post": {
        "tags": ["Media Tools"],
        "summary": "Transcribe audio from a video",
        "operationId": "createTranscriptionJob",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TranscribeRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Transcription job accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Job" }
              }
            }
          }
        }
      }
    },
    "/ffmpeg": {
      "post": {
        "tags": ["Media Tools"],
        "summary": "Run a custom FFmpeg command",
        "operationId": "runFfmpegCommand",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/FfmpegRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "FFmpeg job accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Job" }
              }
            }
          }
        }
      }
    },
    "/jobs/{jobId}": {
      "get": {
        "tags": ["Jobs"],
        "summary": "Get job status",
        "operationId": "getJob",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Job details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Job" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/health": {
      "get": {
        "tags": ["Jobs"],
        "summary": "Health check",
        "operationId": "getHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key issued from the FetchMedia dashboard at app.fetchmedia.io"
      }
    },
    "schemas": {
      "TranscodeRequest": {
        "type": "object",
        "required": ["source", "outputs"],
        "properties": {
          "source": {
            "type": "string",
            "format": "uri",
            "description": "Source video URL (https or s3)"
          },
          "outputs": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/OutputRendition" }
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "description": "Webhook called when the job completes"
          }
        }
      },
      "OutputRendition": {
        "type": "object",
        "required": ["codec", "resolution"],
        "properties": {
          "codec": {
            "type": "string",
            "enum": ["h264", "h265", "vp9", "av1"]
          },
          "resolution": {
            "type": "string",
            "enum": ["480p", "720p", "1080p", "4k"]
          },
          "container": {
            "type": "string",
            "enum": ["mp4", "webm", "mov"],
            "default": "mp4"
          },
          "bitrate_kbps": {
            "type": "integer",
            "minimum": 100
          }
        }
      },
      "FetchRequest": {
        "type": "object",
        "required": ["url"],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Source social media URL (YouTube, TikTok, Instagram, Twitter, LinkedIn)"
          },
          "transcode": {
            "$ref": "#/components/schemas/TranscodeRequest"
          }
        }
      },
      "TranscribeRequest": {
        "type": "object",
        "required": ["source"],
        "properties": {
          "source": { "type": "string", "format": "uri" },
          "language": {
            "type": "string",
            "description": "BCP-47 language code, or 'auto' to detect"
          },
          "format": {
            "type": "string",
            "enum": ["json", "srt", "vtt"],
            "default": "json"
          }
        }
      },
      "FfmpegRequest": {
        "type": "object",
        "required": ["inputs", "command"],
        "properties": {
          "inputs": {
            "type": "array",
            "items": { "type": "string", "format": "uri" }
          },
          "command": {
            "type": "string",
            "description": "FFmpeg arguments without the binary name"
          },
          "output_filename": { "type": "string" }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "status": {
            "type": "string",
            "enum": ["queued", "processing", "completed", "failed"]
          },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time" },
          "outputs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": { "type": "string", "format": "uri" },
                "codec": { "type": "string" },
                "resolution": { "type": "string" },
                "duration_seconds": { "type": "number" },
                "size_bytes": { "type": "integer" }
              }
            }
          },
          "error": { "$ref": "#/components/schemas/Error" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": { "type": "string" },
          "message": { "type": "string" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  }
}