This document describes the REST API and WebSocket protocol used by aMuTorrent.
- Authentication
- REST API v1 — General-purpose API for downloads, categories, search, logs
- Metrics API
- History API
- Torznab API — Exposes aMule ED2K search as a Torznab indexer for Sonarr/Radarr
- qBittorrent-Compatible API — Exposes aMule as a qBittorrent-compatible download client for Sonarr/Radarr
- WebSocket Protocol
When web UI authentication is enabled, the following authentication methods apply:
The web interface and internal APIs use session-based authentication. Users must log in through the web interface to obtain a session cookie, or provide an API key via the X-API-Key header.
Session login:
curl -c cookies.txt -X POST http://host:4000/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"yourpass"}'
# Use the cookie in subsequent requests
curl -b cookies.txt http://host:4000/api/v1/categoriesAPI key:
curl -H 'X-API-Key: your-api-key' http://host:4000/api/v1/categoriesAPI keys are per-user and can be found/regenerated in Settings → User Management.
Protected endpoints:
/api/v1/*- REST API v1 (capability-gated per endpoint)/api/metrics/*- Metrics API/api/history/*- History API/api/config/*- Configuration API
WebSocket connections are also protected when authentication is enabled. The WebSocket upgrade request must include a valid session cookie (amule.sid) from an authenticated web session.
The Torznab indexer API uses API key authentication (admin-only).
- API Key: Use your admin user's API key (found in Settings → User Management)
- Pass the key via the
apikeyquery parameter
Example:
GET /indexer/amule/api?t=search&q=test&apikey=YOUR_API_KEY
When configuring in Sonarr/Radarr, enter your admin API key in the "API Key" field.
The qBittorrent-compatible API uses HTTP Basic Authentication (admin-only). Two credential methods are supported:
- Username + password — use your aMuTorrent admin username and password
- API key as password — use any username with your admin API key as the password
When configuring the download client in Sonarr/Radarr:
- Username: Your admin username (or any value when using API key)
- Password: Your admin password or API key
General-purpose REST API for managing downloads, categories, search, and more. All endpoints are under /api/v1/.
All /api/v1/ endpoints require authentication when auth is enabled. Two methods are supported:
- Session cookie — Log in via
POST /api/auth/loginand include the session cookie in subsequent requests - API key — Pass the
X-API-Keyheader with a user's API key (found in Settings → User Management)
Each endpoint requires specific capabilities (permissions). Admin users have all capabilities. Non-admin users need the listed capability assigned to their account.
All responses are JSON objects with a type field indicating the response type. On error, the response has type: "error" with a message field.
Returns the current state of all downloads, shared files, and statistics. This is the same data the WebSocket sends on connection.
Capabilities: None (any authenticated user)
Response:
{
"type": "batch-update",
"data": {
"stats": {
"instanceSpeeds": { "amule-host-4712": { "uploadSpeed": 1024, "downloadSpeed": 0 } },
"instances": { "amule-host-4712": { "type": "amule", "connected": true, "name": "aMule" } }
},
"items": [
{
"hash": "abc123...",
"name": "file.mkv",
"client": "amule",
"instanceId": "amule-host-4712",
"status": "active",
"progress": 45.2,
"size": 1073741824,
"downloadSpeed": 512000,
"uploadSpeed": 0
}
]
}
}Add magnet links to a BitTorrent client.
Capabilities: add_downloads
Request Body:
{
"links": ["magnet:?xt=urn:btih:..."],
"instanceId": "rtorrent-host-8000",
"categoryName": "Default"
}Response:
{
"type": "magnet-added",
"results": [{ "link": "magnet:?...", "success": true }],
"clientId": "rtorrent"
}Add ED2K links to an aMule instance.
Capabilities: add_downloads
Request Body:
{
"links": ["ed2k://|file|name|size|hash|/"],
"instanceId": "amule-host-4712",
"categoryName": "Default"
}Response:
{
"type": "ed2k-added",
"results": [{ "link": "ed2k://...", "success": true }]
}Add a torrent file (base64-encoded in JSON body).
Capabilities: add_downloads
Request Body:
{
"data": "base64-encoded-torrent-data",
"fileName": "file.torrent",
"instanceId": "rtorrent-host-8000",
"categoryName": "Default"
}Download files from an ED2K search result (aMule).
Capabilities: add_downloads
Request Body:
{
"fileHashes": ["abc123...", "def456..."],
"instanceId": "amule-host-4712",
"categoryName": "Default"
}Response:
{
"type": "batch-download-complete",
"results": [{ "fileHash": "abc123...", "success": true }],
"message": "Downloaded 2/2 files"
}All control endpoints accept an items array with fileHash and instanceId per item.
Capabilities: pause_resume
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }]
}Response:
{
"type": "batch-pause-complete",
"results": [{ "fileHash": "abc123...", "success": true, "instanceId": "rtorrent-host-8000" }],
"message": "1/1 successful"
}Capabilities: pause_resume
Same request/response format as pause.
Capabilities: pause_resume
Same request/response format as pause. Fully closes the torrent (releases file handles).
Capabilities: remove_downloads
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000", "fileName": "file.mkv" }],
"deleteFiles": false
}Response:
{
"type": "batch-delete-complete",
"results": [{ "fileHash": "abc123...", "success": true, "instanceId": "rtorrent-host-8000" }],
"message": "Deleted 1/1 files"
}Move files to a destination path without changing category.
Capabilities: edit_downloads
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }],
"destPath": "/downloads/movies"
}Change the category/label of downloads.
Capabilities: assign_categories
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }],
"categoryName": "Movies",
"moveFiles": true
}Rename a file.
Capabilities: rename_files
Request Body:
{
"fileHash": "abc123...",
"instanceId": "rtorrent-host-8000",
"newName": "new-name.mkv"
}Set the rating and comment on a shared file. Currently supported only by aMule
shared (completed) files — use the client capability fileRatingComment in
/api/v1/clients/instances to detect support.
aMule's EC handler writes both fields together; omitting one clears it. To
preserve an existing value, pass it through unchanged. rating uses the
scale: 0 = Not rated, 1 = Fake, 2 = Poor, 3 = Fair, 4 = Good,
5 = Excellent.
Capabilities: set_comment
Request Body:
{
"fileHash": "abc123...",
"instanceId": "amule-host-4712",
"comment": "High-quality rip",
"rating": 4
}Pre-flight checks to verify paths are accessible before performing operations.
Capabilities: remove_downloads
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }]
}Response:
{
"type": "delete-permissions",
"results": [{ "fileHash": "abc123...", "canDelete": true, "path": "/downloads/file.mkv" }],
"isDocker": true
}Check permissions for category-based move.
Capabilities: move_files
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }],
"categoryName": "Movies"
}Check permissions for direct path move.
Capabilities: edit_downloads
Request Body:
{
"items": [{ "fileHash": "abc123...", "instanceId": "rtorrent-host-8000" }],
"destPath": "/downloads/movies"
}Response:
{
"type": "move-to-permissions",
"results": [{ "fileHash": "abc123...", "canMove": true, "reason": "ok" }],
"canMove": true,
"destPath": "/downloads/movies"
}List all categories.
Capabilities: None (any authenticated user)
Response:
{
"type": "categories-update",
"data": [
{ "name": "Default", "title": "Default", "path": "", "color": 13421772, "comment": "", "priority": 0 }
]
}Create a new category.
Capabilities: manage_categories
Request Body:
{
"title": "Movies",
"path": "/downloads/movies",
"comment": "Movie downloads",
"color": 255,
"priority": 0
}Update an existing category.
Capabilities: manage_categories
Request Body:
{
"name": "Movies",
"path": "/downloads/movies-updated",
"comment": "Updated path"
}Delete a category.
Capabilities: manage_categories
Request Body:
{
"name": "Movies"
}Start an ED2K search. By default this is a blocking call that waits for aMule to return results (up to 120 seconds). Set wait: false for non-blocking mode.
Capabilities: search
Request Body:
{
"query": "ubuntu",
"type": "global",
"instanceId": "amule-host-4712",
"wait": true
}| Field | Default | Description |
|---|---|---|
query |
(required) | Search query string |
type |
global |
Search type: global, local, kad |
instanceId |
(first aMule) | Target aMule instance ID |
wait |
true |
If true, blocks until results are ready (up to 120s). If false, returns immediately. |
Response (blocking, wait: true):
{
"type": "search-results",
"data": [
{ "fileName": "ubuntu-24.04.iso", "fileSize": 5120000000, "fileHash": "abc123...", "sourceCount": 42 }
]
}Response (non-blocking, wait: false):
{
"type": "search-started",
"message": "Search started. Poll GET /api/v1/search/results for results."
}When using non-blocking mode, poll GET /api/v1/search/results to retrieve results once the search completes.
Get cached results from the last search.
Capabilities: search
Query Parameters:
| Parameter | Description |
|---|---|
instanceId |
aMule instance ID (optional — defaults to first connected) |
Response:
{
"type": "previous-search-results",
"data": [...]
}List ED2K servers.
Capabilities: view_servers
Connect, disconnect, or remove an ED2K server.
Capabilities: view_servers
Request Body:
{
"action": "connect",
"ip": "45.82.80.155",
"port": 5687,
"instanceId": "amule-host-4712"
}Actions: connect, disconnect, remove
Get ED2K server info (message of the day).
Capabilities: view_servers
Get aMule statistics tree.
Capabilities: view_statistics
Trigger a shared files rescan.
Capabilities: view_shared
Request Body:
{
"instanceId": "amule-host-4712"
}Admin-only endpoints for managing aMule's shareddir.dat file.
Read current shared directories. Returns config roots as authoritative, merges any dat-only roots.
Response (configured):
{
"configured": true,
"path": "/home/amule/.aMule/shareddir.dat",
"exists": true,
"canWrite": true,
"roots": ["/downloads/movies", "/downloads/tv"],
"inaccessibleRoots": [],
"isDocker": false
}Response (unconfigured):
{
"configured": false,
"path": null,
"isDocker": false
}Save shared directories. Persists roots to config.json, auto-expands each root to include all subdirectories via find -type d, writes to shareddir.dat, and reloads aMule shared files.
Request Body:
{
"directories": ["/downloads/movies", "/downloads/tv"]
}Rescan subdirectories using roots from config and reload. Picks up new subdirectories without changing root dirs.
Save the sharedDirDatPath for an aMule instance. Send an empty string to clear the configuration (removes both sharedDirDatPath and sharedDirRoots).
Request Body:
{
"sharedDirDatPath": "/home/amule/.aMule/shareddir.dat"
}Get aMuTorrent application log.
Capabilities: view_logs
Get aMule log.
Capabilities: view_logs
Get qBittorrent log.
Capabilities: view_logs
Most endpoints accept an instanceId field to target a specific client instance. Instance IDs can be found in the snapshot response (data.stats.instances). If omitted, the server selects the first connected instance of the expected type.
Historical metrics for speed and transfer data.
Returns speed data with different granularities based on time range.
Query Parameters:
| Parameter | Values | Description |
|---|---|---|
range |
24h, 7d, 30d |
Time range |
Granularity:
- 24h: 15-second buckets (~5,760 points)
- 7d: 15-minute buckets (672 points)
- 30d: 1-hour buckets (720 points)
Response:
{
"range": "24h",
"data": [
{
"timestamp": 1234567890000,
"uploadSpeed": 102400,
"downloadSpeed": 512000
}
]
}Returns data transferred with time buckets.
Query Parameters:
| Parameter | Values | Description |
|---|---|---|
range |
24h, 7d, 30d |
Time range |
Granularity:
- 24h: 15-minute buckets (96 bars)
- 7d: 2-hour buckets (84 bars)
- 30d: 6-hour buckets (120 bars)
Response:
{
"range": "24h",
"data": [
{
"timestamp": 1234567890000,
"uploadSpeed": 102400,
"downloadSpeed": 512000,
"uploadedDelta": 1024000,
"downloadedDelta": 5120000
}
]
}Returns summary statistics for a time range.
Query Parameters:
| Parameter | Values | Description |
|---|---|---|
range |
24h, 7d, 30d |
Time range |
Response:
{
"range": "24h",
"totalUploaded": 10737418240,
"totalDownloaded": 53687091200,
"avgUploadSpeed": 124108,
"avgDownloadSpeed": 620540,
"peakUploadSpeed": 1048576,
"peakDownloadSpeed": 5242880
}Download history tracking.
Returns paginated download history.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
limit |
50 |
Items per page |
offset |
0 |
Pagination offset |
sortBy |
started_at |
Sort field |
sortDir |
desc |
Sort direction (asc/desc) |
search |
- | Filter by filename |
status |
- | Filter by status |
Response:
{
"entries": [
{
"hash": "abc123...",
"filename": "file.mkv",
"size": 1073741824,
"status": "completed",
"started_at": "2024-01-15T10:00:00Z",
"completed_at": "2024-01-15T12:00:00Z",
"username": "user1"
}
],
"total": 150,
"trackUsername": true
}Deletes a history entry by file hash.
Exposes aMule's ED2K search as a Torznab-compatible indexer, allowing Sonarr, Radarr, and other *arr apps to search the ED2K network directly. See authentication above.
Returns indexer capabilities.
Response: XML with supported categories and search capabilities.
Performs an ED2K search.
Query Parameters:
| Parameter | Description |
|---|---|
q |
Search query |
cat |
Category filter (optional) |
limit |
Max results |
offset |
Pagination offset |
Response: XML in Torznab format with search results.
Exposes aMule as a qBittorrent-compatible download client, allowing Sonarr, Radarr, and other *arr apps to add ED2K downloads, monitor progress, and manage categories through aMule. See authentication above.
Returns application version.
Response: v4.5.0
Returns Web API version.
Response: 2.8.3
Lists current downloads.
Query Parameters:
| Parameter | Description |
|---|---|
filter |
Filter by status (all, downloading, completed, etc.) |
category |
Filter by category |
hashes |
Filter by specific hashes |
Response:
[
{
"hash": "abc123...",
"name": "file.mkv",
"size": 1073741824,
"progress": 0.75,
"dlspeed": 512000,
"upspeed": 102400,
"state": "downloading",
"category": "sonarr",
"content_path": "/downloads/sonarr/file.mkv",
"save_path": "/downloads/sonarr"
}
]Adds a download from ED2K link.
Form Data:
| Field | Description |
|---|---|
urls |
ED2K link(s), one per line |
category |
Category name |
Pauses download(s).
Form Data:
| Field | Description |
|---|---|
hashes |
Hash(es) to pause, all for all |
Resumes download(s).
Form Data:
| Field | Description |
|---|---|
hashes |
Hash(es) to resume, all for all |
Deletes download(s).
Form Data:
| Field | Description |
|---|---|
hashes |
Hash(es) to delete |
deleteFiles |
true to also delete files |
Returns configured categories.
Response:
{
"sonarr": {
"name": "sonarr",
"savePath": "/downloads/sonarr"
},
"radarr": {
"name": "radarr",
"savePath": "/downloads/radarr"
}
}The server exposes a WebSocket endpoint at ws://HOST:PORT for real-time communication.
All messages are JSON objects with an action field.
{ "action": "search", "query": "file name", "type": "global" }{ "action": "getDownloads" }
{ "action": "pauseDownload", "fileHash": "..." }
{ "action": "resumeDownload", "fileHash": "..." }
{ "action": "delete", "fileHash": "..." }
{ "action": "download", "fileHash": "..." }{ "action": "getUploadingQueue" }{ "action": "getShared" }
{ "action": "reloadSharedFiles" }{ "action": "getStats" }
{ "action": "getStatsTree" }{ "action": "getServers" }
{ "action": "connectServer", "serverAddress": "ip:port" }
{ "action": "disconnectServer" }
{ "action": "removeServer", "serverAddress": "ip:port" }{ "action": "getLog" }
{ "action": "getServerInfo" }{ "action": "getCategories" }
{ "action": "createCategory", "category": { "title": "...", "path": "...", "color": 0xCCCCCC, "priority": 0 } }
{ "action": "updateCategory", "id": 1, "category": { ... } }
{ "action": "deleteCategory", "id": 1 }
{ "action": "setFileCategory", "fileHash": "...", "categoryId": 1 }{ "action": "addEd2kLink", "link": "ed2k://...", "categoryId": 0 }All messages are JSON objects with a type field.
{ "type": "search-results", "data": [...] }{ "type": "downloads-update", "data": [...] }{ "type": "uploads-update", "data": [...] }{ "type": "stats-update", "data": { ... } }{ "type": "shared-update", "data": [...] }{ "type": "servers-update", "data": [...] }{ "type": "categories-update", "data": [...] }{ "type": "log-update", "data": [...] }
{ "type": "serverinfo-update", "data": [...] }{ "type": "error", "message": "Error description" }{ "type": "connection-status", "connected": true }