Every videois a dataset.

Describe the fields you want, send up to 200 YouTube URLs, get typed and validated JSON rows back.

How it works
One video. Five steps.Four validated rows.
schema · street-food-toursmultiple: true
restaurant_nameverbatim-string
Name of the restaurant or stall, as spoken.
food_orderedstring[]
Every dish or drink the host orders there.
pricenumber
Price mentioned for the order, if any.
verdictenum
loved, fine or skip, from what the host says.
POSTapi.tubeextract.dev/v1
curl https://api.tubeextract.dev/v1 \
-H "X-API-Key: $TUBEEXTRACT_KEY" \
-d '{
"videos": ["https://youtu.be/dQ8x2Kp"],
"multiple": true,
"schema": [
{ "name": "restaurant_name",
"type": "verbatim-string" },
{ "name": "food_ordered",
"type": "string[]" },
...
]
}'
202 Acceptedjob_id: "8f2c1e40-91a3"
job log
›0.4sjob accepted · 1 video
›1.3scaption track found · auto-generated · 13:02
›2.2stranscript split into 3 chunks at sentence ends
›3.1schunks queued for extraction
chunk 100:00–04:40
chunk 204:40–09:20
chunk 309:20–13:02
entities foundspecialised model · 3 chunks in parallel
0
restaurants
0
dishes
0
prices
Corner Butcherlamb gyro18 dollarsBlue DoorbaklavaespressoFisherman Alfish sandwichStuffed musselsDiner 19232 dollars
200 OKGET /v1/8f2c1e40
restaurantfood_orderedpriceverdict
Corner Butcherlamb gyro18loved
Blue Doorbaklava, espresso—loved
Fisherman Alfish sandwich—fine
Diner 1923stuffed mussels2loved
usage: { credits_charged: 140, duration_seconds: 782, chunk_count: 3 }
200
videos in a single batch call
10
credits per started minute of video
0
credits for a video that fails
Built for production

A specialised pipeline, not a wrapper around a chat model.

restaurant_nameverbatim-stringdishesstring[]pricenumberverdictenumis_sponsoredbooleansummarystring

Schema, not scraping code

Columns are a name, a type and a sentence. Rows come back validated against them, so nothing malformed reaches your database.

200 videos, one call

Each video runs as its own job under one job id, so a bad URL in the batch does not sink the rest.

no_captions0 credits
schema_invalid0 credits
13:02 video, done140 credits
14 started minutes at 10 credits each.

Failures cost nothing

10 credits per started minute of a video that returns a result. Every response says what it charged.

GET /v1/8f2c1e40 → rows: [4]
GET /v1/8f2c1e40 → rows: null
result and video URL deleted on first read

Deleted on fetch

The result JSON and the submitted URL leave our database the moment your GET succeeds.

POST https://your.app/hooks
{ "event": "job.completed",
  "job_id": "8f2c1e40" }

Webhooks, no polling

Get told when a job finishes, then collect the rows on your own schedule.

chunk 100:00–04:40
chunk 204:40–09:20
chunk 309:20–13:02

Our model, our GPU

A specialised extraction model with deterministic post-processing. The cost of a minute rounds to zero, which is what the pricing is built on.

Use cases

Ask anything of what was said.

Product reviews into a catalogue

Turn a channel of review videos into a product table your app can query: what was reviewed, the price quoted, and the reviewer's verdict.

productverbatim-string
price_usdnumber
verdictenum
200GET /v1/c41a9e02 · 38 videos · 212 rows
productprice_usdverdictSony WH-1000XM6399recommendedFramework 131049recommendedPixel Buds Pro 2229mixed
The API

Two calls and a header.

Submit, then collect. Everything else is your schema.

POST/v1Submit 1–200 videos with a schema
GET/v1/:job_idCollect rows, then they are deleted
GET/v1/usageCredits used this cycle
no_captions
The video has no caption track. Not charged.
batch_too_large
More than 200 videos in one call.
schema_invalid
A column type or name the API cannot use.
insufficient_credits
The balance cannot pay for the video.
# 1. Submit a job
curl https://api.tubeextract.dev/v1 \
-H "X-API-Key: $TUBEEXTRACT_KEY" \
-H "Content-Type: application/json" \
-d '{ "videos": ["https://youtu.be/dQ8x2Kp"],
"multiple": true,
"schema": [{ "name": "restaurant_name",
"type": "verbatim-string" }] }'
# 2. Collect the rows
curl https://api.tubeextract.dev/v1/8f2c1e40 \
-H "X-API-Key: $TUBEEXTRACT_KEY"
not sentPOST /v1 → GET /v1/:job_id
Press Run to send this request against a recorded response. No credits spent.
FAQ

Questions we actually get

Anything missing? Write to support@tubeextract.dev. A person, not a ticket queue, answers.

A transcript API returns the caption text and leaves the rest to you. TubeExtract reads the same captions and returns rows that match a schema you describe, typed and validated, so there is no parsing or prompting to write. You get the data itself, ready to store, query or chart.

Yes. Ask for the entities as columns -- people, companies, products, places -- and each one comes back as its own typed field, with an enum column if you want the entity type named from a fixed list. Names are copied as spoken when the column is verbatim-string, so they can be matched against your own records.

It returns no_captions and costs nothing, so you can send whole playlists without checking each video first. TubeExtract reads the manual or auto-generated caption track, which keeps every job fast and simply priced per minute.

10 credits for every started minute of a video that returns a result, however many rows come back: a 14-minute video is 140 credits. Jobs that fail are never charged, and every response reports what it charged.

The result JSON and the submitted video URL are deleted from our database the moment your GET request succeeds. A second fetch of the same job returns status: done with each video's rows: null.

Up to 200 videos in a single call. Each video runs as its own job under one job id, so a bad URL in the batch does not sink the rest.

Try it on your own video.

3,000 free credits are on the account when you sign up. Point the API at one video, check the rows, then batch the rest.