API Reference

REST endpoints, chunked uploads, streaming previews, background jobs, and WebSocket messages.

API Reference

BoxBox exposes a REST API, streaming endpoints, and a WebSocket endpoint under /api/v1.

Base URLs

http://localhost:8080/api/v1   # if Docker maps 8080 -> container port 80
http://localhost/api/v1        # inside a reverse proxy host

Health checks are available at both /health and /api/v1/health.

Authentication

All API routes except auth and health require a JWT access token.

Login

POST /api/v1/auth/login
Content-Type: application/json

{
  "username": "admin",
  "password": "your-password"
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "expiresAt": "2026-05-13T10:15:00Z"
}

Use an Access Token

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Refresh

POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Logout

POST /api/v1/auth/logout
Content-Type: application/json

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Files

List Mount Points

GET /api/v1/files
{
  "roots": [
    { "name": "home", "readOnly": false },
    { "name": "backups", "readOnly": true }
  ]
}

Drive Stats

GET /api/v1/files/stats
{
  "drives": [
    {
      "name": "home",
      "path": "/home/user",
      "device": "/dev/sda2",
      "fsType": "ext4",
      "mountPoint": "/",
      "totalBytes": 250000000000,
      "freeBytes": 100000000000,
      "usedBytes": 150000000000,
      "usedPct": 60,
      "readOnly": false
    }
  ]
}

List a Directory

GET /api/v1/files/{path}?page=1&pageSize=50&sortBy=name&sortDir=asc&filter=log

{path} starts with the mount name, for example home/projects.

Query options:

Name Default Notes
page 1 Positive integer.
pageSize 50 Maximum 1000.
sortBy name name, size, modTime, or type.
sortDir asc asc or desc.
filter empty Name contains filter.

Response:

{
  "path": "home/projects",
  "items": [
    {
      "name": "BoxBox",
      "path": "home/projects/BoxBox",
      "size": 4096,
      "isDir": true,
      "modTime": "2026-05-13T09:00:00Z",
      "permissions": "drwxr-xr-x"
    }
  ],
  "totalCount": 1,
  "page": 1,
  "pageSize": 50
}

Get File Info

GET /api/v1/files/{path}

If the path is a file, the response is one FileInfo object. If it is a directory, the response is a FileList.

Create Directory

POST /api/v1/files/{basePath}
Content-Type: application/json

{
  "name": "new-folder"
}

Rename or Move

PUT /api/v1/files/{oldPath}
Content-Type: application/json

{
  "newPath": "home/projects/renamed.txt"
}

Delete

DELETE /api/v1/files/{path}

Directories require confirmation:

DELETE /api/v1/files/{path}?confirm=true

Streaming

Download

GET /api/v1/stream/download/{path}

The download endpoint supports HTTP range requests.

Preview

GET /api/v1/stream/preview/{path}

Preview streams inline content for images, PDFs, audio, video, and text/code previews.

Chunked Upload

POST /api/v1/stream/upload/{destinationPath}
Content-Type: application/octet-stream
X-Upload-ID: upload_123
X-Chunk-Index: 0
X-Total-Chunks: 12
X-Chunk-Size: 10485760
X-Total-Size: 120000000
X-Checksum: sha256:abc123...

[binary chunk body]

X-Checksum is optional and normally sent on the final chunk.

Response:

{
  "uploadId": "upload_123",
  "chunkIndex": 0,
  "receivedChunks": 1,
  "totalChunks": 12,
  "complete": false
}

Final response:

{
  "uploadId": "upload_123",
  "chunkIndex": 11,
  "receivedChunks": 12,
  "totalChunks": 12,
  "complete": true,
  "path": "home/uploads/archive.zip"
}

Upload Status

GET /api/v1/stream/upload/status/?uploadId=upload_123
GET /api/v1/search?path=home&q=invoice
{
  "path": "home",
  "query": "invoice",
  "results": [],
  "count": 0
}

Both path and q are required.

Jobs

Background jobs handle copy, move, and delete operations.

GET /api/v1/jobs
GET /api/v1/jobs/{id}
DELETE /api/v1/jobs/{id}

Create a job:

POST /api/v1/jobs
Content-Type: application/json

{
  "type": "copy",
  "sourcePath": "home/movie.mkv",
  "destPath": "backups/movie.mkv"
}

Valid job types are copy, move, and delete. Copy and move require destPath.

Create response uses 202 Accepted:

{
  "id": "job_abc123",
  "type": "copy",
  "state": "pending",
  "progress": 0,
  "sourcePath": "home/movie.mkv",
  "destPath": "backups/movie.mkv",
  "createdAt": "2026-05-13T09:00:00Z"
}

System and Settings

System drives:

GET /api/v1/system/drives

Custom drive names:

GET /api/v1/settings/drive-names
PUT /api/v1/settings/drive-names
DELETE /api/v1/settings/drive-names/{mountPoint}

Set a drive name:

{
  "mountPoint": "home",
  "customName": "Main Home"
}

WebSocket

Connect with a token in the query string or Authorization header:

ws://localhost:8080/api/v1/ws?token=eyJhbGciOiJIUzI1NiIs...

Client messages:

{ "type": "subscribe", "jobId": "job_abc123" }
{ "type": "unsubscribe", "jobId": "job_abc123" }
{ "type": "ping" }

Server messages:

{
  "type": "job_update",
  "payload": {
    "jobId": "job_abc123",
    "state": "running",
    "progress": 45
  }
}

Terminal jobs use job_complete. Errors use error; ping replies use pong.

Errors

Errors use:

{
  "error": "Path is required",
  "code": "VALIDATION_ERROR",
  "details": ""
}

Common codes include VALIDATION_ERROR, UNAUTHORIZED, TOKEN_INVALID, ACCESS_DENIED, READ_ONLY, INVALID_PATH, NOT_FOUND, CONFLICT, JOB_NOT_FOUND, CHECKSUM_MISMATCH, and INTERNAL_ERROR.