eMuleBB REST API Contract¶
Status: beta 0.7.3 broadband contract
Source of truth: REST-API-OPENAPI.yaml
Adapter subsets: REST-API-ADAPTERS.md
Migrated action inventory: REST-API-PARITY-INVENTORY.md
Primary implementation: EMULE_WORKSPACE_ROOT\workspaces\workspace\app\emulebb-main\srchybrid\WebServerJson.cpp
Route seam: EMULE_WORKSPACE_ROOT\workspaces\workspace\app\emulebb-main\srchybrid\WebServerJsonSeams.h
Overview¶
main exposes an authenticated in-process JSON API from the existing eMule
WebServer listener. The broadband release contract is the resource-oriented
/api/v1 surface described by the OpenAPI document above.
The API is designed for aMuTorrent and other trusted local controllers. The beta 0.7.3 contract intentionally prioritizes consistency and aMuTorrent completeness over preserving old command-style route names.
After beta 0.7.3, the same OpenAPI document is also the canonical
product-family contract for p2p-overlord implementations that choose to expose
an eMuleBB-compatible REST surface. p2p-overlord may implement a documented
subset, but that subset must be proven against this OpenAPI source rather than
creating a parallel contract.
Controller Boundary¶
aMuTorrent is the primary UI consumer and beta 0.7.3 proof target, but it is not
the authority for native route shape. The aMuTorrent eMuleBB adapter must
translate UI expectations to the clean /api/v1 contract instead of requiring
native aliases, qBittorrent-compatible response shapes, or legacy command-style
routes.
Arr integrations are separate compatibility adapters. Prowlarr Torznab,
Radarr/Sonarr controller flows, and qBittorrent-compatible download-client
routes may keep adapter-specific quirks where those clients require them, but
shared parsing, validation, safety, and serialization should come from the same
native helpers wherever practical. Adapter compatibility must not broaden or
weaken the native /api/v1 OpenAPI contract. Torznab movie and TV searches run
connected global and kad probes and combine results; non-media Torznab
families keep the native default automatic search policy.
qBittorrent-compatible transfer delete requests are adapted to native cancel
semantics and therefore forward deleteFiles: true to the shared transfer
delete command even when a qBit caller omits or clears its optional flag.
The /api/v2 surface is a qBittorrent-compatible adapter for Arr download
client integration only. It is complete when Prowlarr, Radarr, Sonarr, and other
Arr clients can authenticate, test the client, add transfers, inspect transfer
state, mutate Arr-relevant transfer state, assign categories, and remove
transfers through the qBittorrent-shaped routes they call. It is not a promise
to implement the full qBittorrent Web API surface, including unrelated RSS,
tracker, peer-management, sync, logging, ban-list, global-speed, or complete
content-layout operations.
The legacy template-based WebServer UI is a frozen surface behind the same listener. The release goal for that engine is compile preservation only until it is removed. HTML templates, legacy page routes, and template interaction state are not part of the REST v1 contract, not part of the adapter contract, not supported, and not a release-gated behavior surface beyond avoiding shared listener regressions.
Contract Rules¶
- root every endpoint at
/api/v1/... - authenticate only with
X-API-Key - serve JSON only
- inherit the normal WebServer bind, HTTPS, and allowed-IP behavior
- use
camelCasefield names - use lowercase compact exact tokens for enum-like string values, with no camelCase, snake_case, case folding, or aliases
- keep native priority families separate: transfer download priority uses
auto,verylow,low,normal,high, andveryhigh; shared-file upload priority usesauto,verylow,low,normal,high, andrelease - return success envelopes as
{ "data": ..., "meta": ... } - return unpaged collections as
{ "data": { "items": [...] }, "meta": ... } - return transfer add and transfer pause/resume/stop/delete operations as stable per-item operation envelopes, including the single-link and single-hash routes
- expose
offset/limitpagination only onGET /shared-filesandGET /upload-queue, with responses shaped as{ "data": { "items": [...], "total": n, "offset": n, "limit": n }, "meta": ... } - expose
limitwithoutoffsetonly for bounded snapshots/tails such asGET /snapshotandGET /logs - expose shared-files startup readiness through
status.stats.sharedFilesReadyandstatus.sharedStartupCache; clients must not infer readiness from an emptysharedFilesarray during startup warmup - expose app lifecycle through
app.lifecycleandstatus.lifecycleusing lowercase compact state tokens:starting,running,shuttingdown, anddone; the exit-confirmation dialog remains publicrunningstate - reject mutating REST requests, diagnostic unsafe requests, and
POST /app/shutdownwhile lifecycle isstarting, and reject all REST requests once lifecycle isshuttingdownordone - return errors as
{ "error": { "code": "...", "message": "...", "details": {} } } - return the updated resource from mutations when practical; asynchronous or native operation routes return explicit operation-result DTOs instead
- keep public response DTOs closed in OpenAPI; additive fields require an explicit OpenAPI update and matching contract tests in the same change
- expose one canonical public route for each operation; upload removal uses
POST /uploads/{clientId}/operations/remove, not a duplicateDELETEalias - validate method/path/body/query through the native route schema table before dispatching commands
- reject unknown JSON body fields and unknown or malformed query parameters with
400 INVALID_ARGUMENT - validate public rename text with the same UTF-8/control-character and 255-character public filename limit used by REST-adjacent link conversion
- accept server.met and nodes.dat URL imports only as trimmed
http://orhttps://URLs with a host, no whitespace, and a 2048-character limit - require explicit booleans such as
deleteFiles: truefor destructive local file deletion - use HTTP 200 for valid bulk requests with per-item results
- marshal native commands through the main UI thread before touching eMule state owned by dialogs, sockets, queues, and list controls
- keep the route execution model explicit in the native route seam; only static/direct-safe routes may bypass the UI-thread dispatch path
- reject pre-release alias spellings; public request fields are the final
OpenAPI names such as
categoryId,searchId,deleteFiles,uploadLimitKiBps, anddownloadLimitKiBps
Scope¶
The release API must cover controller-relevant runtime capabilities that were
historically reachable through WebServer command handlers: transfers, shared
files, shared directories, uploads, upload queue, servers, Kad, searches,
friends, logs, categories, statistics, preferences, and application shutdown.
That inventory tracks migrated behavior, not a promise that the deprecated
template UI keeps functioning. Operator diagnostic dump capture and crash-test
endpoints live under /diagnostics, require explicit diagnostic REST opt-in,
and remain outside broad automated mutation/stress loops.
The release API intentionally excludes:
- HTML sessions, login/logout, templates, sort state, column hiding, and other frozen legacy WebServer presentation state
- WebServer page-only preferences such as HTML gzip and refresh interval
- host operating-system shutdown and reboot
- binary shared-file streaming
- granular REST permissions or low-rights REST mode
- dynamic capability negotiation between eMuleBB and aMuTorrent
PATCH /api/v1/shared-directories replaces the configured shared-directory
roots and requires confirmReplaceRoots: true. Each root may be either a
non-empty string path or an object with a non-empty path and optional
recursive flag. Response-only directory state such as existence, monitoring,
or shareability is not accepted in the replacement request.
Search Semantics¶
POST /api/v1/searches starts a native eMule search using the requested method:
automatic, server, global, or kad. The request may also select a native
search file type with the exact REST file-type token: empty string for any
type, arc, audio, iso, image, pro, video, doc, or
emulecollection. No aliases, alternate casing, or request-time type remapping
are accepted. The route maps those public tokens directly to the existing
eD2K/Kad search modes and file-type filters and must not change stock search
semantics for beta 0.7.3. automatic resolves from live network state:
connected eD2K uses global, Kad-only uses kad, and no connected network is
rejected as not connected. Search resources echo the resolved method and
selected REST type so
controllers can distinguish eD2K server/global searches from Kad searches and
audit the selected file filter without inferring from result timing or counts.
GET /api/v1/searches lists active native search sessions without expanding
their result rows. GET /api/v1/searches/{searchId} returns the current native
visible result snapshot for one search. RC 0.7.3 intentionally does not
expose search result paging; search routes do not accept limit or offset,
and the strict route table rejects unknown query parameters. Controllers should
poll the search resource and treat results as a bounded native snapshot
governed by eMule's existing search-result retention and visibility behavior.
Each native result also carries the resolved search method and selected search
type when the result is returned through a search resource. SearchResult.fileType
is the raw native file-type tag reported for that row; SearchResult.fileType
remains row metadata and is not constrained to or remapped through the
search-filter token enum.
Search results expose grouped SearchResult.evidence instead of a single
risk score. Controllers must treat this as explanatory evidence, not a
safety guarantee:
riskEvidencecovers local fake-file, spam, rating, header, media-plausibility, and AICH-conflict warnings.availabilityEvidencecovers source counts, complete-source counts, observed clients/servers, and Kad publisher counts.nameEvidencecovers observed names, canonical names, ignored tokens, and meaningful name divergence groups.kadPublisherEvidencedecodes Kad publish metadata into publisher count, different-name count, raw Kad value, and a low/normal/high evidence band.integrityEvidencecovers AICH presence, multiple-AICH conflicts, pending or cached header checks, and claimed/detected file type evidence.
Unknown evidence is neutral, not positive; clients must not display it as
trusted or safe. Search creation does not clear existing searches as a side
effect; controllers must call
DELETE /api/v1/searches with confirmDeleteAllSearches: true when they need a
clean search set.
POST /api/v1/searches/{searchId}/results/{hash}/operations/download starts a
download from one visible search result by lowercase 32-character eD2K hash and
returns an operation result with the accepted search id and hash. It does not
pretend to return a Transfer resource before the native download queue has
materialized one.
DELETE /api/v1/transfers/{hash} cancels an incomplete native transfer. eMule
does not preserve partial .part state on cancel, so controllers must send
deleteFiles: true for incomplete transfers and treat that as native cancel
semantics rather than an optional disk-delete toggle. The route validator
rejects deleteFiles: false before dispatch.
Selected peer reads are available for controller drill-down through
GET /transfers/{hash}/sources/{clientId}, GET /uploads/{clientId}, and
GET /upload-queue/{clientId}. These routes use the same clientId selector
as peer operations and expose read models only; chat/message APIs and peer
shared-file browse result retrieval remain outside the beta 0.7.3 native v1
contract.
Transfer source rows expose downloadState with the same lowercase compact
token policy as the rest of v1; native debug labels are not part of the REST
contract.
Implementation Status¶
The OpenAPI contract is the implemented target contract for the current beta 0.7.3 pass. Native route-seam tests cover the route schema table, strict validation behavior, and the internal route execution model. The Python smoke harness includes OpenAPI route consistency checks, validates success/error envelopes, and reports whether each native route is direct or UI-thread dispatched. aMuTorrent's eMuleBB adapter consumes the same final field names while keeping aMuTorrent's own public routes stable.
The live smoke harness validates route coverage and response envelopes against
OpenAPI. The strict DTO policy is enforced by tests that reject open-ended
public response schemas except for explicitly documented extension maps such as
error.details and app.capabilities.
Search Refactoring Notes¶
Future cleanup should keep the current wire contract unchanged while reducing
implementation duplication: the native REST command seam can collapse toward the
exact type string contract instead of maintaining a parallel enum, and the
Torznab family-to-search-type mapping still resolves to REST tokens accepted by
/api/v1/searches.
Controller Compatibility Matrix¶
- Native REST clients
- Surface:
/api/v1 - Contract boundary: OpenAPI is authoritative; adapters do not define route names or envelopes.
-
Proof lane: REST smoke, OpenAPI drift, live completeness
-
aMuTorrent
- Surface:
/api/v1through its own adapter - Contract boundary: Translates UI expectations to final native fields and unwraps native envelopes.
-
Proof lane: aMuTorrent browser smoke
-
Prowlarr Torznab
- Surface: Torznab XML adapter
- Contract boundary: Keeps Torznab XML/error shape adapter-local while reusing native parsing and search commands.
-
Proof lane: Prowlarr live
-
Radarr/Sonarr
- Surface: Torznab plus qBit-compatible download client
- Contract boundary: Uses Arr-facing compatibility routes without broadening
/api/v1. -
Proof lane: Radarr/Sonarr live
-
qBittorrent-compatible clients
- Surface:
/api/v2 - Contract boundary: Implements the Arr-needed qBit subset only; qBit text/session errors stay adapter-shaped.
-
Proof lane: qBit route completeness and Arr live
-
p2p-overlord agents
- Surface: Claimed subset of
/api/v1 - Contract boundary: OpenAPI remains authoritative; missing endpoints are p2p-overlord implementation gaps, not contract drift.
- Proof lane: Future p2p-overlord REST conformance
Adapter subset details are documented in REST-API-ADAPTERS.md.
Execution Model¶
The native route table records whether a route is direct or UI-thread
dispatched. GET /api/v1/app is currently the only direct route because it
serves application identity, lifecycle, build metadata, and static
capabilities. Lifecycle gating is evaluated before direct execution, so direct
routes are still rejected after shutdown begins. Runtime reads, mutations,
destructive operations, and adapter bridges remain UI-thread dispatched until
ownership is proven safe at the implementation layer.
The same lifecycle command policy is reused by qBit-compatible and Torznab
bridge calls that invoke native REST commands in-process, so adapter bridges do
not bypass startup/shutdown safety gates.
Use REST-API-PARITY-INVENTORY.md for the completed WebServer-to-REST action parity ledger. Runtime route completeness is expected to match REST-API-OPENAPI.yaml.
Retired Before Public Release¶
The following earlier command-style routes are not part of the final broadband release contract and should not be used by aMuTorrent:
/api/v1/app/version/api/v1/stats/global/api/v1/transfers/add/api/v1/transfers/pause/api/v1/transfers/resume/api/v1/transfers/stop/api/v1/transfers/delete/api/v1/uploads/list/api/v1/uploads/queue/api/v1/servers/list/api/v1/servers/status/api/v1/search/start/api/v1/search/results/api/v1/search/stop/api/v1/log