Getting Started
Basic Concept
View files across multiple devices in one place
Unified File Explorer connects multiple devices so you can browse the files and folders on each device from a single interface.
Users can select a connected device, browse its folders, locate the files they need, and work with files across multiple devices from one workspace.

For example, you can view documents on a work PC, data on a server, and result files in storage from the same browsing environment and select the files you need.
Exploration Flow
Move from device selection to file review and transfer
Unified File Explorer provides a workflow for finding files on connected devices and transferring selected files to the next work environment.
① Select a device
↓
② Browse folders
↓
③ Review files
↓
④ Select the required files
↓
⑤ Select a transfer target
↓
⑥ Transfer files
↓
⑦ Review results

This flow takes you from locating files to transferring them to the required work location and reviewing the results.
Workflow Changes
Connect file browsing and transfer in a single workflow
When work depends on files across multiple devices, users must identify where the required files are stored, locate them on the relevant device, and prepare them for the next work environment.
With Unified File Explorer, users can find the files they need on connected devices and transfer selected files directly to a specified device or workspace.
| Category | File Management by Device | Unified File Explorer |
|---|---|---|
| Start Work | Identify the device containing the required files | Select directly from the connected device list |
| Browse Files | Review files and folders in each device environment | Browse devices and files from one screen |
| Prepare Files | Prepare files for the next work location after reviewing them | Transfer selected files directly to the target device |
| Continue Work | Continue to the next task after preparing files | Use transferred files immediately after completion |
By combining file browsing and transfer into one flow, files across multiple work environments can be used directly where they are needed.
IT Engineers
Configure and manage a file browsing environment across multiple devices
Connect Devices
Connect devices for browsing and expand the environment as needed
To configure Unified File Explorer, first connect the PCs, servers, storage systems, and other devices that contain the files you need to access.
After configuring the connection information for each device, you can browse that system's files and folders from the unified explorer.

As the work environment expands, you can add new servers or storage systems in the same way. After configuring their connection information, the new devices can be included in the existing browsing environment.
| Device Type | Files Used |
|---|---|
| Work PC | Personal and team work files |
| Windows Server | Business documents and operational files |
| Linux Server | Data and processing files |
| Storage | Shared files and result files |
Adding devices extends the browsing scope to additional systems while preserving the existing file exploration environment.
Access Scope
Define which files and folders users can access on each device
After connecting devices, configure which devices and file paths users can access based on their roles and responsibilities.
You can assign devices to individual users or user groups and define the folder scope available on each device.

For example, the operations team can be given access to designated folders on operational servers, while the data team can access work paths on analytics servers and data storage.
| User Group | Devices to Browse | File Scope |
|---|---|---|
| Operations Team | Operations Server | Operational file paths |
| Data Team | Analytics Server | Data folders |
| Business Team | Shared Storage | Work file folders |
Defining access scopes by user lets you operate Unified File Explorer around the devices and files each team needs for its work.
Browse Files
Find the files you need across connected devices
After devices and access scopes are configured, users can select a device in the unified explorer and browse its folders and files.
Selecting a system from the device list displays its folder structure and file list, allowing users to locate files by name and path.

The file browser displays the following information:
| Item | Description |
|---|---|
| Device | Device containing the file |
| Path | Current file path |
| File Name | File name |
| Size | File size |
| Modified | Last modified time |
After locating a file, select it to continue directly to the next transfer operation.
File Transfer
Transfer selected files to the required device or workspace
After selecting the required files in the explorer, specify the destination device and target path.
The selected files are transferred from their current location to the specified target device or workspace, where they can be reviewed and used in the next task.

The transfer flow is structured as follows:
Device A
│
│ Browse files
▼
Select files
│
│ Select target
▼
Device B
│
▼
Workspace
Finding files and selecting a destination from the same explorer connects file browsing and transfer in a single workflow.
Verify Results
Review transfer status and file processing results
When a file transfer runs, you can review its progress and processing results in Runs.
Each run shows the Source and Target for the transferred files, file count, transfer volume, progress, execution time, and current status.

