Channel jobs
A whole channel's or profile's transcripts as one background job: start it, follow its progress, and page through its results.
Beta. A channel job fetches the transcripts of a whole YouTube channel or TikTok or Instagram profile as one background job: the call for loading a creator into a knowledge base or a RAG index. Start it with one request, follow its progress, page through its results, and let a webhook tell you when it ends. It costs what the same work by hand costs: the listing pages and each transcript.
Start a job
curl https://transcriptfetch.com/api/v2/jobs/channel \ -H "Authorization: Bearer $TRANSCRIPTFETCH_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel":"@3blue1brown","max_videos":500,"transcripts":{"timestamps":false,"chunks":true},"webhook_url":"https://example.com/hooks/transcriptfetch"}'
The answer is 202 at once, with the job queued. channel takes anything the channel endpoint takes: a YouTube @handle, UC… id or channel URL, or a TikTok or Instagram profile URL. The platform is read from it.
| Field | What it does |
|---|---|
max_videos | The most videos to fetch. Defaults to the plan's limit (below). |
transcripts | What each transcript carries, with the same options as search with transcripts: true (the default) for caption text with timestamps, or { mode, timestamps, markdown, chunks }. |
tab, sort | YouTube only: the uploads, Shorts or live streams; newest first, most popular or oldest first. |
since_video_id | Stop at this video, so a second job fetches only what is newer than the first one's newest. Newest first only. |
webhook_url | Where to send channel_job.started, channel_job.completed and channel_job.failed. |
mode is captions unless you ask for auto, so a job never starts paid AI transcription by surprise. With auto, a captionless video with speech goes to AI Fallback Transcription, and the job waits for it before it completes.
How a job runs
- The job lists 50 videos of the channel, fetches their transcripts, then lists the next 50, until it reaches
max_videos,since_video_idor the end of the channel. - It fetches with at most half of the account's extraction capacity, so the account's own live calls keep the rest.
- A YouTube channel lists up to about its newest 2,000 videos in one order. For a channel longer than that, run a second job with
sort: "oldest"to reach the other end. TikTok and Instagram profiles page all the way. - A channel that does not exist fails the job with
not_found, free. A listing page that keeps failing is tried 3 times before the job fails with that error. - Running out of credits fails the job with
insufficient_credits. Everything fetched until then stays readable. DELETEcancels a job before its next step. Nothing more is charged.
Read progress and results
{ "ok": true, "request_id": "req_…", "data": { "kind": "channel_job", "id": "cjob_m3k1x9qz4vb2p7", "status": "running", "channel": "@3blue1brown", "platform": "youtube", "options": {}, "since_video_id": null, "max_videos": 500, "transcripts": { "mode": "captions", "timestamps": false, "chunks": { "max_tokens": 500, "overlap_tokens": 50 } }, "webhook_url": "https://example.com/hooks/transcriptfetch", "listed": 142, "completed": 96, "failed": 3, "processing": 0, "credits_spent": 98, "error": null, "created_at": "2026-10-21T10:00:00.000Z", "started_at": "2026-10-21T10:00:20.000Z", "finished_at": null, "results_expire_at": null, "poll_url": "/api/v2/jobs/channel/cjob_m3k1x9qz4vb2p7", "results": [ { "video_id": "aircAruvnKk", "url": "https://www.youtube.com/watch?v=aircAruvnKk", "outcome": "ok", "title": "But what is a neural network? | Deep learning chapter 1", "channel": "3Blue1Brown", "duration": 1120, "language": "en", "thumbnail_url": "https://i.ytimg.com/vi/aircAruvnKk/mqdefault.jpg", "source": "captions", "text": "This is a 3. It's sloppily written …", "chunks": [ { "index": 0, "text": "This is a 3. …", "start": 4.22, "end": 139.18, "url": "https://www.youtube.com/watch?v=aircAruvnKk&t=4s", "tokens": 494 } ] } ], "next_cursor": "25" } }
status is queued, running, completed, failed or cancelled. listed counts the videos found so far, completed and failed the transcripts that came back or could not, processing the AI transcriptions still running, and credits_spent what the job has cost.
results holds 25 results at a time in listing order (limit takes up to 50); send next_cursor back as cursor for the next page. Each result is shaped like a batch entry, with the job's transcript options applied:
ok: the transcript, withmarkdownandchunkswhen the job asked for them.pending: listed, not fetched yet.processing: AI transcription is running;job_idandpoll_urlname it.error: the standard error block. Errors cost nothing.
The words come from the transcript cache, so a job's results stay readable for 7 days after it ends (results_expire_at). Read them into your own store within that time; a result whose words have expired answers expired: true.
Webhooks
With webhook_url, the job POSTs channel_job.started when it begins and channel_job.completed or channel_job.failed when it ends. The body carries job_id, status, the counters, error and results_url, and it is signed like a monitor delivery: webhook_secret from the 202 is the key, and Verify the signature shows how in Node and Python. Delivery is best effort; the job itself is the record, so poll it if a webhook does not come.
Limits and cost
| Plan | Videos per job | Jobs at a time |
|---|---|---|
| Free, Basic, Pro | 1,000 | 1 |
| Mega, Scale | 25,000 | 2 |
A job is billed as it goes, at the API's normal prices: 1 credit for each listing page that has videos, 1 for each caption transcript delivered, and AI Fallback Transcription 1 credit per started 5 minutes of audio in auto mode. Failures are free, and starting, reading and cancelling a job cost nothing. A channel of 500 captioned videos costs 510 credits: 10 pages and 500 transcripts.
Starting a job is refused with 402 insufficient_credits when the account cannot pay for the first page, with 400 invalid_request when max_videos is over the plan's limit, and with 409 job_limit_reached while the plan's number of jobs is already running.
Channel job endpoints
Every call for starting and reading channel jobs: parameters, request and response.
/api/v2/jobs/channelidempotentStart a channel job
Fetch a channel's or profile's transcripts as one job: it lists the channel a page at a time and fetches each page's transcripts in the background, then calls your webhook. Answers 202 at once; poll the job for progress and read its results a page at a time. Beta.
- Billing as it goes, what the same work by hand costs: 1 credit per listing page with videos, 1 per caption transcript delivered, AI Fallback Transcription at its usual rate in mode auto. Failures are free; starting is free.
- Limits: 1,000 videos a job and 1 job at a time on Free, Basic and Pro; 25,000 videos and 2 jobs at a time on Mega and Scale. Refused at the start: an account that cannot pay for even the first page (402 insufficient_credits), more max_videos than the plan allows (400), and a job past the plan's running jobs (409 job_limit_reached).
- A YouTube channel lists up to about its newest 2,000 videos in one order (sort oldest reaches the other end); TikTok and Instagram profiles page all the way.
- Running out of credits mid-way fails the job; results fetched so far stay readable.
- Results are read back from the transcript cache: they stay readable for 7 days after the job finishes (results_expire_at).
- The 202 carries webhook_secret when webhook_url is set, shown this once.
Body parameters
channelstringrequiredplatformstringoptionaltabstringoptionalsortstringoptionalsince_video_idstringoptionalmax_videosintegeroptionaltranscriptsboolean | { mode, timestamps, markdown, chunks }optionalwebhook_urlstringoptionalRequest example
Responses
{
"ok": true,
"request_id": "req_…",
"data": {
"kind": "channel_job",
"id": "cjob_m3k1x9qz4vb2p7",
"status": "queued",
"channel": "@3blue1brown",
"platform": "youtube",
"options": {},
"since_video_id": null,
"max_videos": 500,
"transcripts": {
"mode": "captions",
"timestamps": false,
"chunks": {
"max_tokens": 500,
"overlap_tokens": 50
}
},
"webhook_url": "https://example.com/hooks/transcriptfetch",
"listed": 0,
"completed": 0,
"failed": 0,
"processing": 0,
"credits_spent": 0,
"error": null,
"created_at": "2026-10-21T10:00:00.000Z",
"started_at": null,
"finished_at": null,
"results_expire_at": null,
"poll_url": "/api/v2/jobs/channel/cjob_m3k1x9qz4vb2p7",
"webhook_secret": "whsec_…"
}
}/api/v2/jobs/channelList channel jobs
The account's 20 most recent channel jobs, newest first, without their results. Free.
Request example
Responses
{
"ok": true,
"request_id": "req_…",
"data": {
"kind": "channel_job_list",
"jobs": [
{
"kind": "channel_job",
"id": "cjob_m3k1x9qz4vb2p7",
"status": "running",
"channel": "@3blue1brown",
"platform": "youtube",
"options": {},
"since_video_id": null,
"max_videos": 500,
"transcripts": {
"mode": "captions",
"timestamps": false,
"chunks": {
"max_tokens": 500,
"overlap_tokens": 50
}
},
"webhook_url": "https://example.com/hooks/transcriptfetch",
"listed": 142,
"completed": 96,
"failed": 3,
"processing": 0,
"credits_spent": 98,
"error": null,
"created_at": "2026-10-21T10:00:00.000Z",
"started_at": "2026-10-21T10:00:20.000Z",
"finished_at": null,
"results_expire_at": null,
"poll_url": "/api/v2/jobs/channel/cjob_m3k1x9qz4vb2p7"
}
]
}
}/api/v2/jobs/channel/{channelJobId}Get a channel job and its results
Progress (status queued, running, completed, failed or cancelled; listed, completed, failed, processing, credits_spent) and a page of results in listing order, each shaped like a batch entry with the job's transcript options applied. Free.
- A result is pending (not fetched yet), ok, processing (AI Fallback Transcription running: job_id and poll_url) or error. An ok result whose words have left the cache answers expired: true.
- Page with cursor: next_cursor is null once every listed result has been returned; a running job may list more later.
Query parameters
cursorstringoptionallimitinteger (1–50)optionalRequest example
Responses
{
"ok": true,
"request_id": "req_…",
"data": {
"kind": "channel_job",
"id": "cjob_m3k1x9qz4vb2p7",
"status": "running",
"channel": "@3blue1brown",
"platform": "youtube",
"options": {},
"since_video_id": null,
"max_videos": 500,
"transcripts": {
"mode": "captions",
"timestamps": false,
"chunks": {
"max_tokens": 500,
"overlap_tokens": 50
}
},
"webhook_url": "https://example.com/hooks/transcriptfetch",
"listed": 142,
"completed": 96,
"failed": 3,
"processing": 0,
"credits_spent": 98,
"error": null,
"created_at": "2026-10-21T10:00:00.000Z",
"started_at": "2026-10-21T10:00:20.000Z",
"finished_at": null,
"results_expire_at": null,
"poll_url": "/api/v2/jobs/channel/cjob_m3k1x9qz4vb2p7",
"results": [
{
"video_id": "aircAruvnKk",
"url": "https://www.youtube.com/watch?v=aircAruvnKk",
"outcome": "ok",
"title": "But what is a neural network? | Deep learning chapter 1",
"channel": "3Blue1Brown",
"duration": 1120,
"language": "en",
"thumbnail_url": "https://i.ytimg.com/vi/aircAruvnKk/mqdefault.jpg",
"source": "captions",
"text": "This is a 3. It's sloppily written …",
"chunks": [
{
"index": 0,
"text": "This is a 3. …",
"start": 4.22,
"end": 139.18,
"url": "https://www.youtube.com/watch?v=aircAruvnKk&t=4s",
"tokens": 494
}
]
}
],
"next_cursor": "25"
}
}/api/v2/jobs/channel/{channelJobId}Cancel a channel job
Stops a queued or running job before its next step; nothing more is charged, and results fetched so far stay readable. A finished job is returned unchanged. Free.
Request example
Responses
{
"ok": true,
"request_id": "req_…",
"data": {
"kind": "channel_job",
"id": "cjob_m3k1x9qz4vb2p7",
"status": "cancelled",
"channel": "@3blue1brown",
"platform": "youtube",
"options": {},
"since_video_id": null,
"max_videos": 500,
"transcripts": {
"mode": "captions",
"timestamps": false,
"chunks": {
"max_tokens": 500,
"overlap_tokens": 50
}
},
"webhook_url": "https://example.com/hooks/transcriptfetch",
"listed": 142,
"completed": 96,
"failed": 3,
"processing": 0,
"credits_spent": 98,
"error": null,
"created_at": "2026-10-21T10:00:00.000Z",
"started_at": "2026-10-21T10:00:20.000Z",
"finished_at": "2026-10-21T10:05:00.000Z",
"results_expire_at": null,
"poll_url": "/api/v2/jobs/channel/cjob_m3k1x9qz4vb2p7"
}
}