> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tornadoapi.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Spotify Show Has Video

> Check whether a Spotify podcast show has any video episodes

## 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

<ParamField path="id" type="string" required>
  The Spotify show id — the base62 id from a show URL, e.g. `11VjrLJfoiNvgjjqov4RWh` in `https://open.spotify.com/show/11VjrLJfoiNvgjjqov4RWh`.
</ParamField>

## Header Parameters

<ParamField header="x-api-key" type="string" required>
  Your API key for authentication.
</ParamField>

## Response

<ResponseField name="show_id" type="string">
  The Spotify show id you queried.
</ResponseField>

<ResponseField name="has_video" type="boolean">
  `true` when at least one episode exposes a video variant.
</ResponseField>

<ResponseField name="episodes_scanned" type="integer">
  How many episodes were inspected to reach the answer. When answered from the episode list (the normal path) this equals `total_episodes`.
</ResponseField>

<ResponseField name="total_episodes" type="integer">
  Total number of episodes the show lists.
</ResponseField>

<ResponseField name="determinate" type="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.
</ResponseField>

<ResponseField name="cached" type="boolean">
  `true` when the response was served from the 24-hour server-side cache. Cached responses are **not** billed.
</ResponseField>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.tornadoapi.io/spotify/show/11VjrLJfoiNvgjjqov4RWh/hasVideo" \
    -H "x-api-key: sk_your_api_key"
  ```

  ```javascript Node.js theme={null}
  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.');
  }
  ```

  ```python Python theme={null}
  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)")
  ```
</CodeGroup>

## Success Response

<ResponseExample>
  ```json 200 — Video podcast theme={null}
  {
    "show_id": "11VjrLJfoiNvgjjqov4RWh",
    "has_video": true,
    "episodes_scanned": 100,
    "total_episodes": 100,
    "determinate": true,
    "cached": false
  }
  ```

  ```json 200 — Audio-only podcast theme={null}
  {
    "show_id": "2zzBL9Oe9bygUGlOban5fW",
    "has_video": false,
    "episodes_scanned": 157,
    "total_episodes": 157,
    "determinate": true,
    "cached": false
  }
  ```

  ```json 200 — Served from cache theme={null}
  {
    "show_id": "11VjrLJfoiNvgjjqov4RWh",
    "has_video": true,
    "episodes_scanned": 100,
    "total_episodes": 100,
    "determinate": true,
    "cached": true
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 400 Bad Request — Invalid show id theme={null}
  {
    "error": "Invalid Spotify show id"
  }
  ```

  ```json 401 Unauthorized — Invalid key theme={null}
  {
    "error": "Invalid API Key"
  }
  ```

  ```json 404 Not Found — No episodes theme={null}
  {
    "error": "Show not found or has no episodes"
  }
  ```

  ```json 502 Bad Gateway — Upstream failure theme={null}
  {
    "error": "Failed to resolve the show upstream"
  }
  ```
</ResponseExample>

The `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_video` is `true` if **any** episode has video, even when most episodes are audio-only.
* **Authoritative negatives**: a `has_video: false` with `determinate: true` means the whole show was inspected and no video episode exists.
