# VideoHub Documentation

VideoHub transcribes YouTube and Instagram videos via REST API, MCP server,
or a "URL prefix" shortcut designed for AI conversations.

**Public, no auth required for short videos. Cache hits are always free.**

## Table of contents

1. [Shortcut: prefix any video URL with `videohub.pro/`](#shortcut) (best for AI chats)
2. [REST API quickstart](#quickstart)
3. [Full REST reference](#rest)
4. [MCP server (Claude Desktop, Claude Code, etc.)](#mcp)
5. [Anonymous quotas and preview policy](#quotas)
6. [Errors](#errors)

---

## 1. Shortcut: prefix with `videohub.pro/` {#shortcut}

This is the shortcut designed for **AI conversations**. When you ask
ChatGPT/Claude/Gemini to summarize a video and it replies "I can't watch
videos", paste this:

```
Transcreva este vídeo: https://videohub.pro/<COLE A URL DO VÍDEO AQUI>
```

(In English: `Transcribe this video: https://videohub.pro/<PASTE THE VIDEO URL>`)

Apenas isso. A IA faz um GET na URL acima e recebe HTML server-rendered
com toda a informação relevante (igual qualquer página da web pública).
**Não é preciso especificar `Accept`, parâmetros, headers especiais ou
qualquer convenção** — o serviço responde de forma útil pra qualquer
GET.

**O que a IA recebe:**

- **Se o vídeo já foi transcrito**: redirect (303) pra URL canônica
  curta `videohub.pro/transcript/<id>`, que renderiza o HTML com
  título, canal, duração e a transcrição completa em markdown — tudo
  visível direto no HTML, sem JavaScript.

- **Se é uma transcrição em andamento**: HTML com título, duração,
  estágio atual, estimativa de conclusão e um **link permanente** pra
  o resultado final. Tudo server-rendered. Junto vem uma nota explícita
  pra a IA: "a transcrição completa estará disponível no link acima em
  ~X minutos. Faça um novo GET nesse link após esse tempo." A IA repassa
  pro usuário ou faz o segundo GET quando o usuário pedir de novo.

**Opt-in JSON**: se quiser dado estruturado pra integração programática,
use `?format=json` ou header `Accept: application/json`. Aí volta um JSON
com `markdown`, `canonical_url`, `title`, `channel`, `duration_seconds`,
`source_url` e um `_meta` descrevendo o serviço.

Examples:

```
https://videohub.pro/https://youtu.be/JAz0jPetSjI
https://videohub.pro/https://www.youtube.com/watch?v=UF8uR6Z6KLc
https://videohub.pro/https://www.instagram.com/reel/DY68F5wlbAU/
```

### Behavior

| Caller | Cache hit | Cache miss |
|---|---|---|
| Browser (Accept: text/html) | 303 to short canonical URL `videohub.pro/transcript/<id>` | 200 HTML "in progress" page with live SSE updates that swap to result in-place |
| Agent (Accept: application/json **OR** AI bot User-Agent) | **200 JSON inline** with `markdown`, `canonical_url`, `title`, `channel`, `duration_seconds`, `language` | **Blocks synchronously up to ~90s** then returns 200 JSON inline; if timeout → 202 with `status_url` and `stream_url` |

Notable:

- For agents we do **not** redirect — the JSON is returned directly on the
  shortcut URL in 1 round-trip, even on cache hit.
- Videos > 10 min for anonymous callers return a preview (first 10 min) with
  an `upsell` object pointing to the pricing page. No 402, always 200.
- The JSON always includes `canonical_url` so your AI can cite the short
  link in its response.

### Example response (cache hit, full transcript)

```json
{
  "status": "done",
  "is_preview": false,
  "transcription_id": "1a9923cb6e7f0e8b9a0c1d2e3f4567...",
  "title": "Recriei o Claude Dynamic Workflows com LangGraph",
  "channel": "Ronnald Hawk",
  "duration_seconds": 1445.0,
  "language": "Portuguese",
  "source_type": "youtube",
  "source_url": "https://youtu.be/JAz0jPetSjI",
  "markdown": "# Recriei o Claude...\n\n## Transcript\n\n...",
  "canonical_url": "https://videohub.pro/transcript/1a9923cb6e7f"
}
```

### Preview response (long video, anonymous)

```json
{
  "status": "done",
  "is_preview": true,
  "preview_cap_seconds": 600,
  "title": "Steve Jobs' 2005 Stanford Commencement Address",
  "duration_seconds": 904.0,
  "markdown": "# Steve Jobs...",
  "upsell": {
    "message": "This is a free preview with the first 10 minutes...",
    "pricing_url": "https://videohub.pro/pricing",
    "signup_url": "https://videohub.pro/signup"
  }
}
```

### Useful tricks

- Pass `?wait=120` to extend the synchronous window (max 120s).
- Pass `?format=html` to force the human page even from an AI bot.
- The canonical URL `https://videohub.pro/transcript/<short_id>` also
  works directly in browsers and MCP-compatible tools.

---

## 2. REST API quickstart {#quickstart}

Same data, structured POST. Useful when the URL is a data field, not part
of the path.

```
curl -X POST https://videohub.pro/api/v1/transcribe \
  -H "Content-Type: application/json" \
  -d '{"url":"https://youtu.be/JAz0jPetSjI"}'
```

Response (abridged):

```json
{
  "status": "done",
  "transcription_id": "1a9923cb...",
  "markdown": "# ...",
  "canonical_url": "https://videohub.pro/transcript/1a9923cb"
}
```

## 3. Full REST reference {#rest}

OpenAPI spec: <https://videohub.pro/api/v1/openapi.json>
Interactive Swagger: <https://videohub.pro/api/v1/docs>

Main endpoints:

- `POST /api/v1/transcribe` — submit + wait or 202.
- `GET /api/v1/transcribe/{id}` — current status / final result.
- `GET /api/v1/transcribe/{id}/stream` — Server-Sent Events stream.

## 4. MCP server {#mcp}

Streamable HTTP (current MCP spec) at `https://videohub.pro/mcp`.
Auth is required: `Authorization: Bearer <api_key>` (free account →
<https://videohub.pro/app/api-keys>).

Claude Code (one-liner):

```
claude mcp add --transport http videohub https://videohub.pro/mcp \
  --header "Authorization: Bearer vh_live_YOUR_SECRET"
```

Claude Desktop and other clients (JSON config):

```json
{
  "mcpServers": {
    "videohub": {
      "type": "http",
      "url": "https://videohub.pro/mcp",
      "headers": { "Authorization": "Bearer vh_live_YOUR_SECRET" }
    }
  }
}
```

Six tools exposed:

- `transcribe_video(url, wait_seconds=60, include_frames=false)` — global cache: hits are instant
- `get_transcription(transcription_id, include_frames=false)`
- `list_my_transcriptions(limit=20)`
- `search_transcript(transcription_id, query, max_results=10)` — keyword search, returns segments with `[MM:SS]` timestamps
- `get_frames(transcription_id, timestamps|count)` — returns actual JPEG frame images (max 10 per call)
- `get_comments(transcription_id)` — top comments by likes

Legacy SSE transport still works at `https://videohub.pro/mcp/sse`.

**Claude Code skill** (teaches Claude when/how to use these tools —
study, verification, citation and creator workflows):

```
mkdir -p ~/.claude/skills/videohub
curl -o ~/.claude/skills/videohub/SKILL.md https://videohub.pro/claude-skill.md
```

## 5. Anonymous quotas {#quotas}

- **Cache hits**: unlimited, free, no auth.
- **New (cache-miss) transcriptions**: 5 per hour per IP, anonymous.
- **Video length** (anonymous): videos > 10 minutes return a 10-minute
  preview + an upsell. Logged-in users with Pro get full-length.
- **Hard limit**: 7 hours per video.

## 6. Errors {#errors}

Standard HTTP codes. JSON bodies look like:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Try again in a few minutes."
  }
}
```

Common codes: `invalid_url`, `not_found`, `transcription_failed`,
`rate_limited`, `too_long`, `payment_required` (REST POST only — the
shortcut returns preview instead).
