Introduction
The Tunelio API gives you direct YouTube video and audio URLs, rich media metadata, and timestamped transcripts. Download links come back in the same request — no queues, no polling, no progress webhooks.
Base URL: https://tunelio.dev. All requests use TLS 1.2+. Responses are JSON with UTF-8 encoding.
Mental model
Call /info to see what formats are available for a given URL, then call /create with the chosen quality. The response from /create contains a url that points to our stream tunnel — hand that to your user, your downloader, or a presigned S3 upload. There's no step three.
Authentication
All requests require an API key sent as a Bearer token in the Authorization header.
Authorization: Bearer tnl_8f3a92b1c4d5e6f7a8b9c0d1e2f3a4b5Sign in with Telegram (one tap with our bot) or register with your Email, then generate your API key from the Dashboard. The whole flow takes about 60 seconds and doesn't require a payment method.
Quickstart
Make your first call in three lines. Replace the key with your own and the URL with any YouTube link.
curl "https://tunelio.dev/create?quality=720p&url=https://youtu.be/dQw4w9WgXcQ" \
-H "Authorization: Bearer tnl_…"Extract full timestamped text, auto vs manual subtitles, SRT, VTT, or plain text without bot detection walls (6 credits).
curl -X GET "https://tunelio.dev/transcript?url=dQw4w9WgXcQ&lang=en&format=json" \
-H "Authorization: Bearer tnl_…"GET /info
Resolves a YouTube URL and returns the full metadata — title, duration, thumbnail, and every available video and audio format with file sizes and dimensions.
Query parameters
urlstringrequiredA YouTube URL: watch?v=, youtu.be/, /shorts/, /embed/, or /live/. Any of these resolve identically.Try it
tunelio.dev/infoGET tunelio.dev/info?url=https://youtu.be/dQw4w9WgXcQResponse shape
titlestringVideo title as published.duration_secondsintegerTotal length in seconds.duration_strstringHuman-readable HH:MM:SS (or MM:SS when < 1h). Zero-padded.thumbnailstring (URL)Highest-resolution thumbnail available.formats[]array<Format>Every video format. See sub-fields below.formats[].qualitystringHuman label: 144p, 240p, 360p, 480p, 720p, 1080p.formats[].file_sizeinteger (bytes)Exact size in bytes.formats[].file_size_strstringHuman-readable size — e.g. "84.50 MB" or "1.20 GB".formats[].widthintegerEncoded frame width in pixels.formats[].heightintegerEncoded frame height in pixels.audioFormatobject<Audio>|nullThe best MP3 audio rendition — single object, or null if no audio track is available.audioFormat.formatstringContainer — currently mp3.audioFormat.file_sizeintegerExact MP3 size in bytes.audioFormat.file_size_strstringHuman-readable MP3 size — e.g. "35.01 MB".Cost
6 credits per call.
GET /create
Generates a direct, signed download URL for a chosen format. The link comes back in the same response — there's no job to poll, no webhook to listen for.
Query parameters
urlstringrequiredYouTube URL — same formats as /info.qualitystringrequiredOne of 144p, 240p, 360p, 480p, 720p, 1080p, 2160p (Mega only), mp3 for audio, or opus for raw Opus audio (no re-encode).audioBitrateintegeroptionalOptional. Only used when quality is opus — selects the nearest native Opus bitrate tier in kbps (e.g. 64). Ignored for every other quality.Try it
tunelio.dev/createGET tunelio.dev/create?url=https://youtu.be/dQw4w9WgXcQ&quality=1080pResponse shape
urlstring (URL)Signed stream tunnel URL. Hand to your user or pipe to storage.filenamestringSuggested filename based on the video title and chosen format.qualitystringEcho of your requested quality — e.g. 1080p, mp3, or opus.modestring"video" or "audio".expiresinteger (unix)Timestamp when the signed URL stops working — typically 6 hours out.file_sizeintegerFinal file size in bytes.file_size_strstringHuman-readable size — e.g. "84.50 MB".statusstring"ok" on success — otherwise the error message.Cost
10 credits per call. The cost is the same regardless of file size — you pay for the resolution work, not the bytes.
GET /transcript
Fetch full transcripts and subtitles for any YouTube video with timestamps, language selection, and manual vs. auto-generated indicators.
Query parameters
urlstringrequiredYouTube watch, shorts, embed, youtu.be URL or 11-char Video ID.langstringoptionalTarget language code (e.g. en, es, de, ja). Defaults to en.typestringoptionalFilter by type: any (prefers manual), manual, or auto.formatstringoptionalOutput format: json (default), text, srt, or vtt.Try it
tunelio.dev/transcriptGET tunelio.dev/transcript?url=https://youtu.be/dQw4w9WgXcQ&lang=en&format=jsonResponse shape
video_idstringThe 11-character YouTube video ID.titlestringTitle of the YouTube video.languagestringSelected language code.language_namestringDisplay name of selected language.is_generatedbooleanTrue if auto-generated ASR, false if manually uploaded.typestring"manual" or "auto".available_languagesarray<Language>List of all available subtitle/transcript tracks.segments_countintegerNumber of timed text segments.segmentsarray<Segment>Array of { start, duration, text } objects.full_textstringComplete continuous text of the transcript.statusstring"ok" on success.Cost
Extracting a transcript costs 6 credits per unique video request. Cached repeats respond in under 5ms.
GET /credits
Returns your remaining credit balance and effective plan. Use it to check how much you have left before a batch of calls, or to surface a balance in your own dashboard.
No query parameters — just your API key. The same Bearer token (or X-API-Key header) used everywhere else authenticates this call.
Try it
tunelio.dev/creditsGET tunelio.dev/creditsResponse shape
creditsintegerRemaining credit balance, as an integer.planstringYour effective plan: trial, pro, ultra, or mega. A lapsed paid plan reports trial.Response headers
The same balance is mirrored in response headers, matching /info and /create — handy if you want the numbers without parsing the body:
X-Credits-RemainingintRemaining credit balance.X-Credits-PlanstrYour effective plan name.Cost
Free. Checking your balance never consumes credits.
/tunnel
/tunnel is the URL you get back from /create. You never call it from your code — you hand the URL to your user, your <a download> tag, your S3 uploader, your Telegram bot, etc.
What it returns
The actual file — MP4 or MP3 — with appropriate Content-Type and Content-Disposition: attachment; filename="…" headers. It supports HTTP range requests, so video players can seek and downloaders can resume.
Authentication
None. The URL is self-signed with an exp timestamp and a sig HMAC. After expires passes, the link returns 410 Gone — call /create again for a fresh one.
Costs
Free. Bandwidth is on us within reason — we throttle abuse but normal use never triggers it.
Repackaging
By default /tunnel streams the file as it is built — right for a download, wrong for a player: there is no Range and no length known up front. Add one of these to the same link to get the same media packaged differently. The link does not change, nothing extra is charged, and the result is built once and then cached.
Repackaging applies to merged mp4 downloads. Audio-only and other formats answer 400, a clip combined with hls answers 400, and a file too large to build answers 413 — download it normally instead.
Rate limits
Rate limits are per API key, measured in requests per minute. They reset every 60 seconds on a rolling window. Ultra and Mega plans have no rate limit.
Exceeding the limit returns 429 Too Many Requests with a Retry-After header (in seconds). If you regularly bump the ceiling, upgrade rather than adding client-side backoff — limits exist so you don't accidentally drain your credits.
Errors
All error responses follow the same shape:
{
"error": "invalid_url",
"message": "Provided URL is not a recognised YouTube link."
}Status codes
invalid_requestMissing or malformed parameter — usually a bad URL or unknown quality.unauthorizedMissing or invalid Bearer token.insufficient_creditsYour account is out of credits. Top up or upgrade.not_foundVideo does not exist, is private, or was deleted.goneYou called a /tunnel URL after its expires timestamp.rate_limitedPlan rate limit hit. Respect the Retry-After header.server_errorUnexpected on our side. Safe to retry with exponential backoff.upstream_changedYouTube changed something we hadn't patched yet. Usually self-heals within an hour.Credits & billing
Every call costs a fixed number of credits regardless of video size or duration:
GET /info6 creditsGET /create10 credits/tunnel downloadfreeA typical "fetch info, then download" round-trip is 16 credits. New accounts start with 100 free credits. Paid plans refresh monthly with fresh credits each cycle. Unused credits expire at the end of the cycle; wallet funds never expire.
Failed requests (4xx and 5xx) do not consume credits — you're only billed for successful resolutions.