API Reference

The OutlierKit API

A clean, versioned surface for outlier discovery, channel intelligence, video analysis, and keyword expansion. Send JSON, receive JSON, build something interesting.

Base URL https://outlierkit.com/api/v1
Auth Bearer token
Content-Type application/json

Each call costs 1 credit, deducted from your account balance before the response is returned. Credits are shared with the OutlierKit app — usage from the API and the app draws from the same pool.

Need a key? Generate one in the API console →

Response envelope

Every endpoint wraps its payload in a consistent shape:

{
  "success": true,
  "data":    { /* endpoint-specific payload */ },
  "credits": { "charged": 1, "remaining": 499 },
  "timing":  { "totalMs": 850 },
  "requestId": "1dc70a3a-91a7-4884-8a83-8168255b6082"
}

On error, the shape is structured for easy switching:

{
  "success": false,
  "status":  "BAD_REQUEST",                // machine-switchable enum
  "error": {
    "message": "Validation failed",        // human-readable description
    /* status-specific extras (only the relevant block appears): */
    "errors":   [...],                     // 400 only
    "credits":  {...},                     // 402 only
    "rateLimit": {...},                    // 429 only
    "upstream":  {...},                    // 502 / 504 only
    "resource":  "channel",                // 404 only
    "id":        "UCxxx"                   // 404 only
  },
  "requestId": "..."
}
  • data contains the endpoint-specific payload (documented per endpoint below).
  • credits.charged is the cost of this call; credits.remaining is your account balance afterwards.
  • requestId is a UUID assigned per request — include it when reporting issues.
  • status on errors is a machine-switchable enum string — use it instead of parsing error.message.
  • error.<extras> blocks (e.g. credits, rateLimit, upstream) appear only on relevant status codes.

Status codes

HTTPstatus enumMeaningExtras
200OKSuccess
400BAD_REQUESTMissing or invalid request field.errors: [{ code, message, path }]
401UNAUTHORIZEDMissing or invalid API key.
402INSUFFICIENT_CREDITSNot enough credits to charge this request.credits: { required, available }
403FORBIDDENYour plan does not include API access.
404NOT_FOUNDChannel or video could not be found.resource: "channel" \| "video", id
429RATE_LIMIT_EXCEEDEDPer-key request quota exceeded.rateLimit: { limit, current, remaining, resetTime }
500INTERNAL_ERRORUnexpected error on our side. Include requestId when reporting.
502UPSTREAM_ERRORAn upstream provider returned a non-success status.upstream: { status }
504UPSTREAM_TIMEOUTAn upstream provider request timed out.upstream: { timeoutMs }

Error envelope examples

Switch tabs to see the exact response body for each error status. The HTTP status is in the header; the status enum mirrors it.

{
  "success": false,
  "status":  "BAD_REQUEST",
  "error": {
    "message": "Validation failed",
    "errors":  [{ "code": "required", "message": "query is required", "path": ["query"] }]
  },
  "requestId": "..."
}
POST /api/v1/outliers/refresh
Live 5 credits

Deep Outlier Search

Use this when you need MORE results — or NEWER results — than the regular Outlier Search. It fetches fresh videos live from YouTube, ranks them by outlier score, and returns them immediately in the same shape as Outlier Search (note: `similarity` is null — the live path does not run semantic search), plus a `refresh` summary. The fetched outliers are also saved to the index in the background, so they become similarity-searchable via Outlier Search on later calls. Pricier than search because it queries YouTube live. PRO plan or higher.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
query requiredstringSearch text to refresh (max 8000 chars).
example: "rural blacksmithing forge"
maxPages integer3Pages of live YouTube results to pull per duration. Higher = more thorough but slower.
range: 1–5
limit integer20Max results to return from the refreshed set.
range: 1–100
offset integer0Pagination offset.
minOutlierScore number1Filter out videos below this outlier score.

Response — data shape

FieldTypeDescription
searchTextstringEcho of trimmed query.
totalFoundintegerCount of results returned.
hasMorebooleanTrue if more results may exist past offset+limit.
resultsVideo[]Freshly-fetched outliers, ranked by outlier score. `similarity` is null on this endpoint.
refreshobjectLive-refresh summary: liveVideosFetched, returned, backgroundSave, truncated, fetchOk, durationMs.
cURL POST /api/v1/outliers/refresh
curl -X POST 'https://outlierkit.com/api/v1/outliers/refresh' \
  -H 'Authorization: Bearer <your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"query":"rural blacksmithing forge","maxPages":3}'
