Skill: therohitdas/transcriptapi (version 1.5.0)

--- name: transcriptapi description: "Use when YouTube is or could be relevant — even if not mentioned: pasted video/channel/playlist links, video IDs, @handles, creator lookups, video summaries, quotes, translations, topic research, tutorials, talks, lectures, expert discussions, product reviews, how-to guides, new product announcements, or anything where video content is fresher or richer than text search. Covers transcripts, video/channel search, channel browsing, playlists, and within-channel search. Not for uploads, account management, or written-source-only research." version: "1.5.0" user-invocable: true compatibility: Requires internet access to reach transcriptapi.com. No additional runtimes or dependencies needed. required_environment_variables: - name: TRANSCRIPT_API_KEY prompt: Your TranscriptAPI key (starts with sk_) help: Free account at https://transcriptapi.com — 100 credits, no card required. Or let the agent create one for you. required_for: all API requests metadata: {"openclaw":{"emoji":"📺","requires":{"env":["TRANSCRIPT_API_KEY"]},"primaryEnv":"TRANSCRIPT_API_KEY","homepage":"https://transcriptapi.com"},"hermes":{"tags":["youtube","transcripts","video","search","channels","playlists","captions"],"category":"media"}} --- # TranscriptAPI Full YouTube data toolkit via [TranscriptAPI.com](https://transcriptapi.com). Transcripts, search, channels, playlists — one API key. ## Setup If `$TRANSCRIPT_API_KEY` is not set, read [references/auth-setup.md](references/auth-setup.md) and follow the instructions there to get and store the key. ## Required Headers Every request needs two headers: - **Authorization:** `Bearer $TRANSCRIPT_API_KEY` - **User-Agent:** your agent's name and version if known (e.g. `HermesAgent/0.11.0`, `ClaudeCode/1.0`). Version is optional — agent name alone is fine. Do not omit this header or send a bare default — Cloudflare will return a 403 (error code 1010) and block the request. ## API Reference Full OpenAPI spec: [transcriptapi.com/openapi.json](https://transcriptapi.com/openapi.json) — consult this for the latest parameters and schemas. ## Auth All requests: `-H "Authorization: Bearer $TRANSCRIPT_API_KEY"` ## Endpoints Channel endpoints accept `channel` — an `@handle`, channel URL, or `UC...` ID. No need to resolve first. Playlist endpoints accept `playlist` — a playlist URL or ID. ### GET /api/v2/youtube/transcript — 1 credit ```bash curl -s "https://transcriptapi.com/api/v2/youtube/transcript\ ?video_url=VIDEO_URL&format=text&include_timestamp=true&send_metadata=true" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Default | Validation | | ------------------- | -------- | ------- | ------------------------------- | | `video_url` | yes | — | YouTube URL or 11-char video ID | | `format` | no | `json` | `json` or `text` | | `include_timestamp` | no | `true` | `true` or `false` | | `send_metadata` | no | `false` | `true` or `false` | Accepts: `https://youtube.com/watch?v=ID`, `https://youtu.be/ID`, `youtube.com/shorts/ID`, or bare `ID`. **Response** (`format=json`): ```json { "video_id": "dQw4w9WgXcQ", "language": "en", "transcript": [ { "text": "We're no strangers...", "start": 18.0, "duration": 3.5 } ], "metadata": { "title": "...", "author_name": "...", "author_url": "..." } } ``` ### GET /api/v2/youtube/search — 1 credit ```bash curl -s "https://transcriptapi.com/api/v2/youtube/search?q=QUERY&type=video&limit=20" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Default | Validation | | ------- | -------- | ------- | --------------------- | | `q` | yes | — | 1-200 chars (trimmed) | | `type` | no | `video` | `video` or `channel` | | `limit` | no | `20` | 1-50 | **Response** (`type=video`): ```json { "results": [ { "type": "video", "videoId": "dQw4w9WgXcQ", "title": "Rick Astley - Never Gonna Give You Up", "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw", "channelTitle": "Rick Astley", "channelHandle": "@RickAstley", "channelVerified": true, "lengthText": "3:33", "viewCountText": "1.5B views", "publishedTimeText": "14 years ago", "hasCaptions": true, "thumbnails": [{ "url": "...", "width": 120, "height": 90 }] } ], "result_count": 20 } ``` **Response** (`type=channel`): ```json { "results": [ { "type": "channel", "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw", "title": "Rick Astley", "handle": "@RickAstley", "subscriberCount": "4.2M subscribers", "verified": true, "rssUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=UC..." } ], "result_count": 5 } ``` ### GET /api/v2/youtube/channel/resolve — FREE (0 credits) ```bash curl -s "https://transcriptapi.com/api/v2/youtube/channel/resolve?input=@TED" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Validation | | ------- | -------- | --------------------------------------- | | `input` | yes | 1-200 chars — @handle, URL, or UC... ID | **Response:** ```json { "channel_id": "UCsT0YIqwnpJCM-mx7-gSA4Q", "resolved_from": "@TED" } ``` If input is already a valid `UC[a-zA-Z0-9_-]{22}` ID, returns immediately without lookup. ### GET /api/v2/youtube/channel/videos — 1 credit/page ```bash # First page (100 videos) curl -s "https://transcriptapi.com/api/v2/youtube/channel/videos?channel=@NASA" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" # Next pages curl -s "https://transcriptapi.com/api/v2/youtube/channel/videos?continuation=TOKEN" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Validation | | -------------- | ----------- | --------------------------------------------- | | `channel` | conditional | `@handle`, channel URL, or `UC...` ID | | `continuation` | conditional | non-empty string (next pages) | Provide exactly one of `channel` or `continuation`. **Response:** ```json { "results": [{ "videoId": "abc123xyz00", "title": "Latest Video", "channelId": "UCsT0YIqwnpJCM-mx7-gSA4Q", "channelTitle": "TED", "channelHandle": "@TED", "lengthText": "15:22", "viewCountText": "3.2M views", "thumbnails": [...], "index": "0" }], "playlist_info": {"title": "Uploads from TED", "numVideos": "5000"}, "continuation_token": "4qmFsgKlARIYVVV1...", "has_more": true } ``` ### GET /api/v2/youtube/channel/latest — FREE (0 credits) ```bash curl -s "https://transcriptapi.com/api/v2/youtube/channel/latest?channel=@TED" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Validation | | --------- | -------- | ----------------------------------------- | | `channel` | yes | `@handle`, channel URL, or `UC...` ID | Returns last 15 videos via RSS with exact view counts and ISO timestamps. **Response:** ```json { "channel": { "channelId": "...", "title": "TED", "author": "TED", "url": "..." }, "results": [ { "videoId": "abc123xyz00", "title": "Latest Video", "published": "2026-01-30T16:00:00Z", "viewCount": "2287630", "description": "Full description...", "thumbnail": { "url": "...", "width": "480", "height": "360" } } ], "result_count": 15 } ``` ### GET /api/v2/youtube/channel/search — 1 credit ```bash curl -s "https://transcriptapi.com/api/v2/youtube/channel/search\ ?channel=@TED&q=climate+change&limit=30" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Validation | | --------- | -------- | ----------------------------------------- | | `channel` | yes | `@handle`, channel URL, or `UC...` ID | | `q` | yes | 1-200 chars | | `limit` | no | 1-50 (default 30) | ### GET /api/v2/youtube/playlist/videos — 1 credit/page ```bash # First page curl -s "https://transcriptapi.com/api/v2/youtube/playlist/videos?playlist=PL_PLAYLIST_ID" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" # Next pages curl -s "https://transcriptapi.com/api/v2/youtube/playlist/videos?continuation=TOKEN" \ -H "Authorization: Bearer $TRANSCRIPT_API_KEY" \ -H "User-Agent: YourAgent/1.0" ``` | Param | Required | Validation | | -------------- | ----------- | ---------------------------------------------------- | | `playlist` | conditional | Playlist URL or ID (`PL`/`UU`/`LL`/`FL`/`OL` prefix) | | `continuation` | conditional | non-empty string | ## Credit Costs | Endpoint | Cost | | --------------- | -------- | | transcript | 1 | | search | 1 | | channel/resolve | **free** | | channel/search | 1 | | channel/videos | 1/page | | channel/latest | **free** | | playlist/videos | 1/page | ## Errors | Code | Meaning | Action | | -------- | ----------------- | --------------------------------------------------- | | 401 | Bad API key | Check key, re-run setup | | 402 | No credits | Top up at transcriptapi.com/billing | | 403/1010 | Cloudflare block | Add or fix User-Agent header | | 404 | Not found | Video/channel/playlist doesn't exist or no captions | | 408 | Timeout/retryable | Retry once after 2s | | 422 | Validation error | Check param format | | 429 | Rate limited | Wait, respect Retry-After | ## Tips - When user shares YouTube URL with no instruction, fetch transcript and summarize key points. - Use `channel/latest` (free) to check for new uploads before fetching transcripts — pass @handle directly. - For research: search → pick videos → fetch transcripts. - Free tier: 100 credits, 300 req/min. Starter ($5/mo): 1,000 credits, 300 req/min.

