openapi: 3.1.2 info: title: ShadowMount HTTP API version: "1" description: | HTTP/JSON API exposed by the ShadowMountPlus payload. The service has no authentication and should only be exposed on a trusted network. servers: - url: http://127.0.0.1:10101 description: Default loopback endpoint on the PS5 - url: http://{address}:{port} description: Configured network endpoint variables: address: default: 192.168.1.50 description: PS5 IPv4 address or hostname port: default: "10101" description: Value of api_port security: [] tags: - name: Service - name: Storage - name: Scanner - name: Manual sources - name: Images - name: Games paths: /: options: operationId: preflightIndex summary: CORS preflight tags: [Service] responses: "204": $ref: "#/components/responses/Preflight" get: operationId: getWebInterface summary: Get the optional web interface description: Serves /data/shadowmount/index.html when it is a regular file. tags: [Service] responses: "200": description: ShadowMount web interface headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: text/html: schema: type: string "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalError" /api/v1/version: options: operationId: preflightVersion summary: CORS preflight tags: [Service] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getVersion summary: Get API version and capabilities tags: [Service] requestBody: $ref: "#/components/requestBodies/EmptyRequest" responses: "200": $ref: "#/components/responses/VersionSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/images: options: operationId: preflightImages summary: CORS preflight tags: [Images] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: listImages summary: Get the complete image snapshot tags: [Images] requestBody: $ref: "#/components/requestBodies/EmptyRequest" responses: "200": $ref: "#/components/responses/ImagesSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/storage: options: operationId: preflightStorage summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getStorageSpace summary: Get free space for mounted storage filesystems tags: [Storage] requestBody: $ref: "#/components/requestBodies/EmptyRequest" responses: "200": $ref: "#/components/responses/StorageSpaceSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/scan: options: operationId: preflightScan summary: CORS preflight tags: [Scanner] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: rescan summary: Queue an immediate full rescan description: Retry counters are preserved by default. With reset_attempts=true, all title registration/install-remount and path-owned image-mount retry counters are reset immediately before the requested scan starts. If game runtime mounts are busy, the request remains queued until scanning is safe. tags: [Scanner] requestBody: $ref: "#/components/requestBodies/ScanRequest" responses: "200": $ref: "#/components/responses/ScanSuccess" "400": $ref: "#/components/responses/BadRequest" "409": $ref: "#/components/responses/Busy" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/manual/list: options: operationId: preflightListManualSources summary: CORS preflight tags: [Manual sources] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: listManualSources summary: List direct game source paths from manual.lst description: Entries identify individual game folders or images, not recursive scan roots. Comments and empty lines are omitted. tags: [Manual sources] requestBody: $ref: "#/components/requestBodies/EmptyRequest" responses: "200": $ref: "#/components/responses/ManualListSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/manual/add: options: operationId: preflightAddManualSource summary: CORS preflight tags: [Manual sources] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: addManualSource summary: Add a source path to manual.lst tags: [Manual sources] requestBody: $ref: "#/components/requestBodies/ManualPathRequest" responses: "200": $ref: "#/components/responses/ManualUpdateSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/manual/remove: options: operationId: preflightRemoveManualSource summary: CORS preflight tags: [Manual sources] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: removeManualSource summary: Remove all matching source lines from manual.lst tags: [Manual sources] requestBody: $ref: "#/components/requestBodies/ManualPathRequest" responses: "200": $ref: "#/components/responses/ManualUpdateSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/games: options: operationId: preflightGames summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: listGames summary: Get the complete game snapshot tags: [Games] requestBody: $ref: "#/components/requestBodies/GamesListRequest" responses: "200": $ref: "#/components/responses/GamesSuccess" "400": $ref: "#/components/responses/BadRequest" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/games/info: options: operationId: preflightGameInfo summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getGameInfo summary: Get detailed metadata and size for a folder, image or installed PKG tags: [Games] requestBody: $ref: "#/components/requestBodies/TitleRequest" responses: "200": $ref: "#/components/responses/GameInfoSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" /api/v1/games/fakelib: options: operationId: preflightGameFakelib summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: setGameFakelib summary: Enable or disable fakelib for a PS5 game on its next launch tags: [Games] requestBody: required: true content: application/json: schema: type: object required: [title_id, enabled] properties: title_id: $ref: "#/components/schemas/TitleId" description: Must identify a PS5 game; homebrew uses its app.db platform. enabled: type: boolean responses: "200": description: Per-title policy saved; existing mounts are preserved content: application/json: schema: type: object required: [status, title_id, fakelib_enabled, fakelib_effective_enabled, saved, applies_on_next_launch] properties: status: type: integer const: 0 title_id: $ref: "#/components/schemas/TitleId" fakelib_enabled: type: boolean fakelib_effective_enabled: type: boolean saved: type: boolean const: true applies_on_next_launch: type: boolean const: true "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalError" "507": description: Exclusion list is full; configuration was not changed /api/v1/games/icon: get: operationId: getGameIcon summary: Stream a game icon or a cached 128x128 thumbnail tags: [Games] parameters: - name: title_id in: query required: true schema: $ref: "#/components/schemas/TitleId" - name: size in: query required: false description: Generate and return the cached thumbnail variant schema: type: string enum: [thumb] responses: "200": description: PNG icon headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: image/png: schema: type: string format: binary "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalError" /api/v1/settings: options: operationId: preflightGetSettings summary: CORS preflight tags: [Settings] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getSettings summary: Read web-managed settings and recursive scan roots tags: [Settings] requestBody: $ref: "#/components/requestBodies/EmptyRequest" responses: "200": description: Current runtime settings content: application/json: schema: $ref: "#/components/schemas/SettingsResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalError" /api/v1/settings/update: options: operationId: preflightUpdateSettings summary: CORS preflight tags: [Settings] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: updateSettings summary: Atomically update web-managed config.ini keys description: Preserves unrelated keys and comments, then queues scanner-owned runtime reload. tags: [Settings] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SettingsUpdateRequest" responses: "200": description: Settings saved and reload queued "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "500": $ref: "#/components/responses/InternalError" /api/v1/debug-log: options: operationId: preflightGetDebugLog summary: CORS preflight tags: [Settings] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getDebugLog summary: Read a bounded tail of debug.log tags: [Settings] requestBody: required: true content: application/json: schema: type: object properties: max_bytes: type: integer minimum: 4096 maximum: 262144 default: 131072 responses: "200": description: Debug log tail content: application/json: schema: $ref: "#/components/schemas/DebugLogResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalError" /api/v1/kernel-log: options: operationId: preflightGetKernelLog summary: CORS preflight tags: [Settings] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getKernelLog summary: Read recent events from the SDK log stream used by crash detection description: Uses the sceKernelDebugGetSdkLogText snapshot shared with crash detection. tags: [Settings] requestBody: required: true content: application/json: schema: type: object properties: max_bytes: type: integer minimum: 4096 maximum: 262144 default: 131072 responses: "200": description: SDK kernel-log tail content: application/json: schema: $ref: "#/components/schemas/KernelLogResponse" "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "500": $ref: "#/components/responses/InternalError" /api/v1/games/move: options: operationId: preflightMoveGameSource summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: moveGameSource summary: Move a game folder or backing image, including across filesystems tags: [Storage] requestBody: $ref: "#/components/requestBodies/StorageDestinationRequest" responses: "202": $ref: "#/components/responses/StorageJobAccepted" "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" "507": $ref: "#/components/responses/InsufficientStorage" /api/v1/games/copy: options: operationId: preflightCopyGameSource summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: copyGameSource summary: Copy a game folder or backing image tags: [Storage] requestBody: $ref: "#/components/requestBodies/StorageDestinationRequest" responses: "202": $ref: "#/components/responses/StorageJobAccepted" "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" "507": $ref: "#/components/responses/InsufficientStorage" /api/v1/games/unpack: options: operationId: preflightUnpackGameImage summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: unpackGameImage summary: Mount an image read-only and copy its game tree into a folder tags: [Storage] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StorageUnpackRequest" responses: "202": $ref: "#/components/responses/StorageJobAccepted" "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" "507": $ref: "#/components/responses/InsufficientStorage" /api/v1/games/storage/status: options: operationId: preflightStorageJobStatus summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: getStorageJobStatus summary: Get the current or last storage job tags: [Storage] requestBody: $ref: "#/components/requestBodies/StorageJobStatusRequest" responses: "200": $ref: "#/components/responses/StorageJobStatusSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalError" /api/v1/games/storage/cancel: options: operationId: preflightStorageJobCancel summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: cancelStorageJob summary: Cancel an active storage job before its irreversible phase tags: [Storage] requestBody: $ref: "#/components/requestBodies/StorageJobCancelRequest" responses: "200": $ref: "#/components/responses/StorageJobStatusSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" /api/v1/games/delete: options: operationId: preflightDeleteGameSource summary: CORS preflight tags: [Storage] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: deleteGameSource summary: Asynchronously delete a game folder or backing image description: A confirmed request for a cached source that is already absent queues safe scanner reconciliation without starting a storage job or directly uninstalling the title. Absence may also mean disconnected storage. Permission and I/O errors remain failures. tags: [Storage] requestBody: $ref: "#/components/requestBodies/StorageDeleteRequest" responses: "200": description: Source already absent; library reconciliation queued content: application/json: schema: $ref: "#/components/schemas/MissingSourceResponse" "202": $ref: "#/components/responses/StorageJobAccepted" "400": $ref: "#/components/responses/BadRequest" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "500": $ref: "#/components/responses/InternalError" /api/v1/games/mount: options: operationId: preflightMountGame summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: mountGame summary: Mount a managed game tags: [Games] requestBody: $ref: "#/components/requestBodies/MountRequest" responses: "200": $ref: "#/components/responses/MountSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/games/unmount: options: operationId: preflightUnmountGame summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: unmountGame summary: Unmount a managed game tags: [Games] requestBody: $ref: "#/components/requestBodies/TitleRequest" responses: "200": $ref: "#/components/responses/UnmountSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" /api/v1/games/uninstall: options: operationId: preflightUninstallGame summary: CORS preflight tags: [Games] responses: "204": $ref: "#/components/responses/Preflight" post: operationId: uninstallGame summary: Request game uninstallation tags: [Games] requestBody: $ref: "#/components/requestBodies/TitleRequest" responses: "200": $ref: "#/components/responses/UninstallSuccess" "400": $ref: "#/components/responses/BadRequest" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Busy" "411": $ref: "#/components/responses/LengthRequired" "413": $ref: "#/components/responses/PayloadTooLarge" "415": $ref: "#/components/responses/UnsupportedMediaType" "431": $ref: "#/components/responses/HeadersTooLarge" "500": $ref: "#/components/responses/InternalError" "501": $ref: "#/components/responses/NotImplemented" components: requestBodies: EmptyRequest: required: true content: application/json: schema: type: object example: {} GamesListRequest: required: true content: application/json: schema: $ref: "#/components/schemas/GamesListRequest" ScanRequest: required: true content: application/json: schema: $ref: "#/components/schemas/ScanRequest" TitleRequest: required: true content: application/json: schema: $ref: "#/components/schemas/TitleRequest" MountRequest: required: true content: application/json: schema: $ref: "#/components/schemas/MountRequest" ManualPathRequest: required: true content: application/json: schema: $ref: "#/components/schemas/ManualPathRequest" StorageDestinationRequest: required: true content: application/json: schema: $ref: "#/components/schemas/StorageDestinationRequest" StorageDeleteRequest: required: true content: application/json: schema: $ref: "#/components/schemas/StorageDeleteRequest" StorageJobStatusRequest: required: true content: application/json: schema: $ref: "#/components/schemas/StorageJobStatusRequest" StorageJobCancelRequest: required: true content: application/json: schema: $ref: "#/components/schemas/StorageJobCancelRequest" headers: AllowOrigin: description: Browser origins allowed to access the API schema: type: string const: "*" AllowMethods: description: Methods allowed by CORS preflight schema: type: string const: GET, POST, OPTIONS AllowHeaders: description: Request headers allowed by CORS preflight schema: type: string const: Content-Type AllowPrivateNetwork: description: Private Network Access permission schema: type: string const: "true" MaxAge: description: Number of seconds for which the preflight may be cached schema: type: integer const: 86400 responses: Preflight: description: CORS preflight accepted headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" Access-Control-Allow-Methods: $ref: "#/components/headers/AllowMethods" Access-Control-Allow-Headers: $ref: "#/components/headers/AllowHeaders" Access-Control-Allow-Private-Network: $ref: "#/components/headers/AllowPrivateNetwork" Access-Control-Max-Age: $ref: "#/components/headers/MaxAge" VersionSuccess: description: API version and capabilities headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/VersionResponse" ImagesSuccess: description: Complete image snapshot headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ImagesResponse" StorageSpaceSuccess: description: Capacity and free space for mounted storage filesystems headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/StorageSpaceResponse" GamesSuccess: description: Complete game snapshot headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/GamesResponse" GameInfoSuccess: description: Detailed managed game metadata and physical source size headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/GameInfoResponse" StorageJobAccepted: description: Copy, move, delete or unpack job accepted for asynchronous execution headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/StorageJobResponse" StorageJobStatusSuccess: description: Current or last copy, move, delete or unpack job status headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/StorageJobResponse" ScanSuccess: description: Full rescan queued headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ScanResponse" ManualUpdateSuccess: description: manual.lst update completed headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ManualUpdateResponse" ManualListSuccess: description: Parsed manual.lst source paths headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ManualListResponse" MountSuccess: description: Game mounted headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/MountResponse" UnmountSuccess: description: Game unmounted headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/UnmountResponse" UninstallSuccess: description: Game uninstallation was accepted by AppInstUtil headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/UninstallResponse" BadRequest: description: Invalid HTTP request, JSON body or title ID headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" Forbidden: description: The source or destination is not allowed headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" NotFound: description: Managed title tracker was not found headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" Busy: description: Runtime state does not currently permit the operation headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: status: 16 error: Device busy LengthRequired: description: Content-Length is required headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" PayloadTooLarge: description: JSON request body exceeds 4096 bytes headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" UnsupportedMediaType: description: Content-Type is not application/json headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" HeadersTooLarge: description: HTTP headers exceed 8192 bytes headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" InternalError: description: Internal failure headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" NotImplemented: description: Unsupported transfer encoding or runtime operation headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" InsufficientStorage: description: The destination filesystem has insufficient free space headers: Access-Control-Allow-Origin: $ref: "#/components/headers/AllowOrigin" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" schemas: TitleId: type: string pattern: "^(CUSA|PPSA|LAPY|FAKE)[0-9]{5}$" examples: [PPSA12345] TitleRequest: type: object required: [title_id] properties: title_id: $ref: "#/components/schemas/TitleId" GamesListRequest: type: object properties: include_size: type: boolean default: false description: Calculate every physical source size. Directory traversal can be slow. ScanRequest: type: object properties: reset_attempts: type: boolean default: false description: Reset title install/mount and image-mount retry counters immediately before this requested full scan starts. MountRequest: type: object required: [title_id] properties: title_id: $ref: "#/components/schemas/TitleId" mode: type: string enum: [ro, rw, r/o, r/w] description: Optional request-scoped mode for every image layer needed by this mount. ManualPathRequest: type: object required: [path] properties: path: type: string pattern: "^/.+" maxLength: 1023 StorageDestinationRequest: type: object required: [title_id, destination_dir] properties: title_id: $ref: "#/components/schemas/TitleId" destination_dir: type: string pattern: "^/.+" maxLength: 1023 description: Existing directory under a configured non-runtime scan root. The original source basename is preserved. StorageDeleteRequest: type: object required: [title_id, confirm] properties: title_id: $ref: "#/components/schemas/TitleId" confirm: type: boolean const: true StorageUnpackRequest: type: object required: [title_id, destination_dir] properties: title_id: $ref: "#/components/schemas/TitleId" destination_dir: type: string pattern: "^/.+" maxLength: 1023 description: Existing directory under a configured scan root. A TITLE_ID child directory is created. delete_source: type: boolean default: false description: Delete the backing image only after a complete copy and successful unmount. StorageJobStatusRequest: type: object properties: job_id: type: integer format: int64 minimum: 1 description: Omit to return the current or most recently completed job. StorageJobCancelRequest: type: object required: [job_id] properties: job_id: type: integer format: int64 minimum: 1 SettingsUpdateRequest: type: object required: [debug, quiet_mode, update_emulators, allow_lan_access, fan_target_temperature, scan_paths] properties: debug: type: boolean quiet_mode: type: boolean update_emulators: type: boolean auto_update_ampr: type: boolean description: Download libSceAmpr.sprx updates from the configured GitHub release URL. Omission preserves the current value for compatibility with older web clients. auto_remove_missing_games: type: boolean description: Remove app registrations whose source remains unavailable. Omission preserves the current value for compatibility with older web clients. auto_remove_missing_delay_seconds: type: integer minimum: 1 maximum: 86400 description: Omission preserves the current value for compatibility with older web clients. allow_lan_access: type: boolean description: Bind to 0.0.0.0 when true or 127.0.0.1 when false. fan_target_temperature: type: integer description: Zero selects system control; otherwise 50 through 91 degrees Celsius. oneOf: - const: 0 - minimum: 50 maximum: 91 scan_paths: type: array description: Explicit custom roots only. An empty array restores compile-time defaults. maxItems: 256 items: type: string pattern: "^/.+" maxLength: 1023 SettingsResponse: allOf: - $ref: "#/components/schemas/SettingsUpdateRequest" - type: object required: [status, api_enabled, scan_path_count] properties: status: type: integer const: 0 api_enabled: type: boolean description: Whether the HTTP API is enabled in config.ini. scan_path_count: type: integer minimum: 0 DebugLogResponse: type: object additionalProperties: false required: [status, file_size, returned_bytes, truncated, content] properties: status: type: integer const: 0 file_size: type: integer format: int64 minimum: 0 returned_bytes: type: integer minimum: 0 maximum: 262144 truncated: type: boolean content: type: string KernelLogResponse: type: object additionalProperties: false required: [status, total_bytes, returned_bytes, truncated, content] properties: status: type: integer const: 0 total_bytes: type: integer minimum: 0 returned_bytes: type: integer minimum: 0 maximum: 262144 truncated: type: boolean content: type: string VersionResponse: type: object additionalProperties: false required: [status, api_version, shadowmount_version, capabilities] properties: status: type: integer const: 0 api_version: type: integer const: 1 shadowmount_version: type: string capabilities: type: array items: type: string enum: [web_ui, storage_space, list_images, list_games, game_info, game_icon, mount_game, unmount_game, uninstall_game, move_game_source, copy_game_source, delete_game_source, unpack_game_image, storage_job_status, storage_job_cancel, list_manual_sources, add_manual_source, remove_manual_source, manage_settings, read_debug_log, read_kernel_log, rescan] example: [web_ui, storage_space, list_images, list_games, game_info, game_icon, mount_game, unmount_game, uninstall_game, move_game_source, copy_game_source, delete_game_source, unpack_game_image, storage_job_status, storage_job_cancel, list_manual_sources, add_manual_source, remove_manual_source, manage_settings, read_debug_log, read_kernel_log, rescan] StorageMount: type: object additionalProperties: false required: [source, mount_point, filesystem, total_bytes, free_bytes, available_bytes, used_bytes, read_only] properties: source: type: string mount_point: type: string pattern: "^/" filesystem: type: string total_bytes: type: integer format: int64 minimum: 0 free_bytes: type: integer format: int64 minimum: 0 available_bytes: type: integer format: int64 minimum: 0 used_bytes: type: integer format: int64 minimum: 0 read_only: type: boolean StorageSpaceResponse: type: object additionalProperties: false required: [status, count, destination_count, mounts, destinations] properties: status: type: integer const: 0 count: type: integer minimum: 0 destination_count: type: integer minimum: 0 mounts: type: array items: $ref: "#/components/schemas/StorageMount" destinations: type: array items: $ref: "#/components/schemas/StorageDestination" StorageDestination: type: object additionalProperties: false required: [path, source, mount_point, filesystem, total_bytes, free_bytes, available_bytes, used_bytes, read_only] properties: path: type: string pattern: "^/" source: type: string mount_point: type: string pattern: "^/" filesystem: type: string total_bytes: type: integer format: int64 minimum: 0 free_bytes: type: integer format: int64 minimum: 0 available_bytes: type: integer format: int64 minimum: 0 used_bytes: type: integer format: int64 minimum: 0 read_only: type: boolean Image: type: object additionalProperties: false required: - path - mount_point - size - mtime_sec - mtime_nsec - unit_id - backend - complete - source_available - mapped - mounted properties: path: type: string mount_point: type: string size: type: integer format: int64 minimum: 0 mtime_sec: type: integer format: int64 mtime_nsec: type: integer minimum: 0 maximum: 999999999 unit_id: type: integer minimum: -1 backend: type: string enum: [LVD, MD, UNKNOWN] complete: type: boolean source_available: type: boolean mapped: type: boolean mounted: type: boolean ImagesResponse: type: object additionalProperties: false required: [status, count, images] properties: status: type: integer const: 0 count: type: integer minimum: 0 images: type: array items: $ref: "#/components/schemas/Image" Game: type: object additionalProperties: false required: - path - runtime_path - source_type - image_type - platform - title_id - content_id - title_name - version - last_access_time - install_time - icon_url - app_db_size_bytes - installed - managed - mounted - image_backed - source_available - installed_pkg - can_uninstall - can_manage_source - can_toggle_fakelib - fakelib_enabled - fakelib_effective_enabled properties: path: type: string description: Physical game folder, outer backing-image path or installed app.pkg. runtime_path: type: string description: Runtime game directory used by ShadowMount; empty for installed PKGs. source_type: type: string enum: [folder, image, pkg] image_type: type: string enum: ["", ufs, exfatfs, pfs, pfsc, unknown] platform: type: string enum: [ps4, ps5, unknown] title_id: $ref: "#/components/schemas/TitleId" content_id: type: string title_name: type: string version: type: string description: AppInfoJson CONTENT_VERSION (PS5) or APP_VER (PS4), or an empty string when unavailable. last_access_time: type: string description: AppInfoJson #_last_access_time value, falling back to app.db lastAccessTime, or an empty string. install_time: type: string description: AppInfoJson #_install_time value, falling back to app.db installTime, or an empty string. icon_url: type: string description: Relative URL of the icon endpoint, or an empty string. app_db_size_bytes: type: integer format: int64 minimum: 0 installed: type: boolean managed: type: boolean mounted: type: boolean image_backed: type: boolean source_available: type: boolean installed_pkg: type: boolean can_uninstall: type: boolean can_manage_source: type: boolean description: False for installed PKGs; source mutations are forbidden. can_toggle_fakelib: type: boolean description: True for PS5 games in PKGs, images and folders. fakelib_enabled: type: boolean description: Per-title policy; changes apply on the next launch. fakelib_effective_enabled: type: boolean description: Per-title policy combined with the global backport_fakelib switch. size_status: type: integer minimum: 0 description: errno-style result of optional physical size calculation. size_bytes: type: integer format: int64 minimum: 0 description: Image file size, sum of folder files or installed PKG size from app.db (package file size when unavailable). status: type: integer const: 0 GamesResponse: type: object additionalProperties: false required: [status, count, size_included, games] properties: status: type: integer const: 0 count: type: integer minimum: 0 size_included: type: boolean games: type: array items: $ref: "#/components/schemas/Game" GameInfoResponse: allOf: - $ref: "#/components/schemas/Game" - type: object required: [status, size_status] StorageJobResponse: type: object additionalProperties: false required: [status, job_id, operation, state, active, cancellable, cancel_requested, title_id, source_type, source, runtime_source, destination, delete_source, total_bytes, processed_bytes, total_files, processed_files, progress_percent, speed_bytes_per_second, elapsed_ms, affected_titles, result_status, result_error, result_error_reason, scan_queued] properties: status: type: integer const: 0 job_id: type: integer format: int64 minimum: 0 operation: type: string enum: ["", move, copy, delete, unpack] state: type: string enum: [idle, preparing, measuring, transferring, deleting, finalizing, completed, failed, cancelled] active: type: boolean cancellable: type: boolean cancel_requested: type: boolean title_id: type: string source_type: type: string enum: ["", folder, image] source: type: string runtime_source: type: string destination: type: string description: Empty for delete jobs. delete_source: type: boolean description: True only for unpack jobs that will remove the image after successful extraction. total_bytes: type: integer format: int64 minimum: 0 processed_bytes: type: integer format: int64 minimum: 0 total_files: type: integer format: int64 minimum: 0 processed_files: type: integer format: int64 minimum: 0 progress_percent: type: number format: double minimum: 0 maximum: 100 speed_bytes_per_second: type: integer format: int64 minimum: 0 description: Average processed-byte rate since transfer or deletion began. elapsed_ms: type: integer format: int64 minimum: 0 affected_titles: type: integer minimum: 0 result_status: type: integer minimum: 0 result_error: type: string description: English error text; localized clients should use result_error_reason when available. result_error_reason: $ref: "#/components/schemas/OperationErrorReason" scan_queued: type: boolean ScanResponse: type: object additionalProperties: false required: [status, queued, reset_attempts, scan_queued, scan_deferred, scan_deferred_reason] properties: status: type: integer const: 0 queued: type: boolean const: true reset_attempts: type: boolean scan_queued: type: boolean const: true scan_deferred: type: boolean description: Whether game runtime or rest mode prevents scanning at response time; queue acceptance does not mean scan completion. scan_deferred_reason: type: string enum: ["", game_active, runtime_prepared, rest_mode] ManualUpdateResponse: type: object additionalProperties: false required: [status, path, present, changed] properties: status: type: integer const: 0 path: type: string present: type: boolean changed: type: boolean ManualListResponse: type: object additionalProperties: false required: [status, count, paths] properties: status: type: integer const: 0 count: type: integer minimum: 0 paths: type: array items: type: string pattern: "^/.+" MountResponse: type: object additionalProperties: false required: [status, title_id, mounted, mode] properties: status: type: integer const: 0 title_id: $ref: "#/components/schemas/TitleId" mounted: type: boolean const: true mode: type: string enum: [default, ro, rw] UnmountResponse: type: object additionalProperties: false required: [status, title_id, mounted] properties: status: type: integer const: 0 title_id: $ref: "#/components/schemas/TitleId" mounted: type: boolean const: false UninstallResponse: type: object additionalProperties: false required: [status, title_id, uninstall_requested, scan_queued, scan_deferred, scan_deferred_reason] properties: status: type: integer const: 0 title_id: $ref: "#/components/schemas/TitleId" uninstall_requested: type: boolean const: true scan_queued: type: boolean description: Full synchronization was queued because the known source was absent before uninstall; retained sources are not immediately rediscovered. scan_deferred: type: boolean scan_deferred_reason: type: string enum: ["", game_active, runtime_prepared, rest_mode] MissingSourceResponse: type: object additionalProperties: false required: [status, title_id, source_missing, scan_queued, scan_deferred, scan_deferred_reason] properties: status: type: integer const: 0 title_id: $ref: "#/components/schemas/TitleId" source_missing: type: boolean const: true scan_queued: type: boolean const: true scan_deferred: type: boolean scan_deferred_reason: type: string enum: ["", game_active, runtime_prepared, rest_mode] ErrorResponse: type: object additionalProperties: false required: [status, error] properties: status: type: integer minimum: 1 description: Positive errno value error: type: string error_reason: $ref: "#/components/schemas/OperationErrorReason" OperationErrorReason: type: string description: Stable reason code for localized operation errors; empty for generic errno failures. enum: ["", rest_mode, game_active, install_pending, runtime_prepared, scanner_busy, runtime_busy, title_unmount_busy, image_unmount_busy, unpack_mounted, storage_busy, storage_unavailable]