Nexlev Logo

Docs

Search documentation

Search docs by page title or heading

YouTube Search API

Search live YouTube for videos, channels, playlists, and shorts. Results come straight from YouTube at request time — nothing is read from the NexLev catalog.

Base URL: https://prod.dashboard.nexlev.io — see Authentication. This operation costs 🥞 1 quota per request — see Rate Limits & Quota.

Requests are served with automatic failover across upstream data providers. The source field in every response reports whether the primary or the fallback path answered; the payload shape is identical either way.

Not to be confused with the catalog search. GET /api/external/videos/video-search searches NexLev's own indexed video catalog and supports catalog-only filters such as outlier score, subscriber count, and RPM. Use that one for research over curated data; use this one when you need what YouTube is returning right now.

Operations Quick Reference

OperationMethod & PathQuota Cost
Search YouTubeGET /api/external/youtube/search🥞 1

Rate Limit

20 requests per minute per API key on this endpoint, on top of your plan quota. Exceeding either returns 429 Too Many Requests — see Rate Limits & Quota.

Search YouTube

GET /api/external/youtube/search

Description: Run a YouTube search and return the videos, channels, playlists, and shorts YouTube currently ranks for that query, with optional type, duration, recency, feature, and region filters.

🥞 Quota Cost: 1 quota per request

Each call to this endpoint deducts 1 quota from your account balance. Paginated requests each count separately. Monitor your usage at Manage API Key to avoid interruptions.

When to use this operation:

  • Checking what YouTube ranks for a keyword right now
  • Keyword and title research against live search results
  • Finding channels or playlists by name when you do not have a channel ID
  • Sampling shorts for a topic without going channel by channel

Query Parameters

Parameter names are camelCase. Unknown parameters are rejected with a 400 rather than silently ignored — so a typo or a snake_case name (sort_by, upload_date) fails loudly instead of returning unfiltered results.

This endpoint's naming differs from the older channels/* routes, which use id, sort_by, and forUsername. Do not copy parameter names between them.

ParameterTypeRequiredDefaultDescription
querystringYesSearch terms, e.g. mkbhd.
typevideo | channel | playlist | shorts | movie | showNoRestrict to one content type. Omit to get a mixed result set — check the type field on each item.
sortByrelevance | popularity | rating | date | viewsNorelevance (YouTube default)Result ordering.
durationshort | medium | longNoshort under 4 min, medium 4–20 min, long over 20 min.
uploadDatehour | today | week | month | yearNoRestrict by upload recency.
featuresstring (comma-separated)NoAny of HD, subtitles, CCommons, 3D, Live, 4K, 360, HDR, VR180. Example: HD,subtitles.
geostringNoISO 3166-2 country code, e.g. US, GB, IN. Changes which regional results YouTube returns.
langstringNoLocale, e.g. en, gb, hi.
tokenstringNoPagination token. Pass the continuation value from the previous response. Omit for the first page.

Example URLs

https://prod.dashboard.nexlev.io/api/external/youtube/search?query=mkbhd
https://prod.dashboard.nexlev.io/api/external/youtube/search?query=mkbhd&type=video&sortBy=views

cURL Example:

curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=mkbhd&type=video&sortBy=views" \
  -H "Authorization: Bearer YOUR_API_KEY"

Status Code: 200 OK

Response Body:

{
  "query": "mkbhd",
  "estimatedResults": "360582",
  "continuation": "EpoDEgVta2JoZBqQA0VnSVFBVWdV...",
  "resultCount": 20,
  "source": "primary",
  "results": [
    {
      "type": "video",
      "videoId": "_xjxwl1zLMc",
      "title": "Framework 13 Pro: The Modular Laptop is Real!",
      "channelTitle": "Marques Brownlee",
      "channelId": "UCBJycsmduvYEL83R_U4JriQ",
      "channelHandle": "@mkbhd",
      "description": "The modular Macbook Pro for Linux users. Color me impressed...",
      "viewCount": "2643412",
      "publishedTime": "3 days ago",
      "duration": "12:49",
      "isLive": false,
      "badges": ["New", "4K"],
      "thumbnail": [
        {
          "url": "https://i.ytimg.com/vi/_xjxwl1zLMc/hq720.jpg?...",
          "width": 720,
          "height": 404
        },
        {
          "url": "https://i.ytimg.com/vi/_xjxwl1zLMc/hq720.jpg?...",
          "width": 360,
          "height": 202
        }
      ]
    }
  ],
  "filters": {
    "type": "video",
    "sortBy": "views"
  }
}

Envelope Fields

  • query - The query that was executed
  • estimatedResults - YouTube's own estimate of total matches, as a numeric string. May be absent on some responses — do not assume it is present
  • continuation - Token for the next page. null means there are no further pages
  • resultCount - Number of items in results for this page
  • source - "primary" or "fallback"; which leg of the failover chain served the request. Informational only
  • results - The result items. The shape varies by type — see below
  • filters - Echo of the filters that were applied. Only type, sortBy, duration, uploadDate, and geo are echoed — features and lang are not. Filters you did not pass are omitted, not null, so this is {} for an unfiltered query

Result Item Shapes

Every item carries a type discriminator. Branch on it — the available fields differ significantly. Pick a type below for its fields and a sample payload.

Video Item

The richest shape — full metadata for a long-form video or a live stream.

