Table of Contents
- API Reference
- Base URL
- Authentication
- Error Format
- Health & System
- GET /ping
- GET /api/v1/health
- GET /api/v1/system/status
- GET /api/v1/system/apikey
- POST /api/v1/system/apikey/regenerate
- GET /api/v1/system/settings
- PUT /api/v1/system/settings
- GET /api/v1/system/ytdlp/status
- POST /api/v1/system/ytdlp/update
- Channels
- GET /api/v1/channel
- POST /api/v1/channel
- GET /api/v1/channel/:id
- PUT /api/v1/channel/:id
- PUT /api/v1/channel/:id/monitoring-mode
- DELETE /api/v1/channel/:id
- POST /api/v1/channel/scan-all
- POST /api/v1/channel/collect-all
- Content Items
- GET /api/v1/content
- GET /api/v1/channel/:id/content
- PATCH /api/v1/content/:id/monitored
- PATCH /api/v1/content/bulk/monitored
- Download Queue
- POST /api/v1/download/:contentItemId
- GET /api/v1/queue
- GET /api/v1/queue/:id
- POST /api/v1/queue
- DELETE /api/v1/queue/:id
- POST /api/v1/queue/:id/retry
- Format Profiles
- GET /api/v1/format-profile
- POST /api/v1/format-profile
- PUT /api/v1/format-profile/:id
- DELETE /api/v1/format-profile/:id
- Notifications
- GET /api/v1/notification
- POST /api/v1/notification
- PUT /api/v1/notification/:id
- DELETE /api/v1/notification/:id
- POST /api/v1/notification/:id/test
- Platform Settings
- Scan & Collect
- History
- Playlists
- WebSocket
API Reference
| Meta | Value |
|---|---|
| Repo | xpltdco/tubearr |
| Page | API-Reference |
| Audience | developers, agents |
| Last Updated | 2026-04-04 |
| Status | current |
Base URL
https://tubearr.xpltd.co/api/v1
Local development: http://localhost:8989/api/v1
Authentication
All API endpoints (except /ping) require authentication via one of:
| Method | Details |
|---|---|
| Same-origin | Requests from the Tubearr UI (matching Origin/Referer header) are authenticated automatically |
| API Key header | X-Api-Key: <your-api-key> |
| API Key query | ?apikey=<your-api-key> |
The API key is a UUID auto-generated on first startup. Retrieve or regenerate it via the System endpoints.
Unauthorized response:
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or missing API key"
}
Error Format
All errors return a consistent JSON structure:
{
"statusCode": 404,
"error": "Not Found",
"message": "Channel not found"
}
In development mode, a stack field may be included. API keys are always redacted from error responses.
Health & System
GET /ping
Liveness probe. No authentication required.
200 OK
GET /api/v1/health
Full health check with component status (database, yt-dlp, disk space, scheduler).
GET /api/v1/system/status
Runtime info: version, uptime, memory usage.
GET /api/v1/system/apikey
Returns the current API key.
POST /api/v1/system/apikey/regenerate
Generate a new API key. Returns the new key. The old key is immediately invalidated.
GET /api/v1/system/settings
Global settings (check interval, concurrent downloads).
PUT /api/v1/system/settings
Update global settings.
{
"checkInterval": 360,
"concurrentDownloads": 2
}
GET /api/v1/system/ytdlp/status
yt-dlp version and last update timestamp.
POST /api/v1/system/ytdlp/update
Force yt-dlp to self-update. Returns the new version string.
Channels
GET /api/v1/channel
List all monitored channels with content counts.
Response:
[
{
"id": 1,
"name": "Example Channel",
"platform": "youtube",
"platformId": "UCxxxxxxx",
"url": "https://youtube.com/@example",
"monitoringEnabled": true,
"monitoringMode": "all",
"checkInterval": 360,
"imageUrl": "https://...",
"lastCheckedAt": "2026-04-04T10:00:00Z",
"lastCheckStatus": "success",
"contentCount": 42,
"downloadedCount": 15
}
]
POST /api/v1/channel
Add a channel by URL. Tubearr resolves metadata (name, image, subscriber count) via yt-dlp.
Request:
{
"url": "https://youtube.com/@example",
"monitoringMode": "future",
"formatProfileId": 1
}
GET /api/v1/channel/:id
Get single channel with full metadata.
PUT /api/v1/channel/:id
Update channel settings.
{
"name": "Updated Name",
"checkInterval": 120,
"formatProfileId": 2,
"monitoringEnabled": true
}
PUT /api/v1/channel/:id/monitoring-mode
Change monitoring mode.
{
"monitoringMode": "future"
}
Modes: all (grab everything), future (new content only), existing (backlog only), none (pause monitoring)
DELETE /api/v1/channel/:id
Delete channel. Cascades to all content items and queue items.
POST /api/v1/channel/scan-all
Manually trigger monitoring scan for all enabled channels. Returns immediately (202 Accepted); scans run in background.
POST /api/v1/channel/collect-all
Trigger back-catalog import for all channels with grabAllEnabled.
Content Items
GET /api/v1/content
Paginated content listing with filters.
Query parameters:
| Param | Type | Description |
|---|---|---|
page |
number | Page number (default: 1) |
limit |
number | Items per page (default: 20) |
status |
string | Filter by status |
contentType |
string | Filter by type (video, audio, livestream) |
search |
string | Search by title |
channelId |
number | Filter by channel |
GET /api/v1/channel/:id/content
Content items for a specific channel. Same pagination and filter params as above.
PATCH /api/v1/content/:id/monitored
Toggle monitoring state for a single content item.
{
"monitored": false
}
PATCH /api/v1/content/bulk/monitored
Bulk toggle monitoring state.
{
"ids": [1, 2, 3],
"monitored": true
}
Download Queue
POST /api/v1/download/:contentItemId
Enqueue a content item for download. Returns 202 Accepted.
{
"priority": 10
}
GET /api/v1/queue
List queue items. Optional ?status=pending|downloading|completed|failed|cancelled filter.
Response:
[
{
"id": 1,
"contentItemId": 42,
"status": "downloading",
"priority": 0,
"attempts": 1,
"maxAttempts": 3,
"error": null,
"startedAt": "2026-04-04T10:05:00Z",
"contentItem": {
"title": "Example Video",
"channelName": "Example Channel"
}
}
]
GET /api/v1/queue/:id
Get single queue item with content details.
POST /api/v1/queue
Alternative enqueue endpoint (accepts contentItemId in body).
DELETE /api/v1/queue/:id
Cancel a queue item (sets status to cancelled).
POST /api/v1/queue/:id/retry
Retry a failed queue item (resets to pending, increments attempts).
Format Profiles
GET /api/v1/format-profile
List all format profiles.
Response:
[
{
"id": 1,
"name": "High Quality",
"videoResolution": "1080p",
"audioCodec": "opus",
"audioBitrate": "192k",
"containerFormat": "mkv",
"isDefault": true,
"embedSubtitles": true,
"sponsorBlockRemove": "sponsor,selfpromo"
}
]
POST /api/v1/format-profile
Create a format profile.
{
"name": "Mobile Friendly",
"videoResolution": "720p",
"audioCodec": "aac",
"audioBitrate": "128k",
"containerFormat": "mp4",
"embedSubtitles": false,
"embedThumbnail": true
}
PUT /api/v1/format-profile/:id
Update a format profile.
DELETE /api/v1/format-profile/:id
Delete a format profile. Channels using it will have their formatProfileId set to NULL.
Notifications
GET /api/v1/notification
List notification channel configurations.
POST /api/v1/notification
Create a notification channel.
{
"type": "discord",
"name": "My Discord Server",
"enabled": true,
"config": {
"webhookUrl": "<your-discord-webhook-url>"
},
"onGrab": true,
"onDownload": true,
"onFailure": true
}
PUT /api/v1/notification/:id
Update notification settings.
DELETE /api/v1/notification/:id
Delete a notification channel.
POST /api/v1/notification/:id/test
Send a test notification to verify configuration.
Platform Settings
GET /api/v1/platform-settings
Get per-platform settings for all platforms.
PUT /api/v1/platform-settings/:platform
Update settings for a specific platform (youtube, soundcloud, generic).
{
"checkInterval": 240,
"concurrencyLimit": 3,
"rateLimitDelay": 2000,
"defaultMonitoringMode": "future",
"grabAllEnabled": false
}
Scan & Collect
POST /api/v1/scan/:channelId
Manually trigger a monitoring scan for a specific channel. Checks for new content and inserts it.
POST /api/v1/collect/:channelId
Trigger back-catalog import for a specific channel.
History
GET /api/v1/history
Download activity log with pagination.
Query parameters: page, limit, eventType
Event types: grabbed, downloaded, failed, imported, deleted
Playlists
GET /api/v1/playlist
List playlists discovered from monitored channels.
WebSocket
GET /ws
Upgrade to WebSocket connection for real-time events.
Events pushed to clients:
| Event | Description |
|---|---|
download:progress |
Download percentage, speed, ETA for an active download |
download:complete |
Download finished successfully |
download:failed |
Download failed (includes error) |
scan:start |
Channel monitoring scan started |
scan:complete |
Channel monitoring scan finished |
scan:new-content |
New content discovered during scan |
Message format:
{
"event": "download:progress",
"data": {
"contentItemId": 42,
"percent": 45.2,
"speed": "5.2MiB/s",
"eta": "00:01:23"
}
}