# YouTube Transcript Scraper — Pay Per Result, No Empty Charges (`greza/youtube-transcript-scraper`) Actor

Extract transcripts/subtitles from YouTube videos in bulk. Paste URLs or IDs — get clean text, timestamped segments, SRT/VTT subtitle files, and video metadata (title, channel, views). Pay per result — videos without captions are never billed.

- **URL**: https://apify.com/greza/youtube-transcript-scraper.md
- **Developed by:** [Sergei Peleskov](https://apify.com/greza) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## YouTube Transcript Scraper — bulk captions & subtitles extractor

Scrape **YouTube transcripts, subtitles and captions in bulk**. Paste a list of video links or IDs and get back clean, LLM/RAG-ready text plus timestamped segments for every video that has captions. **Pay per result** — videos without captions, or videos that are unavailable, are **never billed**.

Works with regular videos, **YouTube Shorts**, live VOD, and bare video IDs. No proxies, no YouTube API keys, no scraping setup on your side.

### Why this Actor

#### This Actor vs typical transcript scrapers

|  | This Actor | Typical transcript scrapers |
|---|---|---|
| Pay for videos without captions | ❌ Never — skipped, not billed | ✅ Charged per call, you get `data: null` |
| Input formats | ✅ watch / youtu.be / Shorts / embed / live / mobile / bare IDs, mixed | ⚠️ One rigid URL field, confusing mutually-exclusive inputs |
| Output | ✅ Both plain `text` AND timestamped `segments`, always | ⚠️ One format, join/split is your problem |
| Subtitle file export | ✅ Ready-to-save SRT and VTT on demand | ⚠️ Rare — build the file yourself |
| Channel/playlist listing | ✅ List every video first, pay transcripts only for the ones you pick | ❌ One-shot channel scrape — you pay for the whole channel blind |
| Batch in one run | ✅ Hundreds of videos | ⚠️ Often one video per run |
| Skipped videos explained | ✅ Human-readable reason per video in `OUTPUT` | ❌ Silent nulls |
| Platform usage on top | ✅ Never — all-inclusive | ❌ Compute + proxy billed separately |

#### Price on the tag vs price on the invoice

Most transcript scrapers charge **$X /1,000 videos + Apify platform usage on top** (compute units, proxy, storage). The sticker price is not the final price.

This Actor is **pay-per-result, all-inclusive**: $5.00 /1,000 successful transcripts already covers residential proxies, retries, and compute. No platform usage line on your bill. Videos without captions are never billed.

Run 1,000 videos, get a predictable invoice. That's the whole pricing model.

### What it does

Give it a list of YouTube videos — full links, short links, Shorts, or bare video IDs, mixed however you like — and it returns each video's transcript as both plain text and timestamped segments. You can batch hundreds of videos in one run. There's no scraping setup, no proxies, and no YouTube API keys to manage on your side: reliability (retries, residential IP rotation, rate-limit handling) is handled for you. Videos that genuinely have no captions are reported separately and cost you nothing.

### Use cases

- **LLM & RAG pipelines** — feed clean transcript text straight into embeddings, summarization, or chat-with-video apps
- **Content research & repurposing** — turn videos into articles, newsletters, show notes
- **Subtitle & caption workflows** — timestamped segments ready for SRT/VTT generation or alignment
- **SEO & competitive analysis** — analyze what competitor channels actually say, at scale
- **Search & indexing** — make video libraries full-text searchable

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `mode` | string | no | `transcripts` (default) — get transcripts of the videos in `videoUrls`. `listVideos` — list every video of one channel/playlist in `videoUrls` (no transcripts). |
| `videoUrls` | list of strings | yes | Transcripts mode: one video per line (links or IDs, mixed), **max 500 per run**. List-videos mode: **exactly one** channel/playlist reference (`@handle`, `/channel/UC…`, `/playlist?list=…`, or a bare playlist/UC id). |
| `language` | string | no | Transcripts mode only. Preferred transcript language code (`en`, `es`, `pt-BR`). Leave empty for the video's default. |
| `strictLanguage` | boolean | no | If `true`, a video is skipped when the exact language isn't available (instead of falling back). Default `false`. |
| `subtitleFormat` | string | no | Add ready-to-use subtitle file content to each result: `none` (default), `srt`, `vtt`, or `both`. Does not change pricing. |

Supported link forms: `youtube.com/watch?v=…`, `youtu.be/…`, `youtube.com/shorts/…`, `/embed/…`, `/live/…`, and their `m.` mobile variants — plus bare video IDs.

### Examples

**1. Mixed links and IDs**

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/jNQXAC9IVRw",
    "9bZkp7q19f0"
  ]
}
````

