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

# Hitorino Videos API — List and Retrieve On-Demand Videos

> Browse Hitorino on-demand video content. Filter by creator or category, paginate with cursors, and access full video metadata including playback URLs.

The Videos API gives you access to Hitorino's library of on-demand content — recordings of past streams, uploaded videos, and highlight clips published by creators. You can use these endpoints to build video galleries, embed content in external sites, or sync Hitorino video metadata into your own database. All responses follow the standard Hitorino JSON format described in the [API Overview](/api/overview).

***

## List Videos

Returns a paginated list of publicly available on-demand videos. Videos are returned in reverse-chronological order (newest first) by default.

```bash theme={null}
GET /videos
```

### Query Parameters

<ParamField query="creator_id" type="string">
  Return only videos published by the creator with this user ID. Useful for building a creator-specific video gallery.
</ParamField>

<ParamField query="category" type="string">
  Filter videos by category slug (e.g., `gaming`, `music`, `coding`). Must match a valid Hitorino category.
</ParamField>

<ParamField query="limit" type="integer">
  Maximum number of videos to return per page. Defaults to `20`. Maximum is `100`.
</ParamField>

<ParamField query="cursor" type="string">
  Pagination cursor from the previous response's `pagination.next_cursor`. Omit to fetch the first page.
</ParamField>

