Media API
Send a public post URL. Receive source media URLs and metadata. Download directly, stream through the API, or request a temporary server copy.
OpenAPI 3.1 specification ยท Import this URL into your API client.
Authentication
Use Authorization: Bearer YOUR_API_KEY. Local setup writes your key to tmp/media-api/api-key and a private curl configuration to tmp/media-api/client.curl.
Resolve a post
curl --config tmp/media-api/client.curl \
-H 'Content-Type: application/json' \
-d '{"url":"https://www.youtube.com/shorts/YIT2Up1imWs","quality":"720"}' \
http://127.0.0.1:8098/v1/resolve
| Field | Values |
|---|---|
url | HTTPS link to a specific supported public media post |
media | all (default), video, audio |
quality | best or a short-edge pixel limit from 144 to 4320 |
proxy_mode | auto (default), direct for ordinary egress, or proxy for a configured paid route |
Results contain ordered items and their formats, with URLs, dimensions, codecs, sizes and safe public headers. Use recommended_format_ids for checked source representations. Separate video/audio streams require client-side merging; HLS/DASH require a suitable downloader. Source cookies and authorization headers are not disclosed.
Source links can expire or depend on IP and headers. expires_at: null means unknown; refresh_after is a cache hint. Cross-network usability must be verified before commercial launch.
There is no 1080p cap: request best or an explicit ceiling up to 4320p. Only available source renditions are returned; the API does not transcode a smaller version.
Streaming fallback
After a failed direct download, send POST /v1/tunnels with the original operation_id, item_index and format_id. The API returns a relative url and expires_at. Both SDKs expose tunnel() and return an absolute URL. GET the ticket URL without an API key; keep that URL private.
{"operation_id":"OPERATION_ID","item_index":0,"format_id":"FORMAT_ID"}
There is no repeated extraction or second resolution unit. Original file bytes stream through the server without storage, conversion or merging. Progressive HTTP(S) files only; HLS/DASH and separate-track merging remain client responsibilities. A tunnel cannot repair an unavailable source or missing login.
Tickets expire within five minutes of resolution and allow three GETs. Limits: 256 MiB and ten minutes per transfer, 1 GiB per client/UTC day, and daily transfer attempts up to three times the resolution quota. Single byte ranges depend on source support. Disconnect cancels upstream. Restarts invalidate tickets.
Automatic delivery and temporary storage
Send POST /v1/deliveries with the same selection, mode: "auto", and failed_modes: []. The response selects a direct link first, a tunnel after a reported direct failure, then temporary storage after both methods fail. Explicit modes are direct, tunnel and stored.
The SDK detects transfer errors and reports them. Python download() and Node downloadTo() perform this sequence automatically. A ready stored copy can be reused after a direct failure without fetching the source again. The server cannot observe a client's independent CDN download or a normal browser download button.
POST /v1/files explicitly stores an owned resolved format. It responds immediately with 202 and a status URL. Poll GET /v1/files/{id}; a ready response includes a download URL, actual size, SHA-256 and expiry. DELETE /v1/files/{id} cancels or deletes it. Repeated requests reuse an active or ready copy.
Only complete original files are published. Defaults: 256 MiB per file, 1 GiB total disk, 15-minute retention, ten GETs per file and two simultaneous transfers. Stored downloads support byte ranges. Source fetches and downloads share the daily traffic budget with tunnels; no extra resolution unit is charged. Expiry, cancellation and restart remove bytes. Storage is never started merely by resolving a URL.
Public-data scraping
The same local API key can run independent scraping operations. GET /v1/scrapers lists registered source/operation pairs and current runtime features. Registration does not guarantee that a source accepts requests from this machine. Use the live catalog rather than a hardcoded site list.
curl --config tmp/media-api/client.curl \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: app-search-example-1' \
-d '{"source":"apple","operation":"search","query":"notes","limit":5}' \
http://127.0.0.1:8098/v1/scrape
Requests accept source, operation, and operation-specific url, query, id, username, country, language, page, limit, headers and options. Responses contain request_id, operation_id, result, cache_hit and usage. The independent result includes source, operation, fetch time and a data object; screenshots expose genuine bytes in data.image_base64. Use /v1/resolve for downloadable media formats.
Successful scraping operations share the existing rate, daily usage and concurrency budgets. Matching idempotent scraping responses remain in bounded memory for up to 60 seconds. Only a request fingerprint is persisted; source parameters, private headers and source bodies are not stored in operation records. Python exposes scrapers() and scrape(source, operation, **options); Node exposes scrapers() and scrape(source, operation, options).
Fetch targets, redirects and browser network requests must pass public HTTP(S) destination validation. Private, loopback, link-local and metadata addresses are rejected. Browser rendering requires its local runtime; real geographic or residential routing requires a matching configured proxy. A browser is not a CAPTCHA solver. Missing integrations return dependency_missing; observed source challenges, login requirements and rate limits return structured errors. Optional error.requires identifies a needed dependency. Paid proxy and CAPTCHA credentials are not provisioned.
Optional adaptive proxy routing
Scraper requests select options.proxy_mode; media resolution selects top-level proxy_mode. auto starts with ordinary egress, through Squid in Compose, and permits one paid retry for eligible source blocks, challenges, rate limits without source backoff, or transport timeouts. A successful retry may create a ten-minute route preference. Ordinary success clears it; paid failure clears it and starts a one-minute cooldown. Login requirements, private/missing content, parse failures, explicit source backoff and cancellation do not trigger a paid retry. Automatic retries do not move configured account sessions or sensitive customer headers to a paid route.
direct uses ordinary egress. proxy requires an enabled matching operator paid pool and may use configured source authentication. Provider credentials and endpoints are operator-only. With no paid pool there is no paid traffic. The API and browser keep their existing isolated networks; paid providers are reached through Squid with exact endpoint CONNECT exceptions, public target validation and IP pinning.
Default shared paid caps: 20 attempts and 128 MiB per UTC day globally, 10 attempts and 64 MiB per client/day, 32 MiB per operation, and one paid grant per source operation. Grants last at most one minute. Limits include HTTP, browser, native extraction and enabled media delivery; metered transport bytes include protocol overhead. Limits and route preferences are held in bounded memory and reset on restart. Private --adaptive-proxy-config settings can change these limits or disable paid routing.
Scraper result.routing contains mode (direct/proxy), attempts and provider_bytes; media routing uses route (free/proxy). Formats marked delivery_requires_proxy may depend on the provider's IP. Paid media streaming and storage require explicit private allow_paid_media: true; by default they return paid_media_disabled before fetching the source. Clients may try returned source URLs from their own connection. Provider refusals and allowance limits return safe codes without revealing provider details. See docs/scraper-api.md for private configuration and restrictions.
Asynchronous scraping
POST /v1/scrape/jobs accepts {"request":{...}} and optional callback_url/callback_secret. Poll the returned status_url with the owning API key or cancel with DELETE. The queue retains at most 64 jobs and 16 MiB of completed results for up to 15 minutes; completed results can expire earlier under memory pressure. Jobs do not survive restart. An optional Idempotency-Key replays a retained owned job with matching request and callback settings. A successful job's result contains the synchronous scrape envelope.
Optional callbacks POST the job ID, status and result/error to a validated public HTTP(S) URL. A nonempty separate secret adds X-Scraper-Signature: sha256=..., an HMAC-SHA256 over the exact JSON body bytes. Empty secrets leave callbacks unsigned. Delivery makes up to three bounded attempts; a delivery failure does not rerun the source. Localhost callbacks are rejected; local clients can poll instead. SDK helpers: Python create_scrape_job(), scrape_job(), cancel_scrape_job(); Node createScrapeJob(), scrapeJob(), cancelScrapeJob().
The repository guide docs/scraper-api.md documents selectors, errors and callback verification. Reference coverage in docs/scraper-catalog.json is a checklist, not a claim of full provider parity or successful live access.
Media platforms
YouTube, Instagram, TikTok, X/Twitter, Facebook and Pinterest. Pinterest accepts individual image/video pins, regional pin URLs and pin.it short links. Playlists, boards, profiles and VK Video are excluded from media resolution.
TikTok photo posts retain their images and separate soundtrack. Instagram photo-post music is returned when the source exposes its audio URL. Instagram supports individual live Stories, current /stories/USER/ collections and saved /stories/highlights/ID/ collections, up to 100 ordered photos/videos. Optional story_media_id selects one item. These routes require a separate API session and a confirmed public owner; missing authorization returns 403 authentication_required. Session setup is described in docs/media-api.md.
Endpoints
| Endpoint | Purpose |
|---|---|
POST /v1/resolve | Resolve source media links |
POST /v1/deliveries | Select direct, tunnel or stored delivery |
POST /v1/tunnels | Create a streaming fallback for an owned result |
GET /v1/tunnels/{token} | Stream the selected source file |
POST /v1/files | Request a temporary source copy |
GET /v1/files/{id} | Own file status and download capability |
DELETE /v1/files/{id} | Cancel or delete own file |
GET /v1/downloads/{token} | Download original stored bytes or a range |
GET /v1/scrapers | Registered source operations and runtime features |
POST /v1/scrape | Run a public-data operation |
POST /v1/scrape/jobs | Create an asynchronous scraping job |
GET /v1/scrape/jobs/{id} | Read an owned job and callback status |
DELETE /v1/scrape/jobs/{id} | Cancel an owned job |
GET /v1/usage | Own media, scraping, transfer and storage usage |
GET /healthz | Local service readiness |
Usage and retries
Successful resolutions consume one usage unit. Failures consume none. In-flight requests reserve a unit. An optional Idempotency-Key prevents duplicate processing/accounting. Matching requests reuse the operation for 24 hours; the original result remains in bounded memory for at most one minute. An expired result returns 409 result_expired; use a new key to resolve again. Errors contain a code, message, retry hint and request ID. Usage units do not trigger payments.
Local setup
Default: two simultaneous source operations, a 45-second deadline, 60 resolution requests per minute per client and a bounded metadata cache. Runtime data and keys are isolated from Telegram. Python/JavaScript clients and server-sizing notes are in examples/media-api and docs/media-api.md.
General web tools
Use source: web with an available operation. Access depends on the target website and runtime features.
binary, extract, images, links, markdown, post, scrape, screenshot, sessions, universal_search
Scraping sources and operations
Registered operations may depend on source availability. Use the live catalog to check runtime features.
Amazon
autocomplete- Public amazon autocomplete data
bestsellers- Public amazon bestsellers data
offers- Public amazon offers data
product- Public amazon product data
reviews- Public amazon reviews data
search- Public amazon search data
App Store
product- Public App Store product
reviews- Public App Store reviews
search- Public App Store search
Bing
images- Extract public bing images results.
search- Extract public bing search results.
shopping- Extract public bing shopping results.
Brave Search
search- Extract public brave search results.
DuckDuckGo
search- Extract public duckduckgo search results.
posts- Public facebook posts data
profile- Public facebook profile data
Flipkart
product- Public flipkart product data
search- Public flipkart search data
ads_transparency- Google ads transparency
ai_mode- Google ai mode
ai_overview- Google ai overview
autocomplete- Extract public google autocomplete results.
finance- Google finance
flights- Google flights
hotels- Google hotels
images- Extract public google images results.
immersive_product- Google immersive product
light_search- Extract public google light_search results.
local- Extract public google local results.
maps_photos- Google maps photos
maps_places- Google maps places
maps_posts- Google maps posts
maps_reviews- Google maps reviews
maps_search- Google maps search
news- Google news
news_search- Google news search
news_v2- Google news v2
patent_details- Google patent details
patents_search- Google patents search
- Google scholar author
- Google scholar author citations
scholar_cite- Google scholar cite
scholar_search- Google scholar search
shopping- Extract public google shopping results.
shorts- Extract public google shorts results.
trends- Google trends
trends_autocomplete- Google trends autocomplete
trends_trending_now- Google trends trending now
videos- Extract public google videos results.
Google Play
apps- Public Google Play apps
books- Public Google Play books
category- Public Google Play category
games- Public Google Play games
product- Public Google Play product
reviews- Public Google Play reviews
search- Public Google Play search
Indeed
jobs- Public indeed jobs data
posts- Public instagram posts data
profile- Public instagram profile data
company- Public linkedin company data
job- Public linkedin job data
jobs- Public linkedin jobs data
post- Public linkedin post data
profile- Public linkedin profile data
Myntra
product- Public myntra product data
search- Public myntra search data
Swiggy Instamart
listing- Public swiggy listing data
product- Public swiggy product data
search- Public swiggy search data
TikTok
ads- Public tiktok ads data
post- Public tiktok post data
profile- Public tiktok profile data
Walmart
autocomplete- Public walmart autocomplete data
product- Public walmart product data
reviews- Public walmart reviews data
search- Public walmart search data
X (Twitter)
post- Public x post data
profile- Public x profile data
Yahoo
images- Extract public yahoo images results.
search- Extract public yahoo search results.
YouTube
channel- Public youtube channel data
comments- Public youtube comments data
search- Public youtube search data
transcripts- Public youtube transcripts data
video- Public youtube video data
Zillow
property- Public zillow property data
search- Public zillow search data