Actions
Endpoints for triggering asynchronous operations: AI analysis, competitor discovery, keyword generation, niche creation, and channel tracking.
All action endpoints return HTTP 202 Accepted and queue the work in the background. Use Webhooks to receive notifications when operations complete.
Endpoints
| Method | Path | Description | Usage Limit |
|---|---|---|---|
| POST | /api/v1/channels/:id/analyze |
Run AI channel analysis | channel_analysis |
| POST | /api/v1/channels/:id/competitors/discover |
Discover channel competitors | competitor_search |
| POST | /api/v1/channels/:id/keywords/generate |
Generate niche keywords | keyword_generation |
| POST | /api/v1/niches |
— | |
| POST | /api/v1/me/channels |
Add a channel to tracking | channels |
Analyze Channel
POST /api/v1/channels/:id/analyze
Run AI-powered analysis on a channel. This generates or updates the channel profile with content style, title formulas, thumbnail patterns, and more.
Parameters
No request body required.
Example Request
curl -X POST "https://tuberalytics.com/api/v1/channels/170/analyze" \
-H "Authorization: Bearer sk_live_your_api_key"
import requests
response = requests.post(
"https://tuberalytics.com/api/v1/channels/170/analyze",
headers={"Authorization": "Bearer sk_live_your_api_key"}
)
data = response.json()
require "net/http"
require "json"
uri = URI("https://tuberalytics.com/api/v1/channels/170/analyze")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer sk_live_your_api_key"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
const response = await fetch("https://tuberalytics.com/api/v1/channels/170/analyze", {
method: "POST",
headers: { "Authorization": "Bearer sk_live_your_api_key" }
});
const data = await response.json();
$ch = curl_init("https://tuberalytics.com/api/v1/channels/170/analyze");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer sk_live_your_api_key"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
Example Response (HTTP 202)
{
"data": {
"status": "pending",
"analysis_id": 456,
"message": "Channel analysis queued."
}
}
Webhook Event: channel.analysis.completed or channel.analysis.failed
Discover Competitors
POST /api/v1/channels/:id/competitors/discover
Discover competitors for a channel based on shared keywords and audience overlap.
Parameters
No request body required.
Example Request
curl -X POST "https://tuberalytics.com/api/v1/channels/170/competitors/discover" \
-H "Authorization: Bearer sk_live_your_api_key"
response = requests.post(
"https://tuberalytics.com/api/v1/channels/170/competitors/discover",
headers={"Authorization": "Bearer sk_live_your_api_key"}
)
data = response.json()
uri = URI("https://tuberalytics.com/api/v1/channels/170/competitors/discover")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer sk_live_your_api_key"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
const response = await fetch(
"https://tuberalytics.com/api/v1/channels/170/competitors/discover",
{ method: "POST", headers: { "Authorization": "Bearer sk_live_your_api_key" } }
);
const data = await response.json();
$ch = curl_init("https://tuberalytics.com/api/v1/channels/170/competitors/discover");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer sk_live_your_api_key"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
Example Response (HTTP 202)
{
"data": {
"status": "pending",
"message": "Competitor discovery queued."
}
}
Webhook Event: competitors.discovered
Generate Keywords
POST /api/v1/channels/:id/keywords/generate
Generate AI-powered keywords for a channel's primary niche.
The channel must have been analyzed and associated with a niche first. Returns
422if no niche is found.
Parameters
No request body required.
Example Request
curl -X POST "https://tuberalytics.com/api/v1/channels/170/keywords/generate" \
-H "Authorization: Bearer sk_live_your_api_key"
response = requests.post(
"https://tuberalytics.com/api/v1/channels/170/keywords/generate",
headers={"Authorization": "Bearer sk_live_your_api_key"}
)
data = response.json()
uri = URI("https://tuberalytics.com/api/v1/channels/170/keywords/generate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer sk_live_your_api_key"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
const response = await fetch(
"https://tuberalytics.com/api/v1/channels/170/keywords/generate",
{ method: "POST", headers: { "Authorization": "Bearer sk_live_your_api_key" } }
);
const data = await response.json();
$ch = curl_init("https://tuberalytics.com/api/v1/channels/170/keywords/generate");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer sk_live_your_api_key"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
Example Response (HTTP 202)
{
"data": {
"status": "pending",
"niche": "AI Automation",
"message": "Keyword generation queued."
}
}
Error Response (HTTP 422)
{
"error": "Channel has no associated niche. Run analysis first."
}
Webhook Event: keywords.generated
Create Niche (Deprecated)
POST /api/v1/niches
Deprecated as of 2026-04-13. Niches are now automatically created from video classification data. This endpoint returns HTTP 410 Gone.
Previously, this endpoint triggered AI-powered niche synthesis via a wizard flow. Niches are now derived automatically from the 3-level topic hierarchy system when a channel's videos are classified.
Response (HTTP 410)
{
"error": "Niche creation is now automatic. Add a channel and niches will be derived from video classification."
}
Add Channel to Tracking
POST /api/v1/me/channels
Add a YouTube channel to your tracked channels list.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
youtube_url |
string | Yes | YouTube channel URL |
Accepted URL formats:
https://youtube.com/channel/UCxxxx...(channel ID)https://youtube.com/@handle(custom handle)https://youtube.com/c/name(old custom URL)
Example Request
curl -X POST "https://tuberalytics.com/api/v1/me/channels" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"youtube_url": "https://youtube.com/@nicksaraev"}'
response = requests.post(
"https://tuberalytics.com/api/v1/me/channels",
json={"youtube_url": "https://youtube.com/@nicksaraev"},
headers={"Authorization": "Bearer sk_live_your_api_key"}
)
data = response.json()
uri = URI("https://tuberalytics.com/api/v1/me/channels")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer sk_live_your_api_key"
req["Content-Type"] = "application/json"
req.body = { youtube_url: "https://youtube.com/@nicksaraev" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
const response = await fetch("https://tuberalytics.com/api/v1/me/channels", {
method: "POST",
headers: {
"Authorization": "Bearer sk_live_your_api_key",
"Content-Type": "application/json"
},
body: JSON.stringify({ youtube_url: "https://youtube.com/@nicksaraev" })
});
const data = await response.json();
$ch = curl_init("https://tuberalytics.com/api/v1/me/channels");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer sk_live_your_api_key",
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["youtube_url" => "https://youtube.com/@nicksaraev"]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
Example Response (HTTP 201)
{
"data": {
"user_channel_id": 22,
"channel_id": 170,
"title": "Nick Saraev",
"message": "Channel added to your tracking list."
}
}
Error Responses
| Code | Error |
|---|---|
| 400 | Missing parameter: youtube_url |
| 404 | YouTube channel not found. |
| 422 | Could not extract YouTube channel from URL. |
| 429 | Monthly channels limit exceeded |