# Channel Data

Pull About info, format overview, daily analytics, videos, shorts, and playlists for any channel.

Look up rich metadata for any YouTube channel by ID. All endpoints take a 24-char channel ID (`UCxxxxxxxxxxxxxxxxxxxxxx`). If you only have a `@handle` or URL, resolve it first via one of the search endpoints or the resolve endpoint.

### `GET /api/channels/:channel_id/about`

Everything from a channel's About page in one call — name, description, subscriber and view counts, country, language, join date, topics, social links, trailer, banner, and more.

**Path Parameters**

| Name | Type | Description |
| --- | --- | --- |
| channel_id | string | 24-char YouTube channel ID (starts with `UC`). |

**Example Response**

```
{
  "success": true,
  "channel": {
    "channel_id": "UCXoyny_UIW-02UwiNPUZT-w",
    "title": "The Geo Network",
    "handle": "@TheGeoNetwork",
    "description": "...",
    "url": "https://www.youtube.com/channel/UCXoyny_UIW-02UwiNPUZT-w",
    "country": { "code": "TR", "name": "Türkiye" },
    "default_language": "en",
    "avatar_url": "...",
    "banner_url": "...",
    "subscriber_count": { "raw": 125000, "display": "125K" },
    "view_count": { "raw": 27325762, "display": "27.3M" },
    "video_count": { "raw": 95, "display": "95" },
    "avg_views_per_video": { "raw": 287639, "display": "287.6K" },
    "joined": {
      "iso": "2019-10-12T00:00:00+00:00",
      "formatted": "Oct 12, 2019",
      "relative": "6 years ago",
      "age_days": 2378
    },
    "privacy_status": "public",
    "made_for_kids": false,
    "hidden_subscribers": false,
    "keywords": "...",
    "topic_categories": ["Military", "Politics"],
    "trailer_video_id": "abc123",
    "uploads_playlist_id": "UUXoyny_UIW-02UwiNPUZT-w",
    "tabs": ["Home", "Videos", "Shorts", "Playlists", "Posts"],
    "has_contact_email": true,
    "social_links": [
      { "platform": "instagram", "url": "instagram.com/thegeonetwork_tgn" }
    ],
    "available_countries_count": 245
  }
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/about"
```

200 Success 400 Invalid channel_id 404 Channel not found 429 Rate limit

### `GET /api/formats/:slug/overview`

Aggregate stats for one of Algrow's 24 canonical channel formats — how many channels are tracked in the niche, average and median subscriber counts, and the biggest channels. The channel About endpoint returns each channel's `format` slug; feed it here.

**Path Parameters**

| Name | Type | Description |
| --- | --- | --- |
| slug | string | One of the 24 canonical format slugs (e.g. `documentary`, `kids_content`, `challenge_videos`). |

**Example Response**

```
{
  "success": true,
  "format": { "slug": "challenge_videos", "display_name": "Challenge Videos" },
  "channels_tracked": 18265,
  "avg_subscribers": 70840,
  "median_subscribers": 7060,
  "top_channels": [
    {
      "channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA",
      "name": "MrBeast",
      "subscribers": 511000000,
      "profile_picture": "...",
      "url": "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA"
    }
  ]
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/formats/challenge_videos/overview"
```

200 Success 404 Unknown format slug 429 Rate limit

### `GET /api/channels/:channel_id/daily-analytics`

See how a channel has grown day-by-day across any date range you pick — subscribers, views, and uploads, plus a summary with total growth over the window.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| start_date | string | Optional | 30 days ago | ISO `YYYY-MM-DD`. |
| end_date | string | Optional | today | ISO `YYYY-MM-DD`. Max window 365 days (clamped). |

**Example Response**

```
{
  "success": true,
  "channel_id": "UCXoyny_UIW-02UwiNPUZT-w",
  "channel_title": "The Geo Network",
  "channel_type": "longform",
  "start_date": "2026-03-16",
  "end_date": "2026-04-15",
  "days_requested": 31,
  "days_with_data": 30,
  "summary": {
    "sub_growth": 12500,
    "view_growth": 8450000,
    "video_growth": 12,
    "starting_subs": 125000,
    "ending_subs": 137500,
    "starting_views": 27000000,
    "ending_views": 35450000
  },
  "days": [
    {
      "date": "2026-03-16",
      "total_subs": 125000,
      "total_views": 27000000,
      "total_videos": 95,
      "sub_increase_24h": 420,
      "view_increase_24h": 215000,
      "video_increase_24h": 0
    }
  ]
}
```

**Example Request**

```
curl -G "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/daily-analytics" \
-H "Authorization: Bearer algrow_..." \
-d "start_date=2026-03-01&end_date=2026-04-15"
```

200 Success 400 Invalid date 404 No data in range

### `GET /api/channels/:channel_id/videos`

