youtube

List YouTube channel videos

Returns a list of recent videos published by a YouTube channel. Each video includes title, view count, like count, comment count, duration, thumbnail URL, and publish date. SHORTS: this reads the channel's Videos tab, which is long-form only. Shorts are a separate shelf on YouTube and never appear here (measured 0 of 30 items on 2 channels, 2026-08-11). For a channel's Shorts call /v1/youtube/channel/shorts (1 credit, same channelId/handle); the two sets are disjoint, so calling both and concatenating gives the channel's full catalogue for 2 credits. Every item on both endpoints carries post.ext.content_type (video or short) so the merged list stays separable. Send include=channel to add the channel's subscriber count to every row in the same call (1 credit). DATES: post.published_at is the exact publish time. A row that ever arrives with only a date derived from a relative label such as "4 months ago" is joined to the per-video lookup for the exact second, free; send exact_dates=false to keep the supplier's estimate instead, marked by post.ext.published_precision. TITLES: the free per-video lookup swaps YouTube's English machine-translated listing title for the creator's own (and description); a title not swapped carries post.ext.title_maybe_translated: true (exact_dates=false skips the lookup).

get/youtube/channel/videos

Request

  • Base URL: https://www.socialcrawl.dev/v1
  • URL: https://www.socialcrawl.dev/v1/youtube/channel/videos
  • Auth: API key in header x-api-key

Query parameters

sincestring

Only videos published on or after this date: YYYY-MM-DD (midnight UTC) or an ISO 8601 timestamp. Older videos are left off the page, and the page that reaches one ends the walk: next_cursor is not returned and pagination.stopped_at is since. Pinned videos sit out of date order and never end the walk. The page still costs what a page costs, so a daily poll pays for the pages it walks and no more.

stop_at_idstring

The id (post.id) or URL (post.url) of the newest video you already hold. The page stops just before it: that video and everything after it are left off, next_cursor is not returned, and pagination.stopped_at is known_id. A pinned video never counts as the stop point. If it is not on this page the page is returned in full with its cursor, so keep walking. pagination.stopped_at is end when the list ran out first and null while there is more to walk.

channelIdstring

YouTube channel ID (one of: channelId, handle; at least one required)

handlestring

YouTube channel handle without the @ symbol (one of: channelId, handle; at least one required)

sort'latest' | 'popular'

Sort by latest or popular

continuationTokenstring

Continuation token to get more videos. Get 'continuationToken' from previous response. Native upstream cursor param. Send the universal cursor instead: the API maps it to this name for you.

includeExtrasstring

Set to true to add the like count and comment count (post.engagement.likes / .comments) and the video description (post.ext.description). For the full per-video detail use /v1/youtube/video. Slows the response slightly.

is_paid_promotionsstring

Set to 'true' to search YouTube's public paid product placement / sponsorship / endorsement surface: returns normal videos where the creator disclosed a paid promotion.

include'channel'

Set to channel (one token only) to add the channel's subscriber count to every row (post.ext.author_followers, YouTube's own figure, rounded to three significant figures above 1,000) plus post.author.display_name, .avatar_url and post.ext.channel_id where missing. Every row is the same channel, so this is one channel lookup for the whole page: 1 credit, refunded if the channel could not be read, and free when the channel was looked up recently. Adds well under a second (never more than 8). Read data.hydration for what it did.

exact_dates'true' | 'false'

Exact publish dates are on by default and free. A row whose date the upstream derived from a relative label such as "4 months ago" (measured up to four months off) is joined to the per-video lookup for its exact publish second, at no extra credit: one lookup per page (two on a page past 50 rows, side by side), adding about 0.2 to 0.7 seconds (never more than 3). The same lookup swaps the listing title, often YouTube's English machine translation, for the creator's own, and computed.language follows it; a title not swapped carries post.ext.title_maybe_translated: true. Set to false to skip the lookup: rows then carry the supplier's date estimate (a day-granular or coarser label truncated to midnight UTC), marked by post.ext.published_precision and post.ext.published_label, and the listing title, marked by post.ext.title_maybe_translated. A row the lookup could not resolve keeps those values and markers, and _warnings carries exact_dates_partial (some rows) or exact_dates_unavailable (none); on channel/videos, whose dates are already exact, the warnings are original_titles_partial and original_titles_unavailable.

untilstring

Only rows published on or before this date: YYYY-MM-DD (that whole UTC day is included) or an ISO 8601 timestamp. Newer rows are left off each page and the walk does not stop, so older pages follow. A row with no date is kept. published_before, end_date and to_date are accepted and applied as until.

cursorstring

Universal pagination cursor. Send pagination.next_cursor from the previous response back verbatim: the API maps it to this endpoint's native continuationToken (cursor style). You never construct, decode, or look up a cursor. Omit it for page 1.

Headers

Cache-Controlstring

Send no-cache to bypass the response cache and force a live fetch. Billed at the normal endpoint cost; the fresh result is written back to cache for the next caller. Only the no-cache directive triggers this. See the Response Schema guide for details.

Idempotency-Keystring

Optional UUID that makes the request safely retriable. The key is reserved atomically per account before billing. A concurrent retry receives 409 IDEMPOTENCY_IN_PROGRESS with a Retry-After of 1 second while the original is young, growing to a quarter of the time it has been running (at most 30); a crashed reservation expires after 5 minutes. A replay keeps the cached payload immutable except for billing metadata: credits_used becomes 0, idempotent_replay becomes true, and credits_remaining is refreshed to the current balance. A known current balance appears in both the body and X-Credits-Remaining header; no balance row resolves to 0. On a transient lookup failure, body credits_remaining is null and X-Credits-Remaining is omitted. Completed outcomes expire after 24 hours. If the claim store is unavailable, the request fails closed before billing. GET endpoints do not combine idempotent replay with Server-Sent Events: use Accept: application/json when sending this header. The unsupported key-plus-SSE combination is rejected before billing.

Response

Successful response

successboolean required

Whether the request succeeded

platformstring required

Platform name

endpointstring required

API endpoint path

credits_usedinteger required

Number of credits consumed

credits_remaininginteger nullable required

Current account balance, or null when this response could not establish one. Free cache hits always return null because they do not establish an authoritative post-request balance. An idempotency replay also returns null when its current-balance lookup fails. It is never a fabricated zero, so a zero here means the account really is empty. The authoritative reading is the one on a billed response, which comes straight from the deduction.

request_idstring required

Unique request identifier for support

cachedboolean required

Whether the response was served from cache

idempotent_replayboolean

True only when this response is an idempotency replay

Example response

{
  "success": true,
  "platform": "youtube",
  "endpoint": "/v1/youtube/channel/videos",
  "credits_used": 1,
  "credits_remaining": 4999,
  "request_id": "req-abc123",
  "idempotent_replay": true,
  "meta": {
    "hint": {
      "code": "search_multi",
      "message": "You searched \"matcha\" on 3 platforms one call at a time; /v1/search/multi returns each platform's own search rows in one call at the same price per platform, and a platform with no rows is not charged.",
      "method": "GET",
      "path": "/v1/search/multi?query=matcha&platforms=instagram,tiktok,youtube"
    }
  },
  "pagination": {
    "next_cursor": "sc.eyJ2IjoyLCJjIjoiMiIsInAiOiJwYWdlIn0",
    "has_more": true,
    "page_size": 30,
    "stopped_at": "known_id"
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.