> ## 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 Streams API — List, Retrieve, and Schedule

> Use the Streams API to list live and scheduled streams, fetch stream details by ID, and schedule new streams with title, category, and privacy settings.

The Streams API is the core of Hitorino's platform. You can use it to retrieve real-time and scheduled stream data for display in your app, or to programmatically schedule new solo streams on behalf of authenticated creators. All three endpoints follow the standard Hitorino request/response conventions described in the [API Overview](/api/overview).

***

## List Streams

Retrieves a paginated list of streams. By default the response includes all streams regardless of status. Use the query parameters below to filter by status, creator, or category.

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

### Query Parameters

<ParamField query="status" type="string">
  Filter by stream status. Accepted values: `live`, `scheduled`, `ended`. Omit to return streams of all statuses.
</ParamField>

<ParamField query="creator_id" type="string">
  Return only streams belonging to the creator with this user ID.
</ParamField>

<ParamField query="category" type="string">
  Filter streams by category slug (e.g., `gaming`, `music`, `talk`). Category slugs are lowercase and hyphen-separated.
</ParamField>

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

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

### Request Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.hitorino.tv/v1/streams?status=live&limit=10" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({ status: 'live', limit: '10' });

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

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

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

  params = {'status': 'live', 'limit': 10}
  headers = {'Authorization': 'Bearer YOUR_API_KEY'}

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

### Response

```json theme={null}
{
  "data": [
    {
      "id": "str_01HXYZ1234",
      "title": "Late Night Lo-Fi Coding",
      "description": "Building a side project with lo-fi beats.",
      "status": "live",
      "category": "coding",
      "privacy": "public",
      "creator_id": "usr_01HABC5678",
      "viewer_count": 142,
      "started_at": "2024-06-10T22:00:00Z",
      "scheduled_at": null,
      "thumbnail_url": "https://cdn.hitorino.tv/thumbnails/str_01HXYZ1234.jpg",
      "stream_url": "https://watch.hitorino.tv/str_01HXYZ1234",
      "created_at": "2024-06-10T21:45:00Z"
    }
  ],
  "pagination": {
    "next_cursor": "cur_01HDEF9012",
    "has_more": true
  }
}
```

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

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

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

    <ResponseField name="description" type="string">
      Optional description provided by the creator.
    </ResponseField>

    <ResponseField name="status" type="string">
      Current status: `live`, `scheduled`, or `ended`.
    </ResponseField>

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

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

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

    <ResponseField name="viewer_count" type="integer">
      Number of current concurrent viewers. `null` for `scheduled` or `ended` streams.
    </ResponseField>

    <ResponseField name="started_at" type="string">
      ISO 8601 timestamp of when the stream went live. `null` for `scheduled` streams.
    </ResponseField>

    <ResponseField name="scheduled_at" type="string">
      ISO 8601 timestamp of the planned start time. `null` for streams that were not pre-scheduled.
    </ResponseField>

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

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

    <ResponseField name="created_at" type="string">
      ISO 8601 timestamp of when the stream resource was created.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pagination" type="object">
  Pagination metadata for fetching subsequent pages.

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

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

***

## Get Stream

Retrieves a single stream by its unique ID, including all fields from the list response plus any extended metadata.

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

### Path Parameters

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