Sample request body
{
  "query": "rural blacksmithing forge",
  "maxPages": 3
}
Sample response (data only)
{
  "searchText": "rural blacksmithing forge",
  "sortBy": "outlierScore",
  "minOutlierScore": 1,
  "totalFound": 20,
  "hasMore": true,
  "source": "live-refresh",
  "results": [
    {
      "id": null,
      "videoId": "dQw4w9WgXcQ",
      "title": "Forging a Sickle Knife from Raw Iron — Start to Finish",
      "description": "Traditional blacksmithing, start to finish.",
      "views": 184000,
      "videoLength": "14:21",
      "publishedDate": "2026-05-22T00:00:00.000Z",
      "thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
      "similarity": null,
      "outlierMetrics": {
        "outlierMultiplier": 4.2,
        "channelOutlierRatio": 1.8,
        "viewsVsChannelAvg": 4.2,
        "viewsVsRecentAverage": 0,
        "highestValue": 4.2
      },
      "channel": {
        "id": null,
        "channelId": "UCFlCMxIIRQLOl3D1_qMVyJQ",
        "title": "Blacksmithing Skills",
        "username": "@blacksmithingskills",
        "subscribers": 17200,
        "thumbnail": "https://yt3.googleusercontent.com/..."
      }
    }
  ],
  "refresh": {
    "liveVideosFetched": 46,
    "returned": 20,
    "backgroundSave": true,
    "truncated": true,
    "fetchOk": true,
    "durationMs": 4200
  }
}
POST /api/v1/channels/similar
Cached 1 credit

Channel similarity

Given a seed channelId, return the most semantically similar channels from our index. Pass `sizeSimilarity: true` to additionally sort results by size proximity (subscribers / avgViewsPerVideo) — useful when you want channels in the same operational weight class as the seed.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
channelId requiredstringInternal channel id.
example: "outlier_gohvvqenpimmfsuzmlo"
limit integer20
range: 1–100
threshold number0.3Minimum semantic similarity. Acts as a gate when `sizeSimilarity` is true.
range: 0–1
includeVideos booleantrueInclude the top outlier videos per similar channel.
videosPerChannel integer5
range: 1–50
minOutlierScore number0
sizeSimilarity booleanfalseWhen true, sort results by size proximity to the seed (subscribers, with avgViewsPerVideo fallback). Semantic `threshold` still gates the candidate pool. Each result gains a `sizeScore` in [0,1] (1.0 = same size, 0.5 = 10× apart, 0 = ≥100× apart).

Response — data shape

FieldTypeDescription
seedobjectThe seed channel summary: id, channelId, title, gist, subscribers, avgViewsPerVideo.
sizeSimilaritybooleanEchoes the request param.
sizeReferencestring|nullWhich size metric drove the rerank: `"subscribers"`, `"avgViewsPerVideo"`, or `null` if the rerank was skipped because the seed had no size signal.
sizeRerankAppliedbooleanTrue if the rerank actually ran. False when `sizeSimilarity` was false or the seed had no usable size metric.
totalFoundinteger
resultsChannel[]Similar channels (excludes seed). Shape matches channels.search results. When `sizeRerankApplied: true`, each result carries an additional `sizeScore` field in [0,1].
cURL POST /api/v1/channels/similar
curl -X POST 'https://outlierkit.com/api/v1/channels/similar' \
  -H 'Authorization: Bearer <your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"channelId":"outlier_gohvvqenpimmfsuzmlo","limit":5,"threshold":0.3,"videosPerChannel":3,"sizeSimilarity":true}'
Sample request body
{
  "channelId": "outlier_gohvvqenpimmfsuzmlo",
  "limit": 5,
  "threshold": 0.3,
  "videosPerChannel": 3,
  "sizeSimilarity": true
}
Sample response (data only)
{
  "seed": {
    "id": "outlier_gohvvqenpimmfsuzmlo",
    "channelId": "UCN-AyQlzb8UBsn937PbAlYw",
    "title": "QuizWheels",
    "gist": "Car knowledge and brand recognition …",
    "subscribers": 24300,
    "avgViewsPerVideo": 48950
  },
  "sizeSimilarity": true,
  "sizeReference": "subscribers",
  "sizeRerankApplied": true,
  "totalFound": 5,
  "results": [
    {
      "id": "outlier_ywvtexjqivmg1st1s4",
      "channelId": "UCNEsxQWYdMAby1Ubu1aOA0g",
      "title": "Classic Car Quiz",
      "similarity": 0.804,
      "sizeScore": 0.887,
      "subscribers": 40900,
      "gist": "Interactive visual quizzes testing vintage automobile knowledge …"
    }
  ]
}
GET /api/v1/channels/:channelId
Cached 1 credit

Channel lookup

