---
title: "Search YouTube or within one channel"
method: GET
path: "/v1/search"
tags: ["Discovery"]
---

# Search YouTube or within one channel

`GET /v1/search`

## Request

- Base URL: `https://api.scripthaul.com`
- URL: `https://api.scripthaul.com/v1/search`
- Auth: HTTP bearer

One credit per delivered page, including an empty page; zero on failure. An identical q, type, channel, and continuation retried with the same key within 60 seconds returns the same page for zero credits and consumes no additional daily page allowance. Other pages are not cached. Search has its own per-key daily allowance of 50 pages for free keys and 2,000 for paid keys, independent of cold transcript fetch counters; the approximate per-key rpm limit and daily credit cap also apply. Search never uses the YouTube Data API search.list endpoint. Resolving a channel handle is free and cached. Send opaque continuations unchanged with the same other parameters. A second daily allowance admits at most 150 attempts per free key or 6,000 per paid key (three times the page cap). Admitted attempts count before upstream work even if they later fail, but failures cost zero credits. Denied admission, in-flight duplicates and successful same-key replays add no attempt or page allowance. An in-flight identical request returns retryable 429 search_in_progress with Retry-After: 1; repeat the same key and parameters after waiting, and once delivery succeeds its page can be replayed free. A failed first request has no delivered page to replay. Malformed individual results are dropped while valid rows remain. Recommendation shelves such as Latest from and People also watched, including their nested results and continuation tokens, are excluded from organic results.

## Query parameters

- `q` string, required
- `type` 'video' | 'channel' | 'playlist'
- `channel` string
- `continuation` string

## Response `200`

Delivered normalized search page, including an empty page.

- SearchPage
  - `ok` unknown, required
  - `results` union[], required: Valid result rows from this page; malformed individual rows are omitted. An empty delivered page still costs one credit. Recommendation shelves and their nested results are excluded.
    - union
      - SearchVideoResult
        - `title` string, required: YouTube result title.
        - `channel_id` string, nullable, required: Owning channel when YouTube reports it.
        - `channel_title` string, nullable, required: Owning channel display name when reported.
        - `duration_seconds` integer, nullable, required: Duration in seconds when reported.
        - `view_count` integer, nullable, required: View count when it can be normalized.
        - `published_text` string, nullable, required: YouTube display text, not an exact publication date.
        - `has_captions` boolean, required: Whether YouTube shows a CC badge on this result; false does not establish that captions are unavailable.
        - `thumbnail_url` string, uri, nullable, required: Public YouTube thumbnail when reported.
        - `type` 'video', required
        - `video_id` string, required
        - `cached` boolean, required: Whether a transcript is already known in the shared cache.
      - SearchChannelResult
        - `title` string, required: YouTube result title.
        - `channel_id` string, required
        - `channel_title` string, nullable, required: Owning channel display name when reported.
        - `duration_seconds` integer, nullable, required: Duration in seconds when reported.
        - `view_count` integer, nullable, required: View count when it can be normalized.
        - `published_text` string, nullable, required: YouTube display text, not an exact publication date.
        - `has_captions` boolean, required: Whether YouTube shows a CC badge on this result; false does not establish that captions are unavailable.
        - `thumbnail_url` string, uri, nullable, required: Public YouTube thumbnail when reported.
        - `type` 'channel', required
      - SearchPlaylistResult
        - `title` string, required: YouTube result title.
        - `channel_id` string, nullable, required: Owning channel when YouTube reports it.
        - `channel_title` string, nullable, required: Owning channel display name when reported.
        - `duration_seconds` integer, nullable, required: Duration in seconds when reported.
        - `view_count` integer, nullable, required: View count when it can be normalized.
        - `published_text` string, nullable, required: YouTube display text, not an exact publication date.
        - `has_captions` boolean, required: Whether YouTube shows a CC badge on this result; false does not establish that captions are unavailable.
        - `thumbnail_url` string, uri, nullable, required: Public YouTube thumbnail when reported.
        - `type` 'playlist', required
        - `playlist_id` string, required: Search-result playlist ID. Enumeration and latest uploads use their own input validation.
  - `continuation` string, nullable, required: Opaque token for the next page, or null when no more results are available.
  - `has_more` boolean, required

## Other responses

- `400`: InvalidInput: query, result type, channel, or continuation is missing or malformed. Costs zero credits.
- `401`: Forbidden: a Bearer API key is missing, malformed, unknown, or revoked. Dashboard cookies cannot authenticate this endpoint. Costs zero credits.
- `402`: InsufficientCredits: available credits cannot cover one page. The response includes required, available, shortfall, and buy_url. Costs zero credits.
- `403`: AccountFrozen or Forbidden: the account is frozen or the authenticated caller cannot use this route. Costs zero credits.
- `404`: InvalidInput: the public channel could not be resolved. Costs zero credits.
- `429`: QuotaExceeded: request rate, daily credit/page/attempt cap, concurrent-search limit, or identical-request lock. search_attempt_cap is nonretryable until UTC midnight (150 free/6,000 paid admitted attempts); failures count once admitted. search_in_progress is retryable with Retry-After: 1 and consumes no additional attempt; retry the same key and parameters to recover a successfully delivered page. Other codes include search_page_cap, search_concurrency_cap and daily_credit_cap. Costs zero credits.
- `502`: UpstreamError, RelayUnavailable, IpBlocked, RateLimited, or PoTokenRequired: the search request failed upstream. Follow retryable and use bounded backoff. Costs zero credits.
- `503`: ConfigurationError, BudgetExhausted, or channel-resolution Data API RateLimited: required configuration, search settlement, or upstream capacity is unavailable. A search settlement failure uses code search_settlement_failed and retryable false; the pending reservation is released, or left for expiry cleanup if the database is unavailable. Costs zero credits. A confirmed committed settlement returns its saved successful page instead.

---

[API](https://skmtc.dev/scripthaul/apis/scripthaul-api.md) · [All operations](https://skmtc.dev/scripthaul/apis/scripthaul-api/llms.txt) · [OpenAPI document](https://skmtc.dev/scripthaul/apis/scripthaul-api/revisions/f476d69f4a6b?raw)
