Skip to main content
Battles Record provides a REST API and WebSocket endpoint for programmatic control and monitoring.

Base URL

DeploymentBase URL
Localhttp://localhost:8080/api
Dockerhttp://{host}:8080/api

Authentication

All endpoints require authentication via API key or JWT token.

API Key

curl -H "Authorization: Bearer YOUR_API_KEY" \
  http://localhost:8080/api/channels

JWT Token

Obtain a token via login:
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "yourpassword"}'

Refresh Token

POST /api/auth/refresh
Refresh an expired or near-expiry token. Tokens can be refreshed for up to 1 hour after expiry (grace period). Response:
{
	"token": "eyJhbGciOiJIUzI1NiIs...",
	"expires_at": "2026-02-04T14:30:00Z"
}

Channels

List Channels

GET /api/channels
Response:
{
	"channels": [
		{
			"id": "ch_abc123",
			"platform": "twitch",
			"name": "shroud",
			"enabled": true,
			"quality": "source",
			"status": "offline"
		}
	]
}

Get Channel

GET /api/channels/{id}

Add Channel

POST /api/channels
Body:
{
	"platform": "twitch",
	"name": "shroud",
	"quality": "source",
	"enabled": true
}

Update Channel

PATCH /api/channels/{id}
Body:
{
	"quality": "1080p60",
	"enabled": false
}

Delete Channel

DELETE /api/channels/{id}

Check Channel Live Status

POST /api/channels/{id}/check
Trigger an immediate live check for a channel.

Stop Channel Recording

POST /api/channels/{id}/stop-recording
Stop an active recording and pause the channel.

Channel Images

Get Channel Profile

GET /api/channels/{id}/profile
Returns channel profile data including image URLs.

Fetch Platform Images

POST /api/channels/{id}/images/fetch-platform
Re-download profile and banner images from the streaming platform.

Profile Image

GET /api/channels/{id}/images/profile
POST /api/channels/{id}/images/profile
DELETE /api/channels/{id}/images/profile
Get, upload (multipart), or delete the custom profile image.
GET /api/channels/{id}/images/banner
POST /api/channels/{id}/images/banner
DELETE /api/channels/{id}/images/banner
Get, upload (multipart), or delete the custom banner image.

Recordings

List Recordings

GET /api/recordings
Query Parameters:
ParameterDescription
channelFilter by channel ID
platformFilter by platform
statusFilter by status
fromStart date (ISO 8601)
toEnd date (ISO 8601)
limitResults per page (default: 50)
offsetPagination offset
Response:
{
	"recordings": [
		{
			"id": "rec_xyz789",
			"channel_id": "ch_abc123",
			"channel_name": "shroud",
			"platform": "twitch",
			"title": "Valorant Ranked",
			"status": "complete",
			"started_at": "2026-02-02T14:30:00Z",
			"duration": 10800,
			"file_size": 5368709120,
			"file_path": "/recordings/shroud/2026-02-02_Valorant Ranked.mp4"
		}
	],
	"total": 150,
	"limit": 50,
	"offset": 0
}

Get Recording

GET /api/recordings/{id}

Delete Recording

DELETE /api/recordings/{id}
Query Parameters:
ParameterDescription
delete_fileAlso delete the file (default: true)

Re-process Recording

POST /api/recordings/{id}/reprocess

Active Recordings

List Active

GET /api/recordings/active
Response:
{
	"active": [
		{
			"id": "rec_active123",
			"channel_name": "shroud",
			"platform": "twitch",
			"title": "Valorant Ranked",
			"started_at": "2026-02-02T14:30:00Z",
			"duration": 3600,
			"segments": 720,
			"quality": "1080p60"
		}
	]
}

Stop Recording

POST /api/recordings/{id}/stop

Pause Recording

POST /api/recordings/{id}/pause

Resume Recording

POST /api/recordings/{id}/resume

Storage

Get Storage Info