Fetch a single channel by internal id or YouTube channelId. Returns cached data when fresh; otherwise fetches live from YouTube and refreshes the cache. The `source` field indicates whether the response was served from cache, refreshed, or fetched for the first time.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
:channelId requiredstringURL path parameter — internal id or YouTube id.
example: outlier_gohvvqenpimmfsuzmlo or UCN-AyQlzb8UBsn937PbAlYw

Response — data shape

FieldTypeDescription
idstringInternal stable id.
channelIdstringYouTube channel id (UCxxxx).
title, username, description, countrystring|null
subscribers, totalViews, totalVideosinteger|null
thumbnail, publishedAtstring|null
avgViewsPerVideo, recentAvgViews, recentVideoCountnumber|null
recentVideosDatestring|nullWhen the recentVideos preview was last refreshed.
recentVideosobject[]Up to 5 recent videos — preview only. Use /channels/:id/videos for the live list.
channelGist, aiEnhancedDescriptionstring|nullAI-generated summary fields. May be absent for channels we haven't indexed before.
channelKeywords, contentFormats, contentTagsstring[]
focusClassification, channelType, audienceAge, contentOriginality, region, contentLanguagestring|null
channelLinksobject{ apiLinks, descriptionUrls, emails, hasEmail }
growthStatsobject|nullWeekly growth metrics (when available).
channelStatusstring"ACTIVE" | "TERMINATED" | "NOT_FOUND"
dataRefreshedAtstringISO timestamp — when we last refreshed this channel from YouTube.
sourcestring`db-fresh` = returned from cache (within 60 days). `live-refresh` = cache was stale, refreshed from YouTube. `live-new` = first-time lookup for this channel.
cacheAgeDaysnumber|nullAge of the cached data when this response was assembled. `null` when freshly fetched.
cURL GET /api/v1/channels/:channelId
curl -X GET 'https://outlierkit.com/api/v1/channels/outlier_gohvvqenpimmfsuzmlo' \
  -H 'Authorization: Bearer <your_api_key>'
Sample response (data only)
{
  "id": "outlier_gohvvqenpimmfsuzmlo",
  "channelId": "UCN-AyQlzb8UBsn937PbAlYw",
  "title": "QuizWheels",
  "username": "@QuizWheels",
  "subscribers": 24300,
  "totalViews": 8544900,
  "totalVideos": 152,
  "country": "Georgia",
  "avgViewsPerVideo": 48950,
  "recentAvgViews": 55552,
  "recentVideoCount": 30,
  "channelGist": "Car knowledge and brand recognition …",
  "focusClassification": "specialist:cars-automotive",
  "channelKeywords": [
    "car quiz",
    "guess the car",
    "car brand"
  ],
  "region": "global",
  "channelStatus": "ACTIVE",
  "dataRefreshedAt": "2026-05-13T16:48:40.481Z",
  "source": "db-fresh",
  "cacheAgeDays": 0.01
}
GET /api/v1/videos/:videoId
Cached 1 credit

Video lookup

Fetch a single video by internal id or YouTube videoId. Returns cached data when fresh; otherwise fetches live from YouTube and refreshes the cache. For newly-discovered videos, outlier scoring is computed in the background and will be available on subsequent requests.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
:videoId requiredstringURL path parameter — internal id or YouTube videoId.
example: outlier_defnsqypf1vmmq9fy0l or nSM1m7Q8gkg

Response — data shape

FieldTypeDescription
id, videoId, title, description, thumbnailUrlstring|null
viewsinteger
videoLength, publishedTime, publishedDate, uploadDatestring|null
keywords, categorystring[] / string|null
isPrivate, isUnlisted, hasCaptionboolean|null
outlierMetricsobjectNested: { outlierMultiplier, channelOutlierRatio, viewsVsChannelAvg, viewsVsRecentAverage, highestValue }. Matches search result shape. May be all-null for first-time lookups (scoring runs in the background).
channelobjectChannel summary: { id, channelId, title, username, subscribers, thumbnail, avgViewsPerVideo, region, channelType }.
dataRefreshedAtstring
sourcestring`db-fresh` = returned from cache. `live-refresh` = cache was stale, refreshed from YouTube. `live-new` = first-time lookup.
cacheAgeDaysnumber|null
cURL GET /api/v1/videos/:videoId
curl -X GET 'https://outlierkit.com/api/v1/videos/outlier_defnsqypf1vmmq9fy0l' \
  -H 'Authorization: Bearer <your_api_key>'
