File operations
Section titled “File operations”These endpoints upload, modify, move, copy, search, and delete files inside a Hoody container. Use them to build file browsers, sync agents, code search tools, and image pipelines. All requests are scoped to a single container, addressed through that container’s files subdomain.
Search and discovery
Section titled “Search and discovery”GET /{directory}?q
Section titled “GET /{directory}?q”Search a directory for files whose name matches a case-insensitive query. Returns HTML by default, or JSON when ?json is present. Results are filtered to what the calling account may read.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
directory | path | string | Yes | Directory to search. |
q | query | string | Yes | Search query (case-insensitive filename match). Maximum 512 bytes of UTF-8, measured both before and after Unicode lowercasing. Longer queries are rejected with 400. |
json | query | string | No | Return JSON instead of HTML. |
theme | query | string | No | Colour theme of the HTML page. One of oc-1, aura, ayu, carbonfox, catppuccin, dracula, gruvbox, monokai, nightowl, nord, onedarkpro, shadesofpurple, solarized, tokyonight, vesper. Default oc-1. |
colorScheme | query | string | No | Light or dark colour scheme. Without it the page follows the system setting. |
font | query | string | No | Monospace font of the editor and listing. One of ibm-plex-mono, cascadia-code, fira-code, hack, inconsolata, intel-one-mono, iosevka, jetbrains-mono, meslo-lgs, roboto-mono, source-code-pro, ubuntu-mono. |
fontSize | query | integer | No | Editor font size in pixels. Default 14. |
embedderOrigin | query | string | No | Origin of the embedding page. Only https origins are accepted. |
chromeless | query | boolean | No | Hide the header, sidebar, preview, footer, and borders at once. |
borderless | query | boolean | No | Hide the page borders. |
hideHeader | query | boolean | No | Hide the header bar. |
hideSidebar | query | boolean | No | Hide the sidebar. |
hidePreview | query | boolean | No | Hide the preview pane. |
hideFooter | query | boolean | No | Hide the footer. |
embedBg | query | string | No | transparent lets the background of the embedding page show through. |
Response
Section titled “Response”The response is HTML by default. When ?json is set, the response is a directory listing with the entries that match the query and the permissions of the calling account.
{ "allow_archive": true, "allow_delete": true, "allow_remote": false, "allow_search": true, "allow_upload": true, "auth": true, "dir_exists": true, "href": "/", "kind": "Index", "paths": [ { "mtime": 1700000000000, "name": "README.md", "path_type": "File", "revisions": 3, "size": 1024 }, { "mtime": 1700000001000, "name": "src", "path_type": "Dir", "revisions": null, "size": 12 } ], "remote_mounts": null, "uri_prefix": "", "user": "alice"}| Field | Type | Required | Description |
|---|---|---|---|
allow_archive | boolean | No | Whether the deployment allows downloading folders as archives. |
allow_delete | boolean | No | Whether the deployment allows deletes. |
allow_remote | boolean | No | Whether the deployment allows remote backends and mounts. |
allow_search | boolean | No | Whether the deployment allows search. |
allow_upload | boolean | No | Whether the deployment allows uploads. |
auth | boolean | No | Whether authentication is configured on this server. |
dir_exists | boolean | No | Whether the searched directory exists. |
href | string | No | The path that was searched. |
kind | string | No | Always Index. |
paths | array | No | Matching entries. |
paths[].mtime | integer | No | Unix timestamp in milliseconds. |
paths[].name | string | No | Entry name. |
paths[].path_type | string | No | File, Dir, SymlinkFile, or SymlinkDir. |
paths[].revisions | integer | No | Journal revisions for this entry, if any. |
paths[].size | integer | No | File size in bytes, or the number of items in a directory. |
remote_mounts | object | No | The mount directory when remote backends are allowed and a folder mounted there can be browsed through this server. |
remote_mounts.dir | string | Yes | The mount directory as an absolute path. |
remote_mounts.path | string | Yes | The mount directory relative to the served root. |
uri_prefix | string | No | URI prefix for the request. |
user | string | No | The authenticated user, if any. |
The query q exceeded 512 bytes of UTF-8, or the path is invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Search is not allowed for this account on this path.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
Nothing is at this path.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
curl -G \ --data-urlencode "q=readme" \ --data-urlencode "json=" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.search('/', { q: 'readme', json: '' });GET /api/v1/files/glob/{path}
Section titled “GET /api/v1/files/glob/{path}”Find files and directories whose path matches a glob pattern. Supports recursive patterns (**/*.rs), brace expansion ({ts,tsx}), character classes ([a-z]), and standard wildcards. Results respect .gitignore by default.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Directory path to search within. |
pattern | query | string | Yes | Glob pattern (for example **/*.rs, src/**/*.{ts,tsx}, *.md). |
max_results | query | integer | No | Maximum entries to return. Default 1000. |
max_depth | query | integer | No | Maximum directory recursion depth. Default 50. |
max_files_scanned | query | integer | No | Maximum filesystem entries to scan. Default 100000. |
timeout | query | integer | No | Search timeout in seconds. Default 30. |
no_ignore | query | boolean | No | Also search files excluded by .gitignore, .ignore, .git/info/exclude, and the global git excludes. Default false. |
hidden | query | boolean | No | Also search names starting with ., which are otherwise skipped unless an ignore file whitelists them. .git folders found inside the searched folder are still skipped. Refused with 403 for an account that may only list this path. Default false. |
sort | query | string | No | Sort results by mtime (default), name, or size. |
order | query | string | No | Sort order: asc or desc. Default desc for mtime, asc for name and size. |
Response
Section titled “Response”Matching files and directories sorted as requested.
{ "count": 1, "duration_ms": 12, "entries": [ { "is_dir": false, "modified": 1700000000, "name": "src/main.ts", "size": 2048 } ], "path": "/", "pattern": "**/*.ts", "total_scanned": 100, "truncated": false}| Field | Type | Required | Description |
|---|---|---|---|
count | integer | Yes | Number of entries returned. |
duration_ms | integer | Yes | Search duration in milliseconds. |
entries | array | Yes | Matching files and directories. |
entries[].is_dir | boolean | Yes | Whether the entry is a directory. |
entries[].modified | integer | No | Last modification time as Unix timestamp in seconds. |
entries[].name | string | Yes | API path of the matched file or directory. |
entries[].size | integer | Yes | File size in bytes, or 0 for directories. |
path | string | Yes | Root directory that was searched. |
pattern | string | Yes | The glob pattern used. |
total_scanned | integer | Yes | Total filesystem entries scanned. |
truncated | boolean | Yes | True if results were limited by budget or timeout. |
The pattern or parameters are invalid, or a grep parameter was passed (this endpoint is for file search only).
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | The backend parameter is accepted only on GET, PUT and DELETE, and on POST with mkdir. Or: A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Drop backend, or use an operation that takes it; Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Search is not allowed, or hidden=true was requested by an account that may only list this path.
| Error Code | Title | Description | Resolution |
|---|
The path was not found.
Too many concurrent searches are running.
curl -G \ --data-urlencode "pattern=**/*.ts" \ --data-urlencode "max_results=100" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/glob/"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.glob('/', { pattern: '**/*.ts', max_results: 100 });GET /api/v1/files/grep/{path}
Section titled “GET /api/v1/files/grep/{path}”Search file or directory contents using regex patterns. Powered by ripgrep, with .gitignore support, binary file detection, and configurable limits. Returns matching lines with optional context.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path to search. |
pattern | query | string | Yes | Search pattern. Regex by default, literal when fixed_string=true. |
ignore_case | query | boolean | No | Case-insensitive matching. Default false. |
fixed_string | query | boolean | No | Treat the pattern as a literal string, not regex. Default false. |
glob | query | string | No | Only search files matching this glob (ripgrep -g syntax, one pattern per request, at most 1024 bytes). Use *.rs to match any depth, src/**/*.go to anchor, !*_test.go to exclude. Matching is case-sensitive whatever ignore_case says. Not applied when the path is a single file. |
context | query | integer | No | Number of context lines before and after each match. Default 0. |
max_count | query | integer | No | Maximum matches per file. Default 50. |
max_matches | query | integer | No | Total maximum matches across all files. Default 500. |
max_depth | query | integer | No | Maximum directory recursion depth. Default 50. |
max_filesize | query | integer | No | Skip files larger than this in bytes. Default 10485760. |
timeout | query | integer | No | Search timeout in seconds. Default 30. |
no_ignore | query | boolean | No | Also search files excluded by .gitignore, .ignore, .git/info/exclude, and the global git excludes. Default false. |
hidden | query | boolean | No | Also search names starting with .. Refused with 403 for an account that may only list this path. Default false. |
Response
Section titled “Response”Matching lines with optional context.
{ "duration_ms": 8, "matches": [ { "column_byte": 5, "context_after": [], "context_before": [], "line": "const foo = 1;", "line_number": 3, "path": "/src/main.ts" } ], "path": "/", "pattern": "foo", "total_files_matched": 1, "total_files_searched": 50, "total_matches": 1, "truncated": false}| Field | Type | Required | Description |
|---|---|---|---|
duration_ms | integer | Yes | Search duration in milliseconds. |
matches | array | Yes | Matching lines. |
matches[].column_byte | integer | Yes | Byte offset of the match start within the line. |
matches[].context_after | array | No | Lines after the match, when context > 0. |
matches[].context_before | array | No | Lines before the match, when context > 0. |
matches[].line | string | Yes | The matched line content, truncated at 4096 characters. |
matches[].line_number | integer | Yes | 1-based line number. |
matches[].path | string | Yes | API path of the matched file. |
path | string | Yes | Root path that was searched. |
pattern | string | Yes | The search pattern used. |
total_files_matched | integer | Yes | Number of files containing matches. |
total_files_searched | integer | Yes | Total files scanned. |
total_matches | integer | Yes | Number of matching lines returned. |
truncated | boolean | Yes | True if results were limited by budget or timeout. |
The pattern or parameters are invalid, including an invalid, too long, or repeated glob filter, or a glob that is only whitespace or a comment.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | backend not accepted here | The backend parameter is accepted only on GET, PUT, DELETE, and on POST with mkdir. | Drop backend, or use an operation that takes it. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Grep is not allowed, or hidden=true was requested by an account that may only list this path.
The path was not found.
Too many concurrent searches are running.
curl -G \ --data-urlencode "pattern=foo" \ --data-urlencode "ignore_case=true" \ --data-urlencode "context=2" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/grep/src"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.grep('/src', { pattern: 'foo', ignore_case: true, context: 2 });GET /api/v1/files/realpath/{path}
Section titled “GET /api/v1/files/realpath/{path}”Resolve a file or directory path to its canonical form by following symbolic links. The returned real_path is relative to the serve root. Input traversal components such as .. are rejected with 400.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path to resolve. |
Response
Section titled “Response”The canonical path is returned relative to the serve root.
{ "path": "/example.txt", "real_path": "/canonical/example.txt"}| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Normalized input path. |
real_path | string | Yes | Canonical path relative to the serve root. |
The path is invalid, or a symlink loop was encountered.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PATH | Invalid path | Path contains invalid characters or traversal attempts. | |
INVALID_PARAMETER | backend not accepted here | The backend parameter is accepted only on GET, PUT, DELETE, and on POST with mkdir. | Drop backend, or use an operation that takes it. |
Permission was denied, or the resolved path escapes the serve root.
The path was not found, or the symlink is dangling.
The filesystem refused the paths of this request.
{ "success": false, "error": "Path conflict", "code": "PATH_CONFLICT"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/realpath/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.realpath('/example.txt');GET /api/v1/files/stat/{path}
Section titled “GET /api/v1/files/stat/{path}”Get detailed metadata for a single file or directory without downloading content. Returns name, type, size, modification time, permissions, ownership, and symlink information.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path. |
backend | query | string | No | Backend ID: the metadata of the path on that remote backend instead of a local path |
Response
Section titled “Response”File or directory metadata.
{ "group": "users", "is_symlink": false, "mtime": 1700000000000, "name": "example.txt", "owner": "alice", "path": "/example.txt", "path_type": "File", "permissions": "644", "revisions": 3, "size": 1024, "symlink_target": null}| Field | Type | Required | Description |
|---|---|---|---|
group | string | Yes | Group name or GID. |
is_symlink | boolean | Yes | Whether the entry is a symbolic link. |
mtime | integer | Yes | Unix timestamp in milliseconds. |
name | string | Yes | Entry name. |
owner | string | Yes | Owner name or UID. |
path | string | Yes | API path of the file. |
path_type | string | Yes | What the path is: File, Dir, SymlinkFile, SymlinkDir, Fifo, Socket, CharDevice, or BlockDevice. A named pipe (Fifo), a socket or a device has no content to read: reading one is refused with 403. |
permissions | string | Yes | Octal permission mode (for example 755). |
revisions | integer | No | Journal revisions for this entry, if any. |
size | integer | Yes | File size in bytes. |
symlink_target | string | Yes | Symlink target path, or null if not a symlink. |
The request was invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
The file or directory was not found.
The filesystem refused the paths of this request.
{ "success": false, "error": "Path conflict", "code": "PATH_CONFLICT"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
BACKEND_UNREACHABLE | Remote backend unreachable | A read of a remote (through ?backend=, or one-off through ?type=) could not reach it: the remote did not answer within 30 seconds (504), or it refused the connection, its TLS or the credentials (502). Nothing was read. | Check the connection details and credentials (for a saved backend, GET /api/v1/backends/{id}/test, and PUT /api/v1/backends/{id} to update them), or retry once the remote is reachable |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes; retry later. The server’s storage check did not pass (for example, the mount directory and the directory of the backends’ own mounts overlap), so no mount or backend connection can start, and backend file operations are refused. When the check fails on the service’s own directories, the message goes on to name the directory (the state or the run directory), what is wrong with it (for example, a directory above it that is writable by group or others, or owned by another user) and how to correct it. The refusal comes before the mount or backend is looked up, so an unknown id is answered 503, not 404, until the check passes. Existing mounts show the error, and the mount list still answers. Other files are served as usual. Nothing was changed. | Correct the directory the message names, if it names one; then retry after the time given in Retry-After (the check runs again by then) |
curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/stat/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.stat('/example.txt');Image processing
Section titled “Image processing”GET /{image}?thumbnail
Section titled “GET /{image}?thumbnail”Process and convert images on the fly, with format conversion, resizing, and effects. Supports JPEG, PNG, WebP, GIF, and BMP input and output. Works for local files and for remote files named with remote connection parameters. The REST v1 ?thumbnail answers 501 for a backend.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
image | path | string | Yes | Path to the image file. |
thumbnail | query | string | Yes | Enable image processing. |
format | query | string | No | Output format. Default jpeg. |
size | query | string | No | Target box in pixels: WIDTHxHEIGHT, or a single N for an N×N box (max 2000×2000). |
width | query | integer | No | Width in pixels. Height is auto-calculated. |
height | query | integer | No | Height in pixels. Width is auto-calculated. |
resize | query | string | No | How the image meets the target box. fit (default) fits inside, fill covers and centre-crops, cover covers, exact forces the box and may distort. |
quality | query | string | No | Resampling filter for resizing: low (box), medium (bilinear, default), or high (Lanczos3). Does not set compression; use q for JPEG quality. |
q | query | integer | No | JPEG quality 1 to 100. Default 85. Only JPEG output uses it. |
blur | query | number | No | Gaussian blur radius 0 to 50. |
grayscale | query | string | No | Convert to grayscale. |
bg | query | string | No | Background colour for transparency as hex RGB (for example ffffff for white). |
Response
Section titled “Response”The processed image bytes in the requested format. The Content-Type header is one of image/jpeg, image/png, image/webp, image/gif, or image/bmp. A Cache-Control: public, max-age=3600 header is set.
The body is binary image data and is not JSON.
The image is invalid or its format is unsupported.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Image processing is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The image was not found.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
curl -G \ --data-urlencode "thumbnail=" \ --data-urlencode "format=webp" \ --data-urlencode "size=256" \ --data-urlencode "q=80" \ --output output.webp \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/photo.jpg"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.images.convert('/photo.jpg', { thumbnail: '', format: 'webp', size: '256', q: 80 });Create, move, and copy
Section titled “Create, move, and copy”POST /api/v1/files/{path}
Section titled “POST /api/v1/files/{path}”Perform a write-time file operation: create a directory, extract an archive, download a file from a URL, or move or copy a file or directory. The operation is selected by a query parameter.
A download started with download_from keeps running if the client stops waiting: it runs to its end and its outcome is recorded in the download history.
The SDK exposes these operations through:
client.files.downloads.create(directory, options)for downloads on this REST endpoint (?download_from). The method sets nothing additional; passdownload,filename,timeout, andownerinoptions.client.files.mkdir(path, options?)for?mkdiron this REST endpoint. The method setsmkdir=""; the caller does not passmkdir.client.files.archives.extract(archive, options)for extraction on this REST endpoint (?extract). The method sets nothing additional; pass the relevant parameters inoptions.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Destination or source path. |
backend | query | string | No | Backend ID, for mkdir only: create the directory on that remote backend. Any other operation with backend is refused with 400 INVALID_PARAMETER. |
mkdir | query | string | No | Create a directory at the path. |
extract | query | string | No | Extract an archive. Empty value extracts all; a non-empty value is a selective path to extract (for example src/). |
dest | query | string | No | Destination directory name for extraction. Default: archive name without extension. |
download_from | query | string | No | Download the file at this URL into the directory named by the path. |
filename | query | string | No | With download_from: the name to save the download as. |
timeout | query | integer | No | With download_from: the most seconds the download may take, capped by the server’s own limit. Default and maximum: 43200 (12 hours). |
move_to | query | string | No | Move the file or directory to the destination path. |
copy_to | query | string | No | Copy the file or directory to the destination path. |
overwrite | query | string | No | Allow overwriting an existing destination for copy. |
owner | query | string | No | Create-time owner for newly-created inodes as user[:group] or uid[:gid]. Requires the deployment to have enabled chown, and must resolve to one of the owners it permits. Refuses root. Applies to mkdir, extract, download_from, and copy_to. |
Response
Section titled “Response”A move or copy returns success, source, destination, and, for a directory copy, skipped and skipped_count. The body matches either files_MoveResponse or files_CopyResponse.
{ "destination": "/new/path.txt", "source": "/old/path.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
destination | string | No | Destination path. |
source | string | No | Source path. |
success | boolean | No | Whether the operation succeeded. |
skipped | array | No | Entries of a directory copy that were left out because they cannot be copied (a pipe, a socket, a device), at most 1000; empty for a file copy. |
skipped[].path | string | Yes | Path of the source entry that was left out. |
skipped[].reason | string | Yes | Why it was left out. |
skipped_count | integer | No | How many entries were left out, including any beyond those listed in skipped. |
A directory creation, extraction, or download finished successfully.
{ "message": "Directory created", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
message | string | No | Human-readable message. |
success | boolean | No | Whether the operation succeeded. |
backend was given with an operation other than mkdir, or a copy or a move names a destination inside the source directory.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | The backend parameter is accepted only on GET, PUT and DELETE, and on POST with mkdir; and copy_to or move_to cannot name a destination inside the directory it copies or moves. | Drop backend, or use an operation that takes it; choose a destination outside the source directory. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
The source file or directory was not found.
An extraction that ran and failed, or was cancelled, also names itself and the archive entries it had left out when it stopped: extraction_id (the extraction, as extraction history lists it), skipped (each entry’s path inside the archive and the reason it was left out, at most 1000) and skipped_count (how many entries were left out, including any beyond those listed). Any other refusal carries only success, error and code.
The destination of a move or copy already exists, the request’s download or extraction was cancelled, the path holds service storage, is reserved for a mount being created or updated, is in use by another operation, a folder on it changed while the request started, a move’s destination is on another filesystem, or uploads from before a service restart are still pending on this backend.
An extraction that ran and failed, or was cancelled, also names itself and the archive entries it had left out when it stopped: extraction_id (the extraction, as extraction history lists it), skipped (each entry’s path inside the archive and the reason it was left out, at most 1000) and skipped_count (how many entries were left out, including any beyond those listed). Any other refusal carries only success, error and code.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path, or the destination, is a directory that holds the service’s own storage, or an entry directly in the directory of attached mounts. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
FILE_MOVE_CROSSES_DEVICES | Move spans filesystems | The source and the destination are on different filesystems, so a move cannot span them. | Copy the source to the destination, then delete the source. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
Too many downloads and extractions are running (at most 10 at once). Retry later.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
JOB_COUNT_LIMIT | Too many downloads and extractions | Downloads and extractions share a limit of 10 running at once, and it is reached, so this one was not started. | Retry when a running download or extraction has ended. |
A server error occurred. This includes create-owner enforcement failure: when the default create-owner feature is active and the service cannot set ownership of a newly-created inode, the request fails closed (the partially-created file or directory is rolled back) rather than leaving it owned by root.
The service cannot carry out this request right now.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes. | Retry after the time given in Retry-After. |
An extraction that ran and failed, or was cancelled, also names itself and the archive entries it had left out when it stopped: extraction_id (the extraction, as extraction history lists it), skipped (each entry’s path inside the archive and the reason it was left out, at most 1000) and skipped_count (how many entries were left out, including any beyond those listed). Any other refusal carries only success, error and code.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy) | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read |
BACKEND_READ_ONLY | Backend is read-only | The request would write through a backend whose remote takes no writes (an http backend): uploads, deletes and new directories are refused, so nothing was written. Its mounts are read-only too. | Read from this backend only; write to a backend whose remote accepts writes |
# Create a directorycurl -X POST \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/new-folder?mkdir="
# Download a file into a directorycurl -X POST -G \ --data-urlencode "download_from=https://example.com/data.csv" \ --data-urlencode "filename=data.csv" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/inbox"
# Move a filecurl -X POST -G \ --data-urlencode "move_to=/archive/old.txt" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/old.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
// Download a file into a directory (the primary method for this endpoint)await client.files.downloads.create('/inbox', { download: 'https://example.com/data.csv', filename: 'data.csv' });
// Create a directoryawait client.files.mkdir('/new-folder');
// Extract an archiveawait client.files.archives.extract('/archive.zip', { extract: '' });POST /api/v1/files/copy/{path}
Section titled “POST /api/v1/files/copy/{path}”Copy a file or directory to a new location. Supports recursive directory copy. Auto-creates parent directories at the destination. Use ?overwrite=true to replace an existing destination.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Source file or directory path. |
copy_to | query | string | Yes | Destination path to copy the file or directory to. |
overwrite | query | string | No | Allow overwriting the existing destination. Default false. |
owner | query | string | No | Create-time owner (user[:group] or uid[:gid]) for newly-created copies. Requires the deployment to have enabled chown and to permit the owner you name. Refuses root. Overwritten files preserve their owner. |
Response
Section titled “Response”The copy succeeded.
{ "destination": "/new/path.txt", "source": "/old/path.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
destination | string | No | Destination path. |
skipped | array of object | No | Entries of a directory copy that were left out because they cannot be copied (a pipe, a socket, a device), at most 1000; empty for a file copy. Each item has path (string, required) and reason (string, required). |
skipped_count | integer | No | How many entries were left out, including any beyond those listed in skipped. |
source | string | No | Source path. |
success | boolean | No | Whether the operation succeeded. |
The request was invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | The backend parameter is accepted only on GET, PUT and DELETE, and on POST with mkdir; or a query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Drop backend, or use an operation that takes it; or correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Copy is not allowed: it requires upload permission, the source is not something this operation reads (a pipe, a socket, a device), or the path leads through a symbolic link this deployment does not follow.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The source file or directory was not found.
The copy cannot be carried out as asked: the destination already exists and ?overwrite=true was not given, the destination is the source, nothing is listening on the destination, a file at either end is held under lease by another process, the path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path, or the destination, is a directory that holds the service’s own storage, or an entry directly in the directory of attached mounts. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started, or the source changed during a cross-mount copy. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
curl -X POST -G \ --data-urlencode "copy_to=/backup/file.txt" \ --data-urlencode "overwrite=true" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/copy/file.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.copy('/file.txt', { copy_to: '/backup/file.txt', overwrite: 'true' });POST /api/v1/files/move/{path}
Section titled “POST /api/v1/files/move/{path}”Move or rename a file or directory to a new location. Works across directories. Auto-creates parent directories at the destination. Requires both upload and delete permissions.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Source file or directory path. |
move_to | query | string | Yes | Destination path to move the file or directory to. |
owner | query | string | No | Create-time owner for newly-created destination parent directories. Requires the deployment to have enabled chown and to permit the owner you name. The moved inode itself preserves its existing owner. |
Response
Section titled “Response”The move succeeded.
{ "destination": "/new/path.txt", "source": "/old/path.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
destination | string | No | Destination path. |
source | string | No | Source path. |
success | boolean | No | Whether the operation succeeded. |
The request was invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | The backend parameter is accepted only on GET, PUT and DELETE, and on POST with mkdir; or a query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Drop backend, or use an operation that takes it; or correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Move is not allowed. It requires both upload and delete permissions.
The source file or directory was not found.
The destination already exists; the path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started; or the move’s destination is on another filesystem.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path, or the destination, is a directory that holds the service’s own storage, or an entry directly in the directory of attached mounts. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
FILE_MOVE_CROSSES_DEVICES | Move spans filesystems | The source and the destination are on different filesystems. | Copy the source to the destination, then delete the source. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
curl -X POST -G \ --data-urlencode "move_to=/archive/old.txt" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/move/old.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.move('/old.txt', { move_to: '/archive/old.txt' });Upload, append, and touch
Section titled “Upload, append, and touch”PUT /{path}
Section titled “PUT /{path}”Upload a file. Creates new files or overwrites existing ones. The body is the raw file content sent as application/octet-stream.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Destination file path. |
If-Match | header | string | No | Write only if the file has this ETag (the one a download of it answers with; a weak ETag never matches), or with ’*’ only if a file exists at the path. Otherwise 412 and nothing is written or created. |
If-None-Match | header | string | No | ’*’ writes only if nothing exists at the path (create only); a tag writes only if the file does not have that ETag. Otherwise 412 and nothing is written. |
If-Unmodified-Since | header | string | No | Without If-Match, write only if the file has not changed since this HTTP date. Otherwise 412 and nothing is written. |
Request body
Section titled “Request body”The request body is the raw file bytes. Set the Content-Type header to application/octet-stream.
Response
Section titled “Response”The file was uploaded successfully.
The path, a parameter, a header, or the body is invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
UPLOAD_INCOMPLETE | Upload incomplete | The upload’s body broke off before it ended, so nothing was sent to the remote backend. | Retry the upload. |
Upload is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The path was not found.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
The path holds service storage, is reserved for a mount, or a folder on it changed while the request started. For a request that names a remote backend with the type query parameter, uploads from before a service restart are still pending on this backend.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
A precondition (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, judged before the body is read and again just before the write, so nothing was written. Read the file again for its current ETag. Without these headers the last write wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PRECONDITION_FAILED | Precondition failed | A precondition of this write (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, so nothing was written. | Read the file again for its current ETag and retry with it. |
The body is too large.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYLOAD_TOO_LARGE | Body too large | The body is over the limit of this operation: the deployment’s upload limit, or 64 KiB for the JSON body of PATCH. | Send a smaller body. |
The path is in use by another operation. Retry. Changes to the content or attributes of one file do not conflict with each other: two uploads, appends, truncations, permission or owner changes, or touches of the same file each run, and the last one wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
The remote backend failed the upload.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
REMOTE_UPLOAD_FAILED | Remote upload failed | The remote backend refused or failed the upload; the message carries its error. The body arrived whole and within the limit. | Check the backend and retry. |
For a request that names a remote backend with the type query parameter, the service cannot connect to it right now.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes. | Retry after the time given in Retry-After. |
curl -X PUT \ --data-binary @local-file.txt \ -H "Content-Type: application/octet-stream" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/remote-file.txt"PUT /{path}?touch
Section titled “PUT /{path}?touch”Create an empty file if it does not exist, or update the modification time if it does. Cannot be used on directories.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File path to touch. |
touch | query | string | Yes | Flag to indicate a touch operation. |
Response
Section titled “Response”The file did not exist and was created.
The file already existed and its modification time was updated. The response carries no body.
The path is invalid, or it names a directory.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Touch is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The path was not found.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
The path holds service storage, is reserved for a mount, or a folder on it changed while the request started. For a request that names a remote backend with the type query parameter, uploads from before a service restart are still pending on this backend.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
The path is in use by another operation. Retry. Changes to the content or attributes of one file do not conflict with each other: two uploads, appends, truncations, permission or owner changes, or touches of the same file each run, and the last one wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
curl -X PUT \ -G \ --data-urlencode "touch=" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/empty.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.touch('/empty.txt', { touch: '' });PUT /api/v1/files/{path}
Section titled “PUT /api/v1/files/{path}”Upload a file to the server or to a remote backend, with optional append and optional chmod. Use ?append to append to an existing file instead of overwriting, and ?chmod to set exact permission bits on the local file. Servers that accept ?chmod list put_chmod in the features of GET /api/v1/version.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Destination file path. |
backend | query | string | No | Backend ID for remote upload. |
append | query | string | No | Append the body to the end of an existing file (creating it if missing) instead of overwriting. |
chmod | query | string | No | Permission bits the local file ends with, in octal (644, 0600, 0o755, 000), whatever the server’s umask; the response echoes them in mode. Requires both upload and chmod to be enabled (403 otherwise). setuid, setgid and sticky bits are refused, as are values above 777. Refused with 400 together with backend or append, and when the path names something other than a regular file (a directory, a pipe, a device, a socket). Every refusal comes before the body is read: nothing is created or changed. |
owner | query | string | No | Create-time owner (user[:group] or uid[:gid]) for a newly-created file. Requires the deployment to have enabled chown and to permit the owner you name. Refuses root. Overwrites and appends preserve the existing file’s owner. |
If-Match | header | string | No | Local files only; with backend it is refused with 400. Write only if the file has this ETag (the one a download of it answers with; a weak ETag never matches), or with ’*’ only if a file exists at the path. Otherwise 412 and nothing is written or created. |
If-None-Match | header | string | No | Local files only; with backend it is refused with 400. ’*’ writes only if nothing exists at the path (create only); a tag writes only if the file does not have that ETag. Otherwise 412 and nothing is written. |
If-Unmodified-Since | header | string | No | Local files only; with backend it is refused with 400. Without If-Match, write only if the file has not changed since this HTTP date. Otherwise 412 and nothing is written. |
X-Expected-Length | header | string | No | The length of the whole body in bytes, for a body streamed without Content-Length. A body that ends before this many bytes, or runs past them, is refused with 400 and nothing is written or appended: the file stays as it was. Send it whenever the length is known: some HTTP/2 clients end a request’s body normally when they are aborted, so without it a cut-off body can look complete. Over the upload size limit it is refused with 413 before the body is read. |
Request body
Section titled “Request body”The request body is the raw file bytes. Set the Content-Type header to application/octet-stream.
Response
Section titled “Response”The data was appended (when ?append was used).
{ "new_size": 2048, "path": "/example.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
new_size | integer | No | New total file size after the append. |
path | string | No | The file path. |
success | boolean | No | Whether the operation succeeded. |
The file was uploaded successfully.
{ "message": "File uploaded", "mode": "600", "path": "/example.txt", "size": 1024, "success": true}| Field | Type | Required | Description |
|---|---|---|---|
message | string | No | Human-readable message. |
mode | string | No | The permission bits the file now has, in canonical octal. Present only when ?chmod was given. |
path | string | No | The file path. |
size | integer | No | The file size in bytes. |
success | boolean | No | Whether the operation succeeded. |
The request cannot be carried out as asked: the body ended before it was complete, the path names a directory, the path or one of its components cannot be used, or the owner in ?owner is not usable. With ?chmod: the value is not octal permission bits, it carries setuid, setgid, or sticky bits, it is combined with backend or append, or the path names something other than a regular file.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Upload is not allowed (feature disabled or insufficient permissions), or ?chmod was given while chmod is disabled.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy) | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read |
BACKEND_READ_ONLY | Backend is read-only | The request would write through a backend whose remote takes no writes (an http backend): uploads, deletes and new directories are refused, so nothing was written. Its mounts are read-only too. | Read from this backend only; write to a backend whose remote accepts writes |
The named backend does not exist, or nothing is there to write to: the path leaves the served directory (answered with an empty body rather than the error object), or it names an existing symbolic link whose target does not exist.
The destination cannot be written right now: nothing is listening on it, or another process holds a lease on it. Or the path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started. For requests that name a remote backend with the backend query parameter, uploads from before a service restart are still pending on this backend.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
PERMISSIONS_NOT_APPLIED | Permissions not applied | The filesystem that holds this path accepted the permission change and did not apply it: it keeps no permission bits of its own (a mount of a remote storage without them reports fixed ones). The message names the bits the file has. A permission change, and an upload whose ?chmod is narrower than those bits, changed nothing; an upload whose ?chmod is broader wrote its body whole, under the bits the file has, and the message says it was written. | Use the bits the file has, or keep the file on storage that records permission bits |
A precondition (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, judged before the body is read and again just before the write, so nothing was written. Read the file again for its current ETag. Without these headers the last write wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PRECONDITION_FAILED | Precondition failed | A precondition of this write (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, so nothing was written. | Read the file again for its current ETag and retry with it. |
The upload is larger than the deployment’s upload size limit. An upload addressed to a backend never reaches it, an ordinary file keeps the contents it had, and a write to a device or a pipe is not staged and may have been partly carried out before the limit was reached.
The upload could not be carried out for a reason that is not about the request: the upload could not be staged locally for a reason other than space, a directory on the way to the destination could not be created, or writing the body locally failed part-way (the last of which is answered with an empty body rather than the error object).
The backend could not be reached, or refused the upload.
The service cannot carry out this request right now.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes. | Retry after the time given in Retry-After. |
The server ran out of space, or exceeded its quota, while creating the destination or staging the upload.
# Uploadcurl -X PUT \ --data-binary @local-file.txt \ -H "Content-Type: application/octet-stream" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"
# Upload with permissionscurl -X PUT \ --data-binary @local-file.txt \ -H "Content-Type: application/octet-stream" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt?chmod=600"
# Appendcurl -X PUT \ --data-binary @chunk.bin \ -H "Content-Type: application/octet-stream" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt?append="import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.upload('/example.txt', fileContents, { chmod: '600' });PUT /api/v1/files/append/{path}
Section titled “PUT /api/v1/files/append/{path}”Append binary data to the end of an existing file. Creates the file if it does not exist. Auto-creates parent directories.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File path. |
owner | query | string | No | Create-time owner (user[:group] or uid[:gid]) when this append creates a new file. Requires the deployment to have enabled chown and to permit the owner you name. Refuses root. |
If-Match | header | string | No | Write only if the file has this ETag (the one a download of it answers with; a weak ETag never matches), or with ’*’ only if a file exists at the path. Otherwise 412 and nothing is written or created. |
If-None-Match | header | string | No | ’*’ writes only if nothing exists at the path (create only); a tag writes only if the file does not have that ETag. Otherwise 412 and nothing is written. |
If-Unmodified-Since | header | string | No | Without If-Match, write only if the file has not changed since this HTTP date. Otherwise 412 and nothing is written. |
Request body
Section titled “Request body”The request body is the raw bytes to append. Set the Content-Type header to application/octet-stream.
Response
Section titled “Response”The data was appended.
{ "new_size": 2048, "path": "/example.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
new_size | integer | No | New total file size after the append. |
path | string | No | The file path. |
success | boolean | No | Whether the operation succeeded. |
The request was invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | backend not accepted here | The backend parameter is accepted only on GET, PUT, DELETE, and on POST with mkdir. | Drop backend, or use an operation that takes it. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Upload is not allowed.
The path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
A precondition (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, judged before the body is read and again just before the write, so nothing was written. Read the file again for its current ETag. Without these headers the last write wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PRECONDITION_FAILED | Precondition failed | A precondition of this write (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, so nothing was written. | Read the file again for its current ETag and retry with it. |
curl -X PUT \ --data-binary @chunk.bin \ -H "Content-Type: application/octet-stream" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/append/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.append('/example.txt', chunkBytes);Modify properties
Section titled “Modify properties”PATCH /{path}
Section titled “PATCH /{path}”Change file permissions (Unix only), change file ownership (Unix only), rename, or perform a resumable append. The shape of the body selects the operation.
For permission and ownership changes, send a JSON body. For a resumable append, send the raw bytes as application/octet-stream and set the X-Update-Range header to append.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path. |
X-Update-Range | header | string | No | Set to append to append the body to the end of the file. |
If-Match | header | string | No | Writes of content (X-Update-Range) only. Write only if the file has this ETag (the one a download of it answers with; a weak ETag never matches), or with ’*’ only if a file exists at the path. Otherwise 412 and nothing is written or created. |
If-None-Match | header | string | No | Writes of content (X-Update-Range) only. ’*’ writes only if nothing exists at the path (create only); a tag writes only if the file does not have that ETag. Otherwise 412 and nothing is written. |
If-Unmodified-Since | header | string | No | Writes of content (X-Update-Range) only. Without If-Match, write only if the file has not changed since this HTTP date. Otherwise 412 and nothing is written. |
Request body
Section titled “Request body”The body is one of three JSON shapes for property changes, or raw bytes for an append.
{ "mode": "755"}| Field | Type | Required | Description |
|---|---|---|---|
mode | string | Yes | Octal permission mode (for example 755, 644). |
{ "group": "users", "owner": "alice"}| Field | Type | Required | Description |
|---|---|---|---|
group | string | No | Group name or GID. |
owner | string | No | Username or UID. |
{ "name": "new-filename.txt"}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | New filename. Cannot contain path separators. |
Send the raw bytes with Content-Type: application/octet-stream and the X-Update-Range: append header.
Response
Section titled “Response”The operation succeeded. The response carries no body.
The operation or parameters are invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
The operation is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The path was not found.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
The file or directory already exists; or the path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
OWNER_NOT_APPLIED | Owner not applied | The filesystem that holds this path accepted the ownership change and did not apply it: it keeps no owners of its own (a mount of a remote storage without them reports fixed ones). The message names the owner the file has. | Leave the owner as it is, or keep the file on storage that records owners |
PERMISSIONS_NOT_APPLIED | Permissions not applied | The filesystem that holds this path accepted the permission change and did not apply it: it keeps no permission bits of its own (a mount of a remote storage without them reports fixed ones). The message names the bits the file has. A permission change, and an upload whose ?chmod is narrower than those bits, changed nothing; an upload whose ?chmod is broader wrote its body whole, under the bits the file has, and the message says it was written. | Use the bits the file has, or keep the file on storage that records permission bits |
A precondition (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, judged before the body is read and again just before the write, so nothing was written. Read the file again for its current ETag. Without these headers the last write wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PRECONDITION_FAILED | Precondition failed | A precondition of this write (If-Match, If-None-Match or If-Unmodified-Since) does not hold for the file as it is now, so nothing was written. | Read the file again for its current ETag and retry with it. |
The body is too large.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYLOAD_TOO_LARGE | Body too large | The body is over the limit of this operation: the deployment’s upload limit, or 64 KiB for the JSON body of PATCH. | Send a smaller body. |
# chmodcurl -X PATCH \ -H "Content-Type: application/json" \ -d '{"mode":"755"}' \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/example.txt"
# chowncurl -X PATCH \ -H "Content-Type: application/json" \ -d '{"owner":"alice","group":"users"}' \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/example.txt"
# renamecurl -X PATCH \ -H "Content-Type: application/json" \ -d '{"name":"renamed.txt"}' \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/example.txt"
# resumable appendcurl -X PATCH \ -H "X-Update-Range: append" \ -H "Content-Type: application/octet-stream" \ --data-binary @chunk.bin \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
// Resumable appendawait client.files.writeChunk('/example.txt', chunkBytes);PATCH /api/v1/files/{path}
Section titled “PATCH /api/v1/files/{path}”Modify file properties (chmod, chown), rename, or move to a new directory. The operation is selected by a query parameter or the body shape.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File path. |
owner | query | string | No | Create-time owner for newly-created destination parent directories on a JSON-body move_to. Requires the deployment to have enabled chown and to permit the owner you name. Cannot be root. The moved item keeps its own owner. |
chmod | query | string | No | Set file permissions using an octal mode value (for example ?chmod=755). |
chown | query | string | No | Set file ownership (for example ?chown=user:group or ?chown=user). |
Request body
Section titled “Request body”The body is a JSON object for rename or cross-directory move.
{ "move_to": "/new/dir/file.txt"}| Field | Type | Required | Description |
|---|---|---|---|
move_to | string | Yes | Full destination path. |
{ "name": "new-filename.txt"}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | New filename. Cannot contain path separators. |
Response
Section titled “Response”The operation succeeded. The body matches one of three shapes: files_ChmodResponse, files_ChownResponse, or files_MoveResponse. The example below shows a chmod result.
{ "mode": "755", "path": "/example.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
mode | string | No | Applied octal mode (chmod result). |
path | string | No | The file path. |
success | boolean | No | Whether the operation succeeded. |
group | string | No | Applied group (chown result). |
owner | string | No | Applied owner (chown result). |
destination | string | No | Destination path (move result). |
source | string | No | Source path (move result). |
The operation or parameters are invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | The backend parameter is accepted only on GET, PUT and DELETE, and on POST with mkdir; and move_to cannot name a destination inside the directory it copies or moves. | Drop backend, or use an operation that takes it; choose a destination outside the source directory. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
The operation is not allowed.
The file or directory was not found.
The destination already exists (for move or rename); or the path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started; or a move’s destination is on another filesystem.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
FILE_MOVE_CROSSES_DEVICES | Move spans filesystems | The source and the destination are on different filesystems. | Copy the source to the destination, then delete the source. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
OWNER_NOT_APPLIED | Owner not applied | The filesystem that holds this path accepted the ownership change and did not apply it: it keeps no owners of its own (a mount of a remote storage without them reports fixed ones). The message names the owner the file has. | Leave the owner as it is, or keep the file on storage that records owners |
PERMISSIONS_NOT_APPLIED | Permissions not applied | The filesystem that holds this path accepted the permission change and did not apply it: it keeps no permission bits of its own (a mount of a remote storage without them reports fixed ones). The message names the bits the file has. A permission change, and an upload whose ?chmod is narrower than those bits, changed nothing; an upload whose ?chmod is broader wrote its body whole, under the bits the file has, and the message says it was written. | Use the bits the file has, or keep the file on storage that records permission bits |
# chmodcurl -X PATCH -G \ --data-urlencode "chmod=755" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"
# chowncurl -X PATCH -G \ --data-urlencode "chown=alice:users" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"
# move (cross-directory)curl -X PATCH \ -H "Content-Type: application/json" \ -d '{"move_to":"/archive/example.txt"}' \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"
# renamecurl -X PATCH \ -H "Content-Type: application/json" \ -d '{"name":"renamed.txt"}' \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.update('/example.txt', { move_to: '/archive/example.txt' });PATCH /api/v1/files/chmod/{path}
Section titled “PATCH /api/v1/files/chmod/{path}”Change file or directory permissions using octal mode (Unix only). Pass the mode value in the chmod query parameter, for example ?chmod=755.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path. |
chmod | query | string | Yes | Octal permission mode (for example 755, 644, 0755). |
Response
Section titled “Response”The permissions were changed.
{ "mode": "755", "path": "/example.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
mode | string | No | Applied octal mode. |
path | string | No | The file path. |
success | boolean | No | Whether the operation succeeded. |
The octal mode value is invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | backend not accepted here | The backend parameter is accepted only on GET, PUT, DELETE, and on POST with mkdir. | Drop backend, or use an operation that takes it. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
chmod is not allowed.
The file or directory was not found.
The path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
PERMISSIONS_NOT_APPLIED | Permissions not applied | The filesystem that holds this path accepted the permission change and did not apply it: it keeps no permission bits of its own (a mount of a remote storage without them reports fixed ones). The message names the bits the file has. A permission change, and an upload whose ?chmod is narrower than those bits, changed nothing; an upload whose ?chmod is broader wrote its body whole, under the bits the file has, and the message says it was written. | Use the bits the file has, or keep the file on storage that records permission bits |
curl -X PATCH -G \ --data-urlencode "chmod=755" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/chmod/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.chmod('/example.txt', { chmod: '755' });PATCH /api/v1/files/chown/{path}
Section titled “PATCH /api/v1/files/chown/{path}”Change file or directory ownership (Unix only). Pass owner:group in the chown query parameter, for example ?chown=user:group. The group is optional.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path. |
chown | query | string | Yes | Owner and optional group (for example user:group, user, :group, or UID:GID). |
Response
Section titled “Response”The ownership was changed.
{ "group": "users", "owner": "alice", "path": "/example.txt", "success": true}| Field | Type | Required | Description |
|---|---|---|---|
group | string | No | Applied group. |
owner | string | No | Applied owner. |
path | string | No | The file path. |
success | boolean | No | Whether the operation succeeded. |
The owner or group is invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | backend not accepted here | The backend parameter is accepted only on GET, PUT, DELETE, and on POST with mkdir. | Drop backend, or use an operation that takes it. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
chown is not allowed.
The file or directory was not found.
The path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
OWNER_NOT_APPLIED | Owner not applied | The filesystem that holds this path accepted the ownership change and did not apply it: it keeps no owners of its own (a mount of a remote storage without them reports fixed ones). The message names the owner the file has. | Leave the owner as it is, or keep the file on storage that records owners |
curl -X PATCH -G \ --data-urlencode "chown=alice:users" \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/chown/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.chown('/example.txt', { chown: 'alice:users' });Delete
Section titled “Delete”DELETE /{path}
Section titled “DELETE /{path}”Permanently delete a file or directory.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Path to the file or directory to delete. |
Response
Section titled “Response”The file or directory was deleted. The response carries no body.
The path, a parameter, a header, or the body is invalid.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A query parameter, a header or the request body is not one this operation accepts, or a copy or a move names a destination inside the directory it copies or moves; the message names what was refused. | Correct the request. |
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Delete is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | The request is refused: the account may not access this path or where it leads (a symlink to a path the account may not access), the deployment has not enabled this operation (uploads, deletes, touches, permission and owner changes, renames, extraction, thumbnails), or the path is one this server does not write or follow (the served directory itself, a symlink when symlinks are not allowed, a read-only or immutable file, a pipe, a socket or a device, which has no content to read or copy). | Use an account with access to the path, or ask the deployment’s administrator to enable the operation; a pipe, a socket or a device is never read. |
The file or directory was not found.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
RESOURCE_NOT_FOUND | Not found | Nothing is at this path, or the path is private to the server and answers as if absent. | Check the path. |
The path holds service storage, is reserved for a mount, or a folder on it changed while the request started. For a request that names a remote backend with the type query parameter, uploads from before a service restart are still pending on this backend.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
The path is in use by another operation. Retry. Changes to the content or attributes of one file do not conflict with each other: two uploads, appends, truncations, permission or owner changes, or touches of the same file each run, and the last one wins.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
For a request that names a remote backend with the type query parameter, the service cannot connect to it right now.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes. | Retry after the time given in Retry-After. |
curl -X DELETE \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/example.txt"DELETE /api/v1/files/{path}
Section titled “DELETE /api/v1/files/{path}”Delete a file or directory from the server, or from a remote backend when ?backend is set.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Path to the file or directory to delete. |
backend | query | string | No | Backend ID for remote file deletion. |
Response
Section titled “Response”The file or directory was deleted. The response carries no body.
Invalid request: the path, a parameter, a header or the body.
{ "success": false, "error": "Invalid path", "code": "INVALID_PATH"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PATH | Invalid path | The request path is not valid: it does not decode, it has a . or .. component, it is outside the configured path prefix, or it is over the filesystem’s limits (a name over 255 bytes, a path over 4095 bytes). | Send a path of plain components under the served directory, within the filesystem’s limits. |
Delete is not allowed.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
BACKEND_READ_ONLY | Backend is read-only | The request would write through a backend whose remote takes no writes (an http backend): uploads, deletes and new directories are refused, so nothing was written. Its mounts are read-only too. | Read from this backend only; write to a backend whose remote accepts writes |
The file or directory was not found.
The path holds service storage, is reserved for a mount, is in use, or a folder on it changed while the request started. For a remote backend, uploads from before a service restart are still pending on this backend.
A Retry-After header is sent when uploads from before a service restart are still pending on this backend.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINS_SERVICE_STORAGE | Path holds service storage | The path is a directory that holds the service’s own storage. | Act on the entries inside the directory instead, or choose another destination. |
FILE_PATH_BUSY | Path in use | Another operation is using this path, a folder above it, or something inside it, so nothing was changed. | Retry when the other operation has finished. |
FILE_PATH_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started. | Retry. |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path. | Retry when the mount has been created or updated, or choose another path. |
PATH_CONFLICT | Path conflict | The filesystem refused the paths of this request, so nothing was changed: the destination is of the wrong kind or not empty, a component of the path is a file where a directory has to be, the source and the destination are the same file or on different filesystems, a directory would move into itself, or a file the request needs cannot be opened now (nothing is listening on it, or another program holds a lease on it). | Choose another destination, or retry when the file is free. |
The service cannot carry out this request right now.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
MOUNT_STORAGE_UNAVAILABLE | Mounts unavailable | Mounts are unavailable until the server’s storage check passes. | Retry after the time given in Retry-After. |
curl -X DELETE \ "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/example.txt"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.files.delete('/example.txt');