Advanced backends add composable layers to your file system — caching, chunking, aliasing, hashing, unioning, and in-memory storage. This page documents the HTTP API for connecting these backends and managing the persistent FUSE mounts that expose them to your container.
Mounts
Section titled “Mounts”Mount operations create, inspect, update, and remove persistent FUSE mounts for any connected backend. Every mount survives container restarts and can be filtered by label.
GET /api/v1/mounts
Section titled “GET /api/v1/mounts”List all active mounts. Supports filtering by label via the label query parameter.
This endpoint takes no request body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
label | query | string | No | Filter mounts by label. Only mounts with this exact label will be returned. |
Examples
Section titled “Examples”curl -X GET "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/mounts?label=Photos"await client.files.mounts.list("Photos");{ "count": 2, "mounts": [ { "backend_id": "backend_abc123", "created_at": 1700000000, "id": "mount_550e8400", "label": "Photos", "mount_path": "/hoody/mounts/mount_550e8400", "status": "active" }, { "backend_id": "backend_def456", "created_at": 1700000100, "id": "mount_660f9511", "label": "Work S3", "mount_path": "/hoody/mounts/mount_660f9511", "status": "active" } ]}GET /api/v1/mounts/{id}
Section titled “GET /api/v1/mounts/{id}”Get detailed information about a specific mount, including its VFS configuration.
This endpoint takes no request body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Mount ID |
Examples
Section titled “Examples”curl -X GET "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/mounts/mount_550e8400"await client.files.mounts.getDetails("mount_550e8400");{ "backend_id": "backend_abc123", "created_at": 1700000000, "id": "mount_550e8400", "label": "Photos", "mount_path": "/hoody/mounts/mount_550e8400", "status": "active", "vfs_config": { "cache_max_age": 3600, "cache_max_size": 10737418240, "cache_mode": "writes", "dir_cache_time": 300 }}POST /api/v1/mounts
Section titled “POST /api/v1/mounts”Create a persistent FUSE filesystem mount for a connected backend. Every mount is automatically persisted and restored on container restart — there is no separate persistence flag. To remove a mount, use DELETE /api/v1/mounts/{id}.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
backend_id | string | Yes | — | ID of an existing backend connection |
label | string | No | — | Human-readable label for the mount (e.g., "Photos"). Used by the UI and filterable via GET /api/v1/mounts?label=... |
mount_path | string | No | — | Absolute path for the mount. If omitted, defaults to /hoody/mounts/mount_{uuid} |
vfs_config | object | No | — | VFS cache configuration for performance tuning |
vfs_config supports the following properties:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
cache_max_age | integer or string | No | 3600 | Maximum time files are cached. Accepts seconds or duration strings like "1h" |
cache_max_size | integer or string | No | 10737418240 | Maximum cache size in bytes. Accepts bytes or human-readable strings like "10G" |
cache_mode | string | No | "writes" | Cache mode. One of "off", "minimal", "writes", "full" |
dir_cache_time | integer or string | No | 300 | How long directory listings are cached. Accepts seconds or duration strings like "5m" |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/mounts" \ -H "Content-Type: application/json" \ -d '{ "backend_id": "backend_abc123", "label": "Photos", "vfs_config": { "cache_mode": "writes", "cache_max_age": 3600 } }'await client.files.mounts.create({ backend_id: "backend_abc123", label: "Photos", vfs_config: { cache_mode: "writes", cache_max_age: 3600 }});{ "success": true, "message": "Mount created successfully", "data": { "id": "mount_550e8400", "backend_id": "backend_abc123", "label": "Photos", "mount_path": "/hoody/mounts/mount_550e8400", "status": "active" }}PATCH /api/v1/mounts/{id}
Section titled “PATCH /api/v1/mounts/{id}”Update the VFS configuration for an existing mount. Use this to retune cache settings without unmounting and remounting the backend.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Mount ID |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
vfs_config | object | Yes | VFS configuration parameters (same shape as the vfs_config object accepted by POST /api/v1/mounts) |
Examples
Section titled “Examples”curl -X PATCH "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/mounts/mount_550e8400" \ -H "Content-Type: application/json" \ -d '{ "vfs_config": { "cache_mode": "full", "cache_max_age": 7200 } }'await client.files.mounts.update("mount_550e8400", { vfs_config: { cache_mode: "full", cache_max_age: 7200 }});{ "success": true, "message": "Mount configuration updated"}{ "success": false, "error": "Invalid VFS configuration: cache_mode must be one of off, minimal, writes, full"}{ "success": false, "error": "Mount not found"}DELETE /api/v1/mounts/{id}
Section titled “DELETE /api/v1/mounts/{id}”Remove a mount and disconnect the underlying FUSE filesystem.
This endpoint takes no request body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Mount ID |
Examples
Section titled “Examples”curl -X DELETE "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/mounts/mount_550e8400"await client.files.mounts.unmount("mount_550e8400");{ "success": true, "message": "Mount removed successfully"}{ "success": false, "error": "Mount not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_NOT_FOUND | Mount not found | No mount exists with the specified ID | Verify the mount ID is correct or list all mounts |
Advanced Backends
Section titled “Advanced Backends”The endpoints below connect specialized backends that transform or compose other remotes. Use them to layer caching, chunking, hashing, aliasing, unioning, and in-memory storage on top of existing connections. Once connected, mount each backend with POST /api/v1/mounts to access it as a FUSE filesystem.
POST /api/v1/backends/alias
Section titled “POST /api/v1/backends/alias”Create an alias for an existing remote or local path. The alias exposes the source under a new backend ID.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
description | string | No | "" | Description of the remote |
remote | string | Yes | "" | Remote or path to alias. Accepts "myremote:path/to/dir", "myremote:bucket", "myremote:", or "/local/path" |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/alias" \ -H "Content-Type: application/json" \ -d '{ "remote": "myremote:archive/2024", "description": "Archive folder for 2024" }'await client.files.backends.connectAlias({ remote: "myremote:archive/2024", description: "Archive folder for 2024"});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_alias_001", "type": "alias", "backend_type": "alias", "mount_paths": [] }}{ "success": false, "error": "Remote specification is invalid or unreachable"}POST /api/v1/backends/cache
Section titled “POST /api/v1/backends/cache”Create a cache backend that stores file structure metadata and chunk data locally to accelerate reads from a slower remote.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
remote | string | Yes | "" | Remote to cache (e.g., "myremote:path/to/dir" or "myremote:bucket") |
description | string | No | "" | Description of the remote |
chunk_clean_interval | integer | No | 60 | How often the cache performs chunk cleanups (seconds) |
chunk_no_memory | boolean | No | false | Disable the in-memory cache for streaming chunks |
chunk_path | string | No | "/home/user/.cache/hoody-vfs/cache-backend" | Directory where partial file data (chunks) is stored |
chunk_size | string | No | "5242880" | Size of a chunk. One of "1M", "5M", "10M" |
chunk_total_size | string | No | "10737418240" | Maximum total disk usage of chunks. One of "500M", "1G", "10G" |
db_path | string | No | "/home/user/.cache/hoody-vfs/cache-backend" | Directory for the file structure metadata database |
db_purge | boolean | No | false | Clear all cached data for this remote on start |
db_wait_time | integer | No | 1 | Seconds to wait for the DB to become available (0 waits forever) |
info_age | integer | No | 21600 | How long to cache file structure information (seconds). One of "1h", "24h", "48h" |
plex_url | string | No | "" | URL of the Plex server (optional integration) |
plex_username | string | No | "" | Username of the Plex user |
plex_password | string | No | "" | Password of the Plex user |
plex_token | string | No | "" | Plex token for authentication (auto-set normally) |
plex_insecure | string | No | "" | Skip certificate verification when connecting to Plex |
read_retries | integer | No | 10 | Number of times to retry a read from cache storage |
rps | integer | No | -1 | Hard limit on requests per second to the source FS (-1 disables) |
tmp_upload_path | string | No | "" | Directory for temporary files before upload (empty disables) |
tmp_wait_time | integer | No | 15 | Seconds a file must wait in the temp location before upload |
workers | integer | No | 4 | Number of parallel workers for downloading chunks |
writes | boolean | No | false | Cache file data on writes through the FS |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/cache" \ -H "Content-Type: application/json" \ -d '{ "remote": "myremote:bucket/media", "description": "Local cache for media bucket", "chunk_size": "5M", "chunk_total_size": "10G", "workers": 4 }'await client.files.backends.connectCache({ remote: "myremote:bucket/media", description: "Local cache for media bucket", chunk_size: "5M", chunk_total_size: "10G", workers: 4});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_cache_001", "type": "cache", "backend_type": "cache", "mount_paths": [] }}{ "success": false, "error": "Failed to initialize cache: invalid chunk_size"}POST /api/v1/backends/chunker
Section titled “POST /api/v1/backends/chunker”Create a chunker backend that transparently splits large files into smaller chunks on the remote and reassembles them on read.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
remote | string | Yes | "" | Remote to chunk/unchunk (e.g., "myremote:path/to/dir") |
description | string | No | "" | Description of the remote |
chunk_size | string | No | "2147483648" | Files larger than this size will be split into chunks |
fail_hard | boolean | No | false | How chunker handles files with missing or invalid chunks. One of true, false |
hash_type | string | No | "md5" | How chunker handles hash sums. One of "none", "md5", "sha1", "md5all", "sha1all", "md5quick", "sha1quick" |
meta_format | string | No | "simplejson" | Format of the metadata object. One of "none", "simplejson" |
name_format | string | No | "*.hoody-vfs_chunk.###" | String format of chunk file names. The two placeholders are base file name (*) and chunk number (#) |
start_from | integer | No | 1 | Minimum valid chunk number (usually 0 or 1) |
transactions | string | No | "rename" | How chunker handles temporary files during transactions. One of "rename", "norename", "auto" |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/chunker" \ -H "Content-Type: application/json" \ -d '{ "remote": "myremote:bucket/large-files", "description": "Split large backups into chunks", "chunk_size": "1073741824", "hash_type": "sha1" }'await client.files.backends.connectChunker({ remote: "myremote:bucket/large-files", description: "Split large backups into chunks", chunk_size: "1073741824", hash_type: "sha1"});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_chunk_001", "type": "chunker", "backend_type": "chunker", "mount_paths": [] }}{ "success": false, "error": "Invalid chunker configuration"}POST /api/v1/backends/combine
Section titled “POST /api/v1/backends/combine”Create a combine backend that joins several remotes into a single namespace by mapping each to a root directory.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
upstreams | string | Yes | — | Upstreams in the form dir=remote:path dir2=remote2:path. Embedded spaces require quotes ("dir=remote:path with space") |
description | string | No | "" | Description of the remote |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/combine" \ -H "Content-Type: application/json" \ -d '{ "upstreams": "photos=myremote:bucket/photos videos=myremote:bucket/videos", "description": "Combined view of photos and videos" }'await client.files.backends.connectCombine({ upstreams: "photos=myremote:bucket/photos videos=myremote:bucket/videos", description: "Combined view of photos and videos"});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_combine_001", "type": "combine", "backend_type": "combine", "mount_paths": [] }}{ "success": false, "error": "Invalid upstreams specification"}POST /api/v1/backends/hasher
Section titled “POST /api/v1/backends/hasher”Create a hasher backend that provides better checksums for files on another remote by intercepting hash requests.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
remote | string | Yes | "" | Remote to cache checksums for (e.g., "myRemote:path") |
description | string | No | "" | Description of the remote |
auto_size | string | No | "0" | Auto-update checksum for files smaller than this size (disabled by default) |
hashes | string | No | "md5,sha1" | Comma-separated list of supported checksum types |
max_age | integer | No | 0 | Maximum time to keep checksums in cache (seconds). 0 = no cache, off = cache forever |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/hasher" \ -H "Content-Type: application/json" \ -d '{ "remote": "myremote:bucket/backups", "description": "Cached checksums for backups", "hashes": "md5,sha1,sha256", "max_age": 3600 }'await client.files.backends.connectHasher({ remote: "myremote:bucket/backups", description: "Cached checksums for backups", hashes: "md5,sha1,sha256", max_age: 3600});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_hasher_001", "type": "hasher", "backend_type": "hasher", "mount_paths": [] }}{ "success": false, "error": "Invalid hasher configuration"}POST /api/v1/backends/local
Section titled “POST /api/v1/backends/local”Create a local backend that exposes a directory on the container’s local disk.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
description | string | No | "" | Description of the remote |
encoding | string | No | "33554434" | Backend encoding. See the encoding overview for details |
case_insensitive | boolean | No | false | Force the filesystem to report itself as case insensitive |
case_sensitive | boolean | No | false | Force the filesystem to report itself as case sensitive |
copy_links | boolean | No | false | Follow symlinks and copy the pointed-to item |
links | boolean | No | false | Translate symlinks to and from regular files with a .hoody-vfslink extension |
no_check_updated | boolean | No | false | Don’t check whether files change during upload |
no_clone | boolean | No | false | Disable reflink cloning for server-side copies |
no_preallocate | boolean | No | false | Disable preallocation of disk space for transferred files |
no_set_modtime | boolean | No | false | Disable setting modification time after upload |
no_sparse | boolean | No | false | Disable sparse files for multi-thread downloads |
nounc | boolean | No | false | Disable UNC (long path names) conversion on Windows |
one_file_system | boolean | No | false | Don’t cross filesystem boundaries (Unix/macOS only) |
skip_links | boolean | No | false | Don’t warn about skipped symlinks |
time_type | string | No | "0" | Which timestamp to return. One of "mtime", "atime", "btime", "ctime" |
unicode_normalization | boolean | No | false | Apply unicode NFC normalization to paths and filenames |
zero_size_links | boolean | No | false | Assume the stat size of links is zero (deprecated) |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/local" \ -H "Content-Type: application/json" \ -d '{ "description": "Local workspace", "no_check_updated": true }'await client.files.backends.connectLocal({ description: "Local workspace", no_check_updated: true});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_local_001", "type": "local", "backend_type": "local", "mount_paths": [] }}{ "success": false, "error": "Invalid local backend configuration"}POST /api/v1/backends/memory
Section titled “POST /api/v1/backends/memory”Create an in-memory object storage backend. Files written here are kept in RAM and lost when the backend is removed or the container restarts.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
description | string | No | "" | Description of the remote |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/memory" \ -H "Content-Type: application/json" \ -d '{ "description": "Scratch space in RAM" }'await client.files.backends.connectMemory({ description: "Scratch space in RAM"});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_memory_001", "type": "memory", "backend_type": "memory", "mount_paths": [] }}{ "success": false, "error": "Failed to initialize memory backend"}POST /api/v1/backends/union
Section titled “POST /api/v1/backends/union”Create a union backend that merges the contents of several upstream filesystems into a single view.
This endpoint takes no URL parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
upstreams | string | Yes | "" | Space-separated list of upstreams (e.g., "upstreama:test/dir upstreamb:"). Embedded spaces require quotes |
description | string | No | "" | Description of the remote |
action_policy | string | No | "epall" | Policy to choose upstream on ACTION category |
cache_time | integer | No | 120 | Cache time of usage and free space (seconds). Only used with path preserving policies |
create_policy | string | No | "epmfs" | Policy to choose upstream on CREATE category |
min_free_space | string | No | "1073741824" | Minimum viable free space for lfs/eplfs policies (bytes) |
search_policy | string | No | "ff" | Policy to choose upstream on SEARCH category |
Examples
Section titled “Examples”curl -X POST "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.icu/api/v1/backends/union" \ -H "Content-Type: application/json" \ -d '{ "upstreams": "upstreama:test/dir upstreamb:", "description": "Merged view of two remotes", "create_policy": "epmfs", "search_policy": "ff" }'await client.files.backends.connectUnion({ upstreams: "upstreama:test/dir upstreamb:", description: "Merged view of two remotes", create_policy: "epmfs", search_policy: "ff"});{ "success": true, "message": "Backend connected successfully", "data": { "id": "backend_union_001", "type": "union", "backend_type": "union", "mount_paths": [] }}{ "success": false, "error": "Invalid union configuration"}