{
  "openapi": "3.1.0",
  "info": {
    "title": "TubeToTranscript REST API",
    "description": "YouTube transcripts, video metadata, search, channel and playlist data for developers. Lookup endpoints marked free (info, channel/resolve, channel/latest) need an API key but don't use up your request allowance; every other call counts as one request per page.",
    "version": "1.0.0",
    "contact": {
      "name": "TubeToTranscript Developer Support",
      "url": "https://www.tubetotranscript.com/docs"
    }
  },
  "servers": [
    {
      "url": "https://www.tubetotranscript.com/api/v1",
      "description": "Production API Server"
    }
  ],
  "paths": {
    "/transcript": {
      "get": {
        "summary": "Fetch YouTube Video Transcript",
        "description": "Reads accessible YouTube caption tracks and returns clean, timestamped transcript data.",
        "operationId": "getTranscript",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "YouTube video URL or Video ID (e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "description": "ISO language code (e.g. 'en', 'es', 'ur', 'fr')",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Priority list of language codes, tried left to right (e.g. de,en,asr). Region is ignored; asr = any auto-generated track, asr-<code> = a specific one. Returns 404 listing the video's languages when none match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "json (default) returns a segment array; text returns one string.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text"
              ]
            }
          },
          {
            "name": "include_timestamp",
            "in": "query",
            "required": false,
            "description": "Default true. false drops start/duration (json) or the [MM:SS] prefixes (text).",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful transcript retrieval",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptResponse"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid YouTube URL"
          },
          "404": {
            "description": "No captions or transcript available for this video"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "401": {
            "description": "Invalid or inactive API key"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "post": {
        "summary": "Fetch YouTube Video Transcript (JSON Body)",
        "operationId": "postTranscript",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "YouTube video URL or ID"
                  },
                  "language": {
                    "type": "string",
                    "description": "Optional target language code"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transcript retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/batch": {
      "post": {
        "summary": "Batch Multi-Video Transcriber",
        "description": "Processes up to 30 YouTube video URLs per request for standard tiers, with concurrent processing.",
        "operationId": "postBatchTranscript",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "urls": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "List of YouTube URLs"
                  }
                },
                "required": [
                  "urls"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch processing completed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "successCount": {
                      "type": "integer"
                    },
                    "failedCount": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, invalid URLs, or batch exceeds the tier limit"
          },
          "401": {
            "description": "Invalid or inactive API key"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/playlist": {
      "get": {
        "summary": "Enumerate Playlist Videos",
        "operationId": "getPlaylistVideos",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "YouTube Playlist URL or List ID. Requires the configured playlist/channel provider.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Playlist videos extracted when the upstream provider is configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "totalVideos": {
                      "type": "integer"
                    },
                    "videos": {
                      "type": "array"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or inactive API key"
          },
          "503": {
            "description": "Playlist provider is not configured or unavailable"
          }
        }
      }
    },
    "/channel": {
      "get": {
        "summary": "Search Channel Captions (Optional Provider)",
        "operationId": "searchChannelSpeech",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": true,
            "description": "YouTube Channel handle (e.g. '@TED'). Requires the configured playlist/channel provider.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Keyword search query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel caption matches found when the upstream provider is configured"
          },
          "401": {
            "description": "Invalid or inactive API key"
          },
          "503": {
            "description": "Channel provider is not configured or unavailable"
          }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "System Health & Status Check",
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "API status is operational",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "healthy"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "A required production dependency is not configured"
          }
        }
      }
    },
    "/info": {
      "get": {
        "summary": "Video info and caption languages (free)",
        "description": "Title, channel, thumbnail and every available caption track. Pass a returned code (e.g. en, or asr-en for auto-generated English) as the transcript language. Free: requires an API key but does not use up your request allowance.",
        "operationId": "getVideoInfo",
        "parameters": [
          {
            "name": "video_url",
            "in": "query",
            "required": true,
            "description": "YouTube video URL or 11-character ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Video info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "video_id": {
                      "type": "string"
                    },
                    "metadata": {
                      "type": "object"
                    },
                    "available_languages": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "is_generated": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/video/metadata": {
      "get": {
        "summary": "Rich video metadata",
        "description": "Title, description with extracted links, view and like counts, publish date, length and channel summary. include=details adds category, tags and caption tracks; include=related adds suggested videos. Counts as 1 request.",
        "operationId": "getVideoMetadata",
        "parameters": [
          {
            "name": "video_url",
            "in": "query",
            "required": true,
            "description": "YouTube video URL or 11-character ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "Comma-separated extras: details, related.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Video metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/search": {
      "get": {
        "summary": "Search YouTube",
        "description": "Searches videos, channels, playlists or movies. Filters apply to the first page; later pages follow continuation_token. Each page returns about 20 results. Counts as 1 request.",
        "operationId": "searchYouTube",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Search query, 1–200 characters. Required unless continuation is set.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Result type (default video).",
            "schema": {
              "type": "string",
              "enum": [
                "video",
                "channel",
                "playlist",
                "movie"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order.",
            "schema": {
              "type": "string",
              "enum": [
                "relevance",
                "views",
                "upload_date",
                "rating"
              ]
            }
          },
          {
            "name": "upload_date",
            "in": "query",
            "required": false,
            "description": "Upload-date window (videos).",
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "today",
                "week",
                "month",
                "year"
              ]
            }
          },
          {
            "name": "duration",
            "in": "query",
            "required": false,
            "description": "short (<4 min), medium (4–20 min), long (>20 min).",
            "schema": {
              "type": "string",
              "enum": [
                "short",
                "medium",
                "long"
              ]
            }
          },
          {
            "name": "features",
            "in": "query",
            "required": false,
            "description": "Comma-separated: hd, subtitles, cc, creative_commons, 3d, live, 4k, 360, hdr, vr180, location.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sp",
            "in": "query",
            "required": false,
            "description": "Advanced: raw YouTube sp filter; overrides the structured filters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/resolve": {
      "get": {
        "summary": "Resolve a channel (free)",
        "description": "Turns an @handle or channel URL into its UC… channel ID. Free: requires an API key but does not use up your request allowance.",
        "operationId": "resolveChannel",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": true,
            "description": "@handle, channel URL, or UC… ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel ID",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "channelId": {
                      "type": "string"
                    },
                    "handle": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/info": {
      "get": {
        "summary": "Channel profile",
        "description": "Title, handle, description, subscriber/video/view counts, join date, country, links, avatar, banner and tabs. Counts as 1 request.",
        "operationId": "getChannelInfo",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": true,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/search": {
      "get": {
        "summary": "Search within a channel",
        "description": "Searches a channel's videos by title and description, like the search box on a channel page. To search what is said in a channel's videos, use /channel. Counts as 1 request.",
        "operationId": "searchChannel",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Search query, 1–200 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of matching videos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/videos": {
      "get": {
        "summary": "Channel videos, Shorts or live streams",
        "description": "Paginated channel feed. Counts as 1 request.",
        "operationId": "getChannelVideos",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tab",
            "in": "query",
            "required": false,
            "description": "Which feed (default videos).",
            "schema": {
              "type": "string",
              "enum": [
                "videos",
                "shorts",
                "streams"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Order (default latest).",
            "schema": {
              "type": "string",
              "enum": [
                "latest",
                "popular",
                "oldest"
              ]
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of videos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/playlists": {
      "get": {
        "summary": "Channel playlists",
        "description": "Paginated list of a channel's playlists. Counts as 1 request.",
        "operationId": "getChannelPlaylists",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of playlists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/posts": {
      "get": {
        "summary": "Channel community posts",
        "description": "Paginated Posts tab: text, date, likes, and any video, image, poll or playlist attachment. Counts as 1 request.",
        "operationId": "getChannelPosts",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of posts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/sections": {
      "get": {
        "summary": "Channel home sections",
        "description": "The curated shelves on a channel's Home tab (featured video, playlists, popular uploads, Shorts…). Counts as 1 request.",
        "operationId": "getChannelSections",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": true,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel sections",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "channelId": {
                      "type": "string"
                    },
                    "sections": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "section_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/channel/latest": {
      "get": {
        "summary": "Latest uploads (free)",
        "description": "A channel's latest ~15 uploads with publish dates, views and likes, from YouTube's public RSS feed. Free: requires an API key but does not use up your request allowance.",
        "operationId": "getChannelLatest",
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": true,
            "description": "Channel as a UC… ID, @handle, or channel URL.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Latest uploads",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/playlist/videos": {
      "get": {
        "summary": "Playlist videos (paginated)",
        "description": "Lists a playlist's videos about 100 per page, with the playlist's title, owner and counts on the first page. /playlist, by contrast, returns transcripts. Counts as 1 request.",
        "operationId": "getPlaylistVideoPage",
        "parameters": [
          {
            "name": "playlist",
            "in": "query",
            "required": false,
            "description": "Playlist URL (containing list=) or playlist ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "continuation",
            "in": "query",
            "required": false,
            "description": "Token from a previous page's continuation_token. When set, the other parameters are ignored.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of playlist videos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter (code INVALID_INPUT)"
          },
          "401": {
            "description": "Missing, invalid or inactive API key"
          },
          "404": {
            "description": "Video, channel or playlist not found (code NOT_FOUND)"
          },
          "429": {
            "description": "Rate limit or request allowance exhausted"
          },
          "503": {
            "description": "YouTube temporarily unavailable (code UPSTREAM_UNAVAILABLE)"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Bearer token authentication"
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Custom API Key header"
      }
    },
    "schemas": {
      "TranscriptResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "videoId": {
                "type": "string"
              },
              "language": {
                "type": "string"
              },
              "length_seconds": {
                "type": "integer"
              },
              "metadata": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "author": {
                    "type": "string"
                  },
                  "thumbnailUrl": {
                    "type": "string"
                  }
                }
              },
              "transcript": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "start": {
                      "type": "number"
                    },
                    "duration": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Page": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "result_count": {
            "type": "integer"
          },
          "continuation_token": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_more": {
            "type": "boolean"
          }
        }
      }
    }
  }
}
