Surge provides a comprehensive HTTP API for remote control and integration. The API is automatically available when running Surge in TUI or server mode.
API Overview
The Surge HTTP API allows you to:
Queue new downloads
List and monitor download progress
Control download state (pause, resume, delete)
Stream real-time events via Server-Sent Events (SSE)
Update download URLs for expired links
Server Configuration
Starting the API Server
Default Port (1700)
Custom Port
With Authentication
# Start with auto-assigned or default port
surge server
The server binds to 0.0.0.0 (all interfaces) by default, making it accessible from:
localhost (127.0.0.1)
Your local network IP
Public IP (if not behind firewall)
Getting Your Token
The API requires Bearer token authentication:
# Display your current token
surge token
The token is automatically generated on first run and persists across sessions.
Base URL
The API base URL depends on your configuration:
Local server : http://127.0.0.1:1700
Custom port : http://127.0.0.1:<port>
Remote server : http://<server-ip>:1700
All API requests require authentication via the Authorization header: Authorization: Bearer <your-token>
API Endpoints
Health Check
Check if the API server is running.
{
"status" : "ok" ,
"port" : 1700
}
The /health endpoint does not require authentication.
Add Download
Queue a new download.
POST /download
Content-Type : application/json
Authorization : Bearer <token>
{
"url" : "https://example.com/file.zip" ,
"mirrors" : [
"https://example.com/file.zip" ,
"https://mirror1.com/file.zip"
],
"path" : "/custom/output/path"
}
Request Body
Field Type Required Description urlstring Yes Primary download URL mirrorsarray No List of mirror URLs (includes primary) pathstring No Custom output directory
List Downloads
Get all downloads and their status.
GET /list
Authorization : Bearer <token>
[
{
"id" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ,
"url" : "https://example.com/file.zip" ,
"filename" : "file.zip" ,
"status" : "downloading" ,
"progress" : 45.2 ,
"total_size" : 1073741824 ,
"downloaded" : 485395865 ,
"speed" : 12.5 ,
"error" : ""
}
]
Get Download Details
Retrieve detailed information for a specific download.
GET /download?id=<download-id>
Authorization : Bearer <token>
Pause Download
Pause an active download.
POST /pause?id=<download-id>
Authorization : Bearer <token>
{
"status" : "paused" ,
"id" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Resume Download
Resume a paused download.
POST /resume?id=<download-id>
Authorization : Bearer <token>
{
"status" : "resumed" ,
"id" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Delete Download
Remove a download from the queue.
DELETE /delete?id=<download-id>
Authorization : Bearer <token>
# Also accepts POST
POST /delete?id=<download-id>
{
"status" : "deleted" ,
"id" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Update Download URL
Update the source URL for a paused or errored download.
PUT /update-url?id=<download-id>
Content-Type : application/json
Authorization : Bearer <token>
{
"url" : "https://new-mirror.example.com/file.zip"
}
{
"status" : "updated" ,
"id" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ,
"url" : "https://new-mirror.example.com/file.zip"
}
This endpoint is perfect for refreshing expired signed URLs from services like S3, Google Drive, or OneDrive.
Download History
Retrieve completed and past downloads.
GET /history
Authorization : Bearer <token>
Real-time Events (SSE)
Stream download events in real-time using Server-Sent Events.
Request
cURL
JavaScript
Python
GET /events
Authorization : Bearer <token>
The /events endpoint streams real-time updates for all download state changes, progress updates, and completions.
Response Codes
Code Description 200 OKRequest successful 202 AcceptedDownload queued successfully 400 Bad RequestInvalid request (missing parameters) 401 UnauthorizedInvalid or missing token 404 Not FoundDownload ID not found 405 Method Not AllowedWrong HTTP method 500 Internal Server ErrorServer error
Download Status Values
Downloads can have the following status values:
pending - Queued, waiting to start
downloading - Actively downloading
paused - Manually paused
completed - Download finished successfully
error - Download failed (see error field)
Integration Examples
Python Download Manager
import requests
import time
class SurgeClient :
def __init__ ( self , host = "http://localhost:1700" , token = None ):
self .host = host.rstrip( '/' )
self .token = token
def _headers ( self ):
headers = { "Content-Type" : "application/json" }
if self .token:
headers[ "Authorization" ] = f "Bearer { self .token } "
return headers
def add_download ( self , url , mirrors = None , path = None ):
data = { "url" : url}
if mirrors:
data[ "mirrors" ] = mirrors
if path:
data[ "path" ] = path
response = requests.post(
f " { self .host } /download" ,
headers = self ._headers(),
json = data
)
return response.json()
def list_downloads ( self ):
response = requests.get(
f " { self .host } /list" ,
headers = self ._headers()
)
return response.json()
def pause ( self , download_id ):
response = requests.post(
f " { self .host } /pause?id= { download_id } " ,
headers = self ._headers()
)
return response.json()
def resume ( self , download_id ):
response = requests.post(
f " { self .host } /resume?id= { download_id } " ,
headers = self ._headers()
)
return response.json()
# Usage
client = SurgeClient( token = "your-token" )
# Add download
client.add_download( "https://example.com/file.zip" )
# Monitor progress
while True :
downloads = client.list_downloads()
active = [d for d in downloads if d[ 'status' ] == 'downloading' ]
if not active:
break
for d in active:
print ( f " { d[ 'filename' ] } : { d[ 'progress' ] :.1f} % @ { d[ 'speed' ] :.1f} MB/s" )
time.sleep( 2 )
Node.js Web Dashboard
const express = require ( 'express' );
const axios = require ( 'axios' );
const app = express ();
const SURGE_API = 'http://localhost:1700' ;
const SURGE_TOKEN = 'your-token' ;
const headers = {
'Authorization' : `Bearer ${ SURGE_TOKEN } ` ,
'Content-Type' : 'application/json'
};
// Add download endpoint
app . post ( '/api/download' , async ( req , res ) => {
try {
const response = await axios . post (
` ${ SURGE_API } /download` ,
req . body ,
{ headers }
);
res . json ( response . data );
} catch ( error ) {
res . status ( 500 ). json ({ error: error . message });
}
});
// List downloads endpoint
app . get ( '/api/downloads' , async ( req , res ) => {
try {
const response = await axios . get (
` ${ SURGE_API } /list` ,
{ headers }
);
res . json ( response . data );
} catch ( error ) {
res . status ( 500 ). json ({ error: error . message });
}
});
app . listen ( 3000 , () => {
console . log ( 'Dashboard running on http://localhost:3000' );
});
For production deployments, consider:
Using HTTPS with a reverse proxy (nginx, Caddy)
Implementing rate limiting
Adding request validation
Storing tokens securely (environment variables, secret managers)