{
  "type": "video",
  "videoId": "_xjxwl1zLMc",
  "title": "Framework 13 Pro: The Modular Laptop is Real!",
  "channelTitle": "Marques Brownlee",
  "channelId": "UCBJycsmduvYEL83R_U4JriQ",
  "channelHandle": "@mkbhd",
  "description": "The modular Macbook Pro for Linux users. Color me impressed...",
  "viewCount": "2643412",
  "publishedTime": "3 days ago",
  "duration": "12:49",
  "isLive": false,
  "badges": ["New", "4K"],
  "thumbnail": [
    {
      "url": "https://i.ytimg.com/vi/_xjxwl1zLMc/hq720.jpg?...",
      "width": 720,
      "height": 404
    }
  ]
}

Response Fields:

  • videoId - YouTube video ID
  • title - Video title
  • channelTitle / channelId / channelHandle - Uploading channel
  • description - Truncated search-snippet description, not the full video description
  • viewCount - View count as a numeric string
  • publishedTime - Relative human string, e.g. "3 days ago"
  • duration - Display string, e.g. "12:49"
  • isLive - true for an ongoing live stream
  • badges - YouTube badges such as New, 4K, CC
  • thumbnail - Array of thumbnail objects with url, width, height

Integration Notes

These are all consequences of what YouTube returns upstream — worth handling defensively:

  1. viewCount is not consistently typed. It is a numeric string on video items ("2643412") and a number on shorts items (29000000). Coerce before doing arithmetic.
  2. publishedTime is a relative human string, not a timestamp — "3 days ago", "1 year ago". There is no absolute date in the search payload; call Video Details if you need one.
  3. duration is a display string ("12:49"), not seconds.
  4. Shorts are flattened out of their shelf, and their thumbnail array is frequently empty — fall back to https://i.ytimg.com/vi/{videoId}/hqdefault.jpg.
  5. Channel thumbnails may be protocol-relative (//yt3.ggpht.com/...). Prefix with https: before use.
  6. Mixed results by default. Without type, a single page can contain videos, channels, playlists, and shorts together, and resultCount counts them all.
  7. Result counts per page are not fixed and are not controllable — there is no limit parameter. Observed pages range from ~20 to 80+ items, depending on what YouTube returns and how many shorts got unpacked from their shelf. Paginate with token; never assume a page size.
  8. type=movie and type=show are accepted and do return results, but items are tagged with the standard types above — movie comes back as video items, and show returns a mix of video, shorts, and playlist. There is no movie or show item type.

Pagination

When more results are available, the response returns a continuation token. Pass it back as token to fetch the next page.

How to use continuation tokens:

  1. Make an initial request without token to get the first page
  2. Check the continuation field in the response:
    • If it contains a token, more results are available
    • If it is null, you have reached the last page
  3. To fetch the next page, repeat the request with token set to that value — and resend the same query and all the same filters
  4. Repeat until continuation is null

Tokens are opaque and tied to the original query. Changing query, type, sortBy, or any other filter alongside a token invalidates it — start over instead.

Example pagination workflow:

# page 1
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=cooking%20tutorials&type=video" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response: {
  "continuation": "EpoDEgVta2JoZBqQA0VnSVFBVWdV...",
  "resultCount": 20,
  "results": [
    /* Array of result items */
  ]
}
# page 2 — feed `continuation` back in as `token`
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=cooking%20tutorials&type=video&token=EpoDEgVta2JoZBqQA0VnSVFBVWdV..." \
  -H "Authorization: Bearer YOUR_API_KEY"
Response: {
  "continuation": null,  // null means no more results
  "resultCount": 18,
  "results": [
    /* Array of remaining result items */
  ]
}

Unlike the channels/* endpoints, which signal "no more pages" with an empty string, this endpoint uses null. Check for both if you share pagination code across endpoints.

Error Responses

Status Code: 400 Bad Request

Description: Validation failure — a missing query, an out-of-enum value, or an unrecognized parameter name. The response message lists exactly what was wrong.

{
  "success": false,
  "statusCode": 400,
  "message": [
    "property sort_by should not exist",
    "property upload_date should not exist"
  ],
  "error": "Bad Request",
  "path": "/api/external/youtube/search?query=x&sort_by=date&upload_date=week"
}

More Examples

# Most-viewed videos for a term
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=mkbhd&type=video&sortBy=views" \
  -H "Authorization: Bearer YOUR_API_KEY"
 
# Channels only
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=mkbhd&type=channel" \
  -H "Authorization: Bearer YOUR_API_KEY"
 
# Shorts, US region
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=cooking&type=shorts&geo=US&lang=en" \
  -H "Authorization: Bearer YOUR_API_KEY"
 
# Short, recent, HD videos with subtitles
curl "https://prod.dashboard.nexlev.io/api/external/youtube/search?query=news&type=video&duration=short&uploadDate=week&features=HD,subtitles" \
  -H "Authorization: Bearer YOUR_API_KEY"
EndpointData sourceUse when
GET /api/external/youtube/searchLive YouTubeYou need current YouTube search results.
GET /api/external/videos/video-searchNexLev catalogYou need catalog filters — outlier score, subscriber count, RPM, dates.
Video DetailsLive YouTubeFull metadata for one video, including absolute publish date.
Get AboutLive YouTubeChannel stats for one channel (note: takes id, not channelId).
Get VideosLive YouTubeA specific channel's uploads (takes id and sort_by).