Sample response (data only)
{
  "id": "outlier_defnsqypf1vmmq9fy0l",
  "videoId": "nSM1m7Q8gkg",
  "title": "Cars 2 REAL LIFE Cars & Racing Series",
  "description": "Cars 2 REAL LIFE Cars & Racing Series",
  "views": 352900,
  "videoLength": "2:02",
  "publishedDate": "2025-05-14T11:46:19.881Z",
  "keywords": [],
  "outlierMetrics": {
    "outlierMultiplier": 1.43,
    "channelOutlierRatio": 2.17,
    "viewsVsChannelAvg": 0.3,
    "viewsVsRecentAverage": 1.43,
    "highestValue": 2.17
  },
  "channel": {
    "id": "outlier_k6pylhdz34immpzfc3a",
    "channelId": "UC1sh9NMD-5VNE72d1UG87lg",
    "title": "MILOO CARS",
    "username": "@miloocars",
    "subscribers": 167000,
    "avgViewsPerVideo": 1167494,
    "region": "global",
    "channelType": "creator"
  },
  "dataRefreshedAt": "2026-04-03T16:11:40.737Z",
  "source": "db-fresh",
  "cacheAgeDays": 40.03
}
GET /api/v1/channels/:channelId/videos
Live 1 credit

Channel videos

Recent videos uploaded by a channel. Always fetched live from YouTube to ensure freshness.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
:channelId requiredstringURL path parameter — internal id or YouTube channelId.
example: UCTwECeGqMZee77BjdoYtI2Q
limit integer30Query param — max videos to return.
range: 1–100

Response — data shape

FieldTypeDescription
channelobjectSummary of the channel (channelId, title, description, subscribers, totalVideos, thumbnail, username, keywords).
videosVideo[]Light video objects (videoId, title, description, views, publishedTime, thumbnailUrl, videoLength).
nextPageTokenstring|nullOpaque pagination token. Reserved — pagination via `?pageToken=` not yet exposed in v1.
totalReturnedinteger
source"live"
cURL GET /api/v1/channels/:channelId/videos
curl -X GET 'https://outlierkit.com/api/v1/channels/UCTwECeGqMZee77BjdoYtI2Q/videos?limit=10' \
  -H 'Authorization: Bearer <your_api_key>'
Sample response (data only)
{
  "channel": {
    "channelId": "UCTwECeGqMZee77BjdoYtI2Q",
    "title": "Creative Commons",
    "subscribers": 8820,
    "totalVideos": 258
  },
  "videos": [
    {
      "videoId": "abc123",
      "title": "Welcome to Creative Commons",
      "views": 12345,
      "publishedTime": "2 months ago",
      "videoLength": "5:12",
      "thumbnailUrl": "https://i.ytimg.com/…"
    }
  ],
  "totalReturned": 1,
  "nextPageToken": "4qmFsgLZCRIYVUNUd0VDZUdxTVplZTc3Qmpkb1l0SVE…",
  "source": "live"
}
GET /api/v1/videos/:videoId/transcript
Cached 1 credit

Video transcript