Browse a channel's longform uploads, newest first — with titles, view counts, durations, upload dates, and thumbnails.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| limit | integer | Optional | 30 | Max videos (1–100). |

**Example Response**

```
{
  "success": true,
  "channel_id": "UCXoyny_UIW-02UwiNPUZT-w",
  "limit": 30,
  "count": 30,
  "has_more": true,
  "videos": [
    {
      "video_id": "R-NK5pa7KAU",
      "title": "The Collapse Has Begun...",
      "url": "https://www.youtube.com/watch?v=R-NK5pa7KAU",
      "published_text": "5 hours ago",
      "duration_text": "18:31",
      "duration_seconds": 1111,
      "view_count": 106657,
      "view_count_text": "106,657 views",
      "thumbnail_url": "..."
    }
  ]
}
```

**Example Request**

```
curl -G "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/videos" \
-H "Authorization: Bearer algrow_..." -d "limit=50"
```

200 Success 400 Invalid channel_id

### `GET /api/channels/:channel_id/shorts`

Browse a channel's Shorts, newest first — the real Shorts tab, not short-duration regular videos.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| limit | integer | Optional | 30 | Max shorts (1–100). |

**Example Response**

```
{
  "success": true,
  "channel_id": "UCXoyny_UIW-02UwiNPUZT-w",
  "limit": 30,
  "count": 3,
  "has_more": false,
  "shorts": [
    {
      "video_id": "5YKwSHccYTA",
      "title": "Detaylı tarif...",
      "url": "https://www.youtube.com/shorts/5YKwSHccYTA",
      "view_count": 942,
      "view_count_text": "942 views",
      "thumbnail_url": "..."
    }
  ]
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/shorts?limit=20"
```

200 Success 400 Invalid channel_id

### `GET /api/channels/:channel_id/playlists`

See every public playlist on a channel — title, description, video count, and thumbnail for each. Paginates in batches of 50.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| page_token | string | Optional | — | Pass the `next_page_token` from a previous response for subsequent pages. |

**Example Response**

```
{
  "success": true,
  "channel_id": "UCXoyny_UIW-02UwiNPUZT-w",
  "count": 17,
  "next_page_token": null,
  "playlists": [
    {
      "playlist_id": "PL069L7PbBcLx_O3Zv3gzUbScKtRrcMR76",
      "title": "pide tarifleri",
      "description": "",
      "published_at": "2020-08-31T19:26:11Z",
      "video_count": 4,
      "thumbnail_url": "...",
      "url": "https://www.youtube.com/playlist?list=PL069L7PbBcLx_O3Zv3gzUbScKtRrcMR76"
    }
  ]
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/playlists"
```

200 Success 400 Invalid channel_id 429 Rate limit

### `POST /api/channels/bulk-stats`

Subscriber counts — and channel-average views where we hold them — for many channels in one call. Channels already in the Algrow index are answered from our database and cost you nothing; anything we don't hold is resolved live from YouTube in batches. Use this instead of looping a per-channel endpoint when you are annotating a feed.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel_ids | string[] | Required | — | Channel IDs to look up. Must start with `UC` and be 24 characters. Duplicates and malformed entries are dropped silently; at most **300** per call. |

**Partial results are normal.** Compare `resolved` against `requested` — a channel we can't resolve is simply absent from `stats` rather than present with zeroes. Each entry carries a `source` of `algrow` (from our index) or `youtube` (resolved live). `avg_views_per_video` is null for channels we haven't measured.

**Example Response**

```
{
  "success": true,
  "requested": 3,
  "resolved": 2,
  "stats": {
    "UCXoyny_UIW-02UwiNPUZT-w": {
      "subscriber_count": 1240000,
      "avg_views_per_video": 84210.5,
      "source": "algrow"
    },
    "UC_x5XG1OV2P6uZZ5FSM9Ttw": {
      "subscriber_count": 2310000,
      "avg_views_per_video": null,
      "source": "youtube"
    }
  }
}
```

**Example Request**

```
curl -X POST "https://algrow.online/api/channels/bulk-stats" \
-H "Authorization: Bearer algrow_..." \
-H "Content-Type: application/json" \
-d '{"channel_ids": ["UCXoyny_UIW-02UwiNPUZT-w", "UC_x5XG1OV2P6uZZ5FSM9Ttw"]}'
```

200 Success 400 Empty, invalid, or over 300 IDs 429 Rate limit

### `GET /api/channels/:channel_id/video-deltas`

Daily view counts and day-over-day movement for each of a channel's tracked videos. Use it to see which videos are still picking up views and which have gone flat.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| days | integer | Optional | 30 | How far back to read, from 1 to 365 days. |

**Coverage is not universal.** Daily tracking runs for channels our users have opened, so a channel nobody has looked at yet returns `videos: []`. That is an empty series, not an error — render it as "not tracked yet" rather than treating it as a failure.

