Files
tuliprox/docs/src/rest-api-cookbook.md
T
euzuandGitHub 16d32d1298 DVR Feature (#819)
feat: complete DVR and improve streaming, security, configuration, and UI

Complete the Digital Video Recorder subsystem and add a broad set of
reliability, security, streaming, configuration, processing, and Web UI
improvements across Tuliprox.

DVR:

* complete live recording and provider-aware VOD download support
* add recording queue, workers, scheduling, and recurring recording rules
* add conflict detection and capacity-aware scheduling
* add pause, resume, retry, edit, cancel, and delete workflows
* add recording quotas and configurable retention policies
* add crash recovery and startup reconciliation
* add durable lifecycle notifications with per-channel retries
* add DVR health monitoring and diagnostic tooling
* add secure access to recordings, thumbnails, and subtitles
* add WebSocket notifications for recording and rule changes
* add Web UI management for recordings, rules, progress, and task state
* add RBAC, configuration, documentation, and i18n support

Streaming and HLS:

* fix shared-stream idle handling and release dead provider streams correctly
* stop tee streams when both client and cache consumers are gone
* cancel provisioning probes when client streams terminate
* fix transient HLS origin work accounting and intermittent 503 responses
* make stream buffer byte limits configurable
* make shared subscriber idle timeout configurable
* make initial HLS manifest wait timeout configurable
* add configurable TS chunk packet count
* add configurable HLS refresh failure backoff
* centralize redirect limits and retry jitter handling
* improve provider DNS refresh behavior and failover tuning
* preserve UTF-8 characters in catchup templates
* improve stream history validation and persistence error handling

Security:

* use constant-time credential comparisons
* harden library and media path handling against traversal and symlink escapes
* only trust forwarded client IP headers from configured trusted proxies
* redact credentials and sensitive URL data from logs
* reject invalid authentication status-code configuration
* deny users with unresolved plans or invalid content filters
* improve authentication error handling across proxy and HLS endpoints

Configuration and reliability:

* prevent invalid api-proxy.yml reloads from terminating the running server
* fully validate API proxy configuration before persisting changes
* log configuration and EPG cleanup failures instead of silently discarding them
* keep the last valid configuration active after failed hot reloads
* align backend and shared media-server validation
* remove duplicated path and normalization logic
* improve DNS-store recovery and Windows rename fallback handling
* reject invalid duration, timestamp, and numeric conversions safely
* fix playlist bouquet save error handling
* fix provider record update detection
* fix cache boundary handling
* improve startup and persistence failure diagnostics

Filtering, search, sorting, and processing:

* add field-scoped playlist explorer search
* centralize shared stream-history search field definitions
* extend the filter DSL with string, set, and numeric operators
* add EPG ID, channel number, and detected quality as filterable fields
* add filter dry-run preview API with match statistics and samples
* report filter syntax errors with line and column information
* add natural numeric-aware sorting
* add quality-aware channel deduplication
* add accent-independent deduplication
* move natural sorting and quality detection helpers into shared code
* persist explorer search-field selection across reloads

User plans and content access:

* add reusable API user plans for capability tiers
* support inherited cluster and connection limits with per-user overrides
* add plan-level and user-level content filters
* enforce content filters across Xtream, M3U, direct playback, resource access,
  stream info, short EPG, categories, and XMLTV
* add trial plans with automatic expiry and Trial status
* add plan selection and content filtering to the user editor
* add full plan management to the API configuration Web UI
* migrate the API user database to schema V7 with plan and filter persistence

Web UI and accessibility:

* add live logging console to the stats page
* improve login error handling and prevent duplicate authentication requests
* add keyboard navigation to tabs, menus, tables, and search
* add ARIA roles, labels, validation state, and live-region feedback
* add confirmation dialogs for destructive actions
* add unsaved-change warnings and Ctrl/Cmd+S shortcuts
* add loading, progress, empty, and in-flight states across views
* improve dropdown and single-selection behavior
* add clipboard and credential-copy helpers
* persist table pagination and explorer search preferences
* improve error recovery when UI context providers are unavailable
* remove multiple panic-prone unwrap and browser API paths
* replace remaining hardcoded UI strings with translation keys

Maintenance:

* resolve backend and frontend compiler and Clippy warnings
* update packages and test fixtures
* consolidate duplicated helpers and validation logic
* improve documentation for configuration, filters, plans, DVR, and REST APIs
* add and update tests for migrations, filters, deduplication, sorting,
  configuration, streaming, and accessibility behavior
2026-08-21 14:50:12 +02:00

16 KiB

REST API Cookbook

This page contains copy-paste examples for the Tuliprox Web UI REST API.

The examples use:

  • curl for HTTP requests
  • jq for token extraction and pretty-printing JSON

Requirements

  • Tuliprox is running in server mode
  • the Web UI REST API is enabled
  • curl and jq are installed
  • you have a valid Web UI username and password

Base URLs

By default, the login endpoint is:

http://localhost:8901/auth/token

If you configured a custom Web UI path such as web, the login endpoint becomes:

http://localhost:8901/web/auth/token

The protected REST API lives below:

http://localhost:8901/api/v1

or, with a Web UI path:

http://localhost:8901/web/api/v1

Example 1: Get a JWT token

#!/bin/bash

BASE_URL="http://localhost:8901"
USERNAME="admin"
PASSWORD="12345678"

TOKEN=$(curl -s -X POST "$BASE_URL/auth/token" \
    -H 'accept: application/json' \
    -H 'content-type: application/json' \
    --data-raw "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" | jq -r '.token')

if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then
    echo "Error: no token available"
    exit 1
fi

echo "$TOKEN"

If your local setup uses HTTPS with a self-signed certificate, add --insecure to the curl commands.

Example 2: Query server status

#!/bin/bash

BASE_URL="http://localhost:8901"
USERNAME="admin"
PASSWORD="12345678"

TOKEN=$(curl -s -X POST "$BASE_URL/auth/token" \
    -H 'accept: application/json' \
    -H 'content-type: application/json' \
    --data-raw "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" | jq -r '.token')

curl -s -X GET "$BASE_URL/api/v1/status" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" | jq .

Typical use:

  • verify that login works
  • use as a simple health and diagnostics check
  • inspect active users, active provider connections, cache state, and current server time

From this point onward, the examples use:

TOKEN="PUT_YOUR_TOKEN_HERE"

This is only to keep the examples shorter and easier to copy-paste. Example 1 above already shows how to obtain the JWT token, so it is not repeated in every script block below.

Example 3: List active streams

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X GET "$BASE_URL/api/v1/streams" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" | jq .

Typical use:

  • inspect currently active streams
  • see who is connected
  • correlate user activity with provider slot pressure

Example 4: Query stream history summary

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X GET "$BASE_URL/api/v1/stream-history/summary?from=2026-04-01&to=2026-04-03" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" | jq .

Typical use:

  • get an aggregated view over recent stream activity
  • inspect disconnect patterns and provider churn
  • verify that stream history collection is working

Example 5: Query QoS snapshots

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X GET "$BASE_URL/api/v1/qos-snapshots" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" | jq .

Typical use:

  • inspect per-stream reliability snapshots
  • compare 24h, 7d, and 30d quality windows
  • prepare later failover and ranking analysis

Example 6: Inspect a download target before queueing

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"
URL_TO_DOWNLOAD="https://example.invalid/file.mp4"

curl -s -G "$BASE_URL/api/v1/file/download/info" \
    --data-urlencode "url=$URL_TO_DOWNLOAD" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" | jq .

Typical use:

  • inspect filename and metadata before queueing
  • verify that the remote file is reachable
  • test download.read access

Example 7: Queue a file download

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X POST "$BASE_URL/api/v1/file/download" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    --data-raw '{
      "url": "https://example.invalid/file.mp4",
      "filename": "example.mp4",
      "input_name": null,
      "priority": null
    }' | jq .

