Spotify Show Has Video
curl --request GET \
--url https://api.tornadoapi.io/spotify/show/{id}/hasVideo \
--header 'x-api-key: <x-api-key>'import requests
url = "https://api.tornadoapi.io/spotify/show/{id}/hasVideo"
headers = {"x-api-key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<x-api-key>'}};
fetch('https://api.tornadoapi.io/spotify/show/{id}/hasVideo', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tornadoapi.io/spotify/show/{id}/hasVideo",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.tornadoapi.io/spotify/show/{id}/hasVideo"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.tornadoapi.io/spotify/show/{id}/hasVideo")
.header("x-api-key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/spotify/show/{id}/hasVideo")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": false
}
{
"show_id": "2zzBL9Oe9bygUGlOban5fW",
"has_video": false,
"episodes_scanned": 157,
"total_episodes": 157,
"determinate": true,
"cached": false
}
{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": true
}
Metadata
Spotify Show Has Video
Check whether a Spotify podcast show has any video episodes
GET
/
spotify
/
show
/
{id}
/
hasVideo
Spotify Show Has Video
curl --request GET \
--url https://api.tornadoapi.io/spotify/show/{id}/hasVideo \
--header 'x-api-key: <x-api-key>'import requests
url = "https://api.tornadoapi.io/spotify/show/{id}/hasVideo"
headers = {"x-api-key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<x-api-key>'}};
fetch('https://api.tornadoapi.io/spotify/show/{id}/hasVideo', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tornadoapi.io/spotify/show/{id}/hasVideo",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.tornadoapi.io/spotify/show/{id}/hasVideo"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.tornadoapi.io/spotify/show/{id}/hasVideo")
.header("x-api-key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/spotify/show/{id}/hasVideo")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": false
}
{
"show_id": "2zzBL9Oe9bygUGlOban5fW",
"has_video": false,
"episodes_scanned": 157,
"total_episodes": 157,
"determinate": true,
"cached": false
}
{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": true
}
Overview
Return whether a Spotify show (podcast) has any video episode. No download is performed — the answer is read from Spotify’s episode metadata (mediaTypes), so it works even though the audio tracks are DRM-protected.
Each episode advertises a mediaTypes list: an episode with a video variant is ["VIDEO", "AUDIO"], an audio-only episode is ["AUDIO"]. The show has_video when at least one episode contains VIDEO.
Path Parameters
string
required
The Spotify show id — the base62 id from a show URL, e.g.
11VjrLJfoiNvgjjqov4RWh in https://open.spotify.com/show/11VjrLJfoiNvgjjqov4RWh.Header Parameters
string
required
Your API key for authentication.
Response
string
The Spotify show id you queried.
boolean
true when at least one episode exposes a video variant.integer
How many episodes were inspected to reach the answer. When answered from the episode list (the normal path) this equals
total_episodes.integer
Total number of episodes the show lists.
boolean
true when the answer is authoritative (every episode was inspected, or a video episode was found). When false, a has_video: false only means “no video episode was seen in the portion inspected” — not a guarantee the whole show is audio-only.boolean
true when the response was served from the 24-hour server-side cache. Cached responses are not billed.Examples
curl "https://api.tornadoapi.io/spotify/show/11VjrLJfoiNvgjjqov4RWh/hasVideo" \
-H "x-api-key: sk_your_api_key"
const showId = '11VjrLJfoiNvgjjqov4RWh';
const response = await fetch(
`https://api.tornadoapi.io/spotify/show/${showId}/hasVideo`,
{ headers: { 'x-api-key': 'sk_your_api_key' } }
);
const result = await response.json();
if (result.has_video) {
console.log(`This show has video episodes (${result.total_episodes} episodes total).`);
} else if (result.determinate) {
console.log('This show is audio-only.');
}
import requests
show_id = "11VjrLJfoiNvgjjqov4RWh"
response = requests.get(
f"https://api.tornadoapi.io/spotify/show/{show_id}/hasVideo",
headers={"x-api-key": "sk_your_api_key"},
)
result = response.json()
print(f"has_video: {result['has_video']} ({result['total_episodes']} episodes)")
Success Response
{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": false
}
{
"show_id": "2zzBL9Oe9bygUGlOban5fW",
"has_video": false,
"episodes_scanned": 157,
"total_episodes": 157,
"determinate": true,
"cached": false
}
{
"show_id": "11VjrLJfoiNvgjjqov4RWh",
"has_video": true,
"episodes_scanned": 100,
"total_episodes": 100,
"determinate": true,
"cached": true
}
Error Responses
{
"error": "Invalid Spotify show id"
}
{
"error": "Invalid API Key"
}
{
"error": "Show not found or has no episodes"
}
{
"error": "Failed to resolve the show upstream"
}
502 response means a transient upstream issue while resolving the show (Spotify hiccup, token capture, or proxy). Retry after a short delay.
Billing
Each resolved lookup (a cache miss) is billed as a flat 1 MiB of data transfer — the same unit as downloads, so it appears on your usage dashboard and invoice with no separate line item. Roughly 1,024 lookups = 1 GB. Cache hits are free. Results are cached server-side for 24 hours per show; repeat lookups for the same show within that window are served instantly and are not billed.Use Cases
Catalog pre-filtering
Before ingesting a show, decide whether to route it to a video or audio pipeline.UI hints
Badge a show as “Video” in your front-end as soon as a user pastes a Spotify show link.Notes
- First lookup latency: a cache miss takes a few seconds (it lists the show’s episodes upstream). Subsequent lookups within 24 hours are instant (
cached: true). - Mixed shows:
has_videoistrueif any episode has video, even when most episodes are audio-only. - Authoritative negatives: a
has_video: falsewithdeterminate: truemeans the whole show was inspected and no video episode exists.
Was this page helpful?