### Request Examples

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

  ```javascript JavaScript theme={null}
  const streamId = 'str_01HXYZ1234';

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

  const stream = await response.json();
  console.log(stream);
  ```

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

  stream_id = 'str_01HXYZ1234'
  headers = {'Authorization': 'Bearer YOUR_API_KEY'}

  response = requests.get(
      f'https://api.hitorino.tv/v1/streams/{stream_id}',
      headers=headers,
  )
  stream = response.json()
  print(stream)
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "str_01HXYZ1234",
  "title": "Late Night Lo-Fi Coding",
  "description": "Building a side project with lo-fi beats.",
  "status": "live",
  "category": "coding",
  "privacy": "public",
  "creator_id": "usr_01HABC5678",
  "viewer_count": 142,
  "peak_viewer_count": 189,
  "started_at": "2024-06-10T22:00:00Z",
  "ended_at": null,
  "scheduled_at": null,
  "thumbnail_url": "https://cdn.hitorino.tv/thumbnails/str_01HXYZ1234.jpg",
  "stream_url": "https://watch.hitorino.tv/str_01HXYZ1234",
  "created_at": "2024-06-10T21:45:00Z",
  "updated_at": "2024-06-10T22:00:05Z"
}
```

<ResponseField name="peak_viewer_count" type="integer">
  Highest concurrent viewer count recorded during the stream's lifetime.
</ResponseField>

<ResponseField name="ended_at" type="string">
  ISO 8601 timestamp of when the stream ended. `null` if the stream is still live or scheduled.
</ResponseField>

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

<Note>
  All other response fields are identical to those returned in the list endpoint. See the [List Streams](#list-streams) section for full field descriptions.
</Note>

***

## Create Stream

Creates or schedules a new stream. Supply a `scheduled_at` timestamp to schedule the stream for a future time, or omit it to create a stream you intend to start immediately via your streaming software.

```bash theme={null}
POST /streams
```

<Note>
  This endpoint requires a **write-scoped** API key. Requests made with a `read`-scoped key return `403 Forbidden`.
</Note>

### Request Body

<ParamField body="title" type="string" required>
  Display title for the stream. Maximum 120 characters.
</ParamField>

<ParamField body="description" type="string">
  Optional description visible to viewers. Maximum 2,000 characters.
</ParamField>

<ParamField body="scheduled_at" type="string">
  ISO 8601 timestamp of the planned start time (e.g., `2024-07-01T18:00:00Z`). Must be in the future. Omit to create an unscheduled stream ready to go live immediately.
</ParamField>

<ParamField body="category" type="string">
  Category slug for the stream (e.g., `gaming`, `music`, `coding`, `talk`). Must match a valid Hitorino category.
</ParamField>

<ParamField body="privacy" type="string">
  Visibility setting. One of `public` (default) or `private`. Private streams are accessible only via direct link.
</ParamField>

### Request Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.hitorino.tv/v1/streams \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "title": "Sunday Watercolor Session",
      "description": "Painting a mountain landscape from scratch.",
      "scheduled_at": "2024-07-07T14:00:00Z",
      "category": "art",
      "privacy": "public"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.hitorino.tv/v1/streams', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      title: 'Sunday Watercolor Session',
      description: 'Painting a mountain landscape from scratch.',
      scheduled_at: '2024-07-07T14:00:00Z',
      category: 'art',
      privacy: 'public',
    }),
  });

  const stream = await response.json();
  console.log(stream.id); // "str_01HNEW5678"
  ```

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

  headers = {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
  }

  payload = {
      'title': 'Sunday Watercolor Session',
      'description': 'Painting a mountain landscape from scratch.',
      'scheduled_at': '2024-07-07T14:00:00Z',
      'category': 'art',
      'privacy': 'public',
  }

  response = requests.post(
      'https://api.hitorino.tv/v1/streams',
      json=payload,
      headers=headers,
  )
  stream = response.json()
  print(stream['id'])
  ```
</CodeGroup>

### Response

Returns `201 Created` with the newly created stream object.

```json theme={null}
{
  "id": "str_01HNEW5678",
  "title": "Sunday Watercolor Session",
  "description": "Painting a mountain landscape from scratch.",
  "status": "scheduled",
  "category": "art",
  "privacy": "public",
  "creator_id": "usr_01HABC5678",
  "viewer_count": null,
  "peak_viewer_count": null,
  "started_at": null,
  "ended_at": null,
  "scheduled_at": "2024-07-07T14:00:00Z",
  "thumbnail_url": null,
  "stream_url": "https://watch.hitorino.tv/str_01HNEW5678",
  "created_at": "2024-06-15T09:30:00Z",
  "updated_at": "2024-06-15T09:30:00Z"
}
```

<Tip>
  After creating a scheduled stream, share the `stream_url` with your audience. Hitorino automatically sends a `stream.started` webhook event when the stream goes live — see the [Webhooks](/api/webhooks) reference to register your endpoint.
</Tip>
