# Algrow API Documentation > Base URL: https://api.algrow.online > All plans: Channel search, scraping, and data endpoints > Professional or Ultimate: Text-to-speech and voice generation endpoints ## Authentication All endpoints require a valid API key via: - Header: `Authorization: Bearer algrow_...` --- ## GET /api/channels/search Search Shorts channels with similarity search, keyword matching, and advanced filters. Returns channel metadata, realtime growth metrics (24h/48h), and recent videos. Results are paginated. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | q | string | Required | — | Search query. Accepts a channel ID (e.g. UCXx6GV...), @handle (e.g. @MrBeast), a video URL (e.g. https://youtube.com/shorts/..., https://youtu.be/...), or a search term. Comma-separated for multiple keywords. Prefix with - to exclude (e.g. gaming,-minecraft). | | languages | string | Optional | — | Filter by language. Comma-separated (e.g. English,Spanish) | | sort | string | Optional | subs_desc | Sort field and direction. Format: {field}_{asc\|desc}. Fields: subs, views, videos, age, added, views_24h, subs_24h, views_48h, similarity | | page | integer | Optional | 1 | Page number (1-indexed) | | per_page | integer | Optional | 20 | Results per page (max 50) | | min_subs | integer | Optional | — | Minimum subscriber count | | max_subs | integer | Optional | — | Maximum subscriber count | | min_avg_views | integer | Optional | — | Minimum average views per video | | max_avg_views | integer | Optional | — | Maximum average views per video | | min_age | integer | Optional | — | Minimum channel age in days | | max_age | integer | Optional | — | Maximum channel age in days | | min_uploads | integer | Optional | — | Minimum number of videos | | max_uploads | integer | — | — | Maximum number of videos | | min_views | integer | Optional | — | Minimum total view count | | max_views | integer | Optional | — | Maximum total view count | | min_views_24h | integer | Optional | — | Minimum views gained in last 24 hours | | max_views_24h | integer | Optional | — | Maximum views gained in last 24 hours | | min_views_48h | integer | Optional | — | Minimum views gained in last 48 hours | | max_views_48h | integer | Optional | — | Maximum views gained in last 48 hours | | min_similarity | integer | Optional | — | Minimum similarity score (0–100). Tightens the default similarity bar; only effective when q is a channel identifier or topic keyword and an embedding was generated. | **Example Requests** ``` # Similarity search for gaming channels curl "https://api.algrow.online/api/channels/search?q=gaming&languages=English&per_page=5" \ -H "Authorization: Bearer YOUR_API_KEY" # Filter: young channels with high views, sorted by 24h growth curl "https://api.algrow.online/api/channels/search?max_age=90&min_avg_views=500000&sort=views_24h_desc" \ -H "Authorization: Bearer YOUR_API_KEY" # Exclude keywords: cooking channels but not baking curl "https://api.algrow.online/api/channels/search?q=cooking,-baking&per_page=10" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response 200** ``` { "success": true, "page": 1, "per_page": 5, "count": 5, "channels": [ { "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "channel_title": "Epic Gaming Shorts", "subscriber_count": 245000, "avg_views_per_video": 1850000, "total_videos": 47, "channel_age_days": 182, "view_count": 86950000, "primary_language": "English", "thumbnail_url": "https://yt3.ggpht.com/...", "view_increase_24h": 320000, "sub_increase_24h": 1200, "view_increase_48h": 580000, "similarity_score": 87, "recent_videos": [ { "video_id": "dQw4w9WgXcQ", "title": "This game is INSANE", "view_count": 4200000, "upload_date": "2026-03-15", "thumbnail_url": "https://i.ytimg.com/vi/...", "url": "https://www.youtube.com/shorts/dQw4w9WgXcQ" } ] } ] } ``` **Response Fields** | Field | Type | Description | |---|---|---| | channel_id | string | YouTube channel ID | | channel_title | string | Channel name | | subscriber_count | integer | Current subscriber count | | avg_views_per_video | integer | Average views across all videos | | total_videos | integer | Number of videos on the channel | | channel_age_days | integer | Days since first upload | | view_count | integer | Total channel views | | primary_language | string | Detected content language | | thumbnail_url | string | Channel profile picture URL | | view_increase_24h | integer\|null | Views gained in last 24 hours | | sub_increase_24h | integer\|null | Subscribers gained in last 24 hours | | view_increase_48h | integer\|null | Views gained in last 48 hours | | similarity_score | integer\|null | Similarity score (0–100) when using q search. Higher = more relevant. | | recent_videos | array | Up to 6 most recent videos with video_id, title, view_count, upload_date, thumbnail_url, url | --- ## GET /api/longform-channels/search Search Longform channels (standard YouTube creators) with the same similarity search and filtering capabilities. Returns channel metadata, realtime growth metrics, and recent videos with duration info. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | q | string | Required | — | Search query. Accepts a channel ID, @handle, a video URL (e.g. https://youtube.com/shorts/..., https://youtu.be/...), or a search term. Comma-separated for multiple keywords, - to exclude. | | languages | string | Optional | — | Filter by language (e.g. English) | | sort | string | Optional | subs_desc | Sort field and direction. Fields: subs, views, videos, age, total_views, added, views_24h, subs_24h, views_48h, similarity | | page | integer | Optional | 1 | Page number (1-indexed) | | per_page | integer | Optional | 20 | Results per page (max 50) | | min_subs | integer | Optional | — | Minimum subscriber count | | max_subs | integer | Optional | — | Maximum subscriber count | | min_avg_views | integer | Optional | — | Minimum average views per video | | max_avg_views | integer | Optional | — | Maximum average views per video | | min_age | integer | Optional | — | Minimum channel age in days | | max_age | integer | Optional | — | Maximum channel age in days | | min_uploads | integer | Optional | — | Minimum number of videos | | max_uploads | integer | Optional | — | Maximum number of videos | | min_duration | integer | Optional | — | Minimum average video duration in seconds | | max_duration | integer | Optional | — | Maximum average video duration in seconds | | monetized | string | Optional | — | Filter by monetization: yes or no | | min_views_24h | integer | Optional | — | Minimum views gained in last 24 hours | | max_views_24h | integer | Optional | — | Maximum views gained in last 24 hours | | min_views_48h | integer | Optional | — | Minimum views gained in last 48 hours | | max_views_48h | integer | Optional | — | Maximum views gained in last 48 hours | | categories | string | Optional | — | Comma-separated content categories. Lowercase, from: tutorial, educational, documentary, gaming, reviews, commentary, compilation, stories, interview, challenge videos, diy, speeches, memes. Unknown values return 400. | | min_similarity | integer | Optional | — | Minimum similarity score (0–100). Tightens the default 30% similarity floor; only effective when q is a channel identifier or topic keyword. Values below 30 are clamped to the default. | **Example Requests** ``` # Search for finance channels under 1 year old curl "https://api.algrow.online/api/longform-channels/search?q=finance&max_age=365&languages=English" \ -H "Authorization: Bearer YOUR_API_KEY" # High-growth longform channels sorted by 24h views curl "https://api.algrow.online/api/longform-channels/search?min_views_24h=50000&sort=views_24h_desc&per_page=10" \ -H "Authorization: Bearer YOUR_API_KEY" # Monetized channels with specific subscriber range curl "https://api.algrow.online/api/longform-channels/search?min_subs=10000&max_subs=100000&monetized=yes" \ -H "Authorization: Bearer YOUR_API_KEY" # Documentary channels only curl "https://api.algrow.online/api/longform-channels/search?q=ancient+civilizations&categories=documentary" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response 200** ``` { "success": true, "page": 1, "per_page": 20, "count": 20, "channels": [ { "id": "UCxxxxxxxxxxxxxxxxxxxxxx", "name": "Smart Money Moves", "subscriber_count": 52000, "avg_views_per_video": 185000, "total_videos": 34, "upload_day": 210, "view_count": 6290000, "primary_language": "English", "profile_picture": "https://yt3.ggpht.com/...", "monetized": true, "category": "documentary", "url": "https://youtube.com/@SmartMoneyMoves", "views_24h": 18500, "subs_24h": 340, "views_48h": 31200, "similarity_score": 92, "recent_videos": [ { "video_id": "abc123xyz", "title": "How I Built a $10K/Month Side Income", "view_count": 420000, "upload_date": "2026-03-12", "thumbnail_url": "https://i.ytimg.com/vi/...", "url": "https://www.youtube.com/watch?v=abc123xyz", "duration": 845 } ] } ] } ``` > Longform vs Shorts response differences: Longform channels use id and name instead of channel_id and channel_title. Videos include a duration field (in seconds). Longform also has monetized, url, and upload_day (days active) fields. --- ## GET /api/channel-trends Browse the top-growing channels ranked by recent view or subscriber deltas — the leaderboard that powers the Channel Trends page. Use this for browse-by-filter queries with no real topic to anchor a similarity search (e.g. “newest channels”, “biggest by subs”, “started in last 90 days”). Optionally pass q to narrow the leaderboard to a niche via embedding similarity. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | content_type | string | Optional | shorts | shorts or longform — which index to rank. | | metric | string | Optional | views | Sort metric. 24h: views, subs. Rolling 48h: views_48h, subs_48h. Rolling 7d: views_7d, subs_7d. similarity only when q is set. | | q | string | Optional | — | Niche keyword or @handle to narrow the leaderboard. Comma-separated for multiple, - to exclude. Omit to browse the raw growth leaderboard. | | page | integer | Optional | 1 | Page (1–20). | | per_page | integer | Optional | 50 | Results per page (1–50). | | languages | string | Optional | — | Comma-separated (e.g. English,Spanish). | | min_subs / max_subs | integer | Optional | — | Subscriber count range. | | min_avg_views / max_avg_views | integer | Optional | — | Average views per video range. | | min_age / max_age | integer | Optional | — | Channel age in days since first upload. max_age=60 = “started in last 2 months”. | | min_videos / max_videos | integer | Optional | — | Video count range. | | min_avg_duration / max_avg_duration | integer | Optional | — | Average video duration in seconds (longform only; floor of 420s/7min is enforced). | | remove_low_quality | boolean | Optional | false | Exclude channels flagged low-quality. | | remove_music | boolean | Optional | false | Exclude music channels (longform only). | **Example Requests** ``` # Fastest-growing longform channels in the last 90 days curl "https://api.algrow.online/api/channel-trends?content_type=longform&metric=views_7d&max_age=90&per_page=20" \ -H "Authorization: Bearer YOUR_API_KEY" # Top growing Shorts channels in a specific niche curl "https://api.algrow.online/api/channel-trends?q=cooking&metric=subs_48h&content_type=shorts" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## GET /api/voices Browse and search available ElevenLabs voices. Returns voice IDs you can use with provider=elevenlabs. For Stealth voices, use /api/voices/stealth instead. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | search | string | Optional | — | Search by voice name or labels | | gender | string | Optional | — | Filter by gender: male, female, or neutral | | age | string | Optional | — | Filter by age: young, middle_aged, or old | | language | string | Optional | — | Language code (e.g. en, es, fr) | | accent | string | Optional | — | Filter by accent (e.g. american, british) | | sort | string | Optional | trending | Sort by: trending, created_date, usage_character_count_1y | | page_size | integer | Optional | 30 | Results per page (max 100) | | page | integer | Optional | 0 | Page number (0-indexed) | **Example Request** ``` # Browse trending voices curl "https://api.algrow.online/api/voices?sort=trending&page_size=10" \ -H "Authorization: Bearer YOUR_API_KEY" # Search for female English voices curl "https://api.algrow.online/api/voices?search=narrator&gender=female&language=en" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response 200** ``` { "success": true, "voices": [ { "voice_id": "EkK5I93UQWFDigLMpZcX", "name": "James - Husky, Engaging and Bold", "gender": "male", "age": "middle_aged", "accent": "american", "language": "en", "description": "A slightly husky and bassy voice...", "preview_url": "https://...", "category": "high_quality", "use_case": "narrative_story" } ], "has_more": true } ``` --- ## POST /api/generate-simple Create a text-to-speech generation job. Returns a job_id immediately. The audio is generated asynchronously — poll /api/job-status/:job_id to check progress and retrieve the audio URL when complete. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | | Content-Type | string | Auto | Set automatically by curl -F. If manual: multipart/form-data | **Request Parameters (form-data)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | script | string | Required | — | Text to convert to speech. Limit depends on plan & provider (see table below). | | voice_id | string | Required | — | Voice ID. For ElevenLabs: e.g. 21m00Tcm4TlvDq8ikWAM. For Stealth: use the voice_id from /api/voices/stealth. For MiniMax: use the voice_id from /api/voices/minimax (clone first). | | provider | string | Optional | elevenlabs | TTS engine. Values: elevenlabs, stealth, minimax | | model_id | string | Optional | eleven_multilingual_v2 | Model to use. Also available: eleven_v3, eleven_turbo_v2_5, eleven_flash_v2_5, eleven_turbo_v2, eleven_flash_v2 | | stability | float | Optional | 0.5 | Voice consistency. Higher = more stable, lower = more expressive. Range: 0.0 – 1.0 | | similarity_boost | float | Optional | 0.5 | How closely to match the original voice. Range: 0.0 – 1.0 | | style | float | Optional | 0.0 | Speaking style exaggeration. Higher values amplify the voice's style. Range: 0.0 – 1.0 | | speed | float | Optional | 1.0 | Playback speed. Range: 0.7 – 1.2 (ElevenLabs) or 0.5 – 2.0 (MiniMax) | | pitch | int | Optional | 0 | Pitch shift in semitones. Range: -12 – +12. (MiniMax only) | | volume | float | Optional | 1.0 | Output volume multiplier. Range: 0.0 – 10.0. (MiniMax only) | | voice_name | string | Optional | voice_id | Human-readable label for this voice (for your reference only) | | custom_title | string | Optional | — | Custom filename for the output MP3 (without extension) | | generate_srt | string | Optional | false | Set to true to generate an SRT subtitle file (ElevenLabs only). Bills 1.2× characters. | | temperature | float | Optional | 1.1 | Voice expressiveness (Stealth only). Higher = more expressive. | | speaking_rate | float | Optional | 1.0 | Speaking speed multiplier (Stealth only). | | stealth_model | string | Optional | 1.5 | Stealth model tier (Stealth only). 1.5 = standard model (1× characters, default); 2.0 = Stealth 2.0, our newest, most capable model (2× characters). | > Provider-specific parameters: When provider=stealth: only temperature, speaking_rate and stealth_model are used. Parameters stability, similarity_boost, style, speed, and model_id are ignored. When provider=elevenlabs (default): only stability, similarity_boost, style, speed, and model_id are used. Parameters temperature and speaking_rate are ignored. When provider=minimax: only speed, pitch, and volume are used. The voice must be cloned via /api/voices/minimax/clone first. Minimum 200 characters. > Stealth models: Two tiers, selected with stealth_model. 1.5 (default) is the standard model and bills 1× characters. 2.0 is Stealth 2.0 — our newest, most capable model with richer expression and stronger multilingual quality — and bills 2× characters against your Stealth balance. Both auto-chunk at ~1,900 char boundaries. Output: MP3, uploaded to CDN. > SRT subtitles: Setting generate_srt=true (ElevenLabs only) runs an extra forced-alignment pass to produce a word-timed subtitle file alongside the audio, and bills 1.2× the character count of your script. Without it, generation bills 1×. > Per-generation character limits: ProviderProfessionalUltimate ElevenLabs100,000200,000 Stealth45,000100,000 MiniMax100,000200,000 **Example Request (ElevenLabs)** ``` curl -X POST "https://api.algrow.online/api/generate-simple" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "script=Hello, welcome to our channel." \ -F "voice_id=21m00Tcm4TlvDq8ikWAM" \ -F "provider=elevenlabs" \ -F "stability=0.7" \ -F "similarity_boost=0.8" ``` **Example Request (Stealth)** ``` curl -X POST "https://api.algrow.online/api/generate-simple" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "script=Hello, welcome to our channel." \ -F "voice_id=Evan" \ -F "provider=stealth" \ -F "temperature=1.1" \ -F "speaking_rate=1.0" ``` **Example Request (Stealth 2.0 — bills 2x)** ``` curl -X POST "https://api.algrow.online/api/generate-simple" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "script=Hello, welcome to our channel." \ -F "voice_id=Evan" \ -F "provider=stealth" \ -F "stealth_model=2.0" \ -F "temperature=1.1" \ -F "speaking_rate=1.0" ``` **Response 200** ``` { "success": true, "job_id": "d477b67a-bb9d-403e-a6cf-bc8a82c93a61", "status": "pending", "status_detail": "pending", "status_detail_message": "Processing", "message": "Generation queued. Worker will process it.", "payload": { "text": "Hello, welcome to our channel.", "voice_id": "21m00Tcm4TlvDq8ikWAM", "voice_name": "21m00Tcm4TlvDq8ikWAM", "settings": { ... } } } ``` **Response Fields** | Field | Type | Description | |---|---|---| | success | boolean | Whether the request was accepted | | job_id | string | Unique job identifier. Use this to poll for status. | | status | string | Current job status: pending | | status_detail_message | string | Human-readable status message | | message | string | Informational message | | payload | object | Echo of the submitted parameters (text, voice_id, settings, etc.) | --- ## GET /api/job-status/:job_id Retrieve the current status and result of a generation job. Poll this endpoint every 2–3 seconds until status is completed or failed. Typical generation time is 3–15 seconds depending on script length. **Path Parameters** | Name | Type | Required | Description | |---|---|---|---| | job_id | string | Required | The job_id returned from POST /api/generate-simple | **Example Request** ``` curl "https://api.algrow.online/api/job-status/300040" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response — In Progress** ``` { "success": true, "job_id": "d477b67a-bb9d-403e-a6cf-bc8a82c93a61", "status": "processing", "status_detail": "processing", "status_detail_message": "Processing", "created_at": 1772482202.525 } ``` **Response — Completed** ``` { "success": true, "job_id": "d477b67a-bb9d-403e-a6cf-bc8a82c93a61", "status": "completed", "status_detail": "completed", "status_detail_message": "Completed", "created_at": 1772482202.525, "completed_at": 1772482210.831, "audio_url": "https://audio.algrow.online/elevenlabs/tts/user123/300040.mp3", "transcript_url": "https://audio.algrow.online/elevenlabs/tts/user123/transcript_300040.srt" } ``` **Response — Failed** ``` { "success": true, "job_id": "d477b67a-bb9d-403e-a6cf-bc8a82c93a61", "status": "failed", "status_detail": "failed", "status_detail_message": "Failed", "created_at": 1772482202.525, "completed_at": 1772482215.100, "error": "Async job failed: [TERMS_OF_SERVICE_VIOLATION] The text you are trying to use may violate our Terms of Service and has been blocked.", "error_code": "TERMS_OF_SERVICE_VIOLATION", "error_message": "The text you are trying to use may violate our Terms of Service and has been blocked." } ``` **Response Fields** | Field | Type | Description | |---|---|---| | success | boolean | Always true if the job was found | | job_id | string | The job identifier | | status | string | One of: pending, processing, completed, failed | | status_detail_message | string | Human-readable status: "Processing", "Completed", or "Failed" | | created_at | float | Unix timestamp when the job was created | | completed_at | float | Unix timestamp when the job finished (only present when done) | | audio_url | string | Permanent URL to the MP3 file. After generation, audio is uploaded to Cloudflare R2 and served via our CDN at audio.algrow.online — this URL will not expire. (Only when status=completed) | | transcript_url | string | Permanent URL to the SRT subtitle file. Only present when generate_srt=true was passed and the job completed successfully. Uses word-level timestamps via forced alignment. (ElevenLabs only) | | error | string | Error description (only when status=failed) | | error_code | string | Machine-readable error code, e.g. TERMS_OF_SERVICE_VIOLATION (only when status=failed, if available) | | error_message | string | Human-readable error message from the provider (only when status=failed, if available) | > Status lifecycle: pending → processing → completed or failed. Typical completion time is 3–15 seconds. --- ## GET /api/jobs List your generation jobs, sorted by creation time (newest first). Returns only jobs belonging to the authenticated user. Useful for debugging and monitoring your recent generations. **Example Request** ``` curl "https://api.algrow.online/api/jobs" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "success": true, "jobs": [ { "id": "300040", "provider": "elevenlabs", "status": "completed", "script_length": 340, "created_at": 1772482202.525, "completed_at": 1772482210.831 } ] } ``` --- ## GET /api/health Check API health and view your current job counts. No authentication required. Use this to verify the API is online and check how many concurrent slots you have available. **Example Request** ``` curl "https://api.algrow.online/api/health" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "status": "healthy", "active_jobs": 2, "total_jobs": 15 } ``` --- ## GET /api/voices/stealth List available Stealth voices. Returns built-in voices plus any voices you have cloned. **Example Request** ``` curl "https://api.algrow.online/api/voices/stealth" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "success": true, "voices": [ { "voice_id": "james", "name": "James", "language": "en", "description": "", "tags": [], "is_cloned": false }, { "voice_id": "my-custom-voice", "name": "My Custom Voice", "language": "en", "description": "Cloned from sample", "tags": ["custom"], "is_cloned": true } ] } ``` **Response Fields** | Field | Type | Description | |---|---|---| | voice_id | string | Use this as the voice_id parameter in /api/generate-simple | | name | string | Display name of the voice | | language | string | Language code (e.g. en, es, de) | | is_cloned | boolean | Whether this voice was cloned by you | --- ## POST /api/voices/clone Clone a custom Stealth voice from an audio sample. Upload up to 30 seconds of clear speech audio. The cloned voice can then be used with provider=stealth in the generate endpoint. > Clone limits by plan: Professional — 15 clones, Ultimate — unlimited. Requires Professional or Ultimate plan. **Request Parameters (multipart form-data)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | displayName | string | Required | — | Name for the cloned voice | | audioFile | file | Required | — | Audio sample (MP3, WAV, M4A, OGG, WEBM). Max 15MB, max 30 seconds. | | langCode | string | Optional | EN_US | Language of the audio. Values: EN_US, ES_ES, FR_FR, DE_DE, PT_BR, IT_IT, JA_JP, KO_KR, ZH_CN, RU_RU, AR_SA, PL_PL, NL_NL, HI_IN, HE_IL | | transcription | string | Optional | — | Text transcription of the audio sample (improves clone quality) | | description | string | Optional | — | Description of the voice | | tags | string | Optional | — | Comma-separated tags (e.g. narrator,deep) | | removeBackgroundNoise | string | Optional | false | Set to true to remove background noise from the sample | **Example Request** ``` curl -X POST "https://api.algrow.online/api/voices/clone" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "displayName=My Narrator" \ -F "langCode=EN_US" \ -F "audioFile=@sample.mp3" \ -F "transcription=Hello, this is a sample of my voice." \ -F "removeBackgroundNoise=true" ``` **Response** ``` { "success": true, "voice": { "voice_id": "my-narrator", "name": "My Narrator", "language": "EN_US", "description": "", "tags": [] } } ``` --- ## GET /api/voices/minimax List MiniMax voices you have cloned. MiniMax has no built-in catalog — every voice in your library was created via /api/voices/minimax/clone. Requires Professional or Ultimate plan. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | **Example Request** ``` curl "https://api.algrow.online/api/voices/minimax" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "success": true, "voices": [ { "voice_id": "user_abc123_my_narrator", "name": "My Narrator", "language": "English", "is_cloned": true, "created_at": "2026-06-01T12:00:00" } ] } ``` **Response Fields** | Field | Type | Description | |---|---|---| | voice_id | string | Use this as the voice_id parameter in /api/generate-simple with provider=minimax | | name | string | Display name you assigned when cloning | | language | string | Language tag assigned at clone time (e.g. English, Spanish) | | is_cloned | boolean | Always true — MiniMax voices are user-cloned only | | created_at | string | ISO-8601 timestamp when the voice was cloned | --- ## POST /api/voices/minimax/clone Clone a custom MiniMax voice from an audio sample. Upload a clear speech sample of at least 30 seconds. The cloned voice can then be used with provider=minimax in the generate endpoint. Requires Professional or Ultimate plan. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | | Content-Type | string | Auto | Set automatically by curl -F. If manual: multipart/form-data | > Clone limits by plan: Starter — 3 clones, Professional — 8 clones, Ultimate — 15 clones. Pro/Ultimate required to use this endpoint — the Starter limit is informational only. **Request Parameters (multipart form-data)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | voice_name | string | Required | — | Display name for the cloned voice | | audio_file | file | Required | — | Audio sample (MP3, WAV, M4A, OGG, WEBM). Max 5MB. Min 30 seconds. | | language | string | Optional | English | Language of the sample. Values: English, Chinese, Spanish, French, German, Italian, Portuguese, Polish, Russian, Ukrainian, Czech, Slovak, Croatian, Serbian, Bulgarian, Dutch, Romanian, Swedish, Norwegian, Afrikaans, Catalan, Greek, Lithuanian, Latvian, Vietnamese, Indonesian, Malay, Tagalog, Swahili, Hindi, Japanese, Korean, Danish, Finnish, Hungarian, Slovenian | | need_noise_reduction | string | Optional | true | Set to false to skip background-noise reduction on the sample | **Example Request** ``` curl -X POST "https://api.algrow.online/api/voices/minimax/clone" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "voice_name=My Narrator" \ -F "audio_file=@sample.mp3" \ -F "language=English" \ -F "need_noise_reduction=true" ``` **Response** ``` { "success": true, "voice": { "voice_id": "user_abc123_my_narrator", "name": "My Narrator", "language": "English", "is_cloned": true } } ``` **Response Fields** | Field | Type | Description | |---|---|---| | voice_id | string | Use this as the voice_id parameter in /api/generate-simple with provider=minimax | | name | string | Display name you supplied | | language | string | Language tag assigned to the clone | | is_cloned | boolean | Always true | --- ## DELETE /api/voices/minimax/{voice_id} Delete one of your cloned MiniMax voices. Removes the voice from your library and best-effort deletes it upstream. Requires Professional or Ultimate plan. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | **Path Parameters** | Name | Type | Required | Description | |---|---|---|---| | voice_id | string | Required | The voice_id of one of your cloned MiniMax voices (from /api/voices/minimax) | **Example Request** ``` curl -X DELETE "https://api.algrow.online/api/voices/minimax/user_abc123_my_narrator" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "success": true } ``` --- ## POST /api/caption-remover Remove captions and watermarks from a video. Accepts a publicly accessible video URL or a TikTok/Instagram Reel link — the API downloads and processes the video via AI, then returns a cleaned video uploaded to CDN. Credits are deducted upfront and refunded automatically if processing fails. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | video_url | string | Required | Direct video URL, TikTok link (https://www.tiktok.com/@user/video/{id}), or Instagram Reel link (https://www.instagram.com/reels/{id}/) | > Cost: 12 studio credits per minute of video (0.2 credits per second, rounded up). Max duration: 90 seconds. Processing can take up to 30 minutes depending on video length. **Example Request (Direct URL)** ``` curl -X POST "https://api.algrow.online/api/caption-remover" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url": "https://example.com/my-video.mp4"}' ``` **Example Request (TikTok)** ``` curl -X POST "https://api.algrow.online/api/caption-remover" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url": "https://www.tiktok.com/@username/video/1234567890123456789"}' ``` **Example Request (Instagram Reel)** ``` curl -X POST "https://api.algrow.online/api/caption-remover" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url": "https://www.instagram.com/reels/DWPuSZWATDC/"}' ``` **Response 200** ``` { "success": true, "job_id": "a5358a1c-388d-47a3-989e-755291031d77", "status": "pending", "duration_seconds": 28.5, "credit_cost": 6, "message": "Caption removal queued. Poll /api/job-status/{job_id} for progress." } ``` **Completed Job Response (via /api/job-status/:job_id)** ``` { "success": true, "job_id": "a5358a1c-388d-47a3-989e-755291031d77", "job_type": "caption_remover", "status": "completed", "output_url": "https://audio.algrow.online/api/video/caption_remover_abc123.mp4", "completed_at": 1774200779.08 } ``` --- ## POST /api/generate-image Generate AI images from a text prompt. Supports multiple models with optional reference images. Returns one or more image URLs uploaded to CDN. Credits are deducted upfront and refunded automatically if generation fails. Set fast=true to bypass the standard ladder for sub-30s outputs (3 credits instead of 1). **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | prompt | string | Required | — | Text description of the image to generate | | model | string | Optional | nano-banana-2 | Image model. See model table below. | | aspect_ratio | string | Optional | 16:9 | Output aspect ratio (e.g. 16:9, 9:16, 1:1, 4:3) | | reference_image_url | string | Optional | — | URL of a reference image for style guidance. Required for seedream-4.5-edit. | | fast | boolean | Optional | false | Fast mode — bypasses the standard provider ladder for sub-30s outputs. Costs 3 credits per image instead of 1. Same models and prompt; reference images still work. | **Available Models** | Model | Credits | Notes | |---|---|---| | gpt-image-2 | 1 | OpenAI GPT Image 2 — text-to-image, or image-to-image when reference_image_url is supplied | | nano-banana-2 | 1 | Fast general-purpose generation (default) | | nano-banana-pro | 1 | Higher quality, supports up to 8 reference images | | seedream-4.5-edit | 1 | Image editing — requires reference_image_url | | seedream-5.0-lite | 1 | Lightweight generation, optional reference | **Example Request** ``` curl -X POST "https://api.algrow.online/api/generate-image" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "a sunset over mountains, photorealistic", "model": "nano-banana-2", "aspect_ratio": "16:9"}' ``` **Example Request (fast mode)** ``` curl -X POST "https://api.algrow.online/api/generate-image" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "a sunset over mountains, photorealistic", "model": "nano-banana-2", "aspect_ratio": "16:9", "fast": true}' ``` **Response 200** ``` { "success": true, "job_id": "536c20ce-5ee6-4b8d-9f7f-3994014c896e", "status": "pending", "credits_used": 1, "message": "Image generation queued. Poll /api/job-status/{job_id} for progress." } ``` **Completed Job Response (via /api/job-status/:job_id)** ``` { "success": true, "job_id": "536c20ce-5ee6-4b8d-9f7f-3994014c896e", "job_type": "image", "status": "completed", "image_urls": ["https://audio.algrow.online/api/images/user123/1774201509_0_5b0a0050.png"], "completed_at": 1774201512.99 } ``` --- ## POST /api/generate-video Generate AI videos from a text prompt. Supports multiple models including Sora, Kling, Grok, and Veo. Returns a video URL uploaded to CDN. Credits are deducted upfront and refunded automatically if generation fails. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | prompt | string | Required | — | Text description of the video to generate | | model | string | Optional | sora-2 | Video model. See model table below. | | input_reference_url | string | Conditional | — | Reference image URL. Required for kling-2.6, grok-image-to-video, and veo3-fast. | | seconds | string | Optional | 4 | Video duration in seconds (Sora only). Values: 4, 8, 12 | | size | string | Optional | 720x1280 | Output resolution (Sora only). e.g. 720x1280, 1280x720 | | duration | string | Optional | 5 | Video duration (Kling only). Values: 5, 10 | | sound | boolean | Optional | false | Enable audio generation (Kling only). Doubles the credit cost. | | aspect_ratio | string | Optional | 9:16 | Output aspect ratio (Veo only). e.g. 9:16, 16:9 | **Available Models** | Model | Credits | Reference Image | Notes | |---|---|---|---| | sora-2 | 13 / 18 / 25 | Optional | OpenAI Sora. Cost varies by duration: 4s / 8s / 12s | | kling-2.6 | 8 – 30 | Required | Image-to-video. Cost varies by duration and sound. | | grok-image-to-video | 3 | Required | Grok image-to-video generation | | veo3-fast | 8 | Required | Google Veo 3.1 Fast video generation | **Example Request (Sora)** ``` curl -X POST "https://api.algrow.online/api/generate-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "a cat walking through flowers", "model": "sora-2", "seconds": "4", "size": "720x1280"}' ``` **Example Request (Kling with reference image)** ``` curl -X POST "https://api.algrow.online/api/generate-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "person waving at camera", "model": "kling-2.6", "input_reference_url": "https://example.com/photo.jpg", "duration": "5"}' ``` **Response 200** ``` { "success": true, "job_id": "e58464d7-ae8d-41b2-8c52-79bac92b1bb9", "status": "pending", "credit_cost": 13, "message": "Video generation queued. Poll /api/job-status/{job_id} for progress." } ``` **Completed Job Response (via /api/job-status/:job_id)** ``` { "success": true, "job_id": "e58464d7-ae8d-41b2-8c52-79bac92b1bb9", "job_type": "video", "status": "completed", "video_url": "https://audio.algrow.online/sora/videos/user123/video_abc123.mp4", "completed_at": 1774200881.01 } ``` > Processing time: Video generation can take 30 seconds to 30 minutes depending on the model and duration. Poll /api/job-status/:job_id every 5 seconds for updates. --- ## POST /api/thumbnails BETA Generate a YouTube thumbnail from a title and one or more reference thumbnails. The reference is vision-analysed and its design grammar is folded into an engineered prompt for your new title, then rendered. Returns a task_id immediately — poll /api/thumbnails/status/{task_id} for the image URLs. Costs 1 credit (or a flat 3 with fast: true), deducted upfront and refunded automatically if generation fails. > Private beta. Thumbnail generation is currently invite-only. Contact support to request access. Your API key must carry the generations scope. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | prompt | string | Required | — | The new video title to design the thumbnail for. | | reference_urls | string[] | Required | — | One or more references — each a YouTube video URL, a bare 11-char video id, or a direct image URL. The first is used as the primary design reference. At least one is required. | | model | string | Optional | nano-banana-pro | Image model. One of nano-banana-pro, nano-banana-2, seedream-5.0-lite, seedream-4.5-edit, gpt-image-2. | | aspect_ratio | string | Optional | 16:9 | Output aspect ratio (e.g. 16:9, 9:16, 1:1). | | resolution | string | Optional | 2K | Output resolution (1K, 2K, or 4K). | | reference_titles | object | Optional | — | Map of reference_url → the reference video's original title, so the prompt knows why that thumbnail worked for that title. | | find_outliers_first | boolean | Optional | false | Auto-fetch up to 3 topically-similar outlier thumbnails to use as extra references (topic taken from outlier_topic or prompt). | | custom_instructions | string | Optional | — | Extra art-direction appended to the engineered prompt with highest salience. | | fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat 3 credits per generation regardless of model. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "How I Built a $1M App in 30 Days", "reference_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "model": "nano-banana-pro"}' ``` **Response 200** ``` { "success": true, "task_id": "a1b2c3d4-...", "state": "pending", "model": "nano-banana-pro", "credits_used": 1, "message": "Thumbnail generation queued. Poll /api/thumbnails/status/{task_id} for progress." } ``` --- ## POST /api/thumbnails/channel-style BETA Generate a thumbnail in a specific channel's own design style. We resolve the channel, pull its top longform thumbnails, analyse them, pick the one whose design best fits your title, and recreate that treatment for your title (the channel's subjects never carry over — only its design language). Returns a task_id immediately — poll /api/thumbnails/status/{task_id} for the image. Costs 1 credit (or a flat 3 with fast: true), deducted upfront and refunded automatically on failure. > Private beta. Requires beta access and the generations scope. Contact support to request access. The compose step runs inline and can take 30–90 seconds before the task_id is returned. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | channel | string | Required | — | The channel to borrow the style from — a UC channel id, @handle, or channel URL. | | title | string | Required | — | The new video title to design the thumbnail for. | | model | string | Optional | nano-banana-pro | Image model. One of nano-banana-pro, nano-banana-2, seedream-5.0-lite, seedream-4.5-edit, gpt-image-2. | | custom_instructions | string | Optional | — | Extra art-direction applied on top of the matched channel style. | | fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat 3 credits per generation regardless of model. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/channel-style" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel": "@MrBeast", "title": "I Survived 50 Hours in the Arctic"}' ``` **Response 200** ``` { "success": true, "task_id": "a1b2c3d4-...", "state": "pending", "model": "nano-banana-pro", "credits_used": 1, "matched_thumb_url": "https://i.ytimg.com/vi/.../maxresdefault.jpg", "match_reason": "..." } ``` --- ## POST /api/thumbnails/edit BETA Edit an already-generated thumbnail with a plain-English instruction. The image goes back to the model as the canvas and only the requested change is applied — optional reference_urls are source material for the change ("insert THIS product"). Returns a task_id immediately — poll /api/thumbnails/status/{task_id} for the edited image. Costs 1 credit (or a flat 3 with fast: true), deducted upfront and refunded automatically on failure. Note: gpt-image-2 requests are served by nano-banana-pro for edits. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | base_image_url | string | Required | — | Direct http(s) URL of the thumbnail to edit — typically an image URL returned by a previous generation. | | instruction | string | Required | — | The change to make, in plain English (e.g. "make the text yellow"). Max 2000 characters. | | reference_urls | string[] | Optional | — | Extra images used as source material for the change (e.g. the product to insert). Each a YouTube video URL, a bare 11-char video id, or a direct image URL. | | model | string | Optional | nano-banana-pro | Image model. One of nano-banana-pro, nano-banana-2, seedream-5.0-lite, seedream-4.5-edit, gpt-image-2. gpt-image-2 is auto-served by nano-banana-pro for edits. | | aspect_ratio | string | Optional | 16:9 | Output aspect ratio (e.g. 16:9, 9:16, 1:1). | | resolution | string | Optional | 2K | Output resolution (1K, 2K, or 4K). | | fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat 3 credits per edit regardless of model. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/edit" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"base_image_url": "https://cdn.algrow.online/thumbnails/a1b2c3d4.png", "instruction": "make the text yellow"}' ``` **Response 200** ``` { "success": true, "task_id": "a1b2c3d4-...", "state": "pending", "model": "nano-banana-pro", "credits_used": 1, "message": "Thumbnail edit queued. Poll /api/thumbnails/status/{task_id} for progress." } ``` --- ## GET /api/thumbnails/models BETA List the thumbnail models available to your account, their per-generation credit cost, and the fast-mode flat rate. Free — use this for capability discovery instead of hardcoding model names. **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/models" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response 200** ``` { "success": true, "default_model": "nano-banana-pro", "models": [ {"model": "nano-banana-pro", "label": "Nano Banana Pro", "requires_reference": false, "credit_cost": 1}, {"model": "seedream-4.5-edit", "label": "Seedream 4.5 Edit", "requires_reference": true, "credit_cost": 1} ], "fast_mode": {"param": "fast", "credit_cost": 3} } ``` --- ## GET /api/thumbnails/status/:task_id BETA Retrieve the status and result of a thumbnail generation. Poll every 2–3 seconds until state is success or fail. Typical generation time is 30–90 seconds. On a failure, the credits charged at submit are refunded automatically. **Path Parameters** | Name | Type | Required | Description | |---|---|---|---| | task_id | string | Required | The task_id returned from POST /api/thumbnails. | **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/status/a1b2c3d4-..." \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response — Success** ``` { "success": true, "task_id": "a1b2c3d4-...", "state": "success", "images": ["https://...thumbnail.png"], "cost_time_ms": 42137 } ``` **Response — Failed** ``` { "success": true, "task_id": "a1b2c3d4-...", "state": "fail", "error": "Generation failed" } ``` **Response Fields** | Field | Type | Description | |---|---|---| | state | string | Generation state: a pending value (waiting/queuing/generating), success, or fail. | | images | string[] | Generated thumbnail URLs (only when state=success). | | error | string | Error description (only when state=fail). | --- ## POST /api/thumbnails/outliers BETA Find topically-similar, high-performing reference thumbnails for a topic. Free (a database lookup, no credits). Pass the returned thumbnail_url values straight into POST /api/thumbnails as reference_urls to build a thumbnail in a proven style. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | topic | string | Required | — | The topic/niche to find outlier thumbnails for (e.g. minecraft survival). | | content_type | string | Optional | longform | longform or shorts. | | limit | integer | Optional | 12 | Number of results to return. | | min_outlier_score | number | Optional | 2.0 | Minimum outlier score (how far a video outperforms its channel baseline). | | page | integer | Optional | 1 | Page number for pagination. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/outliers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"topic": "minecraft survival", "limit": 12}' ``` --- ## POST /api/thumbnails/channel-videos BETA Page through a channel's LONGFORM upload catalogue (shorts excluded) — newest first, 50 per page, each video with its thumbnail, title and view count, plus the channel's recent-median baseline (median_views) for outlier scoring (view_count / median_views). Free (1–2 YouTube quota units per page, no credits). Pick a thumbnail_url and pass it to POST /api/thumbnails as a reference. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | channel | string | Required | — | Channel @handle, URL, or UC id. | | page_token | string | Optional | — | next_page_token from the previous response. | | playlist_id | string | Optional | — | playlist_id from the previous response — page tokens are playlist-specific. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/channel-videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel": "@MrBeast"}' ``` --- ## GET /api/thumbnails/saved-channels BETA List your saved channel styles (identity only — name, handle, avatar, channel id). The catalogue itself is always fetched live via POST /api/thumbnails/channel-videos. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/saved-channels" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/thumbnails/saved-channels BETA Save a channel style for one-click reuse. Snapshots the channel's name, handle and avatar (1 YouTube quota unit). Upserts by channel. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | channel | string | Required | — | Channel @handle, URL, or UC id. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/saved-channels" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel": "@MrBeast"}' ``` --- ## DELETE /api/thumbnails/saved-channels/{channel_id} BETA Remove a channel from your saved styles. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl -X DELETE "https://api.algrow.online/api/thumbnails/saved-channels/UCX6OQ3DkcsbYNE6H8uQQuVA" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## GET /api/thumbnails/instruction-presets BETA List your saved custom-instruction presets. Apply one by passing its instructions as custom_instructions to the compose/generate endpoints. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/instruction-presets" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/thumbnails/instruction-presets BETA Save (or update, by name) a reusable custom-instruction preset for thumbnail generation. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | name | string | Required | — | Preset name (max 60 chars). Saving an existing name updates it. | | instructions | string | Required | — | The custom-instructions text (max 2000 chars). | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/instruction-presets" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Dark moody", "instructions": "dark moody palette, dramatic rim light"}' ``` --- ## DELETE /api/thumbnails/instruction-presets/{preset_id} BETA Delete a custom-instruction preset by id (from the list endpoint). Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl -X DELETE "https://api.algrow.online/api/thumbnails/instruction-presets/12" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/thumbnails/extract-video BETA Resolve a YouTube URL or video ID to its title, channel, and max-resolution thumbnail. Free (no credits). Use the returned thumbnail_url as a reference for POST /api/thumbnails. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | url_or_id | string | Required | A YouTube watch URL, short URL, or bare 11-character video id. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/extract-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url_or_id": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}' ``` --- ## POST /api/thumbnails/analyze BETA Vision-analyse a thumbnail image into a structured design breakdown (composition, palette, text, focal points). Free (no credits). > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | image_url | string | Required | Public URL of the thumbnail image to analyse. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/analyze" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"}' ``` --- ## POST /api/thumbnails/compose BETA Engineer an image-gen prompt from a title + a single reference, without generating. Free, synchronous. Stateless — there is no style id; save the returned prompt and pass it to POST /api/thumbnails as final_prompt to render. > Private beta. Requires beta access and the generations scope. Two-step flow: compose → review/edit the prompt → POST /api/thumbnails with final_prompt. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | title | string | Required | Your new video title. | | reference_url | string | Required | A YouTube URL, 11-char video id, or direct image URL. | | reference_title | string | Optional | The reference's original video title (improves mapping). | | custom_instructions | string | Optional | Extra art-direction. | **Response 200** ``` { "success": true, "prompt": "A cinematic close-up …", "reference_url": "https://i.ytimg.com/vi/…/maxresdefault.jpg" } ``` --- ## POST /api/thumbnails/compose-channel BETA Channel-style compose without generating — resolve the channel, analyse its top thumbnails, match the best design to your title. Free, synchronous (~30–90s). Returns the engineered prompt + the channel's source_thumb_urls; pass both to POST /api/thumbnails (final_prompt + reference_urls) to render. Stateless. > Private beta. Requires beta access and the generations scope. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | channel | string | Required | UC channel id, @handle, or channel URL. | | title | string | Required | Your new video title. | | custom_instructions | string | Optional | Extra art-direction. | **Response 200** ``` { "success": true, "prompt": "…", "channel_id": "UC…", "matched_title": "…", "source_thumb_urls": ["https://…"] } ``` --- ## GET /api/thumbnails/channel-presets BETA List your saved per-channel thumbnail presets — instructions, subject face, style references, and generation defaults, saved together under a label. Returns the 50 most recent. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/channel-presets" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Example Response** ``` { "success": true, "presets": [ { "id": 12, "label": "Main channel", "instructions": "high contrast, single subject, no text", "face_url": "https://audio.algrow.online/studio/references/ab12/face.png", "channel_style_name": "Documentary", "style_reference_urls": ["https://i.ytimg.com/vi/abc123/maxresdefault.jpg"], "aspect_ratio": "16:9", "resolution": "2K", "model": "nano-banana-pro" } ] } ``` --- ## POST /api/thumbnails/channel-presets BETA Save a per-channel preset, or update an existing one by reusing its label. Only the fields you send are written; on update, everything you leave out keeps its current value. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | label | string | Required | — | Preset label. Sending an existing label updates that preset. | | instructions | string | Optional | — | Custom instructions applied to every render made with this preset. | | face_url | string | Optional | — | URL of the subject face to reuse. Takes precedence over face_image_b64. | | face_image_b64 | string | Optional | — | Base64 face image (raw or a data: URL). Uploaded to storage and saved as face_url when no face_url is given. | | content_type | string | Optional | image/png | MIME type for face_image_b64. | | channel_style_id | string | Optional | — | Saved channel-style id to render in. | | channel_style_name | string | Optional | — | Display name for the channel style. | | style_reference_urls | array | Optional | — | Reference thumbnail URLs that define the look. | | aspect_ratio | string | Optional | — | Default aspect ratio for renders, e.g. 16:9. | | resolution | string | Optional | — | Default resolution, e.g. 2K. | | model | string | Optional | — | Default image model. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/channel-presets" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"label": "Main channel", "instructions": "high contrast, single subject, no text", "aspect_ratio": "16:9"}' ``` **Example Response** ``` { "success": true, "preset": {"id": 12, "label": "Main channel", "instructions": "high contrast, single subject, no text", "aspect_ratio": "16:9"} } ``` --- ## DELETE /api/thumbnails/channel-presets/{preset_id} BETA Delete a per-channel preset by id (from the list endpoint). Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl -X DELETE "https://api.algrow.online/api/thumbnails/channel-presets/12" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Example Response** ``` { "success": true, "deleted": true } ``` --- ## GET /api/thumbnails/history BETA Your generated-thumbnail history, newest first. One shared history across every path — the browser Studio, the MCP tools, and this API all appear. Each item carries the final image URL(s), the title it was made for, model, aspect ratio and created_at. Query params: limit (default 24, max 60) and offset; has_more signals another page. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Example Request** ``` curl "https://api.algrow.online/api/thumbnails/history?limit=24&offset=0" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Example Response** ``` { "success": true, "has_more": true, "items": [ { "id": 1591, "title": "DON'T Make These 5 Going-Gray Mistakes", "image_urls": ["https://audio.algrow.online/studio/images/thumbnails/….png"], "model": "gpt-image-2", "aspect_ratio": "16:9", "source": "studio", "created_at": "2026-08-15T13:17:25" } ] } ``` --- ## POST /api/thumbnails/detect-people BETA Check whether a reference image contains a person, so you can offer to swap in a real face before rendering. Cheaper and faster than a full analysis, and cached per image for six hours. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | image_url | string | Required | — | Reference image URL. YouTube thumbnail URLs and Algrow-hosted references both work. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/detect-people" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"}' ``` **Example Response** ``` { "success": true, "has_person": true, "people": [{"description": "man, centre frame, facing camera"}], "cached": false } ``` --- ## POST /api/thumbnails/crop-reference BETA Crop a region out of a reference image and store it as a character reference. The crop happens server-side, so it works on images a browser canvas is not allowed to read back. Returns a hosted URL you can pass straight to generation as a character reference. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | image_url | string | Required | — | Image to crop. | | crop | object | Required | — | Crop rectangle in normalized coordinates relative to the image's natural size: {"x": 0.2, "y": 0.1, "w": 0.3, "h": 0.4}, each between 0 and 1. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/crop-reference" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", "crop": {"x": 0.2, "y": 0.1, "w": 0.3, "h": 0.4}}' ``` **Example Response** ``` { "success": true, "url": "https://audio.algrow.online/studio/references/ab12cd34/crop-9f2a.png" } ``` --- ## POST /api/thumbnails/search-faces BETA Search the web for photos of a named person so you can use one as a character reference. Pass the chosen photo through /api/thumbnails/import-face before rendering — some image hosts block our downloader. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | query | string | Required | — | Person to search for. Trimmed to 120 characters. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/search-faces" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "Serena Williams"}' ``` **Example Response** ``` { "success": true, "results": [ { "thumb": "https://example.com/thumb.jpg", "full": "https://example.com/full.jpg", "title": "Serena Williams in 2025", "source": "example.com" } ] } ``` --- ## POST /api/thumbnails/import-face BETA Copy an external face photo into Algrow storage and return a stable URL the render pipeline can always fetch. Run every search result through this before using it as a reference. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | image_url | string | Required | — | Image to import. | | fallback_url | string | Optional | — | Second URL to try when the first host blocks the download — e.g. the search result's thumbnail. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/import-face" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://example.com/full.jpg", "fallback_url": "https://example.com/thumb.jpg"}' ``` **Example Response** ``` { "success": true, "url": "https://audio.algrow.online/studio/references/ab12cd34/face-search-7c1e.png" } ``` --- ## POST /api/thumbnails/swap-face BETA Put a real face onto a thumbnail you already rendered. Queues like any other generation and returns a task_id to poll. Costs 1 credit, or 3 with fast enabled. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | base_image_url | string | Required | — | The rendered thumbnail to edit. | | face_url | string | Required | — | Face to place on it. Use an Algrow-hosted URL from /api/thumbnails/import-face or /api/thumbnails/crop-reference. | | model | string | Optional | nano-banana-pro | Image model used for the swap. | | aspect_ratio | string | Optional | 16:9 | Output aspect ratio. | | resolution | string | Optional | 2K | Output resolution. | | fast | boolean | Optional | false | Prioritised render. Costs 3 credits instead of 1. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/swap-face" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"base_image_url": "https://audio.algrow.online/studio/images/ab12/render.png", "face_url": "https://audio.algrow.online/studio/references/ab12/face.png"}' ``` **Example Response** ``` { "success": true, "task_id": "tsk_9f2a41c8", "state": "pending", "fast": false, "credits_used": 1, "message": "Face swap queued. Poll /api/thumbnails/status/{task_id} for progress." } ``` > Poll GET /api/thumbnails/status/{task_id} for the finished image. Credits are refunded automatically if the swap fails. --- ## POST /api/thumbnails/feedback BETA Record a thumbs up or down on a generated thumbnail, with an optional comment. Sending the same task_id again updates the existing rating. Free. > Private beta. Requires beta access and the generations scope. Contact support to request access. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | rating | string | Required | — | up or down. | | task_id | string | Optional | — | Task id of the generation being rated. Rating the same task again updates it. | | image_url | string | Optional | — | URL of the rated image, when you don't have the task id. | | feedback | string | Optional | — | Free-text comment (max 2,000 characters). | **Example Request** ``` curl -X POST "https://api.algrow.online/api/thumbnails/feedback" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"task_id": "tsk_9f2a41c8", "rating": "down", "feedback": "face came out blurry"}' ``` **Example Response** ``` { "success": true } ``` --- ## GET /api/channel-monetization/:channel_id Full monetization profile for one channel — what it sells, each method with its own evidence + source link, products, and store URLs. If the channel isn't classified yet it runs the classifier live (≤60s) and persists the result; pass ?skip_live=true to skip that and get an immediate unclassified response. **Path Parameters** | Name | Type | Required | Description | |---|---|---|---| | channel_id | string | Required | YouTube channel id (UC…, 24 chars). Use /api/channels/resolve for handles/URLs. | **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | skip_live | boolean | Optional | false | Skip the live classifier and return immediately (classified:false if not already known). | **Example Request** ``` curl "https://api.algrow.online/api/channel-monetization/UCX6OQ3DkcsbYNE6H8uQQuVA" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/youtube-scraper-fast Synchronous YouTube channel scrape via the Data API v3 — no job queue, no polling. Returns channel metadata + videos (and optional comments) inline in ~2–5s, the same shape as the queued /api/youtube-scraper result. Transcripts are NOT supported here (use the queued endpoint for those). **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | url | string | Required | — | A YouTube channel URL (youtube.com or youtu.be). | | video_type | string | Optional | both | shorts, videos, or both. | | sort | string | Optional | recent | recent or popular. | | max_videos | integer | Optional | 20 | 1–100. | | include_comments | boolean | Optional | false | Include top comments per video. | | max_comments | integer | Optional | 100 | 1–100, when include_comments is true. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/youtube-scraper-fast" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://youtube.com/@MrBeast", "video_type": "videos", "max_videos": 20}' ``` **Response 200** ``` { "success": true, "status": "completed", "result": { … channel + videos … } } ``` --- ## POST /api/analyze-video Analyze a YouTube video with AI vision — hooks, pacing, visual storytelling, on-screen text, B-roll usage, content strategy, and any other prompt-driven breakdown. Returns structured analysis text. Currently free during preview — no credit cost, no plan requirement — only an API key and the per-user concurrency cap apply. Repeat prompts on the same video within 2 hours reuse a cached upload automatically (faster on the backend, returns cached: true). **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | video_url | string | Required | YouTube video URL. Accepts watch links, youtu.be short links, and Shorts URLs. | | prompt | string | Required | Plain-English instruction describing what to analyze. Max 4,000 characters. | | media_resolution | string | Optional | Analysis fidelity: low (default, recommended for hook / pacing / strategy prompts) or default (higher visual detail at greater backend cost — useful when fine on-screen text or subtle visual cues matter). | > Limits: Maximum video length is 3 hours. Live streams, private, deleted, and age-restricted videos are rejected with clear error messages. Concurrency cap applies (5 / 10 / 20 active jobs by tier). **Example Request (Hook breakdown)** ``` curl -X POST "https://api.algrow.online/api/analyze-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "prompt": "Break down the hook in the first 3 seconds. What grabs attention?", "media_resolution": "low" }' ``` **Example Request (Pacing analysis on a Short)** ``` curl -X POST "https://api.algrow.online/api/analyze-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://youtube.com/shorts/abc123XYZ", "prompt": "Identify the pacing, energy shifts, on-screen text timing, and where attention is most likely to drop." }' ``` **Response 200** ``` { "success": true, "job_id": "f12d4a8b-2e1f-44e1-9aa1-2dfa20c5c7d3", "status": "pending", "duration_seconds": 187.4, "message": "Video analysis queued. Poll /api/job-status/{job_id} for progress." } ``` **Completed Job Response (via /api/job-status/:job_id)** ``` { "success": true, "job_id": "f12d4a8b-2e1f-44e1-9aa1-2dfa20c5c7d3", "job_type": "video_analysis", "status": "completed", "analysis_text": "The opening 3 seconds use a hard cut from black to a wide shot of...", "duration_seconds": 187.4, "video_id": "dQw4w9WgXcQ", "cached": false, "completed_at": 1774203012.45 } ``` > Processing time: Typically 5–25 seconds for Shorts, 30–90 seconds for 5-minute videos, several minutes for hour-long content. The first analysis on a video is slower than follow-up prompts on the same video (which hit the cache and skip download + upload). Poll /api/job-status/:job_id every 5 seconds for updates. > Caching: When you run multiple prompts on the same video_url within 2 hours, the source video is reused from cache — the response includes cached: true. Cache is keyed per (user, video) so each user pays the cold-path cost once per video per 2 hours. --- ## POST /api/download-video Download a YouTube video, audio track, or subtitle file to Algrow’s storage and return a stable public URL the caller can hand to a browser. Each unique (video, format, quality, time-range) tuple is cached for ~30 days; repeat downloads are instant from cache. Requires the generations scope. Hourly cap is per-user — Starter 10/hr, Professional 100/hr, Ultimate unlimited. Capped at 3-hour source duration and 500 MB output. **Request Body (JSON)** | Name | Type | Required | Description | |---|---|---|---| | video_url | string | Required | YouTube video URL. Accepts watch links, youtu.be short links, and Shorts URLs. TikTok / Instagram are not supported here. | | format | string | Optional | What to produce: video (mp4, default), audio (mp3), or subtitles (srt — English; human-authored when available, auto-generated otherwise). | | quality | string | Optional | Video height: 360p, 480p, 720p (default), or 1080p. Ignored when format is audio or subtitles. | | start | string \| number | Optional | Clip start timestamp. Accepts "1:30", "00:01:30", "90", "90s", or a raw number of seconds. Omit for the start of the video. | | end | string \| number | Optional | Clip end timestamp. Same formats as start. Omit for the end of the video. Ignored when format is subtitles (always returns the full transcript). | > Performance. Cold downloads typically run ~60–120s for a full video (proxy-bandwidth limited at ~550 KB/s). Clipped video / audio downloads scale with clip length — a 30s slice of a long video lands in ~15s. Subtitle fetches finish in ~10–15s regardless of source length. Cached hits return in <1s. > Hourly cap by plan. Counted per user (not per API key) and ticked only on successful 200 responses — cached repeats count, but a 400 like “video unavailable” does not. Limits: Starter 10/hr, Professional 100/hr, Ultimate unlimited. When you hit the cap the endpoint returns 429 with the wait time and a link to Subscription settings to upgrade. **Example Request (full video, default 720p)** ``` curl -X POST "https://api.algrow.online/api/download-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }' ``` **Example Request (audio mp3 of a 30s clip)** ``` curl -X POST "https://api.algrow.online/api/download-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "format": "audio", "start": "1:00", "end": "1:30" }' ``` **Example Request (1080p, full video)** ``` curl -X POST "https://api.algrow.online/api/download-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "quality": "1080p" }' ``` **Example Request (subtitles SRT)** ``` curl -X POST "https://api.algrow.online/api/download-video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "format": "subtitles" }' ``` **Response 200** ``` { "success": true, "download_url": "https://audio.algrow.online/downloads/dQw4w9WgXcQ.mp4", "video_id": "dQw4w9WgXcQ", "title": "Rick Astley - Never Gonna Give You Up", "duration_seconds": 213.0, "size_bytes": 23456789, "cached": false, "format": "video", "quality": 720, "start_seconds": null, "end_seconds": null } ``` > Returned URL. The download_url points at Algrow’s R2 bucket (audio.algrow.online) and ships with Content-Disposition attachment so browsers trigger a save instead of inline playback. URLs are public and stable for the lifetime of the cache (~30 days); safe to share or embed. --- ## GET /api/terminated-channels/search Search terminated/deleted YouTube channels. Returns channel metadata, growth metrics at time of termination, and up to 3 top videos per channel. Supports keyword matching and advanced filters. Available on all plans. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | q | string | Required | — | Search query. Matches against channel titles and video titles. Comma-separated for multiple keywords. | | languages | string | Optional | — | Filter by language. Comma-separated (e.g. English,Spanish) | | sort | string | Optional | date_desc | Sort field and direction. Format: {field}_{asc\|desc}. Fields: subs, views, videos, age, views_24h, subs_24h, views_48h, date, similarity (when using q) | | page | integer | Optional | 1 | Page number (1-indexed, max 20) | | per_page | integer | Optional | 20 | Results per page (max 50) | | min_subs | integer | Optional | — | Minimum subscriber count | | max_subs | integer | Optional | — | Maximum subscriber count | | min_views | integer | Optional | — | Minimum total view count | | max_views | integer | Optional | — | Maximum total view count | | min_avg_views | integer | Optional | — | Minimum average views per video | | max_avg_views | integer | Optional | — | Maximum average views per video | | min_age | integer | Optional | — | Minimum channel age in days | | max_age | integer | Optional | — | Maximum channel age in days | | min_uploads | integer | Optional | — | Minimum number of videos | | max_uploads | integer | Optional | — | Maximum number of videos | | monetized | string | Optional | — | Filter by monetization status: yes or no | | min_views_24h | integer | Optional | — | Minimum views gained in last 24h before termination | | max_views_24h | integer | Optional | — | Maximum views gained in last 24h before termination | | min_views_48h | integer | Optional | — | Minimum views gained in last 48h before termination | | max_views_48h | integer | Optional | — | Maximum views gained in last 48h before termination | **Example Requests** ``` # Search for terminated gaming channels curl "https://api.algrow.online/api/terminated-channels/search?q=gaming&languages=English&per_page=10" \ -H "Authorization: Bearer YOUR_API_KEY" # High-sub terminated gaming channels sorted by subscribers curl "https://api.algrow.online/api/terminated-channels/search?q=gaming&min_subs=100000&sort=subs_desc" \ -H "Authorization: Bearer YOUR_API_KEY" # Recently terminated motivation channels curl "https://api.algrow.online/api/terminated-channels/search?q=motivation&sort=date_desc&per_page=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response 200** ``` { "success": true, "page": 1, "per_page": 20, "count": 20, "channels": [ { "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "channel_title": "Deleted Gaming Channel", "subscriber_count": 340000, "view_count": 95000000, "avg_views_per_video": 2100000, "total_videos": 45, "primary_language": "English", "monetized": true, "is_low_quality": false, "thumbnail_url": "https://yt3.ggpht.com/...", "first_upload_date": "2025-06-12", "terminated_date": "2026-03-10", "terminated_days_ago": 15, "view_increase_24h": 120000, "sub_increase_24h": 800, "view_increase_48h": 210000, "sub_increase_48h": 1400, "similarity_score": 85, "recent_videos": [ { "video_id": "abc123", "title": "Most Viewed Video Title", "view_count": 12000000, "thumbnail_url": "https://audio.algrow.online/thumbnails/...", "url": "https://www.youtube.com/watch?v=abc123" } ] } ] } ``` **Response Fields** | Field | Type | Description | |---|---|---| | channel_id | string | YouTube channel ID | | channel_title | string | Channel name at time of termination | | subscriber_count | integer | Subscriber count at termination | | view_count | integer | Total channel views at termination | | avg_views_per_video | integer | Average views per video | | total_videos | integer | Number of videos on the channel | | primary_language | string | Detected content language | | monetized | boolean | Whether the channel was monetized | | is_low_quality | boolean | Whether the channel was flagged as low quality | | thumbnail_url | string | Channel profile picture URL | | first_upload_date | string | Date of the channel's first upload (ISO 8601) | | terminated_date | string | Date the channel was terminated (ISO 8601) | | terminated_days_ago | integer | Days since the channel was terminated | | view_increase_24h | integer\|null | Views gained in last 24h before termination | | sub_increase_24h | integer\|null | Subscribers gained in last 24h before termination | | view_increase_48h | integer\|null | Views gained in last 48h before termination | | sub_increase_48h | integer\|null | Subscribers gained in last 48h before termination | | similarity_score | integer\|null | Similarity score (0–100) when using q search | | recent_videos | array | Top 3 videos by views with video_id, title, view_count, thumbnail_url, url | --- ## GET /api/search Search everything on YouTube in one call — videos, channels, and playlists in the same result list, each tagged with its type. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | q | string | Required | — | Search query. | | type | string | Optional | all | all, video, channel, playlist, movie. | | sort_by | string | Optional | relevance | relevance, view_count, upload_date, rating. | | upload_date | string | Optional | all | all, hour, today, week, month, year. | | duration | string | Optional | all | short (<4m), medium (4–20m), long (>20m). Videos only. | | published_within_days | integer | Optional | — | Narrow videos to those posted in the last N days. Finer than upload_date — use for phrasings like “last 3 days”. Auto-picks the tightest native bucket, fetches a larger batch, and post-filters. | | limit | integer | Optional | 30 | Max results (1–100). | **Example Response** ``` { "success": true, "query": "the rise and fall", "limit": 20, "estimated_results": 1421503, "count": 20, "has_more": true, "results": [ { "type": "video", "video_id": "uSCHW7vAq-s", "title": "The Rise and Fall of America's Most Infamous Detective Agency", "url": "https://www.youtube.com/watch?v=uSCHW7vAq-s", "channel_name": "Wendigang", "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "published_text": "2 days ago", "duration_text": "49:50", "duration_seconds": 2990, "view_count": 381848, "view_count_text": "381,848 views", "thumbnail_url": "https://i.ytimg.com/vi/uSCHW7vAq-s/hq720.jpg", "description_snippet": "..." }, { "type": "channel", "channel_id": "UCnwUjPK7dXety-AJ4fNw_RQ", "name": "The Paint Explainer", "handle": "@ThePaintExplainer", "url": "https://www.youtube.com/channel/UCnwUjPK7dXety-AJ4fNw_RQ", "subscriber_count": 1840000, "subscriber_count_text": "1.84M subscribers", "description_snippet": "...", "thumbnail_url": "..." }, { "type": "playlist", "playlist_id": "PLbdSi72ah3puMBGa4eLQMNKn4OqaVPsHF", "title": "All Casually Explained", "url": "https://www.youtube.com/playlist?list=PLbdSi72ah3puMBGa4eLQMNKn4OqaVPsHF", "channel_name": "Casually Explained", "channel_id": "UCr3cBLTYmIK9kY0F_OdFWFQ", "video_count": 85, "video_count_text": "85 videos", "thumbnail_url": "..." } ] } ``` **Example Request** ``` # Top-viewed "rise and fall" videos posted in the last 3 days curl -G "https://algrow.online/api/search" \ -H "Authorization: Bearer algrow_..." \ --data-urlencode "q=the rise and fall" \ -d "type=video&sort_by=view_count&published_within_days=3&limit=20" ``` --- ## GET /api/channels/:channel_id/about Everything from a channel's About page in one call — name, description, subscriber and view counts, country, language, join date, topics, social links, trailer, banner, and more. **Path Parameters** | Name | Type | Description | |---|---|---| | channel_id | string | 24-char YouTube channel ID (starts with UC). | **Example Response** ``` { "success": true, "channel": { "channel_id": "UCXoyny_UIW-02UwiNPUZT-w", "title": "The Geo Network", "handle": "@TheGeoNetwork", "description": "...", "url": "https://www.youtube.com/channel/UCXoyny_UIW-02UwiNPUZT-w", "country": { "code": "TR", "name": "Türkiye" }, "default_language": "en", "avatar_url": "...", "banner_url": "...", "subscriber_count": { "raw": 125000, "display": "125K" }, "view_count": { "raw": 27325762, "display": "27.3M" }, "video_count": { "raw": 95, "display": "95" }, "avg_views_per_video": { "raw": 287639, "display": "287.6K" }, "joined": { "iso": "2019-10-12T00:00:00+00:00", "formatted": "Oct 12, 2019", "relative": "6 years ago", "age_days": 2378 }, "privacy_status": "public", "made_for_kids": false, "hidden_subscribers": false, "keywords": "...", "topic_categories": ["Military", "Politics"], "trailer_video_id": "abc123", "uploads_playlist_id": "UUXoyny_UIW-02UwiNPUZT-w", "tabs": ["Home", "Videos", "Shorts", "Playlists", "Posts"], "has_contact_email": true, "social_links": [ { "platform": "instagram", "url": "instagram.com/thegeonetwork_tgn" } ], "available_countries_count": 245 } } ``` **Example Request** ``` curl -H "Authorization: Bearer algrow_..." \ "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/about" ``` --- ## GET /api/formats/:slug/overview Aggregate stats for one of Algrow's 24 canonical channel formats — how many channels are tracked in the niche, average and median subscriber counts, and the biggest channels. The channel About endpoint returns each channel's format slug; feed it here. **Path Parameters** | Name | Type | Description | |---|---|---| | slug | string | One of the 24 canonical format slugs (e.g. documentary, kids_content, challenge_videos). | **Example Response** ``` { "success": true, "format": { "slug": "challenge_videos", "display_name": "Challenge Videos" }, "channels_tracked": 18265, "avg_subscribers": 70840, "median_subscribers": 7060, "top_channels": [ { "channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "name": "MrBeast", "subscribers": 511000000, "profile_picture": "...", "url": "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA" } ] } ``` **Example Request** ``` curl -H "Authorization: Bearer algrow_..." \ "https://algrow.online/api/formats/challenge_videos/overview" ``` --- ## GET /api/channels/:channel_id/daily-analytics See how a channel has grown day-by-day across any date range you pick — subscribers, views, and uploads, plus a summary with total growth over the window. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | start_date | string | Optional | 30 days ago | ISO YYYY-MM-DD. | | end_date | string | Optional | today | ISO YYYY-MM-DD. Max window 365 days (clamped). | **Example Response** ``` { "success": true, "channel_id": "UCXoyny_UIW-02UwiNPUZT-w", "channel_title": "The Geo Network", "channel_type": "longform", "start_date": "2026-03-16", "end_date": "2026-04-15", "days_requested": 31, "days_with_data": 30, "summary": { "sub_growth": 12500, "view_growth": 8450000, "video_growth": 12, "starting_subs": 125000, "ending_subs": 137500, "starting_views": 27000000, "ending_views": 35450000 }, "days": [ { "date": "2026-03-16", "total_subs": 125000, "total_views": 27000000, "total_videos": 95, "sub_increase_24h": 420, "view_increase_24h": 215000, "video_increase_24h": 0 } ] } ``` **Example Request** ``` curl -G "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/daily-analytics" \ -H "Authorization: Bearer algrow_..." \ -d "start_date=2026-03-01&end_date=2026-04-15" ``` --- ## GET /api/channels/:channel_id/videos Browse a channel's longform uploads, newest first — with titles, view counts, durations, upload dates, and thumbnails. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | limit | integer | Optional | 30 | Max videos (1–100). | **Example Response** ``` { "success": true, "channel_id": "UCXoyny_UIW-02UwiNPUZT-w", "limit": 30, "count": 30, "has_more": true, "videos": [ { "video_id": "R-NK5pa7KAU", "title": "The Collapse Has Begun...", "url": "https://www.youtube.com/watch?v=R-NK5pa7KAU", "published_text": "5 hours ago", "duration_text": "18:31", "duration_seconds": 1111, "view_count": 106657, "view_count_text": "106,657 views", "thumbnail_url": "..." } ] } ``` **Example Request** ``` curl -G "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/videos" \ -H "Authorization: Bearer algrow_..." -d "limit=50" ``` --- ## GET /api/channels/:channel_id/shorts Browse a channel's Shorts, newest first — the real Shorts tab, not short-duration regular videos. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | limit | integer | Optional | 30 | Max shorts (1–100). | **Example Response** ``` { "success": true, "channel_id": "UCXoyny_UIW-02UwiNPUZT-w", "limit": 30, "count": 3, "has_more": false, "shorts": [ { "video_id": "5YKwSHccYTA", "title": "Detaylı tarif...", "url": "https://www.youtube.com/shorts/5YKwSHccYTA", "view_count": 942, "view_count_text": "942 views", "thumbnail_url": "..." } ] } ``` **Example Request** ``` curl -H "Authorization: Bearer algrow_..." \ "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/shorts?limit=20" ``` --- ## GET /api/channels/:channel_id/playlists See every public playlist on a channel — title, description, video count, and thumbnail for each. Paginates in batches of 50. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | page_token | string | Optional | — | Pass the next_page_token from a previous response for subsequent pages. | **Example Response** ``` { "success": true, "channel_id": "UCXoyny_UIW-02UwiNPUZT-w", "count": 17, "next_page_token": null, "playlists": [ { "playlist_id": "PL069L7PbBcLx_O3Zv3gzUbScKtRrcMR76", "title": "pide tarifleri", "description": "", "published_at": "2020-08-31T19:26:11Z", "video_count": 4, "thumbnail_url": "...", "url": "https://www.youtube.com/playlist?list=PL069L7PbBcLx_O3Zv3gzUbScKtRrcMR76" } ] } ``` **Example Request** ``` curl -H "Authorization: Bearer algrow_..." \ "https://algrow.online/api/channels/UCXoyny_UIW-02UwiNPUZT-w/playlists" ``` --- ## GET /api/viral-videos/search Search for viral videos across Shorts and Longform channels, find videos similar to a specific video, or browse by filters alone. Filter by video views, channel size, growth metrics, upload recency, outlier score, and more. q, video_id, and video_url are all optional — omit them to browse by filters (e.g. “biggest outliers from the last 7 days”). **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | q | string | Optional | — | Search query. Matches video titles and channel names with similarity scoring. Also accepts search as an alias. Omit along with video_id / video_url to browse by filters alone. | | video_id | string | Optional | — | YouTube video ID (e.g. dQw4w9WgXcQ). Finds videos similar to this video using title similarity. | | content_type | string | Optional | shorts | Content type: shorts or longform | | sort_by | string | Optional | views | Sort by: views (most viewed), recent (newest fetched), upload_date (newest uploaded), similarity (most similar — requires q/video_id/video_url; auto-selected when one is given), outlier_score (biggest over-performers — video views vs channel average) | | page | integer | Optional | 1 | Page number (1-indexed, max 20) | | per_page | integer | Optional | 20 | Results per page (max 50) | | min_video_views | integer | Optional | — | Minimum video view count | | max_video_views | integer | Optional | — | Maximum video view count | | min_subs | integer | Optional | — | Minimum channel subscriber count | | max_subs | integer | Optional | — | Maximum channel subscriber count | | min_uploads | integer | Optional | — | Minimum channel video count | | max_uploads | integer | Optional | — | Maximum channel video count | | min_channel_age | integer | Optional | — | Minimum channel age in days | | max_channel_age | integer | Optional | — | Maximum channel age in days | | min_upload_date | integer | Optional | — | Newest allowed upload (days ago, 0 = today) | | max_upload_date | integer | Optional | — | Oldest allowed upload (days ago, e.g. 365 = 1 year) | | min_duration | integer | Optional | — | Minimum video duration in minutes (longform only) | | max_duration | integer | Optional | — | Maximum video duration in minutes (longform only) | | min_views_24h | integer | Optional | — | Minimum channel views gained in last 24h (shorts only) | | max_views_24h | integer | Optional | — | Maximum channel views gained in last 24h (shorts only) | | min_views_48h | integer | Optional | — | Minimum channel views gained in last 48h (shorts only) | | max_views_48h | integer | Optional | — | Maximum channel views gained in last 48h (shorts only) | | min_outlier_score | float | Optional | — | Minimum outlier score. A video's outlier_score = its view count ÷ its channel's average views per video, so 2.5 means “video got 2.5× the channel's typical views.” Use to surface videos over-performing their channel. | | max_outlier_score | float | Optional | — | Maximum outlier score. Rarely needed — usually pair with min_outlier_score. | **Example Requests** ``` # Find viral gaming Shorts with 1M+ views from small channels curl "https://api.algrow.online/api/viral-videos/search?q=gaming&content_type=shorts&min_video_views=1000000&max_subs=50000" \ -H "Authorization: Bearer YOUR_API_KEY" # Longform fitness videos uploaded in last 7 days, sorted by views curl "https://api.algrow.online/api/viral-videos/search?q=fitness+workout&content_type=longform&max_upload_date=7&sort_by=views" \ -H "Authorization: Bearer YOUR_API_KEY" # Find videos similar to a specific video by ID curl "https://api.algrow.online/api/viral-videos/search?video_id=dQw4w9WgXcQ&content_type=longform" \ -H "Authorization: Bearer YOUR_API_KEY" # Search for cooking videos from channels under 100k subs curl "https://api.algrow.online/api/viral-videos/search?q=cooking&max_subs=100000" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response** ``` { "success": true, "content_type": "shorts", "page": 1, "per_page": 20, "count": 20, "videos": [ { "video_id": "dQw4w9WgXcQ", "title": "This cooking hack changed everything", "channel_name": "Chef Secrets", "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "view_count": 4200000, "outlier_score": 4.2, "thumbnail_url": "https://i.ytimg.com/vi/.../maxresdefault.jpg", "upload_date": "2026-03-15T00:00:00+00:00", "url": "https://www.youtube.com/shorts/dQw4w9WgXcQ", "subscriber_count": 32000, "duration": 58, "view_increase_24h": 180000, "view_increase_48h": 320000 } ] } ``` **Response Fields (per video)** | Field | Type | Description | |---|---|---| | video_id | string | YouTube video ID | | title | string | Video title | | channel_name | string | Channel name | | channel_id | string | YouTube channel ID | | view_count | integer | Total video views | | outlier_score | float\|null | Outlier multiplier — video's view count ÷ its channel's average views per video. 4.2 = video got 4.2× the channel's typical views. null for brand-new uploads before the channel average is computed. | | thumbnail_url | string | Video thumbnail URL | | upload_date | string\|null | Upload date (ISO 8601) | | url | string | Full YouTube URL | | subscriber_count | integer | Channel subscriber count | | duration | integer\|null | Video duration in seconds | | view_increase_24h | integer\|null | Channel views gained in last 24h (shorts with realtime filters only) | | view_increase_48h | integer\|null | Channel views gained in last 48h (shorts with realtime filters only) | | similarity_score | integer\|null | Similarity score (0–100) when using search. Higher = more similar. | --- ## POST /api/thumbnail-search Search for longform videos by thumbnail similarity. Provide a YouTube video URL, an image URL, or a text description to find videos with visually similar thumbnails using similarity matching. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | image_url | string | One of three | — | URL of a thumbnail image to search with. Supports JPEG, PNG, WebP, and GIF formats. | | video_url | string | One of three | — | YouTube video URL — automatically extracts its thumbnail. Accepts watch, shorts, and youtu.be links. | | q | string | One of three | — | Text description of the thumbnail style to search for (e.g. “red arrow pointing at shocked face”, “before and after transformation”). | | limit | integer | Optional | 20 | Maximum number of results to return (1–50) | | min_similarity | float | Optional | 0.3 | Minimum similarity threshold (0–1). Higher values return fewer but more visually similar results. | | min_views | integer | Optional | — | Minimum video view count filter | **Example Requests** ``` # Search by image URL — find videos with similar thumbnails curl -X POST "https://api.algrow.online/api/thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://i.ytimg.com/vi/abc123/maxresdefault.jpg", "limit": 10}' # Search by text — describe the thumbnail style you're looking for curl -X POST "https://api.algrow.online/api/thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"q": "red arrow pointing at shocked face", "limit": 20}' # Text search with filters — only high-view results curl -X POST "https://api.algrow.online/api/thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"q": "before and after transformation", "min_views": 100000, "min_similarity": 0.5}' ``` **Response** ``` { "success": true, "count": 10, "videos": [ { "video_id": "abc123", "title": "How I Made $10k in 30 Days", "channel_name": "Finance Tips", "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "view_count": 1500000, "thumbnail_url": "https://i.ytimg.com/vi/abc123/maxresdefault.jpg", "upload_date": "2026-03-20", "url": "https://www.youtube.com/watch?v=abc123", "duration": 612, "subscriber_count": 85000, "similarity_score": 78 } ] } ``` **Response Fields (per video)** | Field | Type | Description | |---|---|---| | video_id | string | YouTube video ID | | title | string | Video title | | channel_name | string | Channel name | | channel_id | string | YouTube channel ID | | view_count | integer | Total video views | | thumbnail_url | string | Video thumbnail URL | | upload_date | string\|null | Upload date (ISO 8601) | | url | string | Full YouTube URL | | duration | integer\|null | Video duration in seconds | | subscriber_count | integer | Channel subscriber count | | similarity_score | integer | Visual similarity score (0–100). Higher = more similar thumbnail. | --- ## POST /api/terminated-thumbnail-search Search terminated/deleted channel videos by thumbnail similarity. Same as /api/thumbnail-search but searches the terminated channels archive instead of active longform channels. Provide a YouTube video URL, an image URL, or a text description. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | image_url | string | One of three | — | URL of a thumbnail image to search with. Supports JPEG, PNG, WebP, and GIF formats. | | video_url | string | One of three | — | YouTube video URL — automatically extracts its thumbnail. Accepts watch, shorts, and youtu.be links. | | q | string | One of three | — | Text description of the thumbnail style to search for (e.g. “red arrow pointing at shocked face”, “before and after transformation”). | | limit | integer | Optional | 20 | Maximum number of results to return (1–50) | | min_similarity | float | Optional | 0.3 | Minimum similarity threshold (0–1). Higher values return fewer but more visually similar results. | | min_views | integer | Optional | — | Minimum video view count filter | | max_views | integer | Optional | — | Maximum video view count filter | **Example Requests** ``` # Search by image URL — find terminated videos with similar thumbnails curl -X POST "https://api.algrow.online/api/terminated-thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://i.ytimg.com/vi/abc123/maxresdefault.jpg", "limit": 10}' # Search by text — describe the thumbnail style curl -X POST "https://api.algrow.online/api/terminated-thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"q": "red arrow pointing at shocked face", "limit": 20}' # Search by YouTube video URL curl -X POST "https://api.algrow.online/api/terminated-thumbnail-search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url": "https://www.youtube.com/watch?v=abc123", "min_views": 50000}' ``` **Response** ``` { "success": true, "count": 10, "videos": [ { "video_id": "abc123", "title": "How I Made $10k in 30 Days", "channel_name": "Finance Tips", "channel_id": "UCxxxxxxxxxxxxxxxxxxxxxx", "view_count": 1500000, "thumbnail_url": "https://audio.algrow.online/thumbnails/abc123.jpg", "url": "https://www.youtube.com/watch?v=abc123", "subscriber_count": 85000, "similarity_score": 78 } ] } ``` **Response Fields (per video)** | Field | Type | Description | |---|---|---| | video_id | string | YouTube video ID | | title | string | Video title | | channel_name | string | Channel name | | channel_id | string | YouTube channel ID | | view_count | integer | Total video views | | thumbnail_url | string | Video thumbnail URL | | url | string | Full YouTube URL | | subscriber_count | integer | Channel subscriber count | | similarity_score | integer | Visual similarity score (0–100). Higher = more similar thumbnail. | --- ## POST /api/youtube-scraper Scrape video data from a YouTube channel or single video. Returns video metadata (title, views, likes, duration, thumbnails), with optional transcripts and comments. Async job — submit a request, then poll for results. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | url | string | Required | — | YouTube channel URL or video URL. Auto-detects single video vs. channel mode. | | video_type | string | Optional | both | Type of videos to scrape: shorts, videos, or both | | sort | string | Optional | recent | Sort order: recent or popular | | max_videos | integer | Optional | 20 | Maximum videos to scrape (1–100) | | include_transcripts | boolean | Optional | false | Include full video transcripts in the response | | include_comments | boolean | Optional | false | Include top comments for each video | **Example Request** ``` # Scrape a channel's most popular videos with transcripts curl -X POST "https://api.algrow.online/api/youtube-scraper" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.youtube.com/@MrBeast", "video_type": "videos", "sort": "popular", "max_videos": 10, "include_transcripts": true }' ``` **Response 200** ``` { "success": true, "job_id": 4521, "mode": "channel", "message": "Scraping job queued. Poll /api/youtube-scraper/{job_id} for results." } ``` --- ## GET /api/youtube-scraper/:job_id Poll for the result of a YouTube scraping job. Returns pending or processing while running, and the full video data when completed. **Example Request** ``` curl "https://api.algrow.online/api/youtube-scraper/4521" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Completed Response 200** ``` { "success": true, "job_id": 4521, "status": "completed", "created_at": "2026-03-24T10:30:00", "completed_at": "2026-03-24T10:31:15", "result": { "total_videos": 10, "total_views": 1250000000, "total_likes": 42000000, "videos": [ { "video_id": "dQw4w9WgXcQ", "title": "Video Title Here", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", "view_count": 250000000, "like_count": 8500000, "comment_count": 2100000, "duration_seconds": 212, "duration_human": "3m 32s", "publish_date": "2025-10-15T14:00:00Z", "channel": "MrBeast", "channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "transcript_url": "https://audio.algrow.online/api/transcripts/a1b2c3d4e5f6_Video_Title.txt", "comments": [ { "author": "@user123", "text": "Great video!", "likes": 5200, "published_time": "2 months ago" } ] } ] } } ``` **Response Fields (per video)** | Field | Type | Description | |---|---|---| | video_id | string | YouTube video ID | | title | string | Video title | | url | string | Full YouTube URL | | thumbnail | string | Thumbnail image URL (highest resolution available) | | view_count | integer | Total views | | like_count | integer | Total likes | | comment_count | integer | Total comments | | duration_seconds | integer | Video length in seconds | | duration_human | string | Human-readable duration (e.g. “3m 32s”) | | publish_date | string | Publish date (ISO 8601) | | channel | string | Channel name | | channel_id | string | YouTube channel ID | | transcript_url | string\|null | URL to the full transcript text file hosted on R2 (only if include_transcripts: true) | | comments | array\|null | Top comments (only if include_comments: true) | --- ## GET /api/folders List the authenticated user's folders with channel counts. **Response 200** ``` { "success": true, "count": 2, "folders": [ { "id": 12, "name": "Cooking Research", "channel_count": 7, "created_at": "2026-03-15T10:30:00" } ] } ``` **Example** ``` curl https://api.algrow.online/api/folders \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/folders Create a new folder. Content-Type application/json. **Body** | Name | Type | Required | Description | |---|---|---|---| | name | string | Required | Folder name (1–50 chars, unique per user). | **Example** ``` curl -X POST https://api.algrow.online/api/folders \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Tech Channels"}' ``` --- ## GET /api/folders/:id/channels List all channels in a folder with live 24h and 48h view/sub deltas. Sorted by save time descending. **Example** ``` curl https://api.algrow.online/api/folders/12/channels \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/saved-channels Save one or more channels into a folder. Hard cap of 30 channels per folder on all plans — if the request would exceed the cap, the entire save fails atomically (no partial save). **Body** | Name | Type | Required | Description | |---|---|---|---| | channel_ids | array | Required | Array of YouTube channel IDs (UC...). | | folder_id | integer | Required | Target folder ID. | **Example** ``` curl -X POST https://api.algrow.online/api/saved-channels \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_ids": ["UCxxxxxx", "UCyyyyyy"], "folder_id": 12}' ``` --- ## POST /api/saved-channels/move Move a saved channel from one folder to another. **Body** | Name | Type | Required | Description | |---|---|---|---| | channel_id | string | Required | YouTube channel ID. | | from_folder_id | integer | Required | Source folder ID. | | to_folder_id | integer | Required | Destination folder ID. | --- ## POST /api/channels/resolve Resolve a YouTube @handle or channel URL to a canonical channel ID. Useful when you have user input and need to call other endpoints with a stable UC... id. **Body** | Name | Type | Required | Description | |---|---|---|---| | input | string | Required | @handle, https://youtube.com/@handle, https://youtube.com/channel/UC..., or a raw UC... id (returned unchanged). | **Example** ``` curl -X POST https://api.algrow.online/api/channels/resolve \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": "@MrBeast"}' ``` --- ## GET /api/alerts List the user's saved alerts. Alerts watch for channels matching specific criteria (e.g. new outliers, high growth) and surface them in /api/alerts/triggered. **Example** ``` curl https://api.algrow.online/api/alerts \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/alerts Create a new alert. The filter body mirrors the search/trends params (subscribers, views, language, etc.) plus an alert type. **Example** ``` curl -X POST https://api.algrow.online/api/alerts \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "New cooking outliers", "content_type": "longform", "filters": {"min_subs": 1000, "max_subs": 100000, "languages": "English"}}' ``` --- ## GET /api/alerts/triggered Channels that matched the user's saved alert filters in the last evaluation cycle (typically the last 24h). Use this as your “new matches” feed. **Query Parameters** | Name | Type | Required | Default | Description | |---|---|---|---|---| | alert_id | integer | Optional | — | Restrict to one alert. Omit to merge across all alerts. | | page | integer | Optional | 1 | Page (1–20). | | per_page | integer | Optional | 50 | Results per page (1–50). | --- ## GET /api/alerts/outlier-status Quick poll endpoint: returns a per-alert summary of how many new channels triggered each alert. Cheap to call repeatedly — use it to drive a notification badge without paginating through /api/alerts/triggered. **Example** ``` curl https://api.algrow.online/api/alerts/outlier-status \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- ## POST /api/process-channel Queue a single YouTube channel for on-demand ingestion. Resolves the input (UC… ID, @handle, channel URL, or video URL) to a canonical channel ID and inserts a row in the processing queue. A dedicated worker picks the job up within seconds and runs the appropriate shorts or longform processor. Returns immediately with a job_id — poll GET /api/process-channel/:job_id for the result. **Headers** | Name | Type | Required | Description | |---|---|---|---| | Authorization | string | Required | Bearer token: Bearer YOUR_API_KEY | | Content-Type | string | Required | application/json | **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | channel | string | Required | — | Channel identifier — UC... ID, @handle, channel URL, or any video URL from that channel. | | type | string | Required | — | Which processor to run: shorts or longform. The caller must choose — there is no auto-detection. | | idempotency_key | string | Optional | — | If a job with this key already exists, that existing job is returned instead of a new one being queued. Use this to safely retry on network errors. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/process-channel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel": "@MrBeast", "type": "longform"}' ``` **Response 200** ``` { "job_id": 1247, "status": "queued", "type": "longform", "channel_input": "@MrBeast", "resolved_channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "requested_at": "2026-05-24T18:42:11.213+00:00" } ``` **Response Fields** | Field | Type | Description | |---|---|---| | job_id | integer | Unique job identifier. Use this to poll for status. | | status | string | One of: queued, running, completed, failed. | | type | string | Echo of the submitted type (shorts or longform). | | channel_input | string | Echo of the raw input passed in the request. | | resolved_channel_id | string | Canonical UC... channel ID we resolved the input to. | | requested_at | string | ISO-8601 timestamp of when the job was enqueued. | | idempotent | boolean | Present and true when an existing job was returned instead of inserting a new one. | --- ## GET /api/process-channel/:job_id Retrieve the current status and result of a channel processing job. Supports server-side long-polling via ?wait_seconds=N (max 30) — pass it and the server holds the connection open until the job finishes or N seconds elapse, so you get the result in one call instead of polling in a loop. Typical processing time is 30 seconds to 2 minutes depending on channel size. **Path Parameters** | Name | Type | Required | Description | |---|---|---|---| | job_id | integer | Required | The job_id returned from POST /api/process-channel. | **Query Parameters** | Name | Type | Default | Description | |---|---|---|---| | wait_seconds | integer | 0 | Server-side long-poll. 0 = return current state immediately. 1–30 = hold the connection open until the job hits a terminal state (completed/failed) or this many seconds pass, whichever comes first. Capped at 30 server-side regardless of input. Recommended: wait_seconds=30 for typical polling. | **Example Request** ``` # Single-call poll: server waits up to 30s for completion curl "https://api.algrow.online/api/process-channel/1247?wait_seconds=30" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response — Running** ``` { "id": 1247, "status": "running", "type": "longform", "channel_input": "@MrBeast", "resolved_channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "claimed_at": "2026-05-24T18:42:13.001+00:00", "elapsed_seconds": 12 } ``` **Response — Completed** ``` { "id": 1247, "status": "completed", "type": "longform", "channel_input": "@MrBeast", "resolved_channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "requested_at": "2026-05-24T18:42:11.213+00:00", "claimed_at": "2026-05-24T18:42:13.001+00:00", "completed_at": "2026-05-24T18:43:02.482+00:00", "duration_seconds": 49, "eligible": true, "result": { ... } } ``` **Response Fields** | Field | Type | Description | |---|---|---| | id | integer | Job ID. | | status | string | One of: queued, running, completed, failed. | | elapsed_seconds | integer | Seconds since the worker claimed the job. Only present while status=running. | | duration_seconds | integer | End-to-end processing time. Present once completed or failed. | | eligible | boolean | Whether the channel passed Algrow's inclusion rules (size, language, content type, etc.). Present once completed. | | result | object | Worker payload — the scraped channel data. Shape depends on type (shorts vs longform). | | error | string | Failure message. Only present when status=failed. | --- ## POST /api/reports Publish a self-contained HTML report to Algrow's public report host and get back a stable URL on audio.algrow.online — no storage credentials needed. Built for agent skills that render analysis reports (channel decodes, audits, idea backlogs) and want to hand the user a hosted link. Reports are namespaced per user: re-posting the same slug overwrites your own report (re-render = same URL); you can never touch another user's. Pages are served with noindex so they stay out of search engines. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | slug | string | Required | — | URL slug for the report: 3–80 chars of a-z 0-9 -, starting alphanumeric. Same slug → overwrite your own previous version. | | html | string | Required | — | The complete, self-contained HTML document (must start with or ). Max 2 MB — inline your CSS; link external images/fonts by URL. | > Limits. 50 uploads per key per 24h, on top of the standard per-key rate limit. A tag is injected automatically if missing. --- ## POST /api/channel-peek First look at up to 2,000 channels in one call — name, subscriber count, best-performing view count, and recent + popular video titles for each. Reads YouTube directly rather than the Algrow index, so brand-new channels are covered and no YouTube Data API quota is spent. Free. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | channel_ids | array | Required | — | Channel IDs (UC...). Max 2,000 per request; extras are dropped. Send pools larger than that in chunks of roughly 1,200 to stay inside the 280s timeout. | | per_sort | integer | Optional | 15 | Videos to return per sort order (recent and popular). Max 30. | | concurrency | integer | Optional | 12 | Channels fetched in parallel. Max 16. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/channel-peek" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_ids": ["UCX6OQ3DkcsbYNE6H8uQQuVA", "UCsXVk37bltHxD1rDPwtNM8Q"], "per_sort": 10}' ``` **Example Response** ``` { "success": true, "requested": 2, "channels": [ { "channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA", "name": "MrBeast", "subs": 634000000, "ceiling": 812443210, "videos": [ {"video_id": "abc123", "title": "I Survived 50 Hours In Antarctica", "views": 128443210, "sort": "popular"} ] } ] } ``` > Timeouts. The request runs synchronously and is cut off at 280 seconds, which returns 504 with a message to send fewer channels. Size each batch so it finishes well inside that. --- ## POST /api/room-sweep Run live paginated YouTube searches across a set of broad topic terms and rank every channel that shows up by how often it appears. Channels that recur across terms sit at the top; a giant that one generic term dragged in appears once and sinks. Use it to map who actually occupies a topic before you commit to it. Free. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | terms | array | Required | — | Topic terms to sweep, e.g. ["mountain men", "frontier survival"]. Only the first 16 are used; the rest come back in terms_dropped. | | pages | integer | Optional | 10 | Result pages per term per result type. Max 10. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/room-sweep" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"terms": ["mountain men", "frontier survival"], "pages": 5}' ``` **Example Response** ``` { "success": true, "partial": false, "channels": [ {"channel_id": "UCabc123", "title": "Frontier Life", "centrality": 34}, {"channel_id": "UCdef456", "title": "Wild Homestead", "centrality": 11} ], "terms_used": ["mountain men", "frontier survival"], "terms_dropped": [], "max_terms": 16 } ``` > Always read partial and terms_dropped. partial: true means the search quota ran out mid-sweep, and a non-empty terms_dropped means you sent more than 16 terms. Either one means the channel list is incomplete — re-run the missing terms rather than treating it as a full picture. --- ## POST /api/video-comments Top-liked comments for a batch of videos, sorted by like count. Videos with comments turned off are skipped instead of failing the batch. Free. **Request Body (JSON)** | Name | Type | Required | Default | Description | |---|---|---|---|---| | video_ids | array | Required | — | YouTube video IDs. Max 25 per request; extras are dropped. | | max_per_video | integer | Optional | 60 | Comments to return per video. Max 100. | | order | string | Optional | relevance | relevance or time. Anything else falls back to relevance. | **Example Request** ``` curl -X POST "https://api.algrow.online/api/video-comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_ids": ["dQw4w9WgXcQ"], "max_per_video": 25}' ``` **Example Response** ``` { "success": true, "comments": { "dQw4w9WgXcQ": [ {"text": "the edit at 3:12 is unreal", "likes": 4821} ] } } ``` --- ## POST /api/upload-text Upload a text string and receive a hosted URL. Useful for storing transcripts or other text content. **Content-Type:** application/json **Parameters:** | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | text | string | Yes | — | Text content to upload | | filename | string | No | transcript.txt | Filename for the hosted file | **Response:** ```json { "success": true, "url": "https://audio.algrow.online/api/transcripts/abc123_transcript.txt" } ``` --- ## Rate Limits Per-minute buckets are counted **per API key**, so a second key gets its own burst allowance. Values are the same on every plan. | Bucket | Requests/min | |--------|-------------| | Most endpoints | 30 | | Channel info (/api/channels/:id/about, /videos, /shorts) | 100 | | Status/polling endpoints (/api/job-status, /api/youtube-scraper/:job_id) | 60 | Daily caps are counted **per account** and shared by every key you own, so minting extra keys does not raise them. The window is a rolling 24h that starts on your first request. | Daily cap | Requests/24h | |-----------|-------------| | Starter | 1,000 | | Professional | 2,000 | | Ultimate | 4,000 | | $1 trial | 300 | The tier caps cover search, channel-data, viral, workspace and other non-credit endpoints; generation endpoints that spend credits are exempt because credits already meter them. The $1-trial cap covers every endpoint, status polls included, and lifts to the tier cap when the subscription is activated. Concurrent-job caps are also per account (8 / 20 / 40 by tier, plus a separate image bucket of 10 / 25 / 50). --- ## Credits | Feature | Cost | |---------|------| | TTS Generation | 1 credit per character of script | | Caption Removal | 12 credits per minute of video (prorated, max 90s) | | Image Generation | 2-3 credits (varies by model — see /api/generate-image) | | Video Generation | 3-30 credits (varies by model and duration — see /api/generate-video) | | Video Analysis | Free during preview (see /api/analyze-video) | | YouTube Scraper | 1 credit per job | | Channel Search | Free (included with plan) | | Terminated Channel Search | Free (included with plan) | | Thumbnail Search | Free (included with plan) | | Viral Video Search | Free (included with plan) | --- ## Error Codes | Code | Meaning | |------|---------| | 400 | Bad request — invalid parameters | | 401 | Unauthorized — missing or invalid API key | | 403 | Forbidden — plan upgrade required | | 404 | Not found — resource doesn't exist | | 429 | Rate limited — too many requests | | 500 | Server error — try again later | Error response format: ```json { "success": false, "error": "Description of what went wrong" } ```