Typical use:

  • queue a normal background download
  • confirm that duplicate queue requests return the existing task instead of creating a second one
  • test download.write access

Example 8: Trigger a playlist update

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X POST "$BASE_URL/api/v1/playlist/update" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    --data-raw '["main"]'

Typical use:

  • trigger a manual processing run for one or more targets
  • verify playlist.write permission
  • integrate Tuliprox into external automation

Example 9: Preview a Stalker live input in the Web UI playlist API

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X POST "$BASE_URL/api/v1/playlist/live" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    --data-raw '{"Input":"stalker"}' | jq .

Typical use:

  • verify that a configured Stalker input handshakes and returns playlist preview rows
  • confirm that the Web UI playlist explorer can inspect Stalker live content
  • distinguish preview/catalog problems from later playback-resolution problems

Notes:

  • Replace "stalker" with the configured input name.
  • The preview endpoint returns catalog items. Actual playback can still require Stalker create_link resolution later, depending on your stalker_pre_resolve_playback / stalker_runtime_resolve_playback settings.
  • If a Stalker item has not been materialized yet, Tuliprox no longer exposes the raw portal cmd as the playlist URL. Runtime playback resolves a real media URL later through the reverse-proxy path.
  • Expired temp links are refreshed automatically when stalker_runtime_resolve_playback is enabled. Only portal-specific extra header/cookie requirements remain a possible follow-up.
  • Runtime refresh only produces http/https playback URLs; Stalker rtmp:// / rtsp:// commands are rejected explicitly rather than proxied half-supported.