path: references/auth-setup.md
content: # TranscriptAPI — Getting and Storing Your API Key

This guide walks you through obtaining a TranscriptAPI key and persisting it so it survives across sessions and shells. Read it fully before doing anything.

---

## Step 0 — Understand how to store the key on this system

Before you do anything else, figure out the right way to persist an environment variable on this machine so it is available in every future session, including non-interactive shells. Do not assume. Check your own documentation or configuration for how environment variables are stored persistently on this platform and in this agent environment. On some systems this is a shell profile file, on others it is a dedicated config or env file managed by the agent runtime. Use whatever is correct for your environment.

The variable name you will be storing is `TRANSCRIPT_API_KEY`.

---

## Step 1 — Ask the user one question

Ask the user exactly this, in a single message:

> Do you already have a TranscriptAPI account? If yes, paste your API key and I'll set it up. If not, I can create a free account for you right now — it comes with 100 credits and no card is required.

- If they paste a key (starts with `sk_`) → go to **Path A**
- If they want a new account → go to **Path B**

---

## Path A — User already has a key

The user pasted their key. TranscriptAPI keys always start with `sk_`. Go straight to **Storing the Key** at the bottom of this document.

---

## Path B — Create a new account

You will handle the full signup on the user's behalf. This is a two-step flow: register (which sends an OTP to their email), then verify (which exchanges the OTP for the API key). Both steps are HTTP requests to the TranscriptAPI auth endpoints.