**2. Prefer Spanish, fall back if unavailable**

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "language": "es"
}
```

Not sure which language a video is in? Leave `language` empty and keep `strictLanguage` off — you'll always get whatever transcript the video has.

**3. Strict: only Spanish, skip otherwise**

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "language": "es",
  "strictLanguage": true
}
```

**4. Also get subtitle files (SRT + VTT)**

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "subtitleFormat": "both"
}
```

Each result then also carries ready-to-save `srt` and `vtt` fields.

### Output

Each successful video becomes one dataset item:

```json
{
  "videoId": "dQw4w9WgXcQ",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "language": "en",
  "kind": "manual",
  "requestedLanguageMatched": true,
  "video": {
    "title": "Rick Astley - Never Gonna Give You Up",
    "channel": "Rick Astley",
    "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "durationSec": 213,
    "viewCount": 1694000000
  },
  "segments": [
    { "startMs": 0, "durationMs": 1200, "text": "..." }
  ],
  "text": "full transcript as plain text ...",
  "srt": "1\n00:00:00,000 --> 00:00:01,200\n...\n",
  "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:01.200\n...\n"
}
```

- `text` is the whole transcript as one plain-text string — ready to drop into an LLM prompt or a RAG pipeline.
- `segments` gives you the same text split into timestamped chunks (`startMs`, `durationMs`) for captioning, search, or alignment.
- `video` is always included: `title`, `channel`, `channelId`, `durationSec`, `viewCount` (any field may be `null` if YouTube omits it).
- `srt` / `vtt` are included only when you set **Subtitle file format** (`srt`, `vtt`, or `both`) — ready-to-save subtitle file content.
- `kind` is `manual` (human-written) or `asr` (auto-generated).
- `requestedLanguageMatched` is `true`/`false` when you asked for a language (`false` = a fallback track was returned), or `null` when you didn't.

Skipped videos are not in the dataset. A per-run summary is written to the key-value store record `OUTPUT`, listing every skipped video with a plain-English reason (no captions, unavailable, etc.).

### List all videos of a channel

Set **What to get** to *List all videos of a channel or playlist* (`mode: listVideos`) and put **exactly one** channel or playlist reference in `videoUrls`. You get one dataset item per video — no transcripts, much cheaper — so you can see a channel's whole catalogue before spending anything on transcripts.

Input:

```json
{
  "mode": "listVideos",
  "videoUrls": ["https://www.youtube.com/@MrBeast"]
}
```

Accepted references: a channel link (`youtube.com/@handle` or `/channel/UC…`), a playlist link (`youtube.com/playlist?list=…`), or a bare playlist / `UC…` id. Exactly one — more than one entry, or a single video link, fails the run before anything is billed.

Each item:

```json
{
  "videoId": "GvgqDSnpRQM",
  "url": "https://www.youtube.com/watch?v=GvgqDSnpRQM",
  "title": "Andrew Willis, Skatepark Engineer",
  "channel": "Google Search Stories",
  "durationSec": 90,
  "position": 1,
  "source": { "type": "playlist", "id": "PLBCF2DAC6FFB574DE", "url": "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE" }
}
```

`position` is the 1-based order as YouTube returns it (newest first). `title`/`durationSec` are best-effort and may be `null`. Very large channels are capped; if so the run still returns the list it got and notes it in the `OUTPUT` summary.

Listing results are written to a dataset named **`video-list`** (not the default dataset) — open it from the run's Storage tab. This keeps listing billed at the cheap per-video rate, separate from transcript results.

**Listing price: $0.50 / 1,000 videos listed** — 10× cheaper than transcripts, so previewing a channel is nearly free.

#### Recipe: preview a channel, then pay only for what you want

1. Run **listVideos** on the channel `@handle` → get every `videoId` (cheap).
2. Skim titles/durations, pick the videos you actually need.
3. Run **transcripts** mode with just those IDs in `videoUrls`.

You pay full transcript price only for the videos you chose — not the whole channel. One-shot "scrape the whole channel" actors can't do this: they transcribe (and bill) everything blind.

### Pricing

**Pay per result. You only pay for successful transcripts** — videos without captions, unavailable videos, and unreadable input are never billed. There are no subscriptions and no charges for empty results. Listing a channel/playlist (`listVideos` mode) is billed separately at **$0.50 / 1,000 videos listed**.

### Reliability

YouTube's transcript backend breaks roughly twice a year — and every time it does, transcript scrapers across the ecosystem go dark for days (most recently December 2025 and January 2026). This Actor is built around that fact:

- **Dedicated gateway, not a script in a container.** Requests go through a self-hosted API layer with automatic retries, residential IP rotation, and rate-limit back-off. A single YouTube hiccup doesn't fail your run.
- **24/7 breakage monitoring.** Upstream error rates are monitored continuously; a spike pages the operator immediately — issues are typically being worked before users notice.
- **Honest failure reporting.** Transient problems are retried transparently. Only genuinely-missing transcripts are reported as skipped — with the reason, and without a charge.
- **Actively maintained.** This is a production service, not an abandoned side project. Check the issue response time on this page.

### FAQ

**A video has no captions — what happens?** It's skipped (not added to the dataset), listed in the `OUTPUT` summary as `NO_CAPTIONS`, and you're not charged for it. The run still succeeds.

**What if I'm not sure of the video's language?** Leave `language` empty (or keep `strictLanguage` off). You'll get the video's available transcript. Set a language only when you specifically want one, and turn on `strictLanguage` only when a fallback is unacceptable.

**Can I get SRT/VTT files?** Yes. Set **Subtitle file format** to `srt`, `vtt`, or `both`, and each result gains an `srt` and/or `vtt` field with ready-to-save subtitle file content (built from the same timestamps as `segments`). It doesn't change pricing — you're still charged one result per video.

**Can I get transcripts for a whole channel?** In two cheap steps. First run **List all videos of a channel** (`mode: listVideos`) on the channel `@handle` — that lists every video ID for $0.50/1,000, no transcripts. Then run **Transcripts** mode with the IDs you actually want. This "preview before you pay" flow means you never pay to transcribe videos you don't need. (There is deliberately no single "whole-channel transcripts" button — it would bill you for the entire back catalogue up front.)

**Do YouTube Shorts work?** Yes. `youtube.com/shorts/…` links (and `youtu.be`, embed, live, mobile `m.` variants) are all accepted.

**Does it work with auto-generated captions?** Yes — both human-written (`manual`) and auto-generated (`asr`) tracks are extracted; the `kind` field tells you which one you got.

**What about region-restricted videos?** If a video can't be accessed due to region restrictions, it's skipped and reported as `GEO_BLOCKED` in the summary — not billed.

**Why did some videos get skipped?** Open the `OUTPUT` record in the run's key-value store. Every skipped video is listed with its reason (`NO_CAPTIONS`, `VIDEO_UNAVAILABLE`, `LANG_NOT_FOUND`, `GEO_BLOCKED`, `INVALID_INPUT`, or a temporary error after retries). The final log line also shows the success count.

### Support

Questions, issues, or a feature request? Open an issue on the **Issues** tab — response times are shown on this page — or email **info@greza.dev**.

# Actor input Schema

## `mode` (type: `string`):

Transcripts of specific videos — paste video links/IDs below and get transcripts (up to 500 per run). List all videos of a channel or playlist — paste ONE channel or playlist link below and get every video's ID, URL, title and duration (cheap, no transcripts). Tip: use listing first to preview a channel, then run Transcripts on the IDs you want.

## `videoUrls` (type: `array`):

Transcripts mode: one video per line — full YouTube links or 11-character IDs (watch, youtu.be, Shorts, embed, live), max 500 per run. Anything unreadable is skipped and listed in OUTPUT, never charged. List-videos mode: put EXACTLY ONE channel or playlist reference here — a channel link (youtube.com/@handle or /channel/UC…), a playlist link (youtube.com/playlist?list=…), or a bare playlist/UC id.

## `language` (type: `string`):

Transcripts mode only (ignored when listing videos). Language code of the transcript you want, e.g. `en` (English), `es` (Spanish), `pt-BR` (Brazilian Portuguese). Leave this EMPTY if you're not sure — we'll return the video's default transcript. If the exact language isn't available, by default we fall back to whatever the video has (see 'Fail if language is missing' below to change that).

## `strictLanguage` (type: `boolean`):

Transcripts mode only (ignored when listing videos). Only matters when you set a Preferred language above. Off (default): if that language isn't available, we return another available transcript so you still get data. On: the video is skipped (reported as LANG\_NOT\_FOUND) instead of falling back. Keep this OFF unless you strictly need one exact language.

## `subtitleFormat` (type: `string`):

Transcripts mode only (ignored when listing videos). Add ready-to-use subtitle file content (SRT/VTT) to each result. None (default): only the plain text and timestamped segments. SRT / VTT: also include that subtitle file as a text field. Both: include SRT and VTT. This does not change pricing — you are still charged one result per video.

## Actor input object example

```json
{
  "mode": "transcripts",
  "videoUrls": [
    "dQw4w9WgXcQ",
    "jNQXAC9IVRw",
    "9bZkp7q19f0"
  ],
  "language": "",
  "strictLanguage": false,
  "subtitleFormat": "none"
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "videoUrls": [
        "dQw4w9WgXcQ",
        "jNQXAC9IVRw",
        "9bZkp7q19f0"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("greza/youtube-transcript-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "videoUrls": [
        "dQw4w9WgXcQ",
        "jNQXAC9IVRw",
        "9bZkp7q19f0",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("greza/youtube-transcript-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "videoUrls": [
    "dQw4w9WgXcQ",
    "jNQXAC9IVRw",
    "9bZkp7q19f0"
  ]
}' |
apify call greza/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=greza/youtube-transcript-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Transcript Scraper — Pay Per Result, No Empty Charges",
        "description": "Extract transcripts/subtitles from YouTube videos in bulk. Paste URLs or IDs — get clean text, timestamped segments, SRT/VTT subtitle files, and video metadata (title, channel, views). Pay per result — videos without captions are never billed.",
        "version": "0.1",
        "x-build-id": "xR6ayQvF1pm0CEOQc"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/greza~youtube-transcript-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-greza-youtube-transcript-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/greza~youtube-transcript-scraper/runs": {
            "post": {
                "operationId": "runs-sync-greza-youtube-transcript-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/greza~youtube-transcript-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-greza-youtube-transcript-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "videoUrls"
                ],
                "properties": {
                    "mode": {
                        "title": "What to get",
                        "enum": [
                            "transcripts",
                            "listVideos"
                        ],
                        "type": "string",
                        "description": "Transcripts of specific videos — paste video links/IDs below and get transcripts (up to 500 per run). List all videos of a channel or playlist — paste ONE channel or playlist link below and get every video's ID, URL, title and duration (cheap, no transcripts). Tip: use listing first to preview a channel, then run Transcripts on the IDs you want.",
                        "default": "transcripts"
                    },
                    "videoUrls": {
                        "title": "YouTube videos, channel or playlist",
                        "minItems": 1,
                        "type": "array",
                        "description": "Transcripts mode: one video per line — full YouTube links or 11-character IDs (watch, youtu.be, Shorts, embed, live), max 500 per run. Anything unreadable is skipped and listed in OUTPUT, never charged. List-videos mode: put EXACTLY ONE channel or playlist reference here — a channel link (youtube.com/@handle or /channel/UC…), a playlist link (youtube.com/playlist?list=…), or a bare playlist/UC id.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "language": {
                        "title": "Preferred language",
                        "type": "string",
                        "description": "Transcripts mode only (ignored when listing videos). Language code of the transcript you want, e.g. `en` (English), `es` (Spanish), `pt-BR` (Brazilian Portuguese). Leave this EMPTY if you're not sure — we'll return the video's default transcript. If the exact language isn't available, by default we fall back to whatever the video has (see 'Fail if language is missing' below to change that).",
                        "default": ""
                    },
                    "strictLanguage": {
                        "title": "Fail if language is missing",
                        "type": "boolean",
                        "description": "Transcripts mode only (ignored when listing videos). Only matters when you set a Preferred language above. Off (default): if that language isn't available, we return another available transcript so you still get data. On: the video is skipped (reported as LANG_NOT_FOUND) instead of falling back. Keep this OFF unless you strictly need one exact language.",
                        "default": false
                    },
                    "subtitleFormat": {
                        "title": "Subtitle file format",
                        "enum": [
                            "none",
                            "srt",
                            "vtt",
                            "both"
                        ],
                        "type": "string",
                        "description": "Transcripts mode only (ignored when listing videos). Add ready-to-use subtitle file content (SRT/VTT) to each result. None (default): only the plain text and timestamped segments. SRT / VTT: also include that subtitle file as a text field. Both: include SRT and VTT. This does not change pricing — you are still charged one result per video.",
                        "default": "none"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
