Directory listing
Section titled “Directory listing”The Files service exposes a directory-and-archive surface rooted at the container’s files instance. This page documents the directory operations (create directory), the archive operations (full extract, selective extract, preview, read a member, download a directory as ZIP), and the extraction status endpoints (list active jobs, history, and cancel). All requests target the container’s files instance on the per-container subdomain.
Directories
Section titled “Directories”MKCOL /{path}
Section titled “MKCOL /{path}”Create a directory at the given path. The path is relative to the served root and is created as a new directory. The request takes no body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Directory path to create under the served root |
Request
Section titled “Request”curl -X MKCOL "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/projects/new-project" \ -H "Authorization: Bearer $HOODY_TOKEN"Response
Section titled “Response”The directory was created.
| Error Code | Title | Description | Resolution |
|---|
The request is invalid: the path, a parameter, a header, or the body is rejected.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 |
Directory creation is not allowed for this account on this path.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 |
No parent directory exists at the requested path, or the path is private to the server and answers as if absent.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 |
Something already exists at this path.
{ "code": "DIRECTORY_EXISTS", "error": "Something already exists at this path", "success": false}| Error Code | Title | Description | Resolution |
|---|---|---|---|
DIRECTORY_EXISTS | Path exists | Something already exists at this path, so no directory was created | Choose another path |
The path holds service storage, is reserved for a mount being created or updated, or a folder on it changed while the request started. For requests that name a remote backend with the type query parameter, uploads from before a service restart may still be pending on this backend; in that case a Retry-After header is sent.
{ "code": "MOUNT_PATH_RESERVED", "error": "A mount that is being created or updated holds this path", "success": false}| 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 (the directory of attached mounts, the directory of service credentials, or a directory above private 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_CHANGED | Path changed | A folder on the path was renamed or replaced while the request started, or the source changed while a copy between a mount and local storage ran | Retry |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path, so nothing was changed | 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.
{ "code": "FILE_PATH_BUSY", "error": "This path is in use by another operation", "success": false}| Error Code | Title | Description | Resolution |
|---|---|---|---|
FILE_PATH_BUSY | Path in use | This path is in use by another operation; retry. Another operation is using this path, a folder above it, or something inside it, so nothing was changed. 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 | Retry when the other operation has finished |
Only for a request that names a remote backend with the type query parameter: the service cannot connect to the backend right now. A Retry-After header is sent.
{ "code": "MOUNT_STORAGE_UNAVAILABLE", "error": "Mounts are unavailable until the server's storage check passes", "success": false}| 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, so no mount or backend connection can start, and backend file operations are refused | Retry after the time given in Retry-After |
Archives
Section titled “Archives”The archive operations read or extract ZIP, plain TAR, and compressed TAR (.tar.gz, .tar.bz2, .tar.xz) files. Empty values for the extract and extract_file query parameters trigger full extraction; non-empty values select the matching path inside the archive.
GET /{archive}?extract
Section titled “GET /{archive}?extract”Extract a ZIP, TAR, or compressed TAR archive to a destination directory. Pass ?extract (empty) to extract all entries, or ?extract=<path> to selectively extract only entries matching the given prefix (for example ?extract=src/).
A large archive can take a long time to extract. The SDK and CLI wait up to 12 hours and 1 minute for the answer unless you set your own timeout; if the client stops waiting, the extraction keeps running on the server. Follow it under Extractions.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
archive | path | string | Yes | Path to the archive file under the served root |
extract | query | string | Yes | Empty for full extraction; path for selective (e.g. src/ or lib/) |
dest | query | string | No | Destination directory name (default: archive name) |
This GET operation takes no owner parameter. The SDK’s client.files.archives.extract() also accepts an optional owner option (create-time owner for newly-created inodes as user[:group] or uid[:gid]; requires the deployment to have enabled chown, must resolve to one of the owners it permits, and refuses root). When owner is given, the SDK sends the extraction through the file-operation endpoint (files_postFileOperation, see File operations) with extract and owner in the query, and refuses the query options backend, mkdir, download_from, filename, timeout, move_to, copy_to and overwrite on that call.
Request
Section titled “Request”# Full extractioncurl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?extract" \ -H "Authorization: Bearer $HOODY_TOKEN"
# Selective extractioncurl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?extract=src/&dest=data-src" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
// Full extractionawait client.files.archives.extract('uploads/data.zip', { extract: '' });
// Selective extraction with custom destinationawait client.files.archives.extract('uploads/data.zip', { extract: 'src/', dest: 'data-src' });Response
Section titled “Response”The extraction completed successfully. Archive entries that were left out are listed in skipped (path, reason; at most 1000): symbolic and hard links (links are never created from an archive), entries that are not a file or a folder (a pipe, a socket, a device), entries whose name is not valid UTF-8 (path shows the name with invalid bytes replaced) and later entries with a path an earlier entry already took. skipped_count counts every entry left out, including any beyond those listed.
{ "destination": "data", "extracted_bytes": 1048576, "extracted_files": 24, "extraction_id": "550e8400-e29b-41d4-a716-446655440000", "message": "Extraction complete", "skipped": [ { "path": "data/latest", "reason": "symbolic link (links are not extracted)" } ], "skipped_count": 1, "success": true}| Error Code | Title | Description | Resolution |
|---|
The archive could not be opened, the path is invalid, or an extraction error occurred.
{ "destination": "data", "error": "Invalid archive format", "extracted_bytes": 0, "extracted_files": 0, "extraction_id": "550e8400-e29b-41d4-a716-446655440000", "message": "Extraction failed", "success": false}| 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 |
Extraction is not allowed for this account on this path.
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.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 archive or its parent path 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.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 extraction was cancelled with DELETE /api/v1/extractions/{id}; or the path holds service storage, is reserved for a mount being created or updated, is in use by another operation, or a folder on it changed while the request started.
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.
{ "code": "FILE_PATH_BUSY", "error": "This path is in use by another operation", "success": false}| 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 (the directory of attached mounts, the directory of service credentials, or a directory above private 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 | This path is in use by another operation; retry. Another operation is using this path, a folder above it, or something inside it, so nothing was changed. 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 | 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 while a copy between a mount and local storage ran | Retry |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path, so nothing was changed | Retry when the mount has been created or updated, or choose another path |
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 |
GET /{archive}?extract_file
Section titled “GET /{archive}?extract_file”Extract a single file or directory from inside a ZIP, TAR, or compressed TAR archive to a destination directory. Only the specified entry (and its children if a directory) is extracted, leaving other archive contents untouched. The extract parameter is required and names the entry inside the archive.
The extract_file flag only names this operation and is ignored: the entry is chosen by extract=<entry path>. ?extract_file alone downloads the archive itself, and ?extract without a value extracts the whole archive (see GET /{archive}?extract above).
The SDK and CLI wait up to 12 hours and 1 minute for the answer unless you set your own timeout; if the client stops waiting, the extraction keeps running on the server. Follow it under Extractions.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
archive | path | string | Yes | Path to archive file |
extract | query | string | Yes | Path of the file or directory inside the archive to extract (e.g. src/ or lib/) |
dest | query | string | No | Destination directory name (default: archive name) |
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?extract_file&extract=README.md&dest=readme-out" \ -H "Authorization: Bearer $HOODY_TOKEN"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.archives.extractMember('uploads/data.zip', { extract: 'README.md', dest: 'readme-out' });Response
Section titled “Response”The selective extraction completed successfully.
{ "destination": "readme-out", "extracted_bytes": 4096, "extracted_files": 1, "extraction_id": "550e8400-e29b-41d4-a716-446655440001", "message": "Selective extraction complete", "selective": true, "selective_path": "README.md", "success": true}| Error Code | Title | Description | Resolution |
|---|
The archive could not be opened, the entry path is invalid, or an extraction error occurred.
{ "destination": "readme-out", "error": "Entry not found in archive", "extracted_bytes": 0, "extracted_files": 0, "extraction_id": "550e8400-e29b-41d4-a716-446655440001", "message": "Selective extraction failed", "selective": true, "selective_path": "README.md", "success": false}| 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 |
Extraction is not allowed for this account on this path.
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.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 archive or its parent path 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.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 extraction was cancelled with DELETE /api/v1/extractions/{id}; or the path holds service storage, is reserved for a mount being created or updated, is in use by another operation, or a folder on it changed while the request started.
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.
{ "code": "FILE_PATH_BUSY", "error": "This path is in use by another operation", "success": false}| 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 (the directory of attached mounts, the directory of service credentials, or a directory above private 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 | This path is in use by another operation; retry. Another operation is using this path, a folder above it, or something inside it, so nothing was changed. 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 | 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 while a copy between a mount and local storage ran | Retry |
MOUNT_PATH_RESERVED | Path reserved for a mount | A mount that is being created or updated holds this path, so nothing was changed | Retry when the mount has been created or updated, or choose another path |
Too many downloads and extractions are running (at most 10 at once); retry later.
{ "code": "JOB_COUNT_LIMIT", "error": "Too many downloads and extractions are running", "success": false}| 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 |
GET /{archive}?preview
Section titled “GET /{archive}?preview”List the contents of a ZIP, TAR, or compressed TAR archive without extracting, or read a specific file from the archive. With an empty ?preview (or ?contents), the response is a JSON listing of all entries. With ?preview=<path> (or ?contents=<path>), the raw content of that file from the archive is returned. The two query parameters are aliases for each other.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
archive | path | string | Yes | Path to archive file |
preview | query | string | No | Empty value lists archive contents; non-empty value reads a specific file from the archive (alias: ?contents) |
contents | query | string | No | Alias for ?preview |
Request
Section titled “Request”# List contentscurl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?preview" \ -H "Authorization: Bearer $HOODY_TOKEN"
# Read a specific member (alias)curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?contents=src/index.js" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
// List contentsawait client.files.archives.preview('uploads/data.zip', { preview: '' });
// Read a specific member using the aliasawait client.files.archives.preview('uploads/data.zip', { contents: 'src/index.js' });Response
Section titled “Response”The archive contents are returned as a JSON listing of entries.
{ "entries": [ { "compressed_size": 4096, "entry_type": "file", "is_dir": false, "modified_time": 1700000000, "path": "README.md", "permissions": 33188, "size": 8192 }, { "compressed_size": 0, "entry_type": "directory", "is_dir": true, "modified_time": 1700000000, "path": "src/", "permissions": 16877, "size": 0 } ], "format": "zip", "total_compressed_size": 4096, "total_files": 2, "total_size": 8192}| Error Code | Title | Description | Resolution |
|---|
The archive format is invalid or the request path cannot be decoded.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 archive entry is password-protected (selective preview only).
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 archive file or the named entry was not found.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 selected file is too large to preview (selective preview only, max 100MB).
{ "error": "The selected file exceeds the 100MB preview size limit", "success": false}GET /{archive}?view_file
Section titled “GET /{archive}?view_file”Read and return a single file from inside a ZIP, TAR, or compressed TAR archive without extracting the entire archive. The preview parameter is required and names the entry inside the archive. The view_file flag only names this operation and is ignored: the entry is chosen by preview=<entry path>. ?view_file alone downloads the archive itself, and ?preview without a value lists the archive’s contents (see GET /{archive}?preview above). The response body is the raw member bytes; the Content-Type is the member’s own type, guessed from its name (text/plain for README.txt, application/json for package.json, image/png, and so on). Read the body as bytes, not by that type. HTML, SVG, XML, and JavaScript members come as attachments.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
archive | path | string | Yes | Path to archive file |
preview | query | string | Yes | Path of the file inside the archive to view (e.g. src/ or README.md) |
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/uploads/data.zip?view_file&preview=README.md" \ -H "Authorization: Bearer $HOODY_TOKEN" \ --output readme.mdimport { 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.archives.readMember('uploads/data.zip', { preview: 'README.md' });Response
Section titled “Response”The member’s bytes. The body is a raw byte stream, not JSON. Treat the body as bytes; the Content-Type header is the member’s type, guessed from its name (application/octet-stream when unknown).
binary| Error Code | Title | Description | Resolution |
|---|
The archive is invalid or the entry path is not valid.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 archive entry is password-protected.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 archive file or the named entry was not found.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 selected file is too large to preview.
{ "error": "The selected file exceeds the 100MB preview size limit", "success": false}GET /{directory}?zip
Section titled “GET /{directory}?zip”Create and download a directory as a ZIP archive. The archive holds the folder whole: a folder of more than 100000 files, of more than 1000000 files and folders in all, or with folders nested deeper than 50 levels is refused with 422 ARCHIVE_TOO_LARGE before anything is sent. A file that cannot be read, or that changes while it is added, is named in a __hoody-files_zip_errors__.txt entry at the end of the archive. With per-account path rules, the results hold only what the account may read: paths outside its rules, and symlinks that lead there, are left out.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
directory | path | string | Yes | Path to the directory to download |
zip | query | string | Yes | Empty literal value triggers ZIP download |
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/projects/my-project?zip" \ -H "Authorization: Bearer $HOODY_TOKEN" \ --output my-project.zipimport { 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.zip('projects/my-project', { zip: '' });Response
Section titled “Response”The body is a ZIP archive containing the directory. Treat the response as raw bytes.
binary| Error Code | Title | Description | Resolution |
|---|
The path, a parameter, a header, or the body is invalid.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 |
Archive download is not allowed for this account on this path.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 exists at this path, or the path is private to the server and answers as if absent.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 folder is too large to fit in one ZIP archive and nothing was sent.
{ "code": "ARCHIVE_TOO_LARGE", "error": "The folder holds more than 100000 files, more than 1000000 files and folders in all, or folders nested deeper than 50 levels", "success": false}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ARCHIVE_TOO_LARGE | Folder too large for one archive | The folder holds more than 100000 files, more than 1000000 files and folders in all, or folders nested deeper than 50 levels: one ZIP archive holds a folder whole or is not sent, so nothing was sent. The message names the limit. | Download the folder’s subfolders separately |
Extractions
Section titled “Extractions”Two distinct endpoints report active extractions, and a separate endpoint reports history. The active-extractions list returned by either endpoint contains only jobs whose every path (directory and file, or archive and destination) the caller may read. A rule that only lists a directory does not count: with /alice:rw the root is only listed, so the caller sees no job outside /alice.
GET /api/v1/extractions
Section titled “GET /api/v1/extractions”Get the progress of every running archive extraction on this container, whether started with POST /api/v1/files/{path}?extract or on the WebDAV-style surface. The endpoint takes no parameters.
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/extractions" \ -H "Authorization: Bearer $HOODY_TOKEN"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.extractions.list();Response
Section titled “Response”The list of currently running extractions.
{ "extractions": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "archive_path": "/uploads/data.zip", "dest_path": "/uploads/data", "extracted_bytes": 524288, "extracted_files": 12, "total_bytes": 1048576, "total_files": 24, "percentage": 50.0, "selective": false, "start_time": 1700000000, "status": "extracting" } ]}| Error Code | Title | Description | Resolution |
|---|
The request is invalid: a parameter, a header, or the body is rejected.
{ "code": "INVALID_PARAMETER", "error": "A query parameter, a header or the request body is not one this operation accepts", "success": false}| 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 |
GET /?extractions
Section titled “GET /?extractions”Get the progress of currently running archive extractions from or into the directory requested. This is the path-scoped variant of the active-extractions listing. The extractions query parameter is required and must be the empty string.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
extractions | query | string | Yes | Empty literal value triggers the active-extractions listing for this path |
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/projects/my-project?extractions" \ -H "Authorization: Bearer $HOODY_TOKEN"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.extractions.listByDirectory({ extractions: '' });Response
Section titled “Response”The list of currently running extractions that touch this path.
{ "extractions": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "archive_path": "/projects/my-project/data.zip", "dest_path": "/projects/my-project/data", "extracted_bytes": 524288, "extracted_files": 12, "total_bytes": 1048576, "total_files": 24, "percentage": 50.0, "selective": false, "start_time": 1700000000, "status": "extracting" } ]}| Error Code | Title | Description | Resolution |
|---|
The request path, a parameter, a header, or the body is invalid.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 account may not access this path or where it leads.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 exists at this path, or the path is private to the server and answers as if absent.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 |
GET /?extraction_history
Section titled “GET /?extraction_history”Get the history of past extractions (successful and failed), wherever they ran. Lists only the jobs whose every path (directory and file, or archive and destination) the caller may read. A rule that only lists a directory does not count: with /alice:rw the root is only listed, so the caller sees no job outside /alice. The extraction_history query parameter is required and must be the empty string.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
extraction_history | query | string | Yes | Empty literal value triggers the extraction history listing |
Request
Section titled “Request”curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/projects/my-project?extraction_history" \ -H "Authorization: Bearer $HOODY_TOKEN"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.extractions.listHistory({ extraction_history: '' });Response
Section titled “Response”The extraction history, including successful and failed jobs. Each history record’s status is one of active, completed, failed, cancelled, or interrupted (where interrupted means the server stopped while the job ran).
{ "history": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "archive_path": "/projects/my-project/data.zip", "dest_path": "/projects/my-project/data", "extracted_bytes": 1048576, "extracted_files": 24, "start_time": 1700000000, "end_time": 1700000010, "status": "completed", "selective": false, "selective_path": null, "total_bytes": 1048576, "total_files": 24, "skipped": [], "skipped_count": 0, "error": null }, { "id": "550e8400-e29b-41d4-a716-446655440002", "archive_path": "/projects/my-project/bad.zip", "dest_path": "/projects/my-project/bad", "extracted_bytes": 0, "extracted_files": 0, "start_time": 1700000020, "end_time": 1700000021, "status": "failed", "selective": true, "selective_path": "src/", "total_bytes": 1048576, "total_files": 24, "error": "Invalid archive format" } ]}| Error Code | Title | Description | Resolution |
|---|
The request path, a parameter, a header, or the body is invalid.
{ "code": "INVALID_PATH", "error": "The request path is not valid", "success": false}| 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 account may not access this path or where it leads.
{ "code": "ACCESS_FORBIDDEN", "error": "The request is refused", "success": false}| 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 exists at this path, or the path is private to the server and answers as if absent.
{ "code": "RESOURCE_NOT_FOUND", "error": "Nothing is at this path", "success": false}| 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 |
DELETE /api/v1/extractions/{id}
Section titled “DELETE /api/v1/extractions/{id}”Stop a running extraction, whether it was started on the REST surface or the WebDAV-style one. The request that started it then answers 409 with its error field naming the cancellation, and its history record has status cancelled. This operation needs write permission on the root.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | The id listed by GET /api/v1/extractions |
Request
Section titled “Request”curl -X DELETE "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/extractions/550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer $HOODY_TOKEN"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.extractions.cancel('550e8400-e29b-41d4-a716-446655440000');Response
Section titled “Response”The extraction was told to stop.
{ "id": "550e8400-e29b-41d4-a716-446655440000", "message": "Extraction cancellation requested", "success": true}| Error Code | Title | Description | Resolution |
|---|
No extraction with this id is running.
{ "error": "No extraction with this id is running", "success": false}