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

# Introduction

> One API. Multiple providers. Verified HLS streams for any movie or TV show — proxied, CORS-safe, and streamed in real time.

<img className="block dark:hidden rounded-xl" src="https://mintcdn.com/vyla/CAMrm3Zw_CvIE3Iu/images/banner.png?fit=max&auto=format&n=CAMrm3Zw_CvIE3Iu&q=85&s=9d68ff7376315f3bf375105e51a62ced" alt="Vyla API" width="2559" height="1274" data-path="images/banner.png" />

<img className="hidden dark:block rounded-xl" src="https://mintcdn.com/vyla/CAMrm3Zw_CvIE3Iu/images/banner.png?fit=max&auto=format&n=CAMrm3Zw_CvIE3Iu&q=85&s=9d68ff7376315f3bf375105e51a62ced" alt="Vyla API" width="2559" height="1274" data-path="images/banner.png" />

## What is Vyla API?

Vyla API is a **Node.js** streaming API hosted on Hugging Face Spaces. It fans out to multiple streaming providers simultaneously, verifies every stream live, and **streams results back to your client in real time via Server-Sent Events (SSE)** — so your player can start as soon as the first source is ready, without waiting for all providers to finish.

Pass a TMDB ID. Get back a live stream of working sources, multi-language subtitles, and TMDB metadata — one event at a time.

<CardGroup cols={2}>
  <Card title="Multi-Provider Fanout">
    All configured providers are queried in parallel with per-source jitter, retries, and timeouts. Dead sources are silently dropped from the stream.
  </Card>

  <Card title="Real-Time SSE Streaming">
    Results are pushed as Server-Sent Events the moment each provider resolves. No waiting for the slowest provider — your UI can render the first source immediately.
  </Card>

  <Card title="Built-in HLS Proxy">
    Stream URLs are wrapped in a server-hosted proxy that rewrites M3U8 segment and key paths. CORS issues in the browser are gone by design.
  </Card>

  <Card title="Subtitles Included">
    VTT and SRT subtitle tracks in multiple languages are streamed as the first event (`meta`) in every movie and TV response.
  </Card>

  <Card title="Download Links">
    A dedicated endpoint returns direct download links for movies and TV episodes with quality labels and file sizes.
  </Card>

  <Card title="Health Monitoring">
    A dedicated health endpoint probes every provider in real time and reports per-source latency and status.
  </Card>
</CardGroup>

<Card title="Try the Player" href="/player">
  Test a live stream directly in your browser — no setup needed. Enter any TMDB ID and hit play.
</Card>

***

## Base URL

```
https://1c34-y.hf.space
```

All endpoints return `Access-Control-Allow-Origin: *`. Requests to protected endpoints require either a session token or an API key — see [Authentication](/authentication).

***

## How It Works

<Steps>
  <Step title="Request arrives">
    Your app opens an SSE connection to `/movie?id=` or `/tv?id=&season=&episode=`.
  </Step>

  <Step title="Meta event fires immediately">
    The server emits a `meta` event with TMDB metadata and all available subtitle tracks — before any provider has finished.
  </Step>

  <Step title="Parallel provider fanout">
    All active providers are queried simultaneously. Each source applies random jitter to stagger upstream requests, then retries on failure up to its configured limit.
  </Step>

  <Step title="Source events stream in">
    As each provider resolves and passes live verification, a `source` event is emitted. Your player can begin immediately on the first one.
  </Step>

  <Step title="Done event closes the stream">
    Once all providers have either resolved or timed out, a `done` event is sent with the total source count. The connection closes cleanly.
  </Step>
</Steps>

***

## Endpoint Overview

| Endpoint                          | Method | Auth required                        | Notes                                                          |
| --------------------------------- | ------ | ------------------------------------ | -------------------------------------------------------------- |
| `/api/auth`                       | `POST` | Yes — any valid API key              | Issue a 30-minute session token; token inherits the key's tier |
| `/movie?id=:id`                   | `GET`  | Yes — standard/partner/session token | SSE stream of sources + meta for a movie                       |
| `/tv?id=:id&season=:s&episode=:e` | `GET`  | Yes — standard/partner/session token | SSE stream of sources + meta for a TV episode                  |
| `/api/subtitles/movie/:id`        | `GET`  | Yes — any valid key or session token | Subtitle tracks for a movie                                    |
| `/api/subtitles/tv/:id/:s/:e`     | `GET`  | Yes — any valid key or session token | Subtitle tracks for a TV episode                               |
| `/api/downloads/movie/:id`        | `GET`  | Yes — any valid key or session token | Download links for a movie                                     |
| `/api/downloads/tv/:id/:s/:e`     | `GET`  | Yes — any valid key or session token | Download links for a TV episode                                |
| `/api/health`                     | `GET`  | Yes — any valid key or session token | Per-provider health check with latency                         |
| `/api/test/:id`                   | `GET`  | Yes — standard/partner/session token | Debug a single provider in isolation                           |

