# Rawcast Media Resolution API

> High-performance developer-first REST API and zero-dependency SDK for resolving media streams (HLS, DASH, MP4), direct downloads, and WebVTT subtitles directly by TMDB ID.
> Zero video bandwidth relay: all media is delivered directly from upstream edge CDNs via HTTP 302 redirects and pre-signed ephemeral tokens.

---

## 1. Quickstart with Official SDK (@rawcast/sdk)

The recommended way for developers and AI agents to integrate with Rawcast is via the official zero-dependency TypeScript/JavaScript SDK:

### Installation
```bash
npm install @rawcast/sdk
# or: bun add @rawcast/sdk / pnpm add @rawcast/sdk
```

### Basic Usage
```typescript
import { Rawcast } from '@rawcast/sdk';

// Initializes with process.env.RAWCAST_API_KEY by default
const rawcast = new Rawcast({ apiKey: 'rc_live_your_key' });

// 1. Resolve Movie Stream (TMDB ID 550 = Fight Club)
const sources = await rawcast.movies.getSources(550, { lang: 'en' });
const stream = sources.bestStream({ preferFormat: 'hls', maxQuality: '1080p' });
console.log('Stream Manifest:', stream.manifestUrl);
console.log('Subtitles:', sources.subtitles.length);

// 2. Resolve TV Show Episode (TMDB ID 1399 = Game of Thrones, S1E1)
const tvSources = await rawcast.tv.getSources(1399, 1, 1);
const tvStream = tvSources.bestStream({ preferFormat: 'hls' });
console.log('TV Manifest:', tvStream.manifestUrl);

// 3. Direct 4-Quality MP4 Downloads
const download = await rawcast.movies.getDownload(550, { quality: '1080p' });
console.log('Direct Download:', download.downloadUrl, download.filename);

// 4. Live Monthly Quota Inspection
console.log('Remaining Monthly Credits:', rawcast.quota.remaining);
```

---

## 2. Architecture & Core Guarantees

Rawcast resolves movies and TV shows using TMDB IDs. It aggregates multiple high-speed CDN backends in parallel, performs automated health checks, rewrites HLS variant manifests, and delivers tamper-proof signed playback tokens.

### Key Guarantees
- **Zero Video Relay**: Video traffic flows directly from upstream CDNs to your user's player. The Rawcast API handles only lightweight JSON metadata and playlist rewriting.
- **Server Tier Separation**:
  - **Server 1 (Primary)**: Adaptive HLS and DASH streaming with automated variant playlist rewriting.
  - **Server 2 (Downloads)**: Direct MP4 video downloads across 1080p, 720p, 480p, and 360p with clean RFC 6266 filename headers.
  - **Server 3 (Extended)**: Multi-audio tracks, alternative language dubs, and international mirrors.
- **Signed Stream Tokens**: Stream URLs returned are signed tokens. When a player requests `/v1/resolve/{token}`, Rawcast validates the token and returns a fast HTTP 302 redirect directly to the edge CDN stream.
- **English Audio Priority**: Streams automatically prioritize English audio across all servers unless an alternative audio language is explicitly specified.

---

## 3. Authentication & Rate Limits

All billable requests require an API key:

```http
X-API-Key: rc_live_...
```
*(or `Authorization: Bearer rc_live_...`)*

### Rate Limit & Quota Headers (Included on all responses)
- `X-RateLimit-Limit`: Total monthly quota limit for your active tier
- `X-RateLimit-Remaining`: Remaining requests this month before 1st-of-month UTC reset
- `X-RateLimit-Reset`: Unix epoch timestamp (seconds) when the monthly quota resets (00:00 UTC on the 1st of next month)
- `Retry-After`: Backoff duration in seconds when receiving HTTP 429

### Subscription Tiers & Quotas (100% Self-Serve Crypto)
- **Free**: 1,000 requests/month · 3 RPS burst throttle ($0)
- **Starter**: 30,000 requests/month · 10 RPS burst throttle ($19/mo)
- **Pro**: 150,000 requests/month · 20 RPS burst throttle ($49/mo)
- **Scale**: 600,000 requests/month · 30 RPS burst throttle ($199/mo)

---

## 4. REST Endpoints Reference

Base URL: `https://rawcast.space/v1`

### 4.1. Movie Streams
Resolve ranked streaming servers for a movie:

```http
GET /v1/sources/movie/{tmdbId}?lang=en&title=Fight+Club
```

#### Response:
```json
{
  "mediaType": "movie",
  "tmdbId": "550",
  "mediaTitle": "Fight Club",
  "servers": [
    {
      "name": "Server 1 (Adaptive HLS)",
      "format": "hls",
      "streams": [
        {
          "quality": "1080p",
          "audio": "English",
          "download": false,
          "url": "https://rawcast.space/v1/resolve/rc_ey...",
          "manifestUrl": "https://rawcast.space/v1/stream/hls/rc_ey.../manifest.m3u8"
        }
      ]
    },
    {
      "name": "Server 2 (Direct MP4 / Fast Download)",
      "format": "mp4",
      "streams": [
        {
          "quality": "1080p",
          "audio": "English",
          "download": true,
          "url": "https://rawcast.space/v1/resolve/rc_mp4...",
          "downloadUrl": "https://rawcast.space/v1/download/rc_mp4..."
        }
      ]
    }
  ],
  "subtitles": [
    {
      "language": "en",
      "label": "English",
      "url": "https://rawcast.space/v1/subtitles/vtt?url=...",
      "format": "vtt"
    }
  ]
}
```

