All API endpoints now provide consistent error responses with appropriate HTTP status codes.
{
"error": "Error Type",
"message": "Human-readable error message",
"path": "/api/endpoint",
"timestamp": "2025-12-30T20:00:00.000Z",
"details": "Additional error details (optional)"
}200 OK- Request successful400 Bad Request- Invalid request parameters or body404 Not Found- Resource or endpoint not found500 Internal Server Error- Unexpected server error502 Bad Gateway- Upstream service (M3U/EPG source) unavailable503 Service Unavailable- Service not ready (e.g., EPG not loaded)
404 Not Found:
{
"error": "Not Found",
"message": "The requested resource was not found",
"path": "/nonexistent",
"method": "GET"
}503 Service Unavailable:
{
"error": "EPG not loaded yet",
"message": "EPG not loaded yet",
"path": "/xmltv.xml",
"timestamp": "2025-12-30T20:00:00.000Z"
}500 Internal Server Error:
{
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"path": "/lineup.m3u",
"timestamp": "2025-12-30T20:00:00.000Z"
}The server fully supports reverse proxy deployments with proper header forwarding.
The following headers are honored for base URL generation:
X-Forwarded-Proto- Protocol (http/https)X-Forwarded-Protocol- Alternative protocol headerX-Url-Scheme- Alternative protocol headerX-Forwarded-Ssl- Set to "on" for HTTPSX-Forwarded-Host- Original host header
Nginx:
location / {
proxy_pass http://localhost:34400;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Apache:
<Location />
ProxyPass http://localhost:34400/
ProxyPassReverse http://localhost:34400/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Host "%{HTTP_HOST}e"
</Location>Basic health check that returns 200 if the server is running.
Response:
{
"status": "ok",
"timestamp": "2025-12-30T20:00:00.000Z"
}Liveness probe for Kubernetes or Docker health checks. Indicates if the server process is running.
Response:
{
"status": "ok",
"message": "Server is alive",
"timestamp": "2025-12-30T20:00:00.000Z"
}Readiness probe that checks if the server is ready to handle requests. Returns 200 if ready, 503 if not ready.
Response (Ready):
{
"timestamp": "2025-12-30T20:00:00.000Z",
"ready": true,
"checks": {
"channels": {
"status": "ok",
"count": 42,
"available": true
},
"channelsFile": {
"status": "ok",
"size": 12345,
"modified": "2025-12-30T19:00:00.000Z"
}
}
}Response (Not Ready):
{
"timestamp": "2025-12-30T20:00:00.000Z",
"ready": false,
"checks": {
"channels": {
"status": "warning",
"count": 0,
"available": false,
"message": "No channels loaded"
},
"channelsFile": {
"status": "ok",
"size": 2,
"modified": "2025-12-30T19:00:00.000Z"
}
}
}Comprehensive system diagnostics endpoint that provides information about the current state of the IPTV proxy.
Response:
{
"timestamp": "2025-12-30T04:19:09.594Z",
"uptime": 41.195943614,
"channels": {
"total": 4,
"bySource": {
"TestSource": 3,
"OtherSource": 1
},
"mapped": 2,
"unmapped": 2,
"file": {
"size": 947,
"modified": "2025-12-30T04:13:25.480Z"
}
},
"sources": {
"m3u": {
"count": 2,
"configured": [
{
"name": "TestSource",
"type": "m3u",
"url": "http://example.com/playlist.m3u"
}
],
"status": {
"TestSource": {
"status": "success",
"lastUpdate": "2025-12-30T04:13:25.480Z",
"error": null
}
}
},
"epg": {
"count": 1,
"configured": [
{
"name": "TestSource",
"url": "http://example.com/epg.xml"
}
]
}
},
"mappings": {
"total": 5,
"channelsCovered": 2,
"channelsNotCovered": 2,
"coveragePercent": 50
},
"parsing": {
"lastUpdate": "2025-12-30T04:13:25.480Z",
"recentErrors": []
}
}Add or update a single channel mapping.
Request Body:
{
"key": "Channel Name",
"mapping": {
"name": "New Channel Name",
"tvg_id": "channel.id",
"number": "101",
"logo": "http://example.com/logo.png"
}
}Response:
{
"status": "saved",
"key": "Channel Name",
"mapping": {
"name": "New Channel Name",
"tvg_id": "channel.id",
"number": "101",
"logo": "http://example.com/logo.png"
}
}Remove a channel mapping by key. The key should be URL-encoded.
Example:
DELETE /api/mapping/Channel%20NameResponse:
{
"status": "deleted",
"key": "Channel Name"
}Add or update multiple channel mappings at once.
Request Body:
{
"mappings": {
"Channel A": {
"name": "Channel A HD",
"tvg_id": "a.1",
"number": "1"
},
"Channel B": {
"name": "Channel B HD",
"tvg_id": "b.2",
"number": "2"
}
}
}Response:
{
"status": "saved",
"count": 2
}The M3U playlist endpoint now supports filtering by source or group.
Query Parameters:
source- Filter channels by source name (e.g.,?source=TestSource)group- Filter channels by group-title (mapped to source name)
Examples:
# Get all channels from TestSource
GET /lineup.m3u?source=TestSource
# Get all channels from a specific group
GET /lineup.m3u?group=TestSourceThe XMLTV EPG endpoint now supports filtering by source or specific channel IDs.
Query Parameters:
source- Filter EPG data by source name (e.g.,?source=TestSource)channels- Comma-separated list of channel IDs to include (e.g.,?channels=test1,test2,demo1)
Examples:
# Get EPG data only for TestSource channels
GET /xmltv.xml?source=TestSource
# Get EPG data for specific channels
GET /xmltv.xml?channels=test1,test2,demo1The following endpoints remain available:
GET /lineup.json- JSON lineup for HDHomeRun compatibilityGET /channels- List all channelsGET /api/config/m3u- Get M3U configurationGET /api/config/epg- Get EPG configurationGET /api/config/app- Get app configurationGET /api/config/channel-map- Get channel mappingsPUT /api/config/m3u- Update M3U configurationPUT /api/config/epg- Update EPG configurationPUT /api/config/app- Update app configurationPUT /api/config/channel-map- Update channel mappingsPOST /api/reload/channels- Reload channels from sourcesPOST /api/reload/epg- Reload EPG dataGET /api/channel-health- Get channel health statusPOST /api/channel-health/run- Run channel health checkGET /api/mapping/candidates- Get mapping candidatesGET /api/mapping/unmapped- Get unmapped channelsGET /api/mapping/conflicts- Get mapping conflicts
All endpoints now include proper error handling and will return appropriate HTTP status codes with detailed error messages.
The IPTV Proxy includes a sophisticated caching system to improve performance and reduce load on source servers.
Get statistics for all caches.
Response:
{
"caches": {
"epg": {
"name": "epg",
"size": 5,
"ttl": 21600000,
"hits": 150,
"misses": 10,
"hitRate": "93.75%",
"entries": [
{
"key": "https://example.com|source:|channels:",
"age": 3600,
"ttlRemaining": 18000,
"expired": false
}
]
},
"m3u": {
"name": "m3u",
"size": 3,
"ttl": 3600000,
"hits": 200,
"misses": 5,
"hitRate": "97.56%",
"entries": []
}
},
"timestamp": "2026-01-11T03:00:00.000Z"
}Clear all caches.
Response:
{
"status": "success",
"message": "All caches cleared",
"timestamp": "2026-01-11T03:00:00.000Z"
}Clear a specific cache by name.
URL Parameters:
name- Cache name (e.g.,epg,m3u,lineup-json)
Response:
{
"status": "success",
"message": "Cache 'epg' cleared",
"timestamp": "2026-01-11T03:00:00.000Z"
}Update the TTL for a specific cache.
URL Parameters:
name- Cache name
Request Body:
{
"ttl": 7200
}Note: TTL is in seconds.
Response:
{
"status": "success",
"message": "Cache 'epg' TTL updated",
"name": "epg",
"ttl": 7200,
"timestamp": "2026-01-11T03:00:00.000Z"
}The Preview API allows you to test configuration changes before saving them.
Preview merged M3U playlist with temporary configuration.
Request Body:
{
"m3uConfig": {
"urls": [
{
"name": "Test Source",
"url": "https://example.com/playlist.m3u"
}
]
},
"channelMapConfig": {
"Channel Name": {
"number": "100",
"tvg_id": "channel-id"
}
}
}Response:
Returns an M3U playlist file with Content-Type: application/x-mpegURL.
Preview merged channels as JSON with temporary configuration.
Request Body:
{
"m3uConfig": {
"urls": [
{
"name": "Test Source",
"url": "https://example.com/playlist.m3u"
}
]
},
"channelMapConfig": {
"Channel Name": {
"number": "100"
}
}
}Response:
{
"channels": [
{
"name": "Channel Name",
"tvg_id": "channel-id",
"logo": "https://example.com/logo.png",
"url": "https://example.com/stream",
"guideNumber": "100",
"source": "Test Source"
}
],
"count": 1,
"sources": ["Test Source"]
}Preview merged EPG with temporary configuration.
Request Body:
{
"epgConfig": {
"urls": [
{
"name": "Test EPG",
"url": "https://example.com/xmltv.xml"
}
]
},
"channels": [
{
"name": "Channel Name",
"tvg_id": "channel-id",
"source": "Test EPG"
}
]
}Response:
Returns an XMLTV file with Content-Type: application/xml.
Preview merged EPG as JSON with temporary configuration.
Request Body:
{
"epgConfig": {
"urls": [
{
"name": "Test EPG",
"url": "https://example.com/xmltv.xml"
}
]
},
"channels": [
{
"name": "Channel Name",
"tvg_id": "channel-id",
"source": "Test EPG"
}
]
}Response:
{
"channels": 50,
"programmes": 1000,
"sources": ["Test EPG"],
"data": {
"tv": {
"channel": [],
"programme": []
}
}
}All endpoints require authentication (session cookie or equivalent).
Create a timestamped snapshot of all YAML configuration files. Backups are stored under data/backups/.
Response:
{
"status": "created",
"name": "backup-2026-01-01T12-00-00",
"files": ["m3u.yaml", "epg.yaml", "app.yaml", "channel-map.yaml"]
}List all available backups (newest first).
Response:
{
"backups": [{ "name": "backup-2026-01-01T12-00-00" }],
"count": 1
}Restore configuration files from the named backup.
URL Parameters:
name- Backup name (e.g.backup-2026-01-01T12-00-00)
Response:
{
"status": "restored",
"name": "backup-2026-01-01T12-00-00",
"files": ["m3u.yaml", "epg.yaml"]
}Error responses:
400– Invalid backup name (name fails validation)404– Backup not found
Delete the named backup directory.
URL Parameters:
name- Backup name
Response:
{
"status": "deleted",
"name": "backup-2026-01-01T12-00-00"
}Return recently completed stream sessions in reverse-chronological order. Requires authentication. The server keeps up to the last 100 sessions in memory.
Response:
{
"history": [
{
"ip": "192.168.1.10",
"channelId": "23.1",
"name": "PBS",
"tvg_id": "PBS",
"startedAt": "2026-01-01T12:00:00.000Z",
"lastSeen": "2026-01-01T12:44:50.000Z",
"endedAt": "2026-01-01T12:45:00.000Z",
"durationSeconds": 2700
}
],
"count": 1
}