### Request Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.hitorino.tv/v1/videos?category=coding&limit=5" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({ category: 'coding', limit: '5' });

  const response = await fetch(`https://api.hitorino.tv/v1/videos?${params}`, {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
  });

  const { data, pagination } = await response.json();
  console.log(data);        // array of video objects
  console.log(pagination);  // { next_cursor, has_more }
  ```

  ```python Python theme={null}
  import requests

  params = {'category': 'coding', 'limit': 5}
  headers = {'Authorization': 'Bearer YOUR_API_KEY'}

  response = requests.get(
      'https://api.hitorino.tv/v1/videos',
      params=params,
      headers=headers,
  )
  result = response.json()
  print(result['data'])
  print(result['pagination'])
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "data": [
    {
      "id": "vid_01HVID1234",
      "title": "Building a REST API in Go — Full Session",
      "description": "Three-hour deep dive into building a production-ready REST API using Go and PostgreSQL.",
      "category": "coding",
      "creator_id": "usr_01HABC5678",
      "duration_seconds": 10842,
      "view_count": 3820,
      "privacy": "public",
      "thumbnail_url": "https://cdn.hitorino.tv/thumbnails/vid_01HVID1234.jpg",
      "video_url": "https://watch.hitorino.tv/videos/vid_01HVID1234",
      "source_stream_id": "str_01HXYZ1234",
      "published_at": "2024-06-11T08:00:00Z",
      "created_at": "2024-06-10T23:00:00Z"
    }
  ],
  "pagination": {
    "next_cursor": "cur_01HVID9999",
    "has_more": true
  }
}
```

<ResponseField name="data" type="array">
  Array of video objects matching the query.

  <Expandable title="video object fields">
    <ResponseField name="id" type="string">
      Unique identifier for the video, prefixed with `vid_`.
    </ResponseField>

    <ResponseField name="title" type="string">
      Display title of the video.
    </ResponseField>

    <ResponseField name="description" type="string">
      Description provided by the creator. May be `null` if no description was set.
    </ResponseField>

    <ResponseField name="category" type="string">
      Category slug assigned to the video.
    </ResponseField>

    <ResponseField name="creator_id" type="string">
      ID of the creator who published the video.
    </ResponseField>

    <ResponseField name="duration_seconds" type="integer">
      Total duration of the video in seconds.
    </ResponseField>

    <ResponseField name="view_count" type="integer">
      Total number of views the video has received since publication.
    </ResponseField>

    <ResponseField name="privacy" type="string">
      Visibility setting: `public` or `private`.
    </ResponseField>

    <ResponseField name="thumbnail_url" type="string">
      URL of the video thumbnail image.
    </ResponseField>

    <ResponseField name="video_url" type="string">
      Public watch page URL for the video.
    </ResponseField>

    <ResponseField name="source_stream_id" type="string">
      ID of the live stream this video was recorded from, if applicable. `null` for directly uploaded videos.
    </ResponseField>

    <ResponseField name="published_at" type="string">
      ISO 8601 timestamp of when the video was made publicly available.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      ISO 8601 timestamp of when the video resource was created (e.g., when processing completed).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pagination" type="object">
  Cursor-based pagination metadata.

  <Expandable title="pagination fields">
    <ResponseField name="next_cursor" type="string">
      Pass this value as the `cursor` query parameter in your next request to retrieve the following page. `null` when `has_more` is `false`.
    </ResponseField>

    <ResponseField name="has_more" type="boolean">
      `true` if more results are available beyond the current page.
    </ResponseField>
  </Expandable>
</ResponseField>

***

## Get Video

Retrieves a single on-demand video by its unique ID, returning all metadata fields plus extended playback information.

```bash theme={null}
GET /videos/{id}
```

### Path Parameters

<ParamField path="id" type="string" required>
  The unique video ID (e.g., `vid_01HVID1234`).
</ParamField>

### Request Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.hitorino.tv/v1/videos/vid_01HVID1234 \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const videoId = 'vid_01HVID1234';

  const response = await fetch(`https://api.hitorino.tv/v1/videos/${videoId}`, {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
  });

  const video = await response.json();
  console.log(video.title);          // "Building a REST API in Go — Full Session"
  console.log(video.duration_seconds); // 10842
  ```

  ```python Python theme={null}
  import requests

  video_id = 'vid_01HVID1234'
  headers = {'Authorization': 'Bearer YOUR_API_KEY'}

  response = requests.get(
      f'https://api.hitorino.tv/v1/videos/{video_id}',
      headers=headers,
  )
  video = response.json()
  print(video['title'])
  print(video['duration_seconds'])
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "vid_01HVID1234",
  "title": "Building a REST API in Go — Full Session",
  "description": "Three-hour deep dive into building a production-ready REST API using Go and PostgreSQL.",
  "category": "coding",
  "creator_id": "usr_01HABC5678",
  "duration_seconds": 10842,
  "view_count": 3820,
  "privacy": "public",
  "thumbnail_url": "https://cdn.hitorino.tv/thumbnails/vid_01HVID1234.jpg",
  "video_url": "https://watch.hitorino.tv/videos/vid_01HVID1234",
  "playback_url": "https://cdn.hitorino.tv/hls/vid_01HVID1234/index.m3u8",
  "source_stream_id": "str_01HXYZ1234",
  "chapters": [
    {
      "title": "Introduction",
      "start_seconds": 0
    },
    {
      "title": "Project setup & dependencies",
      "start_seconds": 420
    },
    {
      "title": "Routing with chi",
      "start_seconds": 1800
    }
  ],
  "tags": ["go", "api", "postgresql", "backend"],
  "published_at": "2024-06-11T08:00:00Z",
  "created_at": "2024-06-10T23:00:00Z",
  "updated_at": "2024-06-11T08:00:00Z"
}
```

<ResponseField name="playback_url" type="string">
  HLS manifest URL for direct video playback. You can pass this to a compatible player (e.g., HLS.js, Video.js) to embed the video in your own application.
</ResponseField>

<ResponseField name="chapters" type="array">
  Creator-defined chapters for the video. Each chapter has a `title` (string) and `start_seconds` (integer) indicating where it begins.
</ResponseField>

<ResponseField name="tags" type="array">
  Array of string tags associated with the video for search and discovery.
</ResponseField>

<ResponseField name="updated_at" type="string">
  ISO 8601 timestamp of the most recent metadata update to this video.
</ResponseField>

<Tip>
  Use the `playback_url` (HLS format) with an open-source player like [HLS.js](https://github.com/video-dev/hls.js/) to embed Hitorino videos directly in your web app without iframes.
</Tip>

<Note>
  The `playback_url` field is only returned on `GET /videos/{id}` — it is intentionally omitted from list responses to keep payloads compact.
</Note>