**`viewIncrease24h` can be null.** Null means there is no earlier day to measure against, so the movement is unknown. It never means zero. `likes` and `comments` follow the same rule.

**Example Response**

```
{
  "channelId": "UCXoyny_UIW-02UwiNPUZT-w",
  "days": 30,
  "videos": [
    {
      "videoId": "dQw4w9WgXcQ",
      "samples": [
        {
          "date": "2026-08-18",
          "views": 412880,
          "viewIncrease24h": null,
          "likes": 18204,
          "comments": 1332
        },
        {
          "date": "2026-08-19",
          "views": 431905,
          "viewIncrease24h": 19025,
          "likes": 18911,
          "comments": 1388
        }
      ]
    }
  ]
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/video-deltas?days=14"
```

200 Success 400 Invalid channel id or days out of range 429 Rate limit

### `POST /api/channels/:channel_id/videos/performance-trends`

The channel's typical view curve by video age — a low and high band for how many cumulative views a video on this channel usually has at a given number of minutes after publication. Plot a video's real curve against this band to see whether it is over- or under-performing for its own channel.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| videoIds | string[] | Optional | — | Restrict the band to these videos. Omit to use the whole channel. Every entry must be a valid video id or the call returns 400. |

**Read the `estimated` flag before you trust the band.** When we hold enough sampled history it is `false` and the band is a real 25th-to-75th percentile of that channel's own videos. When we don't, it is `true` and the band is synthesized from what we do know — still useful for shape, but not a measurement. A channel with no usable videos returns `trends: []`.

**Example Response**

```
{
  "channelId": "UCXoyny_UIW-02UwiNPUZT-w",
  "estimated": false,
  "trends": [
    {"minutesSincePublication": 60, "min": 1420, "max": 8830},
    {"minutesSincePublication": 1440, "min": 24100, "max": 96400}
  ]
}
```

**Example Request**

```
curl -X POST "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/videos/performance-trends" \
-H "Authorization: Bearer algrow_..." \
-H "Content-Type: application/json" \
-d '{}'
```

200 Success 400 Invalid channel id or videoIds 429 Rate limit

### `GET /api/videos/:video_id/stats-history`

The sampled time series for one video: views, likes and comments at each point we recorded, plus the views-per-hour rate between consecutive points. Returns the last sample in each bucket, oldest first.

**Query Parameters**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| granularity | string | Optional | hourly | Bucket size. One of `hourly`, `daily`, `monthly`. |
| from | string | Optional | — | Start of the window. Omit for the earliest sample we hold. |
| to | string | Optional | — | End of the window. Omit for the most recent sample. |

**History is sampled, not continuous.** A video only has points from the moment we started seeing it, so `samples` is empty for videos we have never recorded. `vph` is computed between the returned points, which means a wider granularity gives a smoother, lower-resolution rate.

**Example Response**

```
{
  "videoId": "dQw4w9WgXcQ",
  "granularity": "hourly",
  "samples": [
    {
      "timestamp": "2026-08-19T14:00:00Z",
      "views": 412880,
      "likes": 18204,
      "comments": 1332,
      "vph": null
    },
    {
      "timestamp": "2026-08-19T15:00:00Z",
      "views": 414012,
      "likes": 18251,
      "comments": 1339,
      "vph": 1132
    }
  ]
}
```

**Example Request**

```
curl -H "Authorization: Bearer algrow_..." \
"https://algrow.online/api/videos/dQw4w9WgXcQ/stats-history?granularity=daily"
```

200 Success 400 Invalid video id or granularity 429 Rate limit

### `POST /api/videos/:video_id/observations`

Record one point-in-time reading of a video's stats. This is the write side of [stats-history](#video-stats-history) — every observation you post becomes a point in that video's series.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| viewCount | integer | Required | — | The video's view count at the moment you read it. Must be a whole number. |
| likeCount | integer | Optional | — | Like count. Negative or non-integer values are stored as null rather than rejected. |
| commentCount | integer | Optional | — | Comment count. Same handling as `likeCount`. |

**At most one sample per video per 10 minutes.** Posting more often is safe but the extra readings are discarded. `recorded` tells you which happened: `true` means a new point was stored, `false` means one already existed inside the window. Neither is an error.

**Example Response**

```
{
  "videoId": "dQw4w9WgXcQ",
  "recorded": true
}
```

**Example Request**

```
curl -X POST "https://algrow.online/api/videos/dQw4w9WgXcQ/observations" \
-H "Authorization: Bearer algrow_..." \
-H "Content-Type: application/json" \
-d '{"viewCount": 414012, "likeCount": 18251, "commentCount": 1339}'
```

200 Success 400 Invalid video id or missing viewCount 429 Rate limit
