{"openapi":"3.1.0","info":{"title":"TubeAnalytics Public API","version":"1.0.0","summary":"Authenticated REST API for accessing YouTube channel analytics, video performance, audience insights, and competitor tracking.","description":"Machine-readable API specification for the TubeAnalytics platform. All endpoints require an API key passed as `Authorization: Bearer <key>`.\n\n## Authentication\nEvery request must include a valid API key in the Authorization header:\n```\nAuthorization: Bearer ta_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n## Rate Limits\n- **Starter**: 1,000 requests / month\n- **Professional**: 10,000 requests / month\n- **Enterprise**: 100,000 requests / month\n\nRate limit status is returned in the `X-RateLimit-Remaining` and `X-RateLimit-Reset` response headers.\n\n## Error Codes\n| Code | HTTP Status | Description |\n|------|-------------|-------------|\n| BAD_REQUEST | 400 | Missing or invalid query parameter |\n| UNAUTHORIZED | 401 | Missing or invalid API key |\n| FORBIDDEN | 403 | API key valid but lacks permission for this resource |\n| NOT_FOUND | 404 | Channel or resource not found |\n| RATE_LIMITED | 429 | Monthly quota exceeded |\n| INTERNAL_ERROR | 500 | Unexpected server error |\n\n## Data Freshness\nData is synced from the YouTube Analytics API. Most metrics update within 24–48 hours of a video being published. Revenue data (CPM/RPM) refreshes daily.","contact":{"email":"support@tubeanalytics.net","url":"https://tubeanalytics.net/support"},"license":{"name":"Proprietary","url":"https://tubeanalytics.net/terms"}},"servers":[{"url":"https://tubeanalytics.net","description":"Production"},{"url":"https://tubeanalytics.net/api/external/v1","description":"API base path"}],"tags":[{"name":"Discovery","description":"Public discovery and product contract endpoints."},{"name":"MCP","description":"Streamable HTTP Model Context Protocol transport."},{"name":"Channels","description":"List and manage connected YouTube channels."},{"name":"Analytics","description":"Aggregate and per-video performance metrics."},{"name":"Videos","description":"Individual video data with pagination and sorting."},{"name":"Audience","description":"Audience demographics, segments, and subscriber health."},{"name":"Competitors","description":"Tracked competitor channel data."}],"paths":{"/ai.txt":{"get":{"operationId":"getAiTxt","tags":["Discovery"],"summary":"AI crawler guidance","description":"Returns plain-text AI discovery policy — crawler permissions, product description, and manifest links.","responses":{"200":{"description":"Plain-text AI discovery policy","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/mcp.json":{"get":{"operationId":"getMcpManifest","tags":["Discovery"],"summary":"MCP discovery manifest","description":"Returns the Model Context Protocol manifest with available tools and resources for AI agents.","responses":{"200":{"description":"MCP discovery manifest","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiSpec","tags":["Discovery"],"summary":"OpenAPI specification","description":"Returns this machine-readable OpenAPI 3.1 specification.","responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/mcp":{"get":{"operationId":"getMcpTransport","tags":["MCP"],"summary":"MCP Streamable HTTP transport","description":"Streamable HTTP transport endpoint for the TubeAnalytics MCP server. Clients authenticate by sending a Bearer API key in the Authorization header.","responses":{"200":{"description":"MCP transport response","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"postMcpTransport","tags":["MCP"],"summary":"MCP Streamable HTTP transport","description":"Streamable HTTP transport endpoint for the TubeAnalytics MCP server. Clients authenticate by sending a Bearer API key in the Authorization header.","responses":{"200":{"description":"MCP transport response","content":{"application/json":{"schema":{"type":"object"}}}}}},"delete":{"operationId":"deleteMcpTransport","tags":["MCP"],"summary":"MCP Streamable HTTP transport","description":"Streamable HTTP transport endpoint for the TubeAnalytics MCP server. Clients authenticate by sending a Bearer API key in the Authorization header.","responses":{"200":{"description":"MCP transport response","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/.well-known/agentka.json":{"get":{"operationId":"getAgentkaManifest","tags":["Discovery"],"summary":"A2A / AgentKA protocol manifest","description":"Agent-to-Agent protocol discovery endpoint. Returns capabilities, authentication method, and available skills.","responses":{"200":{"description":"AgentKA manifest","headers":{"X-Robots-Tag":{"description":"Set to noindex — this endpoint is for agents, not search engines","schema":{"type":"string","enum":["noindex"]}}},"content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/external/v1/channels":{"get":{"operationId":"listChannels","tags":["Channels"],"summary":"List connected channels","description":"Returns all YouTube channels connected to the authenticated account. Ordered by connection date (oldest first).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of connected YouTube channels","content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}},"total":{"type":"integer","description":"Total number of connected channels"}},"required":["channels","total"]}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/api/external/v1/analytics":{"get":{"operationId":"getChannelAnalytics","tags":["Analytics"],"summary":"Get channel analytics","description":"Returns aggregate analytics for a specific channel over a configurable time range. Includes total views, likes, comments, engagement rate, and the top-performing videos in that period. Requires `channel_id` as either the TubeAnalytics internal ID or the YouTube channel ID.","security":[{"bearerAuth":[]}],"parameters":[{"name":"channel_id","in":"query","required":true,"description":"TubeAnalytics channel ID or YouTube channel ID","schema":{"type":"string","example":"clxxxxxxxxxxxxxxx"}},{"name":"range","in":"query","required":false,"description":"Time range for aggregate metrics. Default: 28d.","schema":{"type":"string","enum":["7d","28d","30d","90d","1y"],"default":"28d"}}],"responses":{"200":{"description":"Channel analytics for the specified time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsPayload"}}},"headers":{"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Remaining API calls this billing period"},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"unix-timestamp"},"description":"Unix timestamp when the rate limit resets"}}},"400":{"description":"Missing or invalid query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"Channel not found or not owned by this account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/api/external/v1/videos":{"get":{"operationId":"listVideos","tags":["Videos"],"summary":"List channel videos","description":"Returns a paginated list of videos for a channel, sorted by the specified field. Supports sorting by publishedAt, viewCount, likeCount, or commentCount. Include channel_id as either the TubeAnalytics internal ID or the YouTube channel ID.","security":[{"bearerAuth":[]}],"parameters":[{"name":"channel_id","in":"query","required":true,"description":"TubeAnalytics channel ID or YouTube channel ID","schema":{"type":"string","example":"clxxxxxxxxxxxxxxx"}},{"name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"sort","schema":{"type":"string","enum":["publishedAt","viewCount","likeCount","commentCount"],"default":"publishedAt"}},{"name":"order","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of videos for a channel","content":{"application/json":{"schema":{"type":"object","properties":{"videos":{"type":"array","items":{"$ref":"#/components/schemas/Video"}},"page":{"type":"integer","description":"Current page number"},"limit":{"type":"integer","description":"Items returned per page"},"total":{"type":"integer","description":"Total number of items matching the query"},"totalPages":{"type":"integer","description":"Total number of pages (total / limit, rounded up)"}},"required":["videos","page","limit","total","totalPages"]}}},"headers":{"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"unix-timestamp"}}}},"400":{"description":"Missing or invalid query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"Channel not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/api/external/v1/audience":{"get":{"operationId":"getAudienceInsights","tags":["Audience"],"summary":"Get audience insights","description":"Returns the latest audience demographics, subscriber health metrics, and audience segment data for a channel. Data is sourced from YouTube Analytics API and may be up to 48 hours stale. Returns null for any subsection where no data has been collected yet.","security":[{"bearerAuth":[]}],"parameters":[{"name":"channel_id","in":"query","required":true,"description":"TubeAnalytics channel ID or YouTube channel ID","schema":{"type":"string","example":"clxxxxxxxxxxxxxxx"}}],"responses":{"200":{"description":"Audience demographics, subscriber health, and segment data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudiencePayload"}}},"headers":{"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"unix-timestamp"}}}},"400":{"description":"Missing channel_id parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"Channel not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/api/external/v1/competitors":{"get":{"operationId":"listCompetitors","tags":["Competitors"],"summary":"List tracked competitors","description":"Returns all competitor channels being tracked for the authenticated account. Competitors are added manually through the TubeAnalytics dashboard. Data is refreshed from YouTube on a daily sync cycle.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of tracked competitor channels","content":{"application/json":{"schema":{"type":"object","properties":{"competitors":{"type":"array","items":{"$ref":"#/components/schemas/Competitor"}},"total":{"type":"integer","description":"Total number of tracked competitors"}},"required":["competitors","total"]}}},"headers":{"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"unix-timestamp"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. BAD_REQUEST, NOT_FOUND)"},"message":{"type":"string","description":"Human-readable error description"}},"required":["code","message"]}},"required":["error"]}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"TubeAnalytics API key. Obtain from your account dashboard."}},"schemas":{"Channel":{"type":"object","description":"A connected YouTube channel","properties":{"id":{"type":"string","description":"TubeAnalytics internal channel ID","example":"clxxxxxxxxxxxxxxx"},"youtubeId":{"type":"string","description":"YouTube channel ID (UC-...)","example":"UC-xxxxxxx"},"title":{"type":"string","description":"Channel display name","example":"TechCreator"},"description":{"type":"string","nullable":true,"description":"Channel description from YouTube"},"thumbnailUrl":{"type":"string","nullable":true,"format":"uri","description":"Channel thumbnail URL"},"subscriberCount":{"type":"integer","nullable":true,"description":"Current subscriber count (may lag behind YouTube)"},"totalViews":{"type":"integer","nullable":true,"description":"All-time total view count"},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected to TubeAnalytics"},"updatedAt":{"type":"string","format":"date-time","description":"Last time data was synced from YouTube"}}},"AnalyticsPayload":{"type":"object","description":"Aggregate analytics and top videos for a channel in a time range","properties":{"channel":{"$ref":"#/components/schemas/ChannelRef"},"range":{"type":"string","description":"Requested time range","example":"28d"},"analytics":{"type":"object","properties":{"totalVideos":{"type":"integer","description":"Total videos ever published on this channel"},"videosPublishedInRange":{"type":"integer","description":"Videos published within the requested range"},"totalViews":{"type":"integer","description":"Cumulative views across all videos in the range"},"totalLikes":{"type":"integer","description":"Cumulative likes across all videos in the range"},"totalComments":{"type":"integer","description":"Cumulative comments across all videos in the range"},"averageViewsPerVideo":{"type":"integer","description":"Average views per video in the range"},"engagementRate":{"type":"number","description":"(likes + comments) / views * 100, formatted to 2 decimal places","example":4.32}},"required":["totalVideos","videosPublishedInRange","totalViews","totalLikes","totalComments","averageViewsPerVideo","engagementRate"]},"topVideos":{"type":"array","description":"Up to 10 most recently published videos within the range","items":{"$ref":"#/components/schemas/VideoRef"}}},"required":["channel","range","analytics","topVideos"]},"ChannelRef":{"type":"object","description":"A connected YouTube channel","properties":{"id":{"type":"string","description":"TubeAnalytics internal channel ID","example":"clxxxxxxxxxxxxxxx"},"youtubeId":{"type":"string","description":"YouTube channel ID (UC-...)","example":"UC-xxxxxxx"},"title":{"type":"string","description":"Channel display name","example":"TechCreator"},"description":{"type":"string","nullable":true,"description":"Channel description from YouTube"},"thumbnailUrl":{"type":"string","nullable":true,"format":"uri","description":"Channel thumbnail URL"},"subscriberCount":{"type":"integer","nullable":true,"description":"Current subscriber count (may lag behind YouTube)"},"totalViews":{"type":"integer","nullable":true,"description":"All-time total view count"},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected to TubeAnalytics"},"updatedAt":{"type":"string","format":"date-time","description":"Last time data was synced from YouTube"}}},"Video":{"type":"object","description":"A YouTube video with performance metrics","properties":{"id":{"type":"string","description":"TubeAnalytics internal video ID"},"youtubeId":{"type":"string","description":"YouTube video ID"},"title":{"type":"string","description":"Video title"},"description":{"type":"string","nullable":true,"description":"Video description (may be truncated)"},"thumbnailUrl":{"type":"string","nullable":true,"format":"uri"},"publishedAt":{"type":"string","format":"date-time"},"duration":{"type":"string","nullable":true,"description":"ISO 8601 duration (PT1H2M3S)","example":"PT12M34S"},"viewCount":{"type":"integer","nullable":true},"likeCount":{"type":"integer","nullable":true},"commentCount":{"type":"integer","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true,"description":"YouTube video tags"}},"required":["id","youtubeId","title","publishedAt"]},"VideoRef":{"type":"object","description":"Summary reference to a video (used in analytics topVideos)","properties":{"youtubeId":{"type":"string"},"title":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"viewCount":{"type":"integer","nullable":true},"likeCount":{"type":"integer","nullable":true},"commentCount":{"type":"integer","nullable":true}},"required":["youtubeId","title","publishedAt"]},"AudiencePayload":{"type":"object","description":"Audience demographics, subscriber health, and segment data","properties":{"channel":{"type":"object","properties":{"id":{"type":"string"},"youtubeId":{"type":"string"},"title":{"type":"string"}},"required":["id","youtubeId","title"]},"demographics":{"type":"object","nullable":true,"description":"Age, gender, geography, device, and traffic source breakdown","properties":{"date":{"type":"string","format":"date","description":"Date of the snapshot"},"age":{"type":"object","properties":{"13-17":{"type":"number","description":"Percentage of viewers aged 13–17"},"18-24":{"type":"number"},"25-34":{"type":"number"},"35-44":{"type":"number"},"45-54":{"type":"number"},"55-64":{"type":"number"},"65+":{"type":"number"}}},"gender":{"type":"object","properties":{"male":{"type":"number","description":"Percentage male viewers"},"female":{"type":"number"},"other":{"type":"number"}}},"topCountries":{"type":"array","description":"Top 10 countries by viewer share","items":{"type":"string"}},"devices":{"type":"object","properties":{"mobile":{"type":"number","description":"Percentage mobile viewers"},"desktop":{"type":"number"},"tablet":{"type":"number"},"tv":{"type":"number"}}},"trafficSources":{"type":"object","description":"Viewer acquisition channels (suggested, browse, external, etc.)","additionalProperties":{"type":"number"}}}},"subscriberHealth":{"type":"object","nullable":true,"description":"Subscriber gain/loss and churn metrics","properties":{"date":{"type":"string","format":"date"},"healthScore":{"type":"number","description":"0–100 health score based on subscriber velocity"},"totalSubscribers":{"type":"integer"},"subscribersGained":{"type":"integer","description":"Subscribers gained in the snapshot period"},"subscribersLost":{"type":"integer","description":"Subscribers lost in the snapshot period"},"netChange":{"type":"integer","description":"Net subscriber change (gained − lost)"},"activeSubscriberPct":{"type":"number","description":"Percentage of subscribers who watched in the last 7 days"},"churnRate":{"type":"number","description":"Monthly subscriber churn rate"}}},"segments":{"type":"array","description":"Audience segment summary — one entry per segment type","items":{"type":"object","properties":{"type":{"type":"string","description":"Segment category (e.g. returning_viewer, casual_viewer, subscriber)"},"size":{"type":"integer","description":"Estimated viewer count in this segment"},"pct":{"type":"number","description":"Percentage of total audience"},"avgAge":{"type":"number","nullable":true,"description":"Average viewer age in this segment"},"topCountries":{"type":"array","items":{"type":"string"}},"topGender":{"type":"string","enum":["male","female","other"]},"trending":{"type":"string","enum":["growing","stable","declining"],"nullable":true}},"required":["type","size","pct"]}}},"required":["channel","demographics","subscriberHealth","segments"]},"Competitor":{"type":"object","description":"A tracked competitor YouTube channel","properties":{"id":{"type":"string","description":"TubeAnalytics competitor record ID"},"youtubeId":{"type":"string","description":"Competitor's YouTube channel ID"},"title":{"type":"string","description":"Competitor channel name"},"description":{"type":"string","nullable":true},"thumbnailUrl":{"type":"string","nullable":true,"format":"uri"},"subscriberCount":{"type":"integer","nullable":true},"videoCount":{"type":"integer","nullable":true},"viewCount":{"type":"integer","nullable":true},"customTags":{"type":"array","items":{"type":"string"},"nullable":true,"description":"User-assigned tags for this competitor"},"addedAt":{"type":"string","format":"date-time","description":"When this competitor was added to tracking"},"lastSyncedAt":{"type":"string","format":"date-time","description":"Last time data was fetched from YouTube"}},"required":["id","youtubeId","title","addedAt","lastSyncedAt"]},"ProductPlan":{"type":"object","properties":{"id":{"type":"string","enum":["starter","professional","enterprise"]},"name":{"type":"string"},"channelLimit":{"type":"integer"},"monthlyPrice":{"type":"number"},"yearlyPrice":{"type":"number"},"yearlyTotal":{"type":"number"}},"required":["id","name","channelLimit","monthlyPrice","yearlyPrice","yearlyTotal"]},"ProductContract":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"trialDays":{"type":"integer","minimum":1},"plans":{"type":"array","items":{"$ref":"#/components/schemas/ProductPlan"}}},"required":["name","description","trialDays","plans"]}}},"x-product-contract":{"name":"TubeAnalytics","description":"YouTube analytics platform for creators, teams, and agencies that need authenticated channel data, competitor tracking, and AI-assisted growth decisions.","trialDays":7,"plans":[{"id":"starter","name":"Starter","channelLimit":1,"monthlyPrice":19,"yearlyPrice":15,"yearlyTotal":180},{"id":"professional","name":"Professional","channelLimit":3,"monthlyPrice":49,"yearlyPrice":39,"yearlyTotal":468},{"id":"enterprise","name":"Enterprise","channelLimit":5,"monthlyPrice":149,"yearlyPrice":119,"yearlyTotal":1428}],"discovery":{"aiTxt":"/ai.txt","agentsTxt":"/agents.txt","aiPricingJson":"/ai-pricing.json","openapiJson":"/openapi.json","mcpJson":"/mcp.json","mcpTransport":"/api/mcp"},"transport":"https://tubeanalytics.net/api/mcp","pricing":"https://tubeanalytics.net/ai-pricing.json"}}