Fetch a video transcript. Cached on first fetch (transcripts don't change), so repeat requests are fast.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
:videoId requiredstring
example: _AbFXuGDRTs

Response — data shape

FieldTypeDescription
videoIdstring
segmentsSegment[]Array of { startMs, endMs, startTime, text }.
fullTextstringConcatenated transcript text.
totalDurationMsinteger|null
source"db-fresh" | "live"
cURL GET /api/v1/videos/:videoId/transcript
curl -X GET 'https://outlierkit.com/api/v1/videos/_AbFXuGDRTs/transcript' \
  -H 'Authorization: Bearer <your_api_key>'
Sample response (data only)
{
  "videoId": "_AbFXuGDRTs",
  "segments": [
    {
      "startMs": 80,
      "endMs": 5759,
      "startTime": "0:00",
      "text": "Hidden in this mountain is a $1 billion"
    },
    {
      "startMs": 3200,
      "endMs": 8000,
      "startTime": "0:03",
      "text": "nuclear bunker. We are 2,000 ft"
    }
  ],
  "fullText": "Hidden in this mountain is a $1 billion nuclear bunker. …",
  "totalDurationMs": 673440,
  "source": "live"
}
GET /api/v1/videos/:videoId/comments
Live 1 credit

Video comments

Comments for a video. Always fetched live from YouTube — not cached.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
:videoId requiredstring
sort enum"top"Query param.
values: "top" | "newest"
limit integer30
range: 1–100

Response — data shape

FieldTypeDescription
commentsComment[]Array of { commentId, author, authorChannelId, text, likes, replies, publishedTime, publishedAt, isChannelOwner, isVerified, isCreator }.
totalCountinteger|nullTotal comments on the video (yt-api commentsCount). May be > returned.
returnedintegerHow many comments this response actually contains.
nextPageTokenstring|nullOpaque pagination token. Reserved — pagination via `?pageToken=` not yet exposed in v1.
sortstring
limitinteger
source"live"
cURL GET /api/v1/videos/:videoId/comments
curl -X GET 'https://outlierkit.com/api/v1/videos/nSM1m7Q8gkg/comments?sort=top&limit=20' \
  -H 'Authorization: Bearer <your_api_key>'
Sample response (data only)
{
  "comments": [
    {
      "commentId": "UgxYZ…",
      "author": "@viewer",
      "authorChannelId": "UCxxxx",
      "text": "Great video!",
      "likes": 124,
      "replies": 3,
      "publishedTime": "2 days ago",
      "publishedAt": "2026-05-09T00:00:00Z",
      "isChannelOwner": false,
      "isVerified": false,
      "isCreator": false
    }
  ],
  "totalCount": 223,
  "returned": 1,
  "nextPageToken": "Eg0SC25TTTFtN1E4Z2tnGAYy…",
  "sort": "top",
  "limit": 20,
  "source": "live"
}
POST /api/v1/keywords/research
Live 1 credit

Keyword research

Expand seed keywords into a ranked list of related YouTube search keywords with monthly search volumes. Results are deduplicated and sorted by volume (highest first). Use `minVolume` and `limit` to filter further.

Authentication: Bearer token

Request parameters

FieldTypeDefaultDescription
keywords requiredstring[]Seed keywords to expand. Multiple seeds are merged and deduplicated.
example: ["fitness","home workout"]
minVolume integer0Drop keywords with monthly search volume below this floor.
limit integer100Max keywords returned.
range: 1–200

Response — data shape

FieldTypeDescription
mode"raw"Reserved field — currently always `"raw"`.
totalKeywordsFoundintegerTotal candidate keywords found across all seeds (before deduplication and filtering).
filteredKeywordsintegerCount after deduplication and `minVolume` filtering.
minVolumeintegerEcho of the floor applied.
limitinteger
keywordsobject[]Each row: { keyword, volume, competition }. Sorted by volume (highest first).
timestampstring
cURL POST /api/v1/keywords/research
curl -X POST 'https://outlierkit.com/api/v1/keywords/research' \
  -H 'Authorization: Bearer <your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"keywords":["fitness"],"minVolume":5000,"limit":25}'
Sample request body
{
  "keywords": [
    "fitness"
  ],
  "minVolume": 5000,
  "limit": 25
}
Sample response (data only)
{
  "mode": "raw",
  "totalKeywordsFound": 240,
  "filteredKeywords": 38,
  "minVolume": 5000,
  "limit": 25,
  "keywords": [
    {
      "keyword": "fitness motivation",
      "volume": 110000,
      "competition": "medium"
    },
    {
      "keyword": "home workout no equipment",
      "volume": 90500,
      "competition": "medium"
    },
    {
      "keyword": "30 day fitness challenge",
      "volume": 49500,
      "competition": "low"
    }
  ],
  "timestamp": "2026-05-13T13:00:00.000Z"
}

Shared object shapes

Field definitions for objects referenced from multiple endpoints.

Video (in search results)

{
  id: string                       // internal stable id
  videoId: string                  // YouTube video id
  title: string
  description: string|null         // truncated to 500 chars
  views: integer
  videoLength: string|null         // "10:45"
  publishedTime: string|null       // "2 days ago"
  publishedDate: string|null       // ISO timestamp
  thumbnailUrl: string|null
  similarity: number               // semantic similarity 0–1 (null for non-similarity sorts)
  outlierMetrics: {
    outlierMultiplier:    number   // composite outlier score
    channelOutlierRatio:  number   // ratio to channel's mean
    viewsVsChannelAvg:    number
    viewsVsRecentAverage: number
    highestValue:         number   // highest of the four metrics above
  }
  channel: { id, channelId, title, username, subscribers, thumbnail }
}

Channel (in search results)

{
  id: string
  channelId: string
  title: string
  subscribers: integer
  thumbnail: string|null
  gist: string|null                // channelGist
  focus: string|null               // focusClassification
  keywords: string[]               // channelKeywords
  channelType: string|null         // "creator" | "brand" | "media" | "clip-channel"
  audienceAge: string|null
  contentOriginality: string|null
  region: string|null
  avgViewsPerVideo: number|null
  similarity: number               // semantic similarity 0–1
  videoCount: integer              // total outlier videos for this channel
  videos: Video[]                  // top N outlier videos (preview shape)
}

v1 — endpoints documented above are stable. Reach out if you need additional capabilities.