Example 10: Dry-run a filter expression against a target

#!/bin/bash

BASE_URL="http://localhost:8901"
TOKEN="PUT_YOUR_TOKEN_HERE"

curl -s -X POST "$BASE_URL/api/v1/playlist/filter/preview" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    --data-raw '{"target": 1, "filter": "Group ~ \"^DE.*\" AND NOT Title CONTAINS \"Shopping\"", "limit": 10}' | jq .

Typical use:

  • test a filter DSL expression against a target's stored playlist before writing it into source.yml
  • see matched/total counts overall and per cluster (live/vod/series)
  • inspect sample matched and excluded channels to verify the expression does what you expect

Notes:

  • target is the numeric target id (same id the playlist explorer uses).
  • filter supports the full filter DSL including !TEMPLATE! references from your configured templates.
  • Optional limit caps the sample lists (default 25, max 50); optional match_as_ascii mirrors the target option.
  • An invalid filter expression returns HTTP 422 with {"error": "...", "line": n, "column": n}; line/column are null for semantic errors without a source position (e.g. an invalid regex value).
  • The preview reads the target's already-processed playlist; it never contacts providers or triggers an update.

Available /api/v1 Endpoints

This is a compact operator-oriented overview of the /api/v1 REST API groups currently registered by the backend.

System and diagnostics

Method Path Purpose
GET /api/v1/status Server status, version, active users, provider connections, cache state
GET /api/v1/streams Current active streams
GET /api/v1/ipinfo External IPv4/IPv6 check if configured
GET /api/v1/stream-history Query raw persisted stream history
GET /api/v1/stream-history/summary Aggregated stream history summary
GET /api/v1/qos-snapshots List QoS snapshots
GET /api/v1/qos-snapshots/{stream_identity_key} QoS detail for one stream
GET /api/v1/geoip/update Trigger GeoIP DB update

Downloads and recordings

Method Path Purpose
GET /api/v1/file/download/info Inspect remote file/download info
POST /api/v1/file/download Queue a file download
POST /api/v1/file/record Queue a live recording
POST /api/v1/file/download/pause Pause a queued or active download
POST /api/v1/file/download/resume Resume a paused download
POST /api/v1/file/download/cancel Cancel a queued or active download
POST /api/v1/file/download/remove Remove a task from the download database
POST /api/v1/file/download/retry Retry a failed download
GET /api/v1/recording/tasks List visible DVR tasks
POST /api/v1/recording/tasks Create a DVR recording task from server-owned source ids
PATCH /api/v1/recording/tasks/{id} Edit an upcoming DVR recording
POST /api/v1/recording/tasks/{id}/cancel Cancel an active, queued, or scheduled DVR recording
DELETE /api/v1/recording/tasks/{id} Delete a finished DVR recording through the safe deletion lifecycle
POST /api/v1/recording/conflicts/preview Advisory conflict preview (severity, optional provider scope, overlap segments)
GET /api/v1/recording/quota Read the caller's private quota and shared DVR usage
GET /api/v1/recording/rules List visible recurring recording rules
POST /api/v1/recording/rules Create a weekly recurring recording rule
PATCH /api/v1/recording/rules/{id} Edit a recurring recording rule
DELETE /api/v1/recording/rules/{id}?future=retain|cancel Delete a recurring recording rule

DVR WebSocket protocol