<Warning>
  The `public` API key cannot access streaming endpoints (`/movie`, `/tv`, `/api/test`, `/api/debug`) or the stream proxy (`/api?url=`). Those require a `standard` or `partner` key, or a session token issued from one. `POST /api/auth` itself requires a valid API key of any tier.
</Warning>

<Tip>
  Check which providers are currently live: [`/api/health`](https://1c34-y.hf.space/api/health)
</Tip>

***

## SSE Event Types

All `/movie` and `/tv` responses are Server-Sent Events. Each event is a JSON-encoded line prefixed with `data: `.

### `meta` — First event

Emitted immediately, before any provider resolves. Contains TMDB metadata and all subtitle tracks for the title.

```json theme={null}
{
  "type": "meta",
  "meta": {
    "id": 550,
    "title": "Fight Club",
    "release_date": "1999-10-15",
    "runtime": 139,
    "vote_average": 8.438
  },
  "subtitles": [
    {
      "label": "English",
      "file": "https://sub.vdrk.site/v1/vtt/movie/550/English.vtt",
      "type": "vtt",
      "source": "v1"
    }
  ]
}
```

### `source` — One per working provider

Emitted each time a provider passes live verification. Your player should start on the first one and fall back to subsequent ones on error.

```json theme={null}
{
  "type": "source",
  "source": {
    "source": "provider-key",
    "label": "Provider Label",
    "url": "https://1c34-y.hf.space/api?url=...&pp=1"
  }
}
```

### `done` — Final event

Signals the stream is complete. The `total` field is the number of working sources that were emitted.

```json theme={null}
{
  "type": "done",
  "total": 14
}
```

***

## Data Models

### Source Object

Returned inside `source` events on movie and TV streams.

```json theme={null}
{
  "source": "provider-key",
  "label": "Provider Name",
  "url": "https://1c34-y.hf.space/api?url=https%3A%2F%2F...&pp=1"
}
```

<ResponseField name="source" type="string">
  Internal provider key. Matches the keys shown in `/api/health`.
</ResponseField>

<ResponseField name="label" type="string">
  Human-readable provider name to display in your UI.
</ResponseField>

<ResponseField name="url" type="string">
  Fully-qualified, proxied, CORS-safe stream URL. For HLS sources, pass directly to `hls.loadSource()` — all M3U8 segment and key URIs are pre-rewritten to flow through the proxy. For MP4 sources, set as `video.src` directly. No base URL prepending needed in either case.
</ResponseField>

***

### Subtitle Object

Returned inside the `subtitles` array of the `meta` event, and as the top-level array on the `/api/subtitles` endpoints.

```json theme={null}
{
  "label": "English",
  "file": "https://sub.vdrk.site/v1/vtt/movie/550/English.vtt",
  "type": "vtt",
  "source": "v1"
}
```

<ResponseField name="label" type="string">
  Language name of the subtitle track, e.g. `English`, `Spanish`, `Arabic`.
</ResponseField>

<ResponseField name="file" type="string">
  Direct URL to a WebVTT (`.vtt`) or SRT subtitle file. Use as a `<track>` element `src`, or pass to any player's subtitle API.
</ResponseField>

<ResponseField name="type" type="string">
  Format of the subtitle file — `vtt` or `srt`.
</ResponseField>

<ResponseField name="source" type="string">
  Internal subtitle source identifier. Informational only.
</ResponseField>

***

### Download Object

Returned inside `downloads[]` on the `/api/downloads` endpoints.

```json theme={null}
{
  "url": "https://...",
  "quality": "1080p",
  "size": "2.14 GB",
  "format": "MP4"
}
```

<ResponseField name="url" type="string">
  Direct download URL.
</ResponseField>

<ResponseField name="quality" type="string">
  Quality label, e.g. `1080p`, `720p`, `480p`. `"Unknown"` if the provider doesn't supply one.
</ResponseField>

<ResponseField name="size" type="string | null">
  Human-readable file size, e.g. `2.14 GB`. `null` if unavailable.
</ResponseField>

<ResponseField name="format" type="string">
  Container format, e.g. `MP4`, `MKV`. Uppercase.
</ResponseField>

***

## Caching

Stream results are cached in-memory with a **5-minute TTL**. The per-source stream cache is keyed by `source_key + tmdb_id + season + episode`; the aggregate source-results cache is keyed by `tmdb_id + season + episode + base`. Cache hits skip the provider fetch entirely and return near-instantly. The cache resets on server restart.

***

## CORS & Headers

Every endpoint returns:

```http theme={null}
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, Origin, Accept, X-Session-Token
Content-Type: application/json  (or text/event-stream for SSE endpoints)
```

Preflight `OPTIONS` requests return `204 No Content` immediately.