### 4.2. TV Episode Streams
Resolve ranked streaming servers for a TV episode:

```http
GET /v1/sources/tv/{tmdbId}/{season}/{episode}?lang=en
```
Example: `/v1/sources/tv/1399/1/1` for Game of Thrones S01E01.

### 4.3. Movie Direct Downloads
Get direct MP4 download links with RFC 6266 attachment headers. If `redirect=false` is passed, returns a JSON object; otherwise returns an immediate HTTP 302 download redirect:

```http
GET /v1/download/movie/{tmdbId}?quality=1080p&redirect=false
```

#### Response (redirect=false):
```json
{
  "tmdbId": "550",
  "mediaType": "movie",
  "title": "Fight Club",
  "quality": "1080p",
  "format": "mp4",
  "url": "https://rawcast.space/v1/resolve/rc_mp4...",
  "downloadUrl": "https://rawcast.space/v1/download/rc_mp4...",
  "filename": "Fight_Club_1080p.mp4"
}
```

### 4.4. TV Episode Direct Downloads
```http
GET /v1/download/tv/{tmdbId}/{season}/{episode}?quality=1080p&redirect=false
```
Also accepts `/v1/download/tv/{tmdbId}?season=1&episode=1&quality=1080p`.

### 4.5. Subtitles & On-The-Fly WebVTT Conversion
```http
GET /v1/subtitles/movie/{tmdbId}?lang=en
GET /v1/subtitles/tv/{tmdbId}/{season}/{episode}?lang=en
GET /v1/subtitles/vtt?url={raw_upstream_srt_or_vtt_url}
```
The `/v1/subtitles/vtt` endpoint dynamically converts remote SRT files into standardized WebVTT with permissive CORS headers.

### 4.6. TMDB Metadata (Free / Excluded from Quota)
```http
GET /v1/meta/movie/{tmdbId}?lang=en-US
GET /v1/meta/tv/{tmdbId}?season=1&lang=en-US
```
Cached in Redis for 24 hours. Does not consume monthly API request credits.

### 4.7. Token Exchange
```http
GET /v1/resolve/{token}
GET /v1/download/{token}
GET /v1/stream/hls/{token}/manifest.m3u8
```
Returns an instant HTTP 302 redirect directly to the edge CDN media URL.

### 4.8. Health Status & Provider Dashboard
```http
GET /v1/health
GET /v1/health/providers
```
Returns service uptime and operational status across all upstream scrapers.

---

## 5. Player Integration Recipes

### HTML5 / Hls.js
```html
<video id="video" controls></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script type="module">
  import { Rawcast } from '@rawcast/sdk';

  const rawcast = new Rawcast('rc_live_...');
  const sources = await rawcast.movies.getSources(550);
  const stream = sources.bestStream({ preferFormat: 'hls' });

  const video = document.getElementById('video');
  if (Hls.isSupported() && stream.manifestUrl) {
    const hls = new Hls();
    hls.loadSource(stream.manifestUrl);
    hls.attachMedia(video);
  } else {
    video.src = stream.url;
  }
</script>
```

### Video.js (Web)
```javascript
videojs('my-player', {
  sources: [{
    src: stream.manifestUrl,
    type: 'application/x-mpegURL'
  }]
});
```

### Android (ExoPlayer / Media3 Kotlin)
```kotlin
val dataSourceFactory = DefaultHttpDataSource.Factory()
    .setUserAgent(stream.headers?.get("User-Agent") ?: "Mozilla/5.0")
    .setDefaultRequestProperties(mapOf(
        "Referer" to (stream.headers?.get("Referer") ?: "")
    ))

val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
    .createMediaSource(MediaItem.fromUri(stream.manifestUrl))

val player = ExoPlayer.Builder(context).build().apply {
    setMediaSource(hlsMediaSource)
    prepare()
    play()
}
```

### iOS / macOS (AVPlayer Swift)
```swift
let streamUrl = URL(string: stream.manifestUrl)!
let headers: [String: String] = [
    "Referer": stream.headers["Referer"] ?? "",
    "User-Agent": stream.headers["User-Agent"] ?? "Mozilla/5.0"
]

let asset = AVURLAsset(url: streamUrl, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
player.play()
```

---

## 6. Machine-Readable Error Codes

| Code | HTTP Status | Meaning & Recommended Action |
| :--- | :--- | :--- |
| `RC_UNAUTHORIZED` | 401 | Missing or invalid API key. |
| `RC_FORBIDDEN` | 403 | IP address not allowlisted or key disabled. |
| `RC_NO_SOURCES` | 404 | No stream servers currently available for this title. |
| `RC_RATE_LIMIT` | 429 | Monthly quota or RPS throttle reached. Check `Retry-After`. |
| `RC_UPSTREAM_ERROR` | 502 | Upstream scraper temporary provider issue. |
| `RC_UPSTREAM_TIMEOUT` | 504 | Upstream CDN timed out during resolution. Retry in 2s. |
| `RC_INTERNAL_ERROR` | 500 | Internal server error. |