The DVR layer ships its own scoped protocol messages on the same WebSocket connection as the rest of the backend. The frontend sends ProtocolMessage::RecordingSnapshotRequest to subscribe and receives:

  • ProtocolMessage::RecordingSnapshotResponse { revision, tasks } — the full filtered task list for the caller's session, sent on connect and after every mutation the session is permitted to see.
  • ProtocolMessage::RecordingDeltaResponse { revision, tasks } — a smaller diff when only a few tasks changed.

The frontend never polls. After a successful POST /api/v1/recording/tasks it relies on the next RecordingSnapshotResponse to update its view. Rule lists are refreshed by hooking into EventMessage::RecordingSnapshot and re-calling GET /api/v1/recording/rules; a dedicated RecordingRulesChanged event is a planned follow-up but not currently shipped.

DVR conflict preview

POST /api/v1/recording/conflicts/preview is advisory only — the response carries a severity bucket (none / soft / hard) plus optional provider scope and overlap segments, but the server does not reject the create call based on it. The frontend renders the preview as a hint next to the recording form's scheduled interval, never as a hard block.

POST /api/v1/file/record (deprecated)

The legacy POST /api/v1/file/record endpoint is admin-gated and scheduled for removal in the next major version. It returns recording_forbidden for non-admin principals. New code should call POST /api/v1/recording/tasks with a CreateRecordingTaskBody payload.

Playlist and web-player helpers

Method Path Purpose
POST /api/v1/playlist/live Query live playlist content for the Web UI, including Stalker inputs
POST /api/v1/playlist/vod Query VOD playlist content
POST /api/v1/playlist/series Query series playlist content
POST /api/v1/playlist/resolve_url Resolve provider-backed stream URLs
POST /api/v1/playlist/update Trigger target updates
POST /api/v1/playlist/epg Query EPG data for the Web UI
POST /api/v1/playlist/series_info/{virtual_id}/{provider_id} Series metadata lookup
POST /api/v1/playlist/series/episode/{virtual_id} Episode item lookup
POST /api/v1/playlist/filter/preview Dry-run a filter DSL expression against a target's stored playlist
GET /api/v1/playlist/resource/{resource} Public resource access for playlist-related assets

Configuration

Method Path Purpose
GET /api/v1/config Read effective configuration
GET /api/v1/config/batchContent/{input_id} Inspect batch input content
POST /api/v1/config/xtream/login-info Test or inspect Xtream login information
POST /api/v1/config/main Save config.yml
POST /api/v1/config/sources Save source.yml
GET /api/v1/config/apiproxy Read api-proxy.yml
PUT /api/v1/config/apiproxy Save api-proxy.yml

API proxy users

Method Path Purpose
POST /api/v1/user/{target} Create a target user
PUT /api/v1/user/{target} Update or move a target user
DELETE /api/v1/user/{target}/{username} Delete a target user

Library

Method Path Purpose
GET /api/v1/library/status Local library status
POST /api/v1/library/scan Trigger a library scan
GET /api/v1/library/thumbnail/{uuid} Read a generated thumbnail

RBAC management

Method Path Purpose
GET /api/v1/rbac/users List Web UI users
POST /api/v1/rbac/users Create a Web UI user
PUT /api/v1/rbac/users/{username} Update a Web UI user
DELETE /api/v1/rbac/users/{username} Delete a Web UI user
GET /api/v1/rbac/groups List permission groups
POST /api/v1/rbac/groups Create a permission group
PUT /api/v1/rbac/groups/{name} Update a permission group
DELETE /api/v1/rbac/groups/{name} Delete a permission group
GET /api/v1/rbac/permissions List available permissions

Permissions

With Web UI authentication enabled, many endpoints require matching permissions such as:

  • system.read
  • system.write
  • playlist.read
  • playlist.write
  • config.read
  • config.write
  • source.read
  • source.write
  • user.read
  • user.write
  • library.read
  • library.write
  • download.read
  • download.write
  • recording.read
  • recording.write

If a request is rejected, verify the logged-in Web UI user's RBAC group assignments first.

See also: the full DVR Operator Reference for the authorization matrix, identity-registry bootstrap, token refresh, recurring-rule matching + DST, cross-store reconciliation, at-most-once notification protocol, and the migration checklist.