// OPENBOX DOCS
API content and imports
Import, metadata, media, storefront, emulator, and audit routes.
Import sources, metadata and media management, emulators, storefronts, Gameyfin, and the library health audit. All routes require X-OpenBox-Token: TOKEN; POST bodies are JSON objects.
Folder and file imports
/api/importScan a folder and add supported files: {"folder": "/absolute/path", "chosen_emulators": {"Platform": "app_id"}}. Supported extensions include .sh, .appimage, .exe, .iso, .rom, console ROMs (.nes, .sfc, .smc, .gba, .gb, .gbc), and archives (.zip, .7z, .rar) plus .m3u, .cue, .chd, .wbfs, .rvz, .n64, .z64, .v64, .nds, .3ds, .cia, .pbp, .vpk, .xci, .nsp, .wad, .ciso, .gcm, .gcz, .wia, .dol, .elf, .xex. Multi-disc groups (Disc/disk/CD/DVD/side markers) are merged into an .m3u; duplicate ROMs are ranked and the best kept with version_candidates. Existing paths are never duplicated. When emulator choices are supplied, chosen emulators are installed from Flathub. Returns {"added", "found", "recommendations"}; media downloads for entries with a launchbox_db_id are queued respecting media_download_limit.
/api/import/wizardLike /api/import but also installs each chosen emulator and returns {"added", "found", "recommendations", "installed": [app_ids]}.
/api/import/watchRescan all configured watch folders once. Returns {"added", "found", "errors": [...]}. The background auto-import worker rescans every 10 seconds (backing off to at most 300 on state errors) when the server runs.
/api/import/xbox360{"folder", "command": ""} scans for default.xex, .xex, and .xbe; titles come from the folder name for default.xex. Returns {"added", "found"}.
/api/import/loose-arcade{"folder", "command": ""} scans .zip, .7z, .singe, .rom files; defaults to hypseus/singe on PATH. Returns {"added", "found"}.
Storefront imports
/api/import/steamImport installed Steam games from local manifests (steamapps/appmanifest_*.acf across all library folders). Missing launcher raises 400 (for example, "Steam, Flatpak, or xdg-open is required to launch imported Steam games."). Returns {"added", "found", "errors"}: unreadable libraries are reported, not skipped silently — each errors entry names the path and the OS error ("<steamapps path>: <strerror>", for example a read-only mount).
/api/import/heroicImport installed Heroic games (legendary/gog/nile installed manifests). Missing launcher raises 400 ("xdg-open is required to launch imported Heroic games."). Returns {"added", "found"}.
/api/import/lutrisImport installed Lutris games (lutris --list-games --installed --json, or Flatpak) with a 30-second timeout. Missing launcher raises 400 ("Lutris or Flatpak is required to import Lutris games."). Returns {"added", "found"}. The health route POST /api/health/dedupe removes library duplicates by identity.
/api/import/arcade{"folder", "dat": "", "command": "", "source": "MAME"} imports a MAME or FinalBurn Neo full set. With a DAT/XML file, entries are classified as parent, merged, split, or non-merged by comparing set ROMs with the ZIP contents. Without a DAT, MAME's own mame -listxml output is used (300-second timeout, 256 MiB cap) and mame must be installed. Missing folder or catalog raises 400. Returns {"added", "found", "sets": {"parent": n, "merged": n, "split": n, "non-merged": n}}.
/api/import/scummvmScan the ScummVM library (scummvm.ini sections). Returns {"added", "found"}.
/api/import/rpcs3Scan the RPCS3 library (dev_hdd0/game/*/PARAM.SFO titles). Returns {"added", "found"}.
/api/import/vita3kScan the Vita3K library (ux0/app/*/sce_sys/param.sfo titles). Returns {"added", "found"}.
/api/faugus/statusReturns Faugus Launcher installation status and discovered data directories: {"installed": bool, "data_dirs": [str, ...]}.
/api/faugus/scanScans Faugus Launcher JSON manifests and prefix directories. Returns {"games": [...], "count": int}.
/api/faugus/importImports scanned Faugus games with UMU launch configurations and wine prefixes into the library. Returns {"added": int, "found": int, "imported": [str, ...], "count": int}.
/api/wine/prefixesDiscovers configured Proton and Wine prefix directories. Returns {"prefixes": [{"name", "path"}, ...], "available": bool}.
/api/wine/protonsDiscovers Proton runtime executables (Steam compatibility tools, Faugus runners, Lutris runners, Flatpak/PATH). Returns {"protons": [{"name", "path"}, ...], "available": bool}.
/api/wine/prefix-for-gameResolves the active Wine prefix directory for a given game (?id=<index> or ?game_id=<id>). Returns {"prefix": str, "available": bool}. Missing game returns 404.
Metadata
/api/metadata/status{"ready": <database file exists>, "job": {...}, "coverage": {...}} where job is the in-memory metadata sync job (state downloading/done/error), and coverage reports library matching statistics (games, matched_games, matched_ratio, with_cover, etc.).
/api/metadata/syncStart a background sync of the LaunchBox Games Database (https://gamesdb.launchbox-app.com/Metadata.zip, 2 GiB cap). Returns 202 {"state":"downloading"}; re-POSTing while downloading returns the current job with 200.
/api/metadata/search?id=<index>&q=<title>&platform=<platform> searches the local database (20 results max). Before the database exists: 409 {"error":"Download the LaunchBox metadata database first."}. Results include database_id, name, platform, release_date, developer, publisher, genre, overview, series, esrb, max_players, cooperative.
/api/metadata/apply{"id"|"game_id", "database_id": <int>, "media": ["cover"|"background"|"screenshots"], "overwrite": bool}. Applies text metadata and downloads the selected media into media/launchbox/<database_id>/. Missing database raises 409. Returns {"updated": [...], "notes": [...]} and bumps the media epoch.
/api/v1/metadata/matchPOST /api/v1/metadata/match (aliased at POST /api/metadata/match) triggers a background job ("metadata-match") to batch auto-match library titles against the local LaunchBox database for all games currently missing launchbox_db_id. Missing database raises 409 Conflict.
Body: {"platform": "all" | "<platform-name>"}. Returns 202 {"state": "running"}.
/api/metadata/steamFetch Steam store metadata (appdetails) for a game with a numeric steam_app_id: name, developer, publisher, genre, year, description, cover, background. Missing App ID raises 400.
/api/metadata/trailerDownload the first Steam store trailer: requires steam_app_id. Returns {"video_trailer": "<path>"}.
/api/metadata/gogDownload GOG cover/background for a Heroic/GOG id. Returns {"cover", "background"}.
/api/metadata/igdb/search?q=<title>&platform=<platform> searches IGDB (requires IGDB_CLIENT_ID/IGDB_CLIENT_SECRET in ~/.env; missing credentials raise 400). Results include id, name, summary, year, genres, platforms, rating, critic_score.
/api/metadata/igdb/apply{"id"|"game_id", "igdb_id": <int>} applies name, description, year, genre, developer, publisher, rating, igdb_id, and time_to_beat_hours. Returns {"applied": true, "game": "<name>"}.
Automatic post-import scrape
The auto-scrape master toggle and its per-provider opt-ins are owned by the metadata routes, not the Settings dialog: they are stored in raw state settings so the feature never touches settings-handler normalization.
/api/v2/metadata/scrape-settingsReturns the four flags: scrape_after_import (master, default true) and scrape_screenscraper_enabled, scrape_igdb_enabled, scrape_steamgrid_enabled (all default false).
/api/v2/metadata/scrape-settingsPersists any subset of those flags. Values are coerced to booleans; unknown keys are ignored.
/api/v2/metadata/auto-scrapeQueues the match and media jobs for one import batch. Body: import_batch_id (required), optional media_types and overwrite. Returns 202 with match_job_id, media_job_id, and preview_id. When scrape_after_import is off the route answers 200 {"queued": false, "reason": "scrape_after_import is disabled"} instead of queueing. A missing batch id returns 400. (v1.14.0+)
/api/v2/metadata/media-candidatesLists the media candidates discovered for a match preview, so the review UI can show what an apply would download before it downloads it.
SteamGridDB artwork hygiene
Batched artwork hygiene: a report pass finds wrong-size, duplicated, or mismatched covers, and fix/undo apply or roll back a batch.
/api/v2/steamgrid/hygiene/reportThe current hygiene findings grouped by issue kind, with the affected games and the recommended action.
/api/v2/steamgrid/hygiene/fixApplies a hygiene batch for the given findings. Requires the API key the other SteamGridDB artwork routes do.
/api/v2/steamgrid/hygiene/undoReverts the most recent hygiene batch and restores the previous artwork.
Media
/api/mediaServe one media file: ?id=<index>&kind=cover|background|clear_logo|fanart|banner|icon|box_back|box_spine|box_3d|title_screen|video|music|video_snap|video_theme|video_trailer|video_recording|screenshot&index=<n> (screenshot index for kind=screenshot). kind=video resolves the active video by priority. Missing file or bad kind: 404 {"error":"Media not found"}. Media responses carry immutable cache headers, ETag, and byte-range support.
/api/media/bulkStart a background media download for every game with a launchbox_db_id: {"media": ["cover"|"background"|"screenshots"], "overwrite": bool, "platform": "<platform>|all"}. Returns 202 {"state":"running"}. Missing database raises 409.
/api/media/bulk/status{"job": {"state": "running"|"done", "current", "total", "updated", "errors": [...]}} (last 20 errors).
/api/media/audit?platform=<name or "all"> reports games, matched (has launchbox_db_id), missing_cover, missing_background, missing_screenshots.
/api/media/duplicates{"groups": [{"keep": "<path>", "duplicates": [...]}]} by SHA-256 + size fingerprint of covers, backgrounds, and screenshots.
/api/media/cleanup{"apply": bool, "platform": "<name>|all"} removes duplicate media. With apply: false it is a dry run returning candidate paths; with apply: true files are deleted only inside the data directory and the media epoch bumps. platform narrows the scan to one platform; blank or all scans the whole library. Returns {"groups", "paths": [...], "applied", "platform"}.
/api/media/queue{"queue": [...]} from media-queue.json (pending media jobs).
/api/screenshotCapture the screen with the first available tool among gnome-screenshot, spectacle, scrot, and ImageMagick import; appends to the game's screenshots and bumps the media epoch. Returns {"path"}.
Emulators
/api/emulators{"emulators": [...], "install_all": {...}, "update_all": {...}}. Each emulator: app_id, name, platforms, installed, mode (native|flatpak|""), profiles (platform to command), can_install (flatpak present), recommendations. The dialog catalog covers Dolphin, PPSSPP, PCSX2, RPCS3, Cemu, MAME, xemu, ScummVM, RetroArch, DuckStation, melonDS, Eden, Vita3K, and Xenia, backed by the 24 adapter YAML files in emulator_defs/ (authoritative registry at GET /api/v2/emulators/registry).
/api/emulators/recommend?platform=<name> returns {"recommendations": [...]} from the platform-to-emulator map.
/api/emulators/dependencies?name=<emulator> returns {"required": [...], "missing": [...]} BIOS/system file checks (DuckStation, PCSX2, RPCS3, RetroArch hints).
/api/emulators/install{"app_id": "org.mamedev.MAME"} installs from Flathub (adding the flathub remote if needed; 120 s remote, 1800 s install timeouts) and merges the platform profiles. Returns 202 {"state":"installing"}; duplicates return 200 with the current job. Errors surface as 400/500 with flatpak's stderr detail.
/api/emulators/install-allInstall every not-installed emulator. Returns 202 {"state":"installing"}; completion job has {"state":"done", "installed": [...], "errors": [...]}.
/api/emulators/update{"app_id"} updates one emulator (Flatpak required; 400 "Flatpak is required for emulator updates."). Returns 202 {"state":"updating"}.
/api/emulators/update-allUpdates all installed flatpak-mode emulators. Returns 202 {"state":"updating"}.
/api/emulators/open{"app_id"} launches the emulator standalone (native binary or flatpak run). Not installed: 400 "<name> is not installed.".
/api/emulators/definitions{"definitions": [...]} YAML emulator definition packs (id, name, extensions, platforms, startup, executable_patterns, flatpak, native).
/api/emulators/scan{"folder"} scans a folder using the definitions. Returns {"added", "found"}.
/api/emulators/scan-configsLists saved scan configurations (folder, emulator_id, auto_update). The auto-import worker executes configs with auto_update: true.
/api/emulators/scan-configsSaves a scan configuration (folder, emulator_id, auto_update). Returns {"config": {...}}.
/api/v2/emulators/registryReturns the emulator registry with platform coverage, adapter types, and installed status. Add ?health=1 to include per-adapter health status: bios_ok (BIOS file exists and SHA1 matches if expected), firmware_ok, and core_ok. The health check also reports BIOS_SHA1_DRIFT when a BIOS file exists but its hash doesn't match the expected value from the emulator definition. (v1.7.2+ for ?health=1)
/api/v2/emulators/defs/statusReports the emulator-definition update channel: the installed community pack and its version, which definitions in the data directory are local edits, and whether the published index offers anything newer. A missing pack is a normal state, not an error — the status still answers.
/api/v2/emulators/defs/updateChecks the published index for a newer signed community pack and reports what an install would do, without writing anything.
/api/v2/emulators/defs/updateInstalls the newest signed community definition pack. The archive is verified with the release Ed25519 key and validated in full before a single file is written; a signature failure raises a persisted security notification. The pack installs into the per-user data directory and shadows the bundled set without overwriting it, and a definition the user already has is kept. Retractions the pack declares are honored. (v1.15.0+)
/api/v2/emulators/defs/rollbackRemoves exactly what the update channel installed and restores the bundled definition set. Never touches definitions the user created or edited.
Storefront catalog
/api/storefront/catalog?source=steam|heroic|lutris|gameyfin returns {"catalog": [...]}. Steam reads installed manifests plus owned app ids from localconfig.vdf; Heroic reads library caches; Lutris uses --list-games --json; Gameyfin queries the configured server (requires gameyfin_url in settings, else 400). Entries carry id, name, source, installed, install_uri, path, launch, and store-specific ids. Provider errors return 400.
/api/storefront/import{"source", "uninstalled_only": bool, "installed_only": bool} imports catalog entries as games (deduplicated by identity), marking store_catalog, store_installed, owned. Returns {"added", "found", "imported"}. Unknown source raises 400.
Gameyfin
/api/gameyfin/providers{"providers": [...]} from the configured server. Connection failures return 400.
/api/gameyfin/testTest connection using posted settings (merged over stored). Returns {"ok": true, "games": <n>, "providers": [...]}.
/api/gameyfin/install{"gameyfin_id"|"id", "library_id": <optional>} downloads the game from Gameyfin into the install directory (staging with rollback; symlinks rejected; 4 GiB per file cap) and updates or appends the library entry. Returns 202 {"state":"installing", "gameyfin_id"}; without a gameyfin_id raises 400.
/api/gameyfin/install/status?gameyfin_id=<id> returns the job: {"state": "idle"|"installing"|"done"|"error", "gameyfin_id", "error"?}. Missing id raises 400.
/api/gameyfin/uninstallRemoves the game's install directory and files (refusing symlinks and paths outside the install directory) and marks the entry uninstalled. Non-Gameyfin entries raise 400. Returns {"removed": [...], "game": {...}}.
Health
/api/healthLibrary audit: {"games", "missing", "duplicates", "unconfigured", "missing_media", "issues": [...]}. Issues are typed Duplicate, Missing game, Missing box front, Missing extra, Missing save path, and No emulator (ROM extensions without a launch command or platform profile).
/api/health/dedupeRemove duplicate games by identity (steam app id, heroic, lutris, arcade rom_name, or normalized path). Returns {"removed": [names]}.
Discovery
/api/discovery{"recently_added": [...], "never_played": [...], "short_sessions": [...], "highly_rated": [...], "continue_playing": [...], "random_picks": [...], "generated_at": ...} index lists (12 each).
Errors
Missing database prerequisites return 409 on metadata routes; missing local tools (mame, xdg-open, 7z, flatpak, lutris) return 400 with the exact requirement; provider failures return 400 with the provider's message. See REST API overview for the shared envelope.