# Virlo API v1 — Complete Reference > Social media intelligence API for TikTok, YouTube Shorts, and Instagram Reels. Track viral content, hashtags, trends, and creators with real-time analytics across 21K+ creators daily. This document contains the complete Virlo API reference optimized for LLM and AI agent consumption. It includes every endpoint specification, response schema, async workflow guidance, credit costs, and recommended usage patterns. --- ## Authentication All requests require a Bearer token in the Authorization header. ``` Authorization: Bearer virlo_tkn_ ``` Get your API key at https://dev.virlo.ai/dashboard. Keys start with `virlo_tkn_`. Keep keys secret — never expose them client-side or commit them to version control. SDKs handle auth automatically. ## Base URL ``` https://api.virlo.ai/v1 ``` Parameter names and most response fields use snake_case. Exception: Satellite creator lookup / run re-read videos use `publishDate` (camelCase) while Orbit/Comet videos use `publish_date`. `author_id` on digest videos may be null when the author row is not linked. Sound `cover_url` may be a relative storage path or full CDN URL. All responses are wrapped in a `{ "data": { ... } }` envelope. GET /v1/orbit/:orbit_id returns full inline videos/slideshows/ads when complete (can be hundreds of KB). For lightweight status polling, read only status/finalized/pending_jobs/counts — or use MCP get_keyword_search_results with data_type=status, which strips inline arrays. ## Pagination Offset-based pagination via `limit` (1-100, default 50) and `page` (1-indexed, default 1). Response includes `total`, `limit`, `offset` fields. ## Rate Limits Rate limits are per API key, tracked by sliding time windows. Response headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`. On 429, check `Retry-After` header. Default limits: - Global: 10,000 requests/day (applies to all endpoints without specific rules) - Satellite creator lookup: 5/min, 100/hour, 1,000/day - Satellite sound lookup: 5/min, 100/hour, 1,000/day - Satellite video outlier: 5/min, 100/hour, 1,000/day - Video digest, trends, hashtags: 50/min, 500/hour, 5,000/day - Tracking endpoints (posts, cadence, collection): global limit only (10,000/day) - Status polling endpoints: global limit only (10,000/day) Tip: Use batch endpoints (POST /v1/satellite/creators/batch) to process up to 25 creators in 1 request. Contact info@virlo.ai for custom rate limits. ## Error Format Errors return: `{ "statusCode": number, "message": string, "error": string }` - 400: Invalid parameters - 401: Missing or invalid API key - 402: Insufficient balance (add funds at https://dev.virlo.ai/dashboard/billing) - 404: Resource not found - 429: Rate limit exceeded - 500: Server error (retry with backoff) ## Billing Pay-as-you-go prepaid balance. Add funds (minimum $10), use the API, auto top-up keeps you running. No subscriptions. Balance never expires. Response headers on every request: - `X-Credits-Used`: Internal credits consumed (1 credit = $0.01) - `X-Credits-Remaining`: Internal credits remaining - `X-Cost`: Dollar cost of this request (e.g. "0.25") - `X-Balance-Remaining`: Dollar balance remaining (e.g. "47.50") ### Pricing Per Endpoint **Free ($0.00):** - GET /v1/orbit/:orbit_id — poll Orbit search status/results - GET /v1/orbit/:orbit_id/videos — retrieve Orbit videos - GET /v1/orbit/:orbit_id/slideshows — retrieve Orbit slideshows (image carousels) - GET /v1/orbit/:orbit_id/ads — retrieve Orbit Meta ads - GET /v1/orbit/:orbit_id/creators/outliers — retrieve Orbit creator outliers - GET /v1/orbit/:orbit_id/analysis/latest — retrieve latest AI analysis - GET /v1/orbit/:orbit_id/analysis — list AI analysis history - GET /v1/orbit/:orbit_id/trends/latest — retrieve latest AI-detected trends - GET /v1/orbit/:orbit_id/trends — list trends history - GET /v1/orbit — list all Orbit searches - GET /v1/comet/:id — get Comet configuration - GET /v1/comet/:id/videos — retrieve Comet videos - GET /v1/comet/:id/slideshows — retrieve Comet slideshows - GET /v1/comet/:id/ads — retrieve Comet Meta ads - GET /v1/comet/:id/creators/outliers — retrieve Comet creator outliers - GET /v1/comet/:id/analysis/latest — retrieve latest Comet AI analysis - GET /v1/comet/:id/analysis — list Comet analysis history - GET /v1/comet/:id/trends/latest — retrieve latest Comet AI trends - GET /v1/comet/:id/trends — list Comet trends history - GET /v1/satellite/creator/status/:job_id — poll Satellite status - GET /v1/satellite/creators/batch/:batch_id — poll batch lookup status - GET /v1/satellite/video-outlier/status/:job_id — poll Video Outlier status - GET /v1/satellite/sounds/status/:job_id — poll sound lookup status - GET /v1/satellite/runs/:run_id — re-read any past satellite run (creator, sound, video, batch) - GET /v1/satellite/runs — list every satellite run owned by your team - GET /v1/satellite/runs/:run_id/videos — paginated videos sub-resource for any past run - GET /v1/account/balance — check credit balance and pricing - GET /v1/orbit/:orbit_id/sounds — top sounds in a keyword search - GET /v1/comet/:id/sounds — top sounds in a niche monitor **$0.25 (tracking):** - POST /v1/tracking/creators — start tracking a creator - POST /v1/tracking/videos — start tracking a video **$0.50 – $2.00 (post collection, varies by depth):** - POST /v1/tracking/creators/:id/posts/collect — trigger deep post collection. Depth tiers: standard (50 videos, $0.50), deep (200 videos, $1.00), full (500 videos, $2.00) **Free (tracking retrieval):** - GET /v1/tracking/creators — list tracked creators - GET /v1/tracking/creators/:id — get tracked creator details (includes AI category slug + content_tags) - GET /v1/tracking/creators/:id/report — get latest creator AI report (auto-generated each cycle) - GET /v1/tracking/creators/:id/snapshots — get creator metric snapshots (supports start_date, end_date, limit) - GET /v1/tracking/creators/:id/posts — list creator's collected posts with is_duet/is_stitch TikTok flags - GET /v1/tracking/creators/:id/posts/:post_id — get single post detail - GET /v1/tracking/creators/:id/posts/collect/:collection_id — poll collection job status - GET /v1/tracking/creators/:id/posting-cadence — get posting frequency analytics - PATCH /v1/tracking/creators/:id — update creator tracking settings - DELETE /v1/tracking/creators/:id — stop tracking creator - GET /v1/tracking/videos — list tracked videos - GET /v1/tracking/videos/:id — get tracked video details - GET /v1/tracking/videos/:id/report — get latest video AI report (auto-generated each cycle) - GET /v1/tracking/videos/:id/snapshots — get video metric snapshots (supports start_date, end_date, limit) - PATCH /v1/tracking/videos/:id — update video tracking settings - DELETE /v1/tracking/videos/:id — stop tracking video **$0.05:** - GET /v1/hashtags — cross-platform hashtag stats - GET /v1/hashtags/:hashtag/performance — detailed hashtag analytics - GET /v1/youtube/hashtags — YouTube-specific hashtag data - GET /v1/tiktok/hashtags — TikTok-specific hashtag data - GET /v1/instagram/hashtags — Instagram-specific hashtag data - GET /v1/sounds/:sound_id — sound details + aggregate stats - GET /v1/sounds/:sound_id/usage-history — daily usage snapshots with deltas **$0.10:** - GET /v1/sounds/search?q=... — fuzzy search sounds by title **$0.25:** - GET /v1/videos/digest — top videos from last 48 hours (all platforms) - GET /v1/youtube/videos/digest — YouTube videos digest - GET /v1/tiktok/videos/digest — TikTok videos digest - GET /v1/instagram/videos/digest — Instagram videos digest - GET /v1/trends — trend groups with rankings - GET /v1/trends/digest — today's trends digest - GET /v1/sounds/trending — sounds currently trending (default sort videos_7d) - GET /v1/sounds/breakout — sounds with high recent-burst ratio (rapidly rising from a small baseline) - GET /v1/sounds/:sound_id/videos — videos using a specific sound - GET /v1/sounds/by-creator/:platform/:handle — creator's sounds with UGC metrics **$0.50:** - POST /v1/orbit — queue keyword search (most valuable: includes AI analysis) - POST /v1/comet — create automated niche monitoring - GET /v1/satellite/creator/:platform/:username — start creator lookup (profile includes AI category slug + content_tags, videos include is_duet/is_stitch flags; +$0.50 with trend_analysis=true to also run LLM trend detection over the creator's body of work) - POST /v1/satellite/creators/batch — batch creator lookup (up to 25 handles, per-handle pricing) - POST /v1/satellite/video-outlier — start video outlier analysis - GET /v1/satellite/sounds/:platform/:music_id — start sound lookup (TikTok only; $0.50 base, +$0.50 with trend_analysis=true) **+$1.00 add-on (Data Intelligence):** - POST /v1/orbit with data_intelligence_enabled: true — adds 40+ AI fields per video ($1.50 total). Add intent for intent-based filtering with intent_match per video and intent_summary - POST /v1/comet with data_intelligence_enabled: true — adds 40+ AI fields per video ($1.50 total). Add intent for intent-based filtering with intent_match per video and intent_summary ### Funding - Add funds at https://dev.virlo.ai/dashboard/billing (minimum $10.00) - Balance never expires. Auto top-up enabled by default. - When balance runs out: API returns 402, auto top-up triggers if enabled. --- ## Async Workflow State Machines Several Virlo endpoints use asynchronous processing. You queue a job, then poll for results. CRITICAL FOR AI AGENTS: Response times vary significantly based on keyword count, whether meta_ads is enabled, and current server load. NEVER set hard timeouts. ALWAYS continue polling until you receive a terminal status. The canonical "done" signal is `finalized: true` (see the Async Data Model guide at https://dev.virlo.ai/docs/async-data) — `status: completed` alone means the main scrape is done but secondary AI jobs may still be running. ### Orbit (Keyword Search) Lifecycle Status flow: queued → processing → completed | partial_failure | failed IMPORTANT: `partial_failure` is a USABLE terminal state, not an error. It means one platform or keyword failed but the rest of the data was collected (this happens on roughly 7% of runs). Retrieve and use the results exactly as you would for `completed`. Only `failed` (under 1% of runs) means no data. Typical execution times (measured in production, variable under load): - Median run: ~15-20 minutes end to end (including AI analysis) - Simple runs (1-3 keywords, single platform) can finish in a few minutes; broad runs with meta_ads can take 30-45 minutes - Plan for up to 45 minutes before telling the user a job is delayed; the job is almost certainly still running - AI analysis and trends are always generated automatically after job completion Recommended polling interval: every 60 seconds (or subscribe to the orbit.run.completed webhook instead) Workflow: POST /v1/orbit → save orbit_id → GET /v1/orbit/:orbit_id (repeat until finalized: true) → GET videos, slideshows, ads, outliers, analysis, trends, sounds ### Satellite (Creator Lookup) Lifecycle Status flow: processing → completed | failed Typical execution time: - Default lookup (max_videos=20): 20-60 seconds (can be longer under high traffic) - trend_analysis=true (100 videos + LLM): 60-120 seconds, can run longer under load Results in the poll cache expire after 24 hours. The durable satellite_run row never expires — re-read via GET /v1/satellite/runs/:run_id. Rate limits: 5/min, 100/hour, 1,000/day. Recommended polling interval: every 10-15 seconds. Polling is free. Workflow: GET /v1/satellite/creator/:platform/:username → save job_id → GET /v1/satellite/creator/status/:job_id (repeat until completed). Save the run_id from the completed payload for free re-reads later. ### Batch Creator Lookup Lifecycle Submit multiple creators at once. Each creator is processed as an independent lookup job. Workflow: POST /v1/satellite/creators/batch → save batch_id → GET /v1/satellite/creators/batch/:batch_id (repeat until all completed/failed) The batch poll returns aggregate counts (completed, failed, processing) and per-creator statuses. Individual creator results can also be polled via GET /v1/satellite/creator/status/:job_id. Recommended polling interval: every 15-30 seconds Batch results expire after 24 hours. ### Video Outlier Analysis Lifecycle Status flow: processing → completed | failed Typical execution time: 20-60 seconds (can be longer under high traffic) Results expire after 5 minutes. Rate limits: 5/min, 100/hour, 1,000/day. Recommended polling interval: every 10-15 seconds Workflow: POST /v1/satellite/video-outlier → save job_id → GET /v1/satellite/video-outlier/status/:job_id (repeat until completed) ### Sound Lookup Lifecycle (TikTok) Status flow: processing → completed | failed Typical execution time (measured in production): - Default (max_videos=50): 1-3 minutes - trend_analysis=true (~300 videos + LLM): ~8 minutes on average, plan for up to 20 minutes - Recommended polling interval: every 30 seconds for trend_analysis lookups Results in the status poll cache expire after 24 hours. The durable satellite_run row never expires — re-read via GET /v1/satellite/runs/:run_id. Recommended polling interval: every 10-15 seconds. Polling is free. Workflow: GET /v1/satellite/sounds/tiktok/:music_id → save job_id → GET /v1/satellite/sounds/status/:job_id (repeat until completed). Save the run_id from the completed payload for free re-reads later. --- ## Endpoint Reference ### GET /v1/hashtags Cross-platform hashtag statistics with date filtering. Cost: $0.05 Query parameters: - start_date (string, required): Start date YYYY-MM-DD. Max range 90 days. - end_date (string, required): End date YYYY-MM-DD. - limit (integer): Results per page, 1-100, default 50. - order_by (string): "count" or "views". Default "count". - sort (string): "asc" or "desc". Default "desc". Response schema: ```json { "data": [ { "hashtag": "#fyp", "count": 6124, "total_views": 7670661488 } ] } ``` ### GET /v1/hashtags/:hashtag/performance Detailed performance analytics for a specific hashtag. Cost: $0.05 Path parameters: - hashtag (string, required): The hashtag to look up (without # prefix). Query parameters: - start_date (string, optional): Start date YYYY-MM-DD. - end_date (string, optional): End date YYYY-MM-DD. Response schema: ```json { "data": { "hashtag": "fyp", "video_count": 434, "total_views": 1159398224, "avg_views": 2671424.48, "total_likes": 76534113, "avg_likes": 176345.88, "total_comments": 443567, "avg_comments": 1022.04 } } ``` ### GET /v1/trends Trend groups with ranked trends. Cost: $0.25 Query parameters: - start_date (string, optional): Default last 24h. - end_date (string, optional): Default now. - limit (integer): Results per page, default 50. Response schema: ```json { "data": [ { "id": "uuid", "title": "Trends for Mar 17th", "trends": [ { "id": "uuid", "trend_id": "uuid", "trend_group_id": "uuid", "ranking": 1, "trend": { "id": "uuid", "name": "Trend name — human readable title", "description": "Detailed description of the trend with context and creator activity.", "trend_type": "content" } } ] } ] } ``` ### GET /v1/trends/digest Today's trends digest (generated daily at 1am UTC in EST/EDT timezone context). Cost: $0.25 Query parameters: - limit (integer): Results per page, default 50. Response schema: Same as GET /v1/trends. ### GET /v1/videos/digest Top performing videos from the last 48 hours across all platforms. Cost: $0.25 Query parameters: - limit (integer): 1-100, default 50. Response schema: ```json { "data": [ { "id": "uuid", "url": "https://www.tiktok.com/@user/video/123", "publish_date": "2026-03-17T00:08:41", "views": 6665489, "number_of_likes": 229785, "number_of_comments": 8088, "description": "Full video description with hashtags and text...", "thumbnail_url": "https://auth.virlo.ai/storage/v1/object/public/thumbnails/uuid.jpg", "hashtags": ["donaldtrump", "funny"], "type": "tiktok", "niche": "unknown", "author_id": "uuid", "bookmarks": 22834, "external_id": "7618009747375017219", "region": "US", "duration": 30, "transcript_raw": "Full video transcript text if available, null otherwise" } ] } ``` Video data includes: URL, publish date, view/like/comment counts, full description, thumbnail, hashtags array, platform type (youtube/tiktok/instagram), niche classification, author reference, bookmarks count, platform-native ID, region code, duration in seconds, and raw transcript text when available. Transcript data is especially valuable for content analysis and keyword extraction. ### GET /v1/youtube/videos/digest, GET /v1/tiktok/videos/digest, GET /v1/instagram/videos/digest Platform-specific video digests. Same parameters and response schema as GET /v1/videos/digest, filtered to a single platform. Cost: $0.25 each. ### GET /v1/youtube/hashtags, GET /v1/tiktok/hashtags, GET /v1/instagram/hashtags Platform-specific hashtag statistics. Same parameters and response schema as GET /v1/hashtags, filtered to a single platform. Cost: $0.05 each. --- ### POST /v1/orbit — Queue Keyword Search Queues an asynchronous keyword-based video discovery job across YouTube, TikTok, and/or Instagram. Returns immediately with an orbit_id for polling. Cost: $0.50 Request body (JSON): - name (string, required): Descriptive name for this search. - keywords (string[], required): 1-10 keywords to search for. Use specific multi-word phrases for best results (e.g., "jeep wrangler mods" not "jeep"). - time_period (string, required): "today", "this_week", "this_month", "this_year". - platforms (string[]): ["youtube", "tiktok", "instagram"]. Defaults to all. - min_views (integer): Minimum view count threshold. Default 0. - enable_meta_ads (boolean): Collect Meta ads related to keywords. Default false. - data_intelligence_enabled (boolean): Enable Data Intelligence to get 40+ AI-analyzed fields per video. Adds $1.00 to total cost ($1.50 total). Default false. See "Data Intelligence" section for details. - run_analysis (boolean): DEPRECATED — analysis is now always generated for every Orbit at no extra cost. This parameter is accepted for backwards compatibility but has no effect. Use GET /v1/orbit/:orbit_id/analysis/latest and GET /v1/orbit/:orbit_id/trends/latest to retrieve AI insights. - exclude_keywords (string[]): Keywords to filter out from results. - exclude_keywords_strict (boolean): Also check video transcripts for exclusions. Default false. Response: ```json { "data": { "orbit_id": "d18109f3-e933-4c06-a4e6-9c0c05b276ac", "status": "queued", "message": "Keyword search job queued with max priority." } } ``` ### GET /v1/orbit — List Searches List all Orbit searches for this account. Paginated. Cost: Free Query parameters: limit, page. Response includes array of orbits with: id, name, keywords, platforms, status, totalVideos, createdAt, executionTimeMs. ### GET /v1/orbit/:orbit_id — Get Search Results (Poll) Poll for status and retrieve results when complete. When status is "processing", results is null. When "completed", results contains the full dataset. Cost: Free The response includes an "analysis" field with a short human-readable summary and "analysis_data" with the full structured object. For complete AI analysis and trends, use the dedicated sub-endpoints: GET /v1/orbit/:orbit_id/analysis/latest and GET /v1/orbit/:orbit_id/trends/latest. Response when completed: ```json { "data": { "id": "uuid", "status": "completed", "name": "Search name", "keywords": ["keyword1", "keyword2"], "analysis": "# Markdown intelligence report...\n\n## Top Trends\n\n...", "results": { "total_videos": 46, "youtube_count": 7, "tiktok_count": 37, "instagram_count": 2, "videos": [...], "ads": [...], "keyword_breakdown": [ { "keyword": "keyword1", "tiktokCount": 21, "youtubeCount": 4, "instagramCount": 0, "metaAdsCount": 0, "videosInserted": 25 } ], "execution_time_ms": 201128 }, "started_at": "2026-03-17T17:27:01.348745" } } ``` ### GET /v1/orbit/:orbit_id/videos — Get Paginated Videos Cost: Free Query parameters: limit, page, min_views, platforms (comma-separated), start_date, end_date, order_by (publish_date/views/created_at), sort, intent_match (boolean — filter by intent match when search used intent + data_intelligence_enabled). Each video includes: id, url, description, platform, views, likes, shares, comments, bookmarks, publish_date, author (username, verified, followers, avatar_url), hashtags, thumbnail_url, keyword_found_by, duration, region, is_duet (TikTok only, null for others), is_stitch (TikTok only, null for others). ### GET /v1/orbit/:orbit_id/slideshows — Get Slideshows (Image Carousels) Cost: Free Query parameters: limit, page, order_by, sort. Slideshows are TikTok image carousels discovered alongside videos. Each slideshow includes: url, description, platform, views, likes, shares, comments, bookmarks, publish_date, hashtags, thumbnail_url, images (array of { image_url, position }), author (username, verified, followers, avatar_url), keyword_found_by, is_eligible_for_commission, region. When the parent orbit was queued with data_intelligence_enabled=true, each slideshow also carries `intelligence_status` (ready | pending | disabled | failed | skipped) plus an `intelligence` payload. Slideshow intelligence uses a separate schema from video intelligence — it analyses per-panel text (panel_texts[], panel_text_full, panel_text_word_count, panel_text_character_count, image_count, narrative_arc, text_density) instead of a transcript, and drops video-only fields like visual_format, camera_perspective, scene_changed, transcript_*. See /docs/intelligence#slideshow-intelligence for the full schema. ### GET /v1/orbit/:orbit_id/ads — Get Meta Ads Cost: Free. Only returns results if enable_meta_ads was true when queuing. Each ad includes: id, ad_archive_id, page_id, page_profile_url, is_active, start_date, end_date, url (Facebook Ad Library link), caption, body, cta_type, page_like_count, title, video_url, keyword_found_by. ### GET /v1/orbit/:orbit_id/creators/outliers — Get Creator Outliers Cost: Free Creators significantly outperforming their follower count. Each outlier includes: creator_url, creator_avatar_url, follower_count, avg_views, outlier_ratio (views/followers), videos_analyzed, creator_topics, matching_topics, platform, identified_at, and videos array with full video data. ### GET /v1/orbit/:orbit_id/analysis/latest — Get Latest AI Analysis Cost: Free Returns the most recent AI-generated analysis for this Orbit search. Includes structured themes with confidence scores, viral tactics, timing analysis, and a human-readable overview. The analysis is automatically generated after job completion at no extra cost. Response schema: ```json { "data": { "id": "uuid", "insight_type": "orbit", "reference_id": "orbit_id", "batch_start": "ISO8601", "batch_end": "ISO8601", "analysis": "Short summary text", "analysis_data": { "themes": [ { "stable_key": "theme-slug", "name": "Theme Name", "why_it_works": "Explanation of why this content pattern resonates", "video_count": 48, "evidence_video_ids": ["vid-001", "vid-002"], "tactics": ["tactic1", "tactic2"], "confidence": 0.91 } ], "viral_tactics": ["tactic1", "tactic2"], "timing_analysis": { "peak_hours": [19, 21], "pattern": "evening spike" }, "overview": { "total_videos": 347, "platforms": { "tiktok": 310, "youtube": 37 } } } } } ``` ### GET /v1/orbit/:orbit_id/analysis — Get Analysis History Cost: Free. Paginated list of all AI analyses generated for this Orbit. Query parameters: page, limit. ### GET /v1/orbit/:orbit_id/trends/latest — Get Latest AI-Detected Trends Cost: Free Returns the most recent AI-detected trend themes for this Orbit search. Each theme includes view counts, video counts, tactics, and confidence scores. Response schema: ```json { "data": { "orbit_id": "uuid", "orbit_name": "Search Name", "themes": [ { "stable_key": "theme-slug", "name": "Theme Name", "why_it_works": "Explanation", "video_count": 48, "total_views": 12500000, "avg_views": 260416, "evidence_video_ids": ["vid-001"], "tactics": ["tactic1"], "confidence": 0.91 } ], "aggregate_stats": { "total_themes": 3, "total_videos_across_themes": 112, "total_views_across_themes": 27600000 } } } ``` ### GET /v1/orbit/:orbit_id/trends — Get Trends History Cost: Free. Paginated list of trend snapshots. Query parameters: limit. --- ### POST /v1/comet — Create Custom Niche Creates an automated monitoring configuration that runs on a recurring cadence. Cost: $0.50 Request body (JSON): - name (string, required): Name for this niche monitor. - keywords (string[], required): 1-20 keywords to track. - platforms (string[], required): At least one of: ["youtube", "tiktok", "instagram"]. - cadence (string, required): "daily", "weekly", "monthly", or a valid cron expression that runs at most once per day. - min_views (integer, required): Minimum views threshold (0 or higher). - time_range (string, required): "today", "this_week", "this_month", "this_year". - is_active (boolean): Whether monitoring is active. Default true. - meta_ads_enabled (boolean): Track Meta ads. Default false. - data_intelligence_enabled (boolean): Enable Data Intelligence to get 40+ AI-analyzed fields per video. Adds $1.00 to total cost ($1.50 total). Default false. See "Data Intelligence" section for details. - exclude_keywords (string[]): Keywords to exclude. - exclude_keywords_strict (boolean): Check transcripts for exclusions. ### GET /v1/comet — List Configurations Cost: Free. Returns all Comet configs with: id, name, keywords, platforms, cadence, min_views, time_range, is_active, meta_ads_enabled, last_run_at, next_run_at. ### GET /v1/comet/:id — Get Configuration Cost: Free. ### PUT /v1/comet/:id — Update Configuration Update any field. Same body as POST. ### DELETE /v1/comet/:id — Delete Configuration Soft delete. Returns 204. ### GET /v1/comet/:id/videos — Get Comet Videos Cost: Free. Same video schema as Orbit videos (includes is_duet/is_stitch for TikTok). Paginated. Supports intent_match query parameter for intent-based filtering. ### GET /v1/comet/:id/slideshows — Get Comet Slideshows Cost: Free. Same slideshow schema as Orbit slideshows (including the same per-slideshow `intelligence_status` + `intelligence` payload when the parent comet was created with data_intelligence_enabled=true). Paginated. ### GET /v1/comet/:id/ads — Get Comet Meta Ads Cost: Free. Same ad schema as Orbit ads. ### GET /v1/comet/:id/creators/outliers — Get Comet Creator Outliers Cost: Free. Same schema as Orbit creator outliers. ### GET /v1/comet/:id/analysis/latest — Get Latest Comet AI Analysis Cost: Free. Same schema as Orbit analysis. Auto-generated after each Comet run. ### GET /v1/comet/:id/analysis — Get Comet Analysis History Cost: Free. Paginated list of AI analyses for this Comet. Query parameters: page, limit. ### GET /v1/comet/:id/trends/latest — Get Latest Comet AI Trends Cost: Free. Same schema as Orbit trends. Auto-generated after each Comet run. ### GET /v1/comet/:id/trends — Get Comet Trends History Cost: Free. Paginated list of trend snapshots. Query parameters: limit. --- ### GET /v1/satellite/creator/:platform/:username — Start Creator Lookup Initiates an asynchronous creator profile analysis. Cost: $0.50 base. `trend_analysis=true` adds a $0.50 surcharge ($1.00 total) and forces a deep fetch (`max_videos` floored to 100), implicitly returning the `videos[]` payload. The audience surcharge ($0.50, cache-aware) can stack on top — all three optional surcharges (audience demographics, audience geography, trend analysis) ride on a single call. Rate limits: 5/min, 100/hour, 1,000/day. Path parameters: - platform (string, required): "tiktok", "youtube", or "instagram". - username (string, required): Creator's username on the platform. Query parameters: - include (string): Comma-separated. Options: "videos", "outliers". Include both for maximum insight. Implicitly forced to include "videos" when trend_analysis=true. - cross_links (boolean): Enable cross-platform link discovery. Finds the same creator on other platforms (YouTube, TikTok, Instagram, Twitter/X, Spotify). Default false. - max_videos (integer): 1-100, how many recent videos to analyze. Floored to 100 when trend_analysis=true. - outlier_threshold (number): Multiplier for outlier detection (default 2). - audience_demographics (boolean): Include engaged-audience age + gender + language distributions (derived from analyzing the creator's commenters, not the raw follower base; see `data_source` in the response). Adds $0.50 surcharge on cache miss (free on cache hits). Default false. - audience_geography (boolean): Include engaged-audience country + city distributions. Shares the $0.50 surcharge with audience_demographics. Default false. - freshness_days (integer, 0-365): Max age of an acceptable cached audience snapshot. Default 30. - trend_analysis (boolean): Run AI trend detection over this creator's body of work. Forces a deep fetch (100 videos), implicitly returns videos[], and adds $0.50 surcharge. Returns a `trends` block with summary + per-trend time_windows[], resurged, momentum, and evidence_video_ids that map back to videos[] in the same response. Persisted with the run — re-reading via GET /v1/satellite/runs/:run_id is free. Default false. Response: ```json { "data": { "job_id": "uuid", "status": "processing" } } ``` ### GET /v1/satellite/creator/status/:job_id — Poll Creator Lookup Cost: Free Response when completed: ```json { "data": { "status": "completed", "result": { "username": "creator_name", "platform": "tiktok", "profile": { "followers": 481648, "following": 0, "avatar_url": "url", "url": "https://www.tiktok.com/@creator_name", "description": "Bio text or null", "is_verified": null, "total_videos": 166, "total_likes": 6045845, "total_views": null, "total_posts": null, "category": "comedy", "bio_link": "https://linktr.ee/creator_name" }, "content_tags": ["silent-comedy", "life-hacks", "reaction"], "stats": { "videos_analyzed": 5, "avg_views": 1969309, "median_views": 341616, "avg_likes": 70773, "avg_comments": 2829, "engagement_rate": 0.04, "top_performing_views": 8375353, "lowest_performing_views": 49430, "posting_frequency_days": 0.8 }, "hashtags": [ { "hashtag": "usa", "total_views": 9846545, "avg_views": 1969309, "avg_likes": 70773, "avg_comments": 2829, "used_count": 5 } ], "videos": [ { "id": "video_id", "title": "Video title", "description": "Full description", "views": 8375353, "likes": 283565, "comments": 9868, "publishDate": "2026-03-17T00:08:41.000Z", "url": "https://www.tiktok.com/@user/video/id", "hashtags": ["tag1", "tag2"], "thumbnail_url": "url", "outlier_ratio": 24.52 } ], "outliers": { "threshold_multiplier": 2, "outlier_videos": [ { "id": "video_id", "views": 8375353, "outlier_ratio": 24.52 } ] }, "cross_links": { "discovered": [ { "platform": "youtube", "username": "creator_yt", "url": "https://www.youtube.com/@creator_yt", "source": "linktree" }, { "platform": "instagram", "username": "creator_ig", "url": "https://www.instagram.com/creator_ig", "source": "bio_text" }, { "platform": "spotify", "username": "Creator Name", "url": "https://open.spotify.com/artist/abc123", "source": "spotify_api" } ], "bio_link_url": "https://linktr.ee/creator_name", "sources_checked": ["structured_fields", "bio_text", "linktree", "spotify_api", "ai_search"] }, "trends": { "analyzed": true, "summary": "Brief read of the creator's overall playbook (only present when trend_analysis=true).", "status": "ok", "model_used": "google/gemini-2.5-flash", "cost_usd": 0.0123, "tokens_used": 18234, "trends": [ { "name": "Short trend label (format/hook/era/pillar)", "description": "1-2 sentence explanation of the pattern.", "tactics": ["concrete tactic 1", "concrete tactic 2"], "confidence": 0.85, "video_count": 6, "evidence_video_ids": ["video_id_1", "video_id_2"], "time_windows": [ { "start_date": "2025-08-12", "end_date": "2025-11-04", "video_count": 3, "total_views": 12400000, "total_likes": 410000, "total_comments": 28000, "total_shares": 4100, "avg_views": 4133333, "description": "Original wave" }, { "start_date": "2026-02-09", "end_date": "2026-04-21", "video_count": 3, "total_views": 19800000, "total_likes": 620000, "total_comments": 41000, "total_shares": 7200, "avg_views": 6600000, "description": "Resurgence wave" } ], "resurged": true, "momentum": "stronger" } ] }, "run_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "credits_charged": 100 } } } ``` The `trends` block is only present when the request set `trend_analysis=true`. When the corpus has fewer than 10 videos, `trends.status` is `"insufficient_corpus"` and `trends.trends` is an empty array. `evidence_video_ids` always map back to entries in the same response's `videos[]` array — no second request needed. Time windows are computed mechanically from real publish dates after the LLM picks IDs, so date hallucination is impossible. `resurged: true` means the trend has ≥2 disjoint time_windows (the creator did something, dropped it, then came back). `momentum` compares the latest window's avg_views to the prior window (`stronger` | `weaker` | `similar`, ±15% deadband); `null` for single-window trends. Results expire after 24 hours from the poll cache, but the run is persisted indefinitely — re-read for free via GET /v1/satellite/runs/:run_id. ### POST /v1/satellite/creators/batch — Batch Creator Lookup Submit multiple creators for parallel lookup. Returns a batch_id and per-creator job_ids. Cost: $0.50 per creator. Rate limits: same as individual lookups. Request body (JSON): - creators (array, required): Array of { platform, username } objects. Max 25 per request. - include (string, optional): Comma-separated list of optional data to include ("videos", "outliers", or "videos,outliers"). - cross_links (boolean, optional): Enable cross-platform link discovery for each creator. Default false. - max_videos (integer, optional): Maximum videos to return per creator (default 30, max 100). - outlier_threshold (number, optional): Outlier sensitivity multiplier (default 2.0). Response (202 Accepted): ```json { "data": { "batch_id": "uuid", "status": "processing", "total": 3, "completed": 0, "failed": 0, "processing": 3, "creators": [ { "platform": "tiktok", "username": "creator1", "job_id": "uuid-1", "status": "processing" }, { "platform": "youtube", "username": "creator2", "job_id": "uuid-2", "status": "processing" }, { "platform": "instagram", "username": "creator3", "job_id": "uuid-3", "status": "processing" } ] } } ``` ### GET /v1/satellite/creators/batch/:batch_id — Poll Batch Status Poll the aggregate status of a batch. Returns current status of each creator's lookup job. Cost: Free Path parameters: - batch_id (string, required): The batch_id returned from the batch lookup endpoint. Response: ```json { "data": { "batch_id": "uuid", "status": "partial", "total": 3, "completed": 2, "failed": 0, "processing": 1, "creators": [ { "platform": "tiktok", "username": "creator1", "job_id": "uuid-1", "status": "completed" }, { "platform": "youtube", "username": "creator2", "job_id": "uuid-2", "status": "completed" }, { "platform": "instagram", "username": "creator3", "job_id": "uuid-3", "status": "processing" } ] } } ``` Batch status values: "processing" (all still running), "partial" (some completed/failed), "completed" (all done), "failed" (all failed). Individual creator results can be retrieved via GET /v1/satellite/creator/status/:job_id once their status is "completed". Batch results expire after 24 hours. ### POST /v1/satellite/video-outlier — Start Video Outlier Analysis Analyzes how a specific video performs relative to its creator's typical content. Cost: $0.50. Rate limits: 5/min, 100/hour, 1,000/day. Request body (JSON): - url (string, required): Full URL of the video. - platform (string, required): "tiktok", "youtube", or "instagram". Response: ```json { "data": { "job_id": "uuid", "status": "processing" } } ``` ### GET /v1/satellite/video-outlier/status/:job_id — Poll Video Outlier Cost: Free Response when completed: ```json { "data": { "status": "completed", "result": { "video": { "url": "video_url", "title": "Video title", "views": 8375590, "likes": 283578, "comments": 9871, "publishDate": "2026-03-17T00:08:41.000Z" }, "creator": { "username": "creator_name", "platform": "tiktok", "profile": { "followers": 481652, "total_videos": 166, "total_likes": 6045870 } }, "analysis": { "videos_analyzed": 98, "median_views": 416241, "avg_views": 938324, "outlier_score": 20.12, "percentile": 98.98, "std_deviation": 1389310, "z_score": 5.35, "performance_label": "mega_viral" } } } } ``` Performance labels: "viral", "above_average", "average", "below_average", "mega_viral". Results expire after 5 minutes. ### GET /v1/satellite/sounds/:platform/:music_id — Start Sound Lookup (TikTok) Initiates an asynchronous sound lookup. Fetches every video using a specific TikTok sound, computes aggregate stats, and (optionally) runs LLM-based trend detection. Cost: $0.50 base. `trend_analysis=true` adds a $0.50 surcharge ($1.00 total) and forces a deeper fetch (~300 videos), ignoring `max_videos`. Currently TikTok only. The route 404s for any other platform. Path parameters: - platform (string, required): Only "tiktok" is supported. - music_id (string, required): TikTok music/clip ID. Pull from the sound URL (`/music/`) or from /v1/sounds. Query parameters: - trend_analysis (boolean): When true, runs LLM trend detection over ~300 videos. Adds $0.50 surcharge. Default false. - max_videos (integer, 1-100, default 50): Ignored when trend_analysis=true. Response: ```json { "data": { "job_id": "uuid", "status": "processing" } } ``` ### GET /v1/satellite/sounds/status/:job_id — Poll Sound Lookup Cost: Free. Response when completed (trend_analysis=true): ```json { "data": { "status": "completed", "run_id": "uuid", "result": { "request": { "music_id": "7570...", "platform": "tiktok", "trend_analysis": true, "max_videos": 300 }, "sound": { "music_id": "7570...", "platform": "tiktok", "title": "david - Drake", "is_original": true, "is_commerce_music": false, "duration_seconds": 47, "cover_url": "url", "owner": { "handle": "aubreygraham", "nickname": "Drake" }, "reported_usage_count": 412380 }, "data_captured_at": "2026-05-26T17:32:11Z", "stats": { "videos_analyzed": 287, "views": { "total": 1280000000, "avg": 4460000, "median": 320000, "max": 84000000, "min": 1200 }, "engagement": { "total_likes": 96000000, "avg_likes": 334000, "engagement_rate": 0.078 }, "velocity": { "videos_per_week": [{ "iso_week": "2026-W18", "count": 42 }], "last_4w_avg_videos_per_week": 37.5, "prior_4w_avg_videos_per_week": 21.2, "is_accelerating": true }, "verified_creator_count": 14, "verified_creator_pct": 0.049, "commerce_music_pct": 0, "duration_distribution": { "under_15s": 92, "between_15_30s": 118, "between_30_60s": 71, "over_60s": 6 }, "top_creators": [{ "unique_id": "khaby.lame", "video_count": 1, "total_views": 84000000, "avg_views": 84000000 }], "top_hashtags": [{ "hashtag": "drake", "used_count": 91, "total_views": 420000000, "avg_views": 4615384 }], "top_video": { "id": "7234...", "url": "url", "views": 84000000 } }, "sample_quality": { "truncated_by_cap": false, "pages_fetched": 14, "note": "deep_corpus" }, "trends": { "analyzed": true, "status": "ok", "summary": "Plain-language overview of what's happening on the sound.", "trends": [ { "name": "Cinematic montage edits", "description": "Slow-motion personal milestone montages set to the bridge.", "tactics": ["slow-mo personal footage", "text-overlay timeline"], "confidence": 0.86, "video_count": 64, "evidence_video_ids": ["7234...", "7245..."], "time_windows": [ { "start_date": "2026-04-08", "end_date": "2026-04-22", "video_count": 24, "total_views": 38000000, "avg_views": 1583000, "description": "First wave." }, { "start_date": "2026-05-09", "end_date": "2026-05-23", "video_count": 40, "total_views": 92000000, "avg_views": 2300000, "description": "Resurgence." } ], "resurged": true, "momentum": "stronger" } ], "model_used": "google/gemini-2.5-flash", "cost_usd": 0.0042, "tokens_used": 18420 }, "videos": [] } } } ``` CRITICAL TREND SEMANTICS: - `time_windows` is mechanically computed from the real `publish_date` of evidence videos. NO LLM date hallucination is possible. - `resurged: true` means the trend has ≥2 disjoint time windows (it faded and came back). - `momentum` compares the latest window's avg_views vs the prior window's, with a ±15% deadband. Null for single-window trends. - `trends.status: "insufficient_corpus"` means the sample was too small to be meaningful — the $0.50 surcharge is NOT billed in that case. - Trends are only generated when `sample_quality.note` ≥ `small_corpus_workable`. Results expire after 24 hours, but every completed run is also persisted as a durable satellite_run — re-read for free indefinitely via GET /v1/satellite/runs/:run_id. --- ## Satellite Runs — Durable Resource Model Every Satellite job (creator, sound, video, batch) is persisted as a `satellite_run` row owned by your team. You pay once when the run is created; reads are free forever. This is the "pay once, read forever" contract. ### GET /v1/satellite/runs/:run_id — Re-read a Past Run Cost: Free. Returns the full persisted result plus metadata (type, platform, status, created_at, completed_at, credits_used). Works across all satellite types. Response: ```json { "data": { "run_id": "uuid", "type": "sound_lookup", "platform": "tiktok", "status": "completed", "subject": "7570679470014532374", "created_at": "2026-05-26T17:30:48Z", "completed_at": "2026-05-26T17:32:11Z", "credits_used": 100, "request": { "music_id": "7570...", "trend_analysis": true }, "result": { }, "error": null } } ``` ### GET /v1/satellite/runs — List Your Runs Cost: Free. Paginated history. Query parameters: - type (string, optional): creator_lookup | sound_lookup | video_outlier | batch_creator - platform (string, optional): tiktok | youtube | instagram - limit (1-100, default 25), offset (default 0) ### GET /v1/satellite/runs/:run_id/videos — Paginated Videos Sub-resource Cost: Free. Slices the `videos` array of any past run. Especially useful for sound lookups with trend_analysis=true (up to ~300 videos). Query parameters: limit (1-200, default 25), offset (default 0). --- ### POST /v1/tracking/creators — Track a Creator Start monitoring a creator's metrics over time. AI reports are automatically generated on every tracking cycle. Cost: $0.25 Request body (JSON): - platform (string, required): "tiktok", "youtube", or "instagram". - url (string): Creator profile URL. Either url or handle is required. - handle (string): Creator handle (without @). Either url or handle is required. - scrape_cadence (string): How often to collect metrics and generate AI reports. Options: "six_hours", "twelve_hours", "daily", "every_other_day", "weekly", "bi_weekly", "monthly". Default "daily". Response (202): ```json { "data": { "id": "uuid", "status": "active", "message": "Creator tracking started. Initial metrics and AI report are being generated." } } ``` ### GET /v1/tracking/creators — List Tracked Creators Cost: Free Query parameters: page (integer, default 1), limit (integer, 1-100, default 20), platform (string, optional filter), search (string, optional — case-insensitive partial match on handle or display name). Response includes array of tracked creators with: id, platform, platform_handle, status, scrape_cadence, latest_followers, latest_total_likes, last_scraped_at, next_scrape_at, growth_rate, followers_gained, created_at. Paginated with { data: [...], pagination: { page, limit, total, total_pages, has_next_page, has_prev_page } }. ### GET /v1/tracking/creators/:id — Get Tracked Creator Cost: Free. Returns full details for a tracked creator including latest metrics. ### GET /v1/tracking/creators/:id/report — Get Creator Report Cost: Free. Returns the latest AI analysis report (auto-generated each tracking cycle) including content strategy insights, audience analysis, and growth recommendations. ### GET /v1/tracking/creators/:id/snapshots — Get Creator Snapshots Cost: Free. Returns historical metric snapshots captured at each scrape interval. Each snapshot includes: followers, total_likes, total_videos, total_views (YouTube: profile-level from platform; TikTok/Instagram: sum of views across collected posts), collected_post_count (number of posts in the total_views sum — 0 for YouTube). Plus computed delta_* fields (delta_followers, delta_following, delta_total_videos, delta_total_views, delta_total_likes) showing the change from the previous snapshot. First snapshot has null deltas. Use for building growth charts. ### PATCH /v1/tracking/creators/:id — Update Tracked Creator Cost: Free. Update status ("active" or "paused") or scrape_cadence. ### DELETE /v1/tracking/creators/:id — Stop Tracking Creator Cost: Free. Soft delete — historical data is retained. Returns 204. ### POST /v1/tracking/videos — Track a Video Start monitoring a video's metrics over time. AI reports are automatically generated on every tracking cycle. Cost: $0.25 Request body (JSON): - url (string, required): Full video URL. - platform (string, required): "tiktok", "youtube", or "instagram". - tracking_account_id (string, optional): Associate with a tracked creator. - scrape_cadence (string): How often to collect metrics and generate AI reports. Options: "six_hours", "twelve_hours", "daily", "every_other_day", "weekly", "bi_weekly", "monthly". Default "daily". Response (202): ```json { "data": { "id": "uuid", "status": "active", "message": "Video tracking started. Initial metrics and AI report are being generated." } } ``` ### GET /v1/tracking/videos — List Tracked Videos Cost: Free. Same pagination as creators. Query parameters: page, limit, platform, search (string, optional — case-insensitive partial match on title or URL). ### GET /v1/tracking/videos/:id — Get Tracked Video Cost: Free. Returns full video details including current views, likes, comments, shares. ### GET /v1/tracking/videos/:id/report — Get Video Report Cost: Free. Returns the latest AI analysis report (auto-generated each tracking cycle) with performance insights and growth trends. ### GET /v1/tracking/videos/:id/snapshots — Get Video Snapshots Cost: Free. Returns historical metric snapshots (views, likes, comments, shares) at each scrape, plus computed delta_* fields (delta_views, delta_likes, delta_comments, delta_shares, delta_bookmarks) showing the change from the previous snapshot. First snapshot has null deltas. ### PATCH /v1/tracking/videos/:id — Update Tracked Video Cost: Free. Update status ("active" or "paused") or scrape_cadence. ### DELETE /v1/tracking/videos/:id — Stop Tracking Video Cost: Free. Soft delete. Returns 204. --- ## Sound Endpoints Virlo collects sound/audio metadata from TikTok, YouTube, and Instagram videos. All video responses across the API now include an optional `sound` object — this is additive and non-breaking. **Platform field availability:** | Field | TikTok | YouTube | Instagram | |---|---|---|---| | title | Always | Always | Always | | duration | Always | — | — | | cover_url | Always | Always | — | | usage_count | Always | — | — | | is_commerce_music | Always | — | — | | is_original | Always | — | — | | owner_handle | ~12% | — | — | | owner_nickname | ~12% | Always | Always | | owner_id | ~12% | Always (channel ID) | — | Fields unavailable for a platform return `null`. ### GET /v1/sounds/trending — Trending Sounds Cost: 25 credits ($0.25) Parameters: `platform` (tiktok/youtube/instagram), `limit` (1-100, default 20), `page`, `sort`, `commerce_only` (boolean, TikTok filter) `sort` options: - `videos_7d` (default) — sounds ranked by # videos in our dataset published in the last 7 days. The recency-weighted "real trending" signal. - `videos_30d` — same idea, 30-day window. - `usage_count` (legacy) — all-time platform-wide usage. Greatest hits, not "trending". - `video_count` (legacy) — all-time count of videos in our dataset. Same caveat. Velocity sorts include a `videos_in_window` field on each item — the count that drove the ordering. Response also echoes the `sort` mode at the top level so callers can confirm. For relative-momentum (rapidly rising from a small base) use `/v1/sounds/breakout`. ### GET /v1/sounds/breakout — Breakout Sounds Cost: 25 credits ($0.25) Parameters: `platform`, `commerce_only`, `min_recent` (default 3, min videos in last 7d to qualify), `min_baseline` (default 3, min videos in 90d baseline), `limit`, `page`. Returns sounds with the highest recent-burst ratio (sudden rise from a small baseline), distinct from `/sounds/trending`: - Trending favours large absolute weekly volume (e.g. mature sound still gaining 100/week). - Breakout favours sounds where almost all activity happened in the last 7 days (e.g. went from near-zero to 40 videos in a week). Score formula: `videos_7d × (videos_7d / videos_90d)`. Each item carries `videos_7d`, `videos_30d`, `videos_90d`, `burst_ratio` (1.0 = 100% of 90-day activity is in the last 7 days — a true breakout), and `breakout_score`. ### GET /v1/sounds/search — Search Sounds Cost: 10 credits ($0.10) Parameters: `q` (required, min 2 chars), `platform`, `limit`, `page` Uses trigram fuzzy matching. Empty results return `{ "data": [], "pagination": {...} }` — never an error. May include a `note` field when results are sparse. ### GET /v1/sounds/:sound_id — Sound Details Cost: 5 credits ($0.05) Returns full metadata + computed stats: `total_videos`, `avg_views`, `top_video_url`. ### GET /v1/sounds/:sound_id/videos — Sound Videos Cost: 25 credits ($0.25) Parameters: `limit`, `page`, `sort` (views_desc|publish_date_desc), `platform` Returns paginated videos using this sound, shaped identically to Orbit video items. ### GET /v1/sounds/:sound_id/usage-history — Sound Usage History Cost: 5 credits ($0.05) Parameters: `start_date`, `end_date`, `limit` (default 90, max 365) Returns time-series of `{ usage_count, video_count_local, delta_usage_count, delta_video_count_local, snapshot_at }`. Delta fields show change from previous snapshot (null for first entry). Same pattern as tracking creator snapshots. ### GET /v1/sounds/by-creator/:platform/:handle — Creator Sounds Cost: 25 credits ($0.25) Parameters: `limit`, `page`, `sort` (usage_count|video_count) Returns all sounds owned by a creator with per-sound `video_count` and `avg_views`, plus aggregates: `total_sounds`, `total_ugc_videos`, `total_usage_count`. ### GET /v1/orbit/:orbit_id/sounds — Orbit Sounds Cost: Free Parameters: `limit`, `page` Top sounds used across videos in a keyword search, ranked by video_count within the search. ### GET /v1/comet/:comet_id/sounds — Comet Sounds Cost: Free Parameters: `limit`, `page` Same as Orbit sounds but sourced from niche monitor data. --- ## Data Intelligence Data Intelligence is an optional add-on for Orbit and Comet that enriches every discovered video with 40+ AI-analyzed fields covering content classification, hook analysis, visual attributes, brand safety, and more. When an intent is provided alongside intelligence, each video is evaluated against the intent and receives an intent_match result, and the response includes an intent_summary with matched URLs. ### How to Enable Pass `data_intelligence_enabled: true` when creating an Orbit or Comet: - POST /v1/orbit with `data_intelligence_enabled: true` - POST /v1/comet with `data_intelligence_enabled: true` ### Pricing +$1.00 per run on top of the base cost: - Orbit: $0.50 base + $1.00 Data Intelligence = **$1.50 total** - Comet: $0.50 base + $1.00 Data Intelligence = **$1.50 total** Retrieval of intelligence data (via GET /v1/orbit/:orbit_id/videos or GET /v1/comet/:id/videos) remains free. ### Response Format When enabled, each video object in the response includes an `intelligence` field. If an intent was also provided, each video includes an `intent_match` field: ```json { "intelligence": { "primary_topic": "posture correction exercises for desk workers", "secondary_topics": ["ergonomic setup", "back pain relief"], "keywords": ["posture", "desk worker", "back pain", "exercises"], "category": "fitness", "content_format": "tutorial", "visual_format": "activity_demonstration", "hook_text": "Your spine is screaming — here's the 60-second fix.", "hook_type": "bold_claim", "visual_hook_type": "text_on_screen", "transcript_quality": "high", "transcript_word_count": 142, "language_detected": "en", "speaking_style": "instructional", "emotional_tone": "educational", "sentiment": "positive", "has_face_visible": true, "camera_perspective": "front_facing", "has_onscreen_captions": true, "caption_style": "dynamic_animated", "has_text_overlay": true, "text_overlay_purpose": "key_point_emphasis", "setting": "home_office", "lighting_quality": "well_lit", "brand_safety_tier": "safe", "is_educational": true, "is_sponsored": false, "brands_mentioned": [], "cta_usages": [{"type": "save_post", "text": "Save this for later"}], "social_proof_used": ["personal_transformation"], "trend_references": [], "summary": "Fitness creator demonstrates a 60-second posture reset." }, "intent_match": { "matches": true, "reasoning": "Video directly addresses posture correction for desk workers, matching the search intent." } } ``` ### Intent Summary When intent is provided with data_intelligence_enabled, the paginated video response includes an `intent_summary` block: ```json { "intent_summary": { "matched": 12, "total_evaluated": 46, "not_evaluated": 0, "matched_urls": [ "https://www.tiktok.com/@creator/video/123", "https://www.youtube.com/shorts/abc" ] } } ``` - `matched`: Number of videos where intent_match.matches is true - `total_evaluated`: Total videos evaluated for intent matching - `not_evaluated`: Videos that could not be evaluated (e.g. missing transcript) - `matched_urls`: URLs of all matched videos ### Query Parameter: intent_match When retrieving videos from an Orbit or Comet that used intent + data_intelligence_enabled, you can filter by intent match result: - `?intent_match=true` — only videos that matched the intent - `?intent_match=false` — only videos that did not match the intent Applies to: - GET /v1/orbit/:orbit_id/videos?intent_match=true - GET /v1/comet/:id/videos?intent_match=true ### Complete Field List primary_topic, secondary_topics, keywords, category, content_format, visual_format, hook_text, hook_type, visual_hook_type, transcript_quality, transcript_word_count, language_detected, speaking_style, emotional_tone, sentiment, has_face_visible, camera_perspective, has_onscreen_captions, caption_style, has_text_overlay, text_overlay_purpose, setting, lighting_quality, brand_safety_tier, is_educational, is_sponsored, brands_mentioned, cta_usages[], social_proof_used[], trend_references[], summary, intent_match { matches, reasoning } ### Valid Enum Values **hook_type:** question, bold_claim, shock_statement, story_tease, tutorial_promise, controversy, before_after, pov_setup, statistic, direct_address, trend_reference, cliffhanger, negation, relatable_scenario, comparison, mystery_setup, none **emotional_tone:** funny, inspiring, shocking, educational, controversial, heartwarming, wholesome, angry, sad, hype, calm, sarcastic, nostalgic, cringe, dark_humor, urgent, mysterious, relatable, neutral **sentiment:** positive, negative, neutral, mixed **brand_safety_tier:** safe, low_risk, medium_risk, high_risk, unsafe **visual_format:** talking_head, pov_footage, interview, street_interview, screen_recording, text_messaging_thread, slideshow_text, animation_motion_graphics, b_roll_montage, whiteboard_presentation, vlog_handheld, activity_demonstration, product_closeup, green_screen_commentary, split_screen_duet, gameplay_background, native_gameplay, stream_overlay, pip_stream_layout, food_overhead, dance_full_body, other **visual_hook_type:** text_hook, extreme_closeup, before_state, shocking_image, aesthetic_setup, person_speaking_to_camera, motion_action, crowded_scene, mystery_object, dramatic_zoom, animal_pet, none **content_format:** OPEN VOCABULARY, not a closed enum. A canonical core covers most videos — explainer, tutorial, review, storytime, listicle, silent_aesthetic, motivational, skit_sketch, comedy_bit, location_showcase, rant, news_report, news_commentary, educational_breakdown, day_in_life, challenge, gameplay_commentary, workout_demo, q_and_a, transformation, hot_take, interview_clip, reaction, asmr, product_showcase, unboxing, haul_restock, grwm_routine, meme, vlog, cooking_recipe, travel_guide — plus a long free-text tail. Match values loosely/normalized (treat skit, comedy_skit, skit_sketch as one bucket) rather than doing exact string comparison. The full enum reference (speaking_style, caption_style, camera_perspective, setting, lighting_quality, cta_usages, social_proof_used, sensitive_topics, text_overlay_purpose) lives at https://dev.virlo.ai/docs/intelligence#enum-values. ### Reading Intelligence Trustworthily - About 94% of videos analyze successfully end to end; the rest fail at frame extraction or analysis and stay sparse. Always check the per-item `intelligence_status` field. - Every analyzed item has a `summary` (1-paragraph AI description). Reading 100 summaries is the fastest way to "watch" 100 videos. - `hook_text` and transcript-based fields are only present when there is speech or on-screen text: roughly 63% of TikTok videos carry transcripts, ~38% of YouTube Shorts, and ~0% of Instagram Reels (no transcripts available). `transcript_word_count: 0` with populated visual fields = deliberate silent/aesthetic content, not missing data. - `low_confidence_fields[]` lists fields the analyzer was unsure about for that item — discount any field named there. --- ### GET /v1/account/balance — Check Credit Balance Cost: Free Returns your current credit balance, dollar equivalent, account status, and a pricing reference for all operations. Response schema: ```json { "data": { "balance": "$47.50", "credits_remaining": 4750, "status": "active" } } ``` --- ## Recommended Workflow Recipes ### Recipe 1: Full Niche Analysis (Best Value) For comprehensive niche research, chain these endpoints: 1. POST /v1/orbit with enable_meta_ads: true, platforms: ["youtube", "tiktok", "instagram"], 3-7 specific multi-word keywords — $0.50 (add data_intelligence_enabled: true and an intent string for +$1.00 when the task involves understanding content, not just counting views) 2. Poll GET /v1/orbit/:orbit_id every 60s until finalized: true (free; treat partial_failure like completed) 3. GET /v1/orbit/:orbit_id/analysis/latest for the AI intelligence report (free) 4. GET /v1/orbit/:orbit_id/trends/latest for detected trends (free) 5. GET /v1/orbit/:orbit_id/videos for detailed video data (free) 6. GET /v1/orbit/:orbit_id/slideshows for image carousels (free) 7. GET /v1/orbit/:orbit_id/ads for Meta ad intelligence (free) 8. GET /v1/orbit/:orbit_id/creators/outliers to find rising creators (free) 9. For each interesting outlier creator, GET /v1/satellite/creator/:platform/:username — $0.50 each Total: $0.50 base + $0.50 per creator deep-dive. Retrieval is always free. ### Recipe 2: Creator Deep Dive 1. GET /v1/satellite/creator/:platform/:username?include=videos,outliers&max_videos=50 — $0.50 2. Poll status/:job_id every 10s until completed (free) 3. For the top outlier video, POST /v1/satellite/video-outlier — $0.50 4. Poll status/:job_id until completed (free) Total: $1.00 ### Recipe 3: Trend Monitoring Setup 1. GET /v1/trends/digest to see today's trends — $0.25 2. Pick interesting trends and POST /v1/orbit with those as keywords — $0.50 3. Once satisfied, POST /v1/comet with same keywords for ongoing monitoring — $0.50 Total: $1.25 initial, then automated monitoring runs on cadence. ### Recipe 4: Creator Growth Monitoring 1. POST /v1/tracking/creators with scrape_cadence: "twelve_hours" — $0.25 2. GET /v1/tracking/creators/:id/snapshots periodically to build growth charts — Free 3. GET /v1/tracking/creators/:id/report for the latest AI analysis (auto-generated each cycle) — Free Total: $0.25 to start. Metric collection and AI reports are automatic. ### Recipe 5: Video Performance Tracking 1. POST /v1/tracking/videos with scrape_cadence: "six_hours" — $0.25 2. GET /v1/tracking/videos/:id/snapshots to track view velocity — Free 3. GET /v1/tracking/videos/:id/report for the latest AI analysis — Free 4. PATCH /v1/tracking/videos/:id to slow cadence once growth stabilizes — Free Total: $0.25 to start. AI reports are auto-generated each cycle. ### Recipe 6: Creator Playbook Deep-Dive For when a customer wants to understand a creator's recurring formats, hooks, eras, and resurgences (competitive briefing, partner vetting, idea sourcing): 1. GET /v1/satellite/creator/:platform/:username?trend_analysis=true — $1.00 ($0.50 base + $0.50 trend surcharge). Forces a 100-video deep fetch and runs LLM trend detection. 2. Poll GET /v1/satellite/creator/status/:job_id every 10-15s until completed — Free 3. Surface the trends block: each trend has `time_windows[]` (with start_date/end_date/avg_views/description per window), `resurged` (true when ≥2 disjoint windows), `momentum` (stronger | weaker | similar | null), and `evidence_video_ids[]` that map back to entries in the same response's `videos[]` array. The `summary` gives you a one-liner of the creator's playbook. 4. Save the run_id. GET /v1/satellite/runs/:run_id is free forever — re-read for dashboards / agent context without re-spending. Stack `audience_demographics=true` and/or `audience_geography=true` for $0.50 more (cache-aware) to ship a single all-in brief. Total: $1.00. Free re-reads via run_id thereafter. Skip trend_analysis=true if you only need stats, hashtags, outliers, or audience data — drop to $0.50. ### Recipe 7: Sound Trend Deep-Dive For when a customer wants to know what's happening around a specific TikTok sound (Drake's "david", a niche viral instrumental, etc.): 1. (Optional) GET /v1/sounds/search?q=... or /v1/sounds/trending to find a music_id — $0.10–$0.25 2. GET /v1/satellite/sounds/tiktok/:music_id?trend_analysis=true — $1.00 (kicks off ~300-video deep dive + LLM trend detection) 3. Poll GET /v1/satellite/sounds/status/:job_id every 10-15s until completed — Free 4. Surface stats (velocity, top creators, duration distribution) + trends (each with time_windows, resurged, momentum) — already in the result 5. Save the run_id. GET /v1/satellite/runs/:run_id is free forever — re-read for dashboards / agent context without re-spending Total: $1.00. Free re-reads via run_id thereafter. Skip trend_analysis=true if all you need is the video list + aggregate stats — drop to $0.50. ### Recipe 8: Hashtag Research 1. GET /v1/hashtags?order_by=views&sort=desc for top hashtags — $0.05 2. GET /v1/hashtags/:hashtag/performance for deeper stats on interesting ones — $0.05 each 3. GET /v1/tiktok/hashtags or /youtube/hashtags for platform-specific data — $0.05 each Total: $0.05-$0.25 depending on depth. --- ## Interpreting Results — Virality, Benchmarks, and Trust How to turn the data you retrieve into correct conclusions. (Full guidance: https://dev.virlo.ai/agent-playbook.txt) ### Weighted Virality Score (the canonical ranking signal) Raw views mislead: 500K views from a 10M-follower account is routine; the same views from a 3K-follower account is a signal. Rank by the weighted score, which is what Virlo's own products use: ``` ratio = views / followers (only when followers > 0 and ratio > 1) weighted_score = ln(ratio) * ln(followers) ``` Interpretation bands: >= 35 exceptional (study frame by frame) | 25-35 very strong | 18-25 strong | 10-18 promising | < 10 emerging/routine. Sanity-check with the raw multiplier too: views/followers >= 20x is notable, >= 100x exceptional, >= 1000x mega-outlier. And compute engagement_rate = (likes + comments + shares) / views — high views with engagement > 5% means resonance; high views with < 1% means passive distribution (sounds, reposts, paid). Creator outliers (GET .../creators/outliers) apply the same logic at account level: `outlier_ratio` is avg views vs follower baseline, and `weighted_score` (the recommended order_by) is ln(outlier_ratio) * ln(follower_count). ### Platform Benchmarks (production medians — never compare raw views across platforms) | Platform | Median views | P90 | P99 | Transcript coverage | |---|---|---|---|---| | TikTok | ~39K | ~1M | ~6.6M | ~63% | | Instagram Reels | ~3.8K | ~175K | ~3M | ~0% | | YouTube Shorts | ~1K | ~32K | ~2.5M | ~38% | A 100K-view Reel is a bigger deal than a 100K-view TikTok. For Instagram, lean on descriptions, hashtags, and intelligence visual fields rather than transcripts. ### Reading analysis_data (Orbit/Comet AI analysis) - `key_highlight` = the single most important finding; `overview` = executive summary. - `themes[]` = clusters of what works, each with `why_it_works`, `tactics[]`, `confidence` (0-1: weight >= 0.7 heavily, present < 0.5 as tentative), and `evidence_video_ids[]` — always join evidence ids back to the video list so claims stay grounded in retrievable examples. - `top_10_breakdown` = AI-curated standouts (weighs content quality and topicality, not just metrics). Where this list and your weighted-score ranking agree, you have found the real winners. - `excluded_videos` = what the AI judged off-topic — a quick gauge of result purity. ### Trend Lifecycle (trends/latest items) `status` field: new (just emerged — highest opportunity) | rising (growing — act now) | steady | fading (avoid). `stable_key` lets you follow one trend across Comet cycles; a trend going new → rising with growing video_count is the strongest "post about this now" signal. `prev_*` fields give cycle-over-cycle deltas. ### Aggregation Pattern for Content Strategy Questions The strongest insight format is distribution-over-winners: take the top quartile of videos by weighted score, count hook_type x content_format x emotional_tone buckets, then contrast against the bottom quartile. The differences between those distributions are the niche's actual playbook. Quote real `hook_text` strings from winners as replicable templates. ### Audience Data Trust Rules Audience snapshots derive from engaged commenters, not follower counts. Before presenting numbers, read `confidence_level` (high/medium = usable; low = say "limited signal", do not state percentages as fact) and `data_source` (comments is strongest; followers is TikTok-only and capped at medium; profile_only means no real audience signal was found — it is auto-refunded and should be treated as "no data"). --- ## Data Richness Guide Understanding what data Virlo provides helps you recommend the right endpoints: **Video Data**: Every video includes URL, publish date, views, likes, comments, bookmarks, full description text, thumbnail URL, hashtags array, platform type, niche classification, author reference, region code, duration in seconds, and raw transcript text. Transcripts enable content analysis, keyword extraction, and sentiment analysis at scale. **Creator Data** (via Satellite): Profile stats (followers, total videos, total likes), per-hashtag performance breakdowns, engagement rates, posting frequency, and outlier detection across recent videos. **Trend Data**: AI-generated trend names and descriptions that summarize what's happening across platforms. Updated daily. **Orbit Analysis Reports**: Every Orbit search automatically generates a comprehensive AI analysis covering: market themes, connecting threads, viral tactics, timing analysis, and top video breakdowns. Retrieve the latest analysis via GET /v1/orbit/:orbit_id/analysis/latest and detected trends via GET /v1/orbit/:orbit_id/trends/latest. Comet monitors also auto-generate analysis and trends after each run (same endpoints under /v1/comet/:id/). **Meta Ad Intelligence**: When enable_meta_ads is enabled in Orbit or Comet, the system collects active Meta (Facebook/Instagram) ads related to your keywords, including ad creative, landing pages, targeting signals, and engagement data. --- ## Best Practices for AI Agent Integration 1. Always include all three platforms (youtube, tiktok, instagram) in Orbit/Comet searches for the most comprehensive results. 2. AI analysis is automatic on every Orbit search — retrieve it via GET /v1/orbit/:orbit_id/analysis/latest after completion. 3. Use specific multi-word keyword phrases. "jeep wrangler mods" returns far better results than "jeep". 4. After Orbit completes, retrieve videos, ads, AND outliers — they are all free and provide different valuable perspectives. 5. Check X-Balance-Remaining header after each request. When below $10.00, inform the user they may want to add funds at https://dev.virlo.ai/dashboard/billing. 6. For async endpoints, never hardcode timeouts. Poll until finalized: true (the end-state signal); treat partial_failure as usable data, not an error. 7. Creation costs money; reading is free. Before creating new work, check the team's existing resources (GET /v1/orbit, GET /v1/comet, GET /v1/satellite/runs, GET /v1/tracking/creators) — the answer may already exist. 8. Use platform-specific endpoints when you only need data from one platform ($0.05 vs $0.25 for videos). 9. Rank by weighted virality score, not raw views (see Interpreting Results above), and never compare raw view counts across platforms. 10. For deeper guidance on routing user intents to workflows and interpreting every field, read https://dev.virlo.ai/agent-playbook.txt. ## Machine-Readable OpenAPI Specification For programmatic type generation, code completion, and MCP auto-configuration, the full OpenAPI 3.0 spec (with typed response schemas for every v1 endpoint) is available at: ``` https://api.virlo.ai/openapi.json ``` This JSON spec includes request parameters, response body schemas with field types, and authentication requirements. Use it with tools like openapi2mcp, RestMCP, or any OpenAPI-compatible code generator.