Skip to content

API

This document describes the REST API and WebSocket protocol used by aMuTorrent.


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:

Terminal window
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/categories

API key:

Terminal window
curl -H 'X-API-Key: your-api-key' http://host:4000/api/v1/categories

API 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 apikey query 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.

qBittorrent-Compatible API (for Sonarr/Radarr)

Section titled “qBittorrent-Compatible API (for Sonarr/Radarr)”

The qBittorrent-compatible API uses HTTP Basic Authentication (admin-only). Two credential methods are supported:

  1. Username + password — use your aMuTorrent admin username and password
  2. 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:

  1. Session cookie — Log in via POST /api/auth/login and include the session cookie in subsequent requests
  2. API key — Pass the X-API-Key header 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
}
FieldDefaultDescription
query(required)Search query string
typeglobalSearch type: global, local, kad
instanceId(first aMule)Target aMule instance ID
waittrueIf 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:

ParameterDescription
instanceIdaMule 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"
}

Shared Directory Management (Experimental)

Section titled “Shared Directory Management (Experimental)”

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"]
}

POST /api/amule/shared-dirs/reload?instanceId=...

Section titled “POST /api/amule/shared-dirs/reload?instanceId=...”

Rescan subdirectories using roots from config and reload. Picks up new subdirectories without changing root dirs.

PUT /api/amule/shared-dirs/config?instanceId=...

Section titled “PUT /api/amule/shared-dirs/config?instanceId=...”

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:

ParameterValuesDescription
range24h, 7d, 30dTime 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:

ParameterValuesDescription
range24h, 7d, 30dTime 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:

ParameterValuesDescription
range24h, 7d, 30dTime 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:

ParameterDefaultDescription
limit50Items per page
offset0Pagination offset
sortBystarted_atSort field
sortDirdescSort 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:

ParameterDescription
qSearch query
catCategory filter (optional)
limitMax results
offsetPagination 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:

ParameterDescription
filterFilter by status (all, downloading, completed, etc.)
categoryFilter by category
hashesFilter 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:

FieldDescription
urlsED2K link(s), one per line
categoryCategory name

Pauses download(s).

Form Data:

FieldDescription
hashesHash(es) to pause, all for all

Resumes download(s).

Form Data:

FieldDescription
hashesHash(es) to resume, all for all

Deletes download(s).

Form Data:

FieldDescription
hashesHash(es) to delete
deleteFilestrue 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 }