# List channel videos



<MethodPage method="GET" path="/v1/channels/{id}/videos" credits={1}>
  <MethodSignature name="listChannelVideos" args={[{ name: "id" }, { name: "query", optional: true }, { name: "options", optional: true }]} returns="ChannelVideosPage" />

  Lists public uploads. Pass `continuation` or `cursor` from the previous page to keep paging.

  <Security permission="videos:read" />

  <SchemaGroup title="Path Parameters">
    <SchemaField name="id" type="string" location="path" required>
      Channel handle or canonical channel ID (`UC...`).
    </SchemaField>
  </SchemaGroup>

  <SchemaGroup title="Query Parameters">
    <SchemaField name="sort_by" type="string" optional location="query">
      Sort order: `newest` (default), `popular`, or `oldest`.
    </SchemaField>

    <SchemaField name="tab" type="string" optional location="query">
      Which tab to list: `videos` (default, 30 per page) or `shorts` (48 per page). Shorts come without `published_text` and `length_text`, and `sort_by` doesn't apply to them (always newest first).
    </SchemaField>

    <SchemaField name="continuation" type="string" optional location="query">
      Continuation token from the previous response.
    </SchemaField>

    <SchemaField name="cursor" type="string" optional location="query">
      Alias for `continuation`.
    </SchemaField>
  </SchemaGroup>

  <div id="returns" className="mt-8">
    Response (HTTP 200) [#response-http-200]

    ```jsonc
    {
      "channel_id": string,          // Canonical 24-character channel ID (UC...)
      "channel_title": string,       // Channel display name
      "has_more": boolean,            // Whether another page is available
      "next_cursor": string | null,   // Cursor token for the next page
      "continuation": string | null,  // Alias of next_cursor
      "videos": [                     // Uploaded video items for this page
        {
          "video_id": string,         // 11-character video ID
          "title": string,            // Video title
          "length_text": string,      // Duration string (e.g. "25:42")
          "thumbnails": [             // Thumbnail variants
            {
              "url": string,
              "width": number,
              "height": number
            }
          ]
        }
      ]
    }
    ```
  </div>

  <MethodSamples>
    <LanguageSample language="TypeScript">
      ```ts
      const response = await fetch(
        "https://api.ytapi.dev/v1/channels/@MrBeast/videos?sort_by=popular",
        {
          headers: {
            Authorization: `Bearer ${process.env.YT_API_KEY}`,
          },
        },
      );

      const page = await response.json();
      console.log(page.videos[0]?.title, page.next_cursor);
      ```
    </LanguageSample>

    <LanguageSample language="Python">
      ```python
      import os
      import requests

      response = requests.get(
          "https://api.ytapi.dev/v1/channels/@MrBeast/videos",
          headers={"Authorization": f"Bearer {os.environ['YT_API_KEY']}"},
          params={"sort_by": "popular"},
      )

      print(response.json())
      ```
    </LanguageSample>

    <LanguageSample language="cURL">
      ```bash
      curl -X GET "https://api.ytapi.dev/v1/channels/@MrBeast/videos?sort_by=popular" \
        -H "Authorization: Bearer $YT_API_KEY"
      ```
    </LanguageSample>

    <LanguageSample language="Go">
      ```go
      package main

      import (
      	"fmt"
      	"net/http"
      	"os"
      )

      func main() {
      	url := "https://api.ytapi.dev/v1/channels/@MrBeast/videos?sort_by=popular"
      	req, _ := http.NewRequest("GET", url, nil)
      	req.Header.Set("Authorization", "Bearer "+os.Getenv("YT_API_KEY"))

      	resp, err := http.DefaultClient.Do(req)
      	if err != nil {
      		panic(err)
      	}
      	defer resp.Body.Close()
      	fmt.Println(resp.Status)
      }
      ```
    </LanguageSample>
  </MethodSamples>
</MethodPage>