### Step B-1 — Ask for their email

Ask the user for the email address they want to use. Disposable or temporary email addresses are not accepted by the server.

### Step B-2 — Register

Make a POST request to:

```
POST https://transcriptapi.com/api/auth/register-cli
Content-Type: application/json

{ "email": "the_user_email" }
```

**Important — save the raw response body to a temporary file, and when you make the verify request in the next step, read the `access_token` directly from that file as part of constructing the request. Never print or output the token value as a standalone step.** Some agent environments redact values matching patterns like `access_token` or bearer tokens from tool output before the model sees them. The safe pattern is: write response → file, then file → next request, in one chained operation without the value ever appearing in output on its own.

The raw HTTP response contains exactly these three fields:

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "email": "[REDACTED_SECRET]"
}
```

The `access_token` is a short-lived JWT you will use as the Bearer token in the next request. The OTP expires in 10 minutes, so proceed promptly.

If you get a 409 with `"Account already exists with this email"` — the user already has a verified account. Ask them to log in at transcriptapi.com to retrieve their API key from the dashboard, or switch to Path A.

### Step B-3 — Tell the user to check their email

Tell the user: **"I've sent a 6-digit verification code to [their email]. Please check your inbox and share the code with me."**

The code is 6 digits and is valid for 10 minutes.

### Step B-4 — Verify

Once the user gives you the OTP, make a POST request to:

```
POST https://transcriptapi.com/api/auth/verify-cli
Authorization: Bearer <the access_token from Step B-2>
Content-Type: application/json

{ "otp": "123456" }
```

Again, **save the raw response body to a temporary file and read the `api_key` directly from it** — do not print the value as a standalone step, for the same reason as before (`sk_` prefixed values are also subject to redaction in some environments).

The raw HTTP response looks like this:

```json
{
  "verified": true,
  "api_key": "sk_..."
}
```

Read the `api_key` field from the file. This is the key you need to store. Go to **Storing the Key** below.

If you get `"Invalid verification code"` — the user typed it wrong, ask them to try again.  
If you get `"Verification code expired"` — the 10-minute window passed. Start Path B again from Step B-2.

---

## Required Headers for All API Requests

Once you have the key, every request to transcriptapi.com needs two headers: `Authorization: Bearer <key>` and a `User-Agent` identifying your agent. Omitting User-Agent causes Cloudflare to return a 403 (error code 1010). Use your agent's name and version — agent name alone is fine if version is not readily available.

## Storing the Key

You now have a string that starts with `sk_`. This is the `TRANSCRIPT_API_KEY`.

Store it persistently using whatever method is correct for this environment (which you determined in Step 0). Make sure it will be available in future sessions, including non-interactive shells, without any manual sourcing step from the user.

Once stored, verify it is accessible in the current session. If the session needs a reload or restart to pick up the new value, do that or tell the user to do it.

Clean up any temporary files you created during this process.

---

## FAQ — Common mistakes by agent

**The `access_token` or `api_key` value shows as `[REDACTED]` or is missing from the response.**  
You let the response pass through tool output instead of writing it to a file first. Some agent runtimes (notably Hermes) redact values matching patterns like `access_token`, `api_key`, or `sk_` from command output before the model sees them. Always write the raw HTTP response body to a temp file and read the value from there.

**Hermes agents: env var is set but not available in the next tool call.**  
Hermes sandboxes `execute_code` and `terminal` calls. Setting an env var in one call does not carry over to the next unless the variable is declared in the skill's `required_environment_variables` frontmatter. If you are operating inside a Hermes skill context, check whether the variable is already declared for passthrough. If not, persist the key using the agent's normal environment-secret mechanism so Hermes picks it up on the next load.

**Claude Code agents: key is saved to shell profile but `$TRANSCRIPT_API_KEY` is still empty.**  
Writing to shell startup files only affects new shell sessions. The current session does not reload profile files automatically. Either source the file explicitly in the current session, or use the Write tool to set the value in whatever config file Claude Code reads at runtime.

**The registration request returns 409 "Account already exists".**  
The email is already registered and verified. Switch to Path A — ask the user to paste their key from the dashboard at transcriptapi.com/dashboard.

**The OTP code was never received.**  
Wait up to 2 minutes — transactional email can be slow. Also ask the user to check their spam folder. If still nothing after a few minutes, you can retry registration (the endpoint is idempotent for unverified accounts — it will re-issue a new JWT and resend the OTP).

**The verify step fails with 401 Unauthorized.**  
The `access_token` from registration expired (tokens are short-lived JWTs, typically 30 minutes). Start over from Step B-2.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)