đĄ Status
Overview
The POST /api/status endpoint is used to retrieve the
status of the given source. It contains information about the source,
channels, and other relevant information.
Request
POST /api/status
{
"clientVersion": "2.1.2",
// Your server's global options can be sent in the status request
"sort": "new",
"flavor": "mint chocolate chip"
}
Server Options
Your server's options can be used to customize the experience for the user. For example, you may return different categories, channels, or notices based on their preferences.
Response
{
"id": "example-server",
"name": "Example Video Server",
"subtitle": "A demo video streaming service.",
"description": "This is an example server demonstrating the Hot Tub API structure and capabilities.",
"iconUrl": "https://example.com/icon.png",
"color": "#007AFF",
"status": "active",
"notices": [
{
"status": "warning",
"message": "Scheduled Maintenance",
"details": "Our servers will undergo maintenance on January 15th from 2:00-4:00 AM UTC. Some features may be temporarily unavailable.",
"priority": true,
"url": null
},
{
"status": "info",
"message": "New Features Available",
"details": "Check out our latest update with improved video quality and faster loading times!",
"priority": false,
"url": "https://example.com/changelog"
}
],
"channels": [
{
"id": "example-tube",
"name": "Example Tube",
"description": "A sample video channel demonstrating the API structure.",
"premium": false,
"favicon": "https://example.com/favicon.ico",
"status": "active",
"categories": ["Entertainment", "Education", "Music"],
"options": [
{
"id": "quality",
"title": "Video Quality",
"systemImage": "video",
"colorName": "blue",
"multiSelect": false,
"options": [
{
"id": "hd",
"title": "HD",
"description": "High definition videos only"
},
{
"id": "any",
"title": "Any Quality",
"description": "Include all video qualities"
}
]
},
{
"id": "duration",
"title": "Duration",
"systemImage": "clock",
"colorName": "orange",
"multiSelect": true,
"options": [
{
"id": "short",
"title": "Short (< 5 min)",
"description": "Videos under 5 minutes"
},
{
"id": "medium",
"title": "Medium (5-20 min)",
"description": "Videos between 5-20 minutes"
},
{
"id": "long",
"title": "Long (> 20 min)",
"description": "Videos over 20 minutes"
}
]
}
],
"nsfw": false,
"ytdlpCommand": "yt-dlp --format best",
"cacheDuration": 1800
}
],
"nsfw": false,
"categories": [
"Funny",
"Cute",
"Action",
"Adventure",
"Animation",
"Comedy",
"Documentary",
"Drama"
],
"options": [
{
"id": "sort",
"title": "Sort",
"systemImage": "arrow.up.arrow.down",
"colorName": "blue",
"multiSelect": false,
"options": [
{
"id": "new",
"title": "New",
"description": "Sort the videos by newest first."
},
{
"id": "likes",
"title": "Most Liked",
"description": "Sort the videos by likes."
}
]
}
],
"popup": null,
"filtersFooter": "Help us improve our algorithms by selecting the categories that best describe you. These may not change search results on your source, but they help personalize the overall app experience."
}
Field Reference
ServerStatus Object
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Unique server identifier |
name |
string |
â | Server display name |
subtitle |
string |
âĒ | Brief server description |
description |
string |
âĒ | Detailed server description |
iconUrl |
string |
âĒ | Server icon/logo URL |
color |
string |
âĒ | Brand color (hex code or Swift color names) |
status |
ChannelStatus |
âĒ | Server operational status |
notices |
Notice[] |
âĒ | Status notices/alerts |
channels |
Channel[] |
âĒ | Available content channels |
channelGroups |
ChannelGroup[] |
âĒ | Explicit channel picker sections (takes priority over per-channel groupKey/sortOrder) |
nsfw |
boolean |
âĒ | Whether server contains adult content |
categories |
string[] |
âĒ | Available content categories |
options |
ChannelOption[] |
âĒ | Global server options |
filtersFooter |
string |
âĒ | Footer text for filter UI |
ChannelGroup Object
An explicit, ordered section definition for the channel picker. When present, channelGroups takes full priority over per-channel groupKey and sortOrder.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Unique group identifier |
title |
string |
â | Section heading displayed in the channel picker |
channelIds |
string[] |
â | Ordered list of channel IDs belonging to this group |
Channel Picker Section Logic
The channel picker builds sections using the following priority order:
channelGroups(top-level, on ServerStatus) â explicit sections with named titles and an ordered list of channel IDs. Use this for full control over grouping and order.groupKey+sortOrder(per-channel fields) â lightweight fallback. Channels are grouped by theirgroupKeystring; within each group they are sorted bysortOrder(ascending), then alphabetically. Use this when you don't want a separate top-level structure.- Default â if neither is provided, channels are split into a "Premium" section and a general "Channels" section, each sorted alphabetically.
// Option A: channelGroups (explicit, recommended for complex layouts)
{
"channelGroups": [
{ "id": "featured", "title": "Featured", "channelIds": ["tube-a", "tube-b"] },
{ "id": "niche", "title": "Niche", "channelIds": ["tube-c"] }
]
}
// Option B: groupKey + sortOrder (per-channel, simpler)
{ "id": "tube-a", "groupKey": "Featured", "sortOrder": 1 }
{ "id": "tube-b", "groupKey": "Featured", "sortOrder": 2 }
{ "id": "tube-c", "groupKey": "Niche", "sortOrder": 1 }
Channel Object
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Unique channel identifier |
name |
string |
â | Channel display name |
favicon |
string |
âĒ | Channel favicon URL |
status |
ChannelStatus |
âĒ | Channel operational status |
categories |
string[] |
âĒ | Content categories for this channel â drives the home screen category browser (tapping one runs a search for that term) |
tags |
ChannelTag[] |
âĒ | Specialization chips shown in the channel picker (e.g. "4K", "Amateur") |
options |
ChannelOption[] |
âĒ | Channel-specific filter options |
maintainers |
ChannelMaintainer[] |
âĒ | Attribution entries shown in video cells |
premium |
boolean |
âĒ | Whether channel requires premium |
description |
string |
âĒ | Channel description |
image |
string |
âĒ | Channel banner/hero image URL |
nsfw |
boolean |
âĒ | Whether channel contains adult content |
default |
boolean |
âĒ | Whether this channel is selected by default |
sortOrder |
number |
âĒ | Display order when channelGroups is not used â lower values appear first |
groupKey |
string |
âĒ | Section key for grouping channels (e.g. "favorites", "premium", or a category name) |
ytdlpCommand |
string |
âĒ | Custom yt-dlp command |
cacheDuration |
number |
âĒ | Cache duration in seconds â yt-dlp re-extracts video details when expired |
Categories vs Tags
categoriesis a flat list of content keywords (e.g."Comedy","Action") shared across videos from this channel. They populate the home screen category browser â tapping one runs a search using that term.tagsare specialization labels for the channel itself (e.g."4K","Amateur","VR") displayed as chips in the channel picker UI. They describe what the site is known for, not individual video content.
ChannelTag Object
Tags can be supplied as a plain string (legacy) or a typed object â the app accepts both transparently.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
â | Tag label displayed on the channel chip |
systemImage |
string |
âĒ | SF Symbol name shown alongside the tag label |
// Plain string (legacy â still accepted)
"categories": ["4K", "Amateur"]
// Object format (recommended â supports icons)
"tags": [
{ "name": "4K", "systemImage": "4k.tv" },
{ "name": "VR", "systemImage": "visionpro" }
]
ChannelMaintainer Object
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Maintainer identifier |
name |
string |
â | Display name |
avatar |
string |
âĒ | Avatar image URL (canonical) |
role |
string |
âĒ | "maintainer" (built the integration) or "upstream" (federated proxy) |
See JSON key names for naming conventions and the legacy profile_picture_url avatar key.
Notice Object
| Field | Type | Required | Description |
|---|---|---|---|
status |
string |
â | Notice type ("success", "info", "error", "warning", etc.) |
message |
string |
âĒ | Notice title/message |
details |
string |
âĒ | Detailed notice description |
priority |
boolean |
âĒ | Whether to display prominently on home page |
url |
string |
âĒ | Action URL for the notice |
ChannelOption Object
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Unique option identifier |
title |
string |
â | Option display title |
options |
ChannelOptionChoice[] |
â | Available choices for this option |
systemImage |
string |
âĒ | SF Symbol name for option icon |
colorName |
string |
âĒ | Swift color name for theming |
multiSelect |
boolean |
âĒ | Whether multiple choices can be selected |
value |
string\|number\|boolean |
âĒ | Current option value |
ChannelOptionChoice Object
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
â | Unique choice identifier |
title |
string |
â | Choice display title |
description |
string |
âĒ | Choice description |
options |
ChannelOption[] |
âĒ | Nested options shown when this choice is selected |
ChannelStatus Enum
| Value | Description |
|---|---|
active |
Channel is online and fully functional (same as normal / ok) |
normal |
Alias for active |
ok |
Alias for active |
inactive |
Channel deliberately disabled or suspended |
degraded |
Channel working with reduced quality or performance |
maintenance |
Channel temporarily unavailable due to planned work |
restricted |
Access is limited (e.g. region-locked, paywalled, or subject to a takedown) |
error |
Channel encountered a critical issue |
unknown |
Channel status is not known |
testing |
Channel is in testing mode for development |
Implementation Notes
- Only
idandnameare truly required for bothServerStatusandChannel - Options create hierarchical filter UIs â choices can have nested options
prioritynotices appear on the home page; others only appear on the lock screen- Colors support both hex codes (
#FF0000) and Swift color names (purple) - Channel
tagsaccept either plain strings (legacy) or{ name, systemImage }objects â mixing both in the same array is fine sortOrderandgroupKeyare the per-channel fallback for sectioning;channelGroupson the server response takes priority when present
Popup System
The popup system allows servers to display onboarding flows, age verification, preferences, and other modal content. Here's an example multi-page onboarding popup:
{
"popup": {
"id": "onboarding",
"pages": [
{
"id": "ageVerification",
"title": "Welcome to",
"subtitle": "Example Server",
"warning": "â ī¸ Adult Content Warning",
"body": "This source contains adult content. You must be 18 years or older to use it. By continuing, you confirm that you meet this requirement and agree to use the app responsibly.",
"items": [
{
"type": "section",
"title": "Age Verification",
"items": [
{
"type": "toggle",
"id": "termsToggle",
"title": "I am over 18 years of age",
"systemImage": "checkmark.seal.fill",
"color": "gray",
"state": false
}
]
}
],
"actions": [
{
"title": "Continue",
"systemImage": "arrow.right.circle.fill",
"color": "blue",
"actionType": "next",
"enabledBy": "termsToggle"
}
]
},
{
"id": "preferences",
"title": "Choose your Preferences",
"subtitle": "Personalize Your Experience",
"body": "Select the type of content you'd like to explore. This can be changed later in the filters menu.",
"items": [
{
"type": "custom",
"view": "ServerFiltersView"
}
],
"actions": [
{
"title": "Continue",
"systemImage": "arrow.right.circle.fill",
"color": "blue",
"actionType": "next"
}
]
}
]
}
}
Popup Features:
- Multi-page flows - Create step-by-step onboarding experiences
- Conditional actions - Use
enabledByto require toggle states before proceeding - Custom views - Embed specialized UI like
ServerFiltersViewfor complex interactions - Rich content - Support for titles, subtitles, warnings, body text, and actions
- Interactive controls - Toggles, buttons, and sections for user input