GET /api/storage
Response:
{
	"total_used": 107374182400,
	"total_available": 536870912000,
	"quota": 214748364800,
	"quota_used_percent": 50,
	"by_channel": {
		"ch_abc123": 53687091200
	}
}

Trigger Cleanup

POST /api/storage/cleanup
Runs retention policies immediately.

Settings

Get Settings

GET /api/settings

Update Settings

PATCH /api/settings
Body:
{
	"output_directory": "/new/path",
	"max_concurrent_recordings": 5
}

System

Health Check

GET /api/health
Response:
{
	"status": "healthy",
	"version": "1.0.0",
	"uptime": 86400
}

Logs

GET /api/logs
Query Parameters:
ParameterDescription
levelFilter by level (error, warn, info, debug)
fromStart timestamp
toEnd timestamp
limitResults per page

System Dependencies

GET /api/system/dependencies
Check status of system dependencies (FFmpeg, Bun, yt-dlp).

Platform Authentication

GET /api/auth/platforms
GET /api/auth/platforms/{platform}
PUT /api/auth/platforms/{platform}
DELETE /api/auth/platforms/{platform}
POST /api/auth/platforms/{platform}/test
POST /api/auth/platforms/{platform}/oauth/start
POST /api/auth/platforms/{platform}/oauth/callback
POST /api/auth/platforms/youtube/cookies
GET /api/auth/platforms/oauth/availability
Manage platform authentication credentials, OAuth flows, and YouTube cookie uploads.

Graceful Shutdown (Local-Only)

POST /api/shutdown
Gracefully shut down the daemon. Only available in local-only mode (desktop sidecar).

WebSocket

Connect for real-time updates:
const ws = new WebSocket("ws://localhost:8080/api/ws");

ws.onopen = () => {
	// Authenticate
	ws.send(
		JSON.stringify({
			type: "auth",
			token: "YOUR_API_KEY"
		})
	);
};

ws.onmessage = (event) => {
	const message = JSON.parse(event.data);
	console.log(message);
};

Event Types

EventDescription
connectedInitial connection with full state
channel_statusChannel status changed
channel_errorChannel encountered an error
recording_startedNew recording began
segment_downloadedSegment captured
recording_endedRecording finished
processing_startedPost-processing began
processing_progressProcessing progress update
processing_completeProcessing finished successfully
processing_failedProcessing encountered error
schedule_skipStream skipped due to schedule
filter_skipStream skipped due to content filters
quota_skipStream skipped due to storage quota
quota_status_changedChannel quota status changed
disk_warningDisk space warning threshold exceeded
config_reloadedConfiguration file reloaded
platform_auth_updatedPlatform auth connected or refreshed
platform_auth_expiredPlatform auth expired (refresh failed)

Event Payload

{
	"type": "recording.started",
	"timestamp": "2026-02-02T14:30:00Z",
	"data": {
		"id": "rec_xyz789",
		"channel": "shroud",
		"platform": "twitch",
		"title": "Valorant Ranked"
	}
}

Subscribe to Channels

Filter events by channel:
{
	"type": "subscribe",
	"channels": ["ch_abc123", "ch_def456"]
}

Unsubscribe

{
	"type": "unsubscribe",
	"channels": ["ch_abc123"]
}

Error Responses

All errors return consistent format:
{
	"error": {
		"code": "CHANNEL_NOT_FOUND",
		"message": "Channel with ID ch_invalid does not exist"
	}
}

Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid auth
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource not found
VALIDATION_ERROR400Invalid request body
CONFLICT409Resource already exists
INTERNAL_ERROR500Server error

Rate Limiting

EndpointLimit
Auth endpoints10 req/min
Read endpoints100 req/min
Write endpoints30 req/min
Rate limit headers:
  • X-RateLimit-Limit: Max requests
  • X-RateLimit-Remaining: Remaining requests
  • X-RateLimit-Reset: Reset timestamp