| Item | Details |
|---|---|
| Source | Device and path where the files were selected |
| Target | Device and workspace receiving the files |
| Files | Number of processed files |
| Size | Total transfer volume |
| Progress | Current transfer progress |
| Status | Current run status |
| Time | Execution and completion times |
Operators can use run results to review file transfer flows and processing status between devices and manage how files are delivered to each work environment.
Developers
Retrieve file lists and search results from remote devices through the API and run transfers between devices
Integration Setup
Prepare shared API calls and status values
import os
import requests
BASE_URL = os.getenv("INNORIX_BASE_URL", "https://app.innorix.com").rstrip("/")
TOKEN = os.environ["INNORIX_ACCESS_TOKEN"]
WORKSPACE_ID = os.getenv("INNORIX_WORKSPACE_ID") # optional; falls back to the current workspace
STATUS_COMPLETE = 2
TERMINAL = {2, 4, 5, 9, 99} # complete / error / cancelled / partial / failed
NOT_SUCCEEDED = {4, 5, 9, 99}
def api(method, path, body=None, params=None):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {TOKEN}",
}
if WORKSPACE_ID:
headers["x-workspace-id"] = WORKSPACE_ID
response = requests.request(
method, BASE_URL + path,
headers=headers, json=body, params=params, timeout=30,
)
payload = response.json() if response.content else {}
if not response.ok:
raise RuntimeError(payload.get("message") or f"HTTP {response.status_code}")
return payload.get("data")
def is_terminal(detail):
return detail.get("isTerminal", detail.get("status") in TERMINAL)Use the following values to determine transfer status. There are five terminal states, and Complete (2) is the successful state.
| Status Value | Meaning | Terminal |
|---|---|---|
| 2 | Complete | Yes |
| 4 | Error | Yes |
| 5 | Cancelled | Yes |
| 9 | Partial Complete | Yes |
| 99 | Failed | Yes |
| 1 · 6 · 12 · 13 | Starting · Transferring · Synchronizing · Receiving | No |
List Folder Contents
Retrieve a device file list and display it in the UI
Specify a device identifier and path to retrieve the files and subfolders in that folder. Because the value passed to --device is used as a path parameter, it must be a device ID.
result = api("GET", f"/api/devices/{device_id}/files", params={
"path": "/data/reports",
"page": 1,
"size": 50,
"sort": "name:asc",
"type": "all",
})
for item in result["items"]:
kind = "DIR " if item["isDir"] else "FILE"
print(kind, item["name"], item["size"], item.get("modifiedAt"))| Response Field | Description |
|---|---|
items | List of files and folders |
total · lastPage | Total item count and final page |
truncated | Whether only part of the result was returned because the item limit was exceeded |
isDir | Whether the item is a folder |
Use the device list endpoint to find the device ID.
result = api("GET", "/api/devices", params={"page": 1, "size": 200})
for device in result["devices"]:
print(device["deviceId"], device["name"], device.get("os"),
device.get("ipAddress"))The device list is returned in the data.devices array.
Search Files
Search recursively through subfolders to find files
Folder listing returns only the current folder. To search through subfolders, start a search and retrieve subsequent results using the cursor.
RESTART_CODES = {"INVALID_CURSOR", "CURSOR_OUT_OF_SEQUENCE", "SEARCH_EXPIRED"}
def start_search(device_id, path, page_size=500):
return api("POST", f"/api/devices/{device_id}/files/search",
{"path": path, "pageSize": page_size})
def iter_search(device_id, path, max_pages=200):
page = start_search(device_id, path)
search_id = page.get("searchId")
for _ in range(max_pages):
for item in page.get("items") or []:
yield search_id, item
if not page.get("hasMore"):
return
try:
page = api("GET", f"/api/devices/{device_id}/files/search",
params={"cursor": page["nextCursor"]})
except RuntimeError:
# restart the scan when the cursor expires or falls out of sequence
page = start_search(device_id, path)
search_id = page.get("searchId")Search requests accept only the base path and page size. Name and extension filters are applied to the returned results, so using a narrower base path reduces the search scope.
| Response Field | Description |
|---|---|
searchId | Search identifier passed when cancelling a search |
items[].type | file or directory |
hasMore · nextCursor | Whether another page exists and the cursor used to retrieve it |
Stop a Search
Stop an active search
A search causes the device to scan its disk. Cancel the search when the user leaves the screen to prevent unnecessary load from accumulating on the device.
def cancel_search(device_id, search_id):
api("POST", f"/api/devices/{device_id}/files/search/cancel",
{"uuid": search_id}) # pass the searchId returned when the search started
search_id = None
try:
for search_id, item in iter_search(device_id, "/data"):
if item["type"] == "file" and item["name"].endswith(".csv"):
print(item["path"], item["size"])
finally:
if search_id:
cancel_search(device_id, search_id)Run the same cleanup logic both when starting a new search and when closing the screen.
File Transfer
Send selected files to another device
For an immediate transfer, a device can be specified by name, IP address, or identifier, and paths are passed as plain-text strings. This differs from the browsing API, which accepts only device IDs.
When sending a list of files, use sourceItem with isDir: false instead of sourcePaths. sourcePaths treats every path as a folder, so passing files causes the server to scan each file as a folder, which can slow the request or cause it to time out.
def send_files(source, target, target_path, paths, action="numbering"):
transfer = api("POST", "/api/transfers/manual", {
"sourceDevice": source,
"targetDevice": target,
"targetPath": target_path,
"sourceItem": [{"path": p, "isDir": False} for p in paths],
"sendAllFolder": False,
"transferOptions": {"target-action": action},
})
return transfer["monitorId"]
monitor_id = send_files("device-a", "device-b", "/data/collected",
["/data/reports/2026-08.csv"])When sending folders, use sourcePaths with sendAllFolder: True.
api("POST", "/api/transfers/manual", {
"sourceDevice": "device-a",
"targetDevice": "device-b",
"targetPath": "/data/collected",
"sourcePaths": ["/data/reports"],
"sendAllFolder": True,
"transferOptions": {"target-action": "numbering"},
})If the file size is already known, pass fileSize to skip the server's per-item lookup.
"sourceItem": [
{ "path": "/data/a.csv", "isDir": false, "fileSize": 1200 }
]
Verify Results
Review transfer status and per-file processing results
import time
def wait(monitor_id, timeout=1800, interval=3):
deadline = time.time() + timeout
while time.time() < deadline:
detail = api("GET", f"/api/transfers/{monitor_id}")
if is_terminal(detail):
return detail
time.sleep(interval)
raise TimeoutError(monitor_id)
detail = wait(monitor_id)
succeeded = detail["status"] == STATUS_COMPLETEFull failures and partial failures should be displayed differently in the UI. Check each file's status through the file listing endpoint and retry only the failed files.
def failed_files(monitor_id):
result = api("GET", f"/api/transfers/{monitor_id}/files", params={
"state": "any", "size": 500,
}) or {}
return [r for r in (result.get("children") or [])
if r.get("status") in NOT_SUCCEEDED]
def retry_failed(monitor_id):
rows = failed_files(monitor_id)
if not rows:
return 0
api("POST", f"/api/transfers/{monitor_id}/retry", {
"filesRetry": [
{"filePath": r["sourceFilePath"], "isDir": bool(r.get("isFolder"))}
for r in rows
]
})
return len(rows)Retries can be requested only after the transfer reaches a terminal state. A retry is rejected while the transfer is still in progress, so check the status first.
| Item | Details |
|---|---|
status | Transfer status value |
statusLabel | Status string displayed in the UI |
percent | Progress percentage |
fileCount · totalSize | Number of processed files and total size |
children[].errorCode | Per-file failure reason |