Reading Files
Section titled “Reading Files”Use these endpoints to read file contents, list directory contents, search files, and download files from a container’s filesystem. The WebDAV-style endpoint at /{path} returns HTML or JSON listings, while the v1 endpoint at /api/v1/files/{path} exposes additional features such as grep, glob, thumbnails, line-range extraction, and remote backends. Both endpoints also support a journal mode for inspecting historical file revisions.
Endpoints
Section titled “Endpoints”GET /{path}
Section titled “GET /{path}”List directory contents in HTML or JSON format, or download a file. For file paths, append ?download (or ?download=true) to force a Content-Disposition: attachment response. The endpoint also exposes journal operations via ?history, ?at, ?revision, and ?diff query parameters.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path |
json | query | string | No | Return JSON format instead of HTML. Pass an empty value. |
simple | query | string | No | Return simple text listing |
sort | query | string | No | Sort by field. Allowed values: name, mtime, size. |
order | query | string | No | Sort order. Allowed values: asc, desc. |
hash | query | string | No | Get SHA256 hash of file (returns plain text hash) |
sha256 | query | string | No | Get SHA256 hash of file (alias for hash) |
base64 | query | string | No | Get file content as base64 encoded string |
edit | query | string | No | Open file in Web UI editor (requires allow-upload permission) |
view | query | string | No | View file in Web UI (read-only mode) |
download | query | string | No | For file paths: force browser download (Content-Disposition: attachment). Allowed values: empty, 1, or true. For directory paths, triggers the URL download-manager operation. |
content-type | query | string | No | Override Content-Type header for file downloads |
history | query | string | No | List all revisions of a file. Returns JSON with a revisions array; paginate via after_id. Mutually exclusive with at, revision, and diff. |
at | query | string | No | Read file content at a point in time. Accepts an RFC3339 timestamp or Unix milliseconds. Mutually exclusive with history, revision, and diff. Composable with lines, hash, and base64. |
revision | query | integer | No | Read file content by stable per-path sequence number. Mutually exclusive with history, at, and diff. Composable with lines, hash, and base64. |
diff | query | string | No | Compute a unified diff between two versions. Requires from_seq or from_ts. Optional to_seq or to_ts (defaults to current file). Mutually exclusive with history, at, and revision. |
from_seq | query | integer | No | Source revision sequence number for ?diff. Mutually exclusive with from_ts. |
from_ts | query | string | No | Source timestamp for ?diff (RFC3339 or Unix ms). Mutually exclusive with from_seq. |
to_seq | query | integer | No | Target revision sequence number for ?diff. Mutually exclusive with to_ts. Defaults to current file on disk. |
to_ts | query | string | No | Target timestamp for ?diff (RFC3339 or Unix ms). Mutually exclusive with to_seq. |
after_id | query | integer | No | Cursor for ?history pagination. Returns entries with id > after_id. |
limit | query | integer | No | Maximum entries to return for ?history. Default: 100. |
Response
Section titled “Response”{ "auth": true, "user": "alice@example.com", "allow_archive": true, "allow_delete": true, "allow_search": true, "allow_upload": true, "dir_exists": true, "href": "/home/alice", "kind": "Index", "uri_prefix": "/", "paths": [ { "name": "documents", "path_type": "Dir", "size": 5, "mtime": 1700000000000, "revisions": null }, { "name": "README.md", "path_type": "File", "size": 2048, "mtime": 1700000000000, "revisions": 3 } ]}{ "success": false, "error": "Access forbidden: user does not have permission to access this path"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ACCESS_FORBIDDEN | Access forbidden | User does not have permission to access this path | Contact administrator for read permissions or authenticate with a different account |
{ "success": false, "error": "File or directory not found"}Example request
Section titled “Example request”curl -X GET "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/home/alice?json=" \ -H "Authorization: Bearer <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.listDirectory('/home/alice', { json: '' });GET /api/v1/files/{path}
Section titled “GET /api/v1/files/{path}”List directory contents in JSON format, download a file, or run a content search (grep/glob), thumbnail, or line-range extraction. Supports an optional backend parameter for remote file access, and the same journal operations (?history, ?at, ?revision, ?diff) as the WebDAV-style endpoint.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | File or directory path |
backend | query | string | No | Backend ID for remote file access |
hash | query | string | No | Get SHA256 hash of file |
sha256 | query | string | No | Get SHA256 hash of file (alias for hash) |
base64 | query | string | No | Get file content as base64 |
preview | query | string | No | Preview archive contents (for zip/tar files). Alias: ?contents. |
contents | query | string | No | Alias for ?preview — list archive contents |
stat | query | string | No | Get file/directory metadata (stat) without downloading content |
thumbnail | query | string | No | Return a processed image (resize, format convert, blur, grayscale). Requires the service to be started with --allow-thumbnails; returns 403 when disabled. |
grep | query | string | No | Search file/directory contents for a regex pattern (or literal if fixed_string=true). Requires --allow-grep. |
ignore_case | query | boolean | No | Case-insensitive grep matching. Default: false. |
fixed_string | query | boolean | No | Treat grep pattern as literal string, not regex. Default: false. |
glob | query | string | No | Find files matching a glob pattern (e.g. **/*.rs, src/**/*.{ts,tsx}). Requires --allow-search. Directory paths only. |
context | query | integer | No | Number of context lines before/after each grep match. Default: 0. |
max_count | query | integer | No | Max matches per file for grep. Default: 50. |
max_matches | query | integer | No | Total max matches across all files for grep. Default: 500. |
max_depth | query | integer | No | Directory recursion depth for grep. Default: 50. |
max_filesize | query | integer | No | Skip files larger than this (bytes) during grep. Default: 10485760. |
timeout | query | integer | No | Grep timeout in seconds. Default: 30. |
no_ignore | query | boolean | No | Bypass .gitignore filtering during grep. Default: false. |
max_results | query | integer | No | Max entries returned for glob search. Default: 1000. |
max_files_scanned | query | integer | No | Max filesystem entries scanned during glob search. Default: 100000. |
sort | query | string | No | Sort glob results by one of mtime, name, or size. Default: mtime. |
order | query | string | No | Sort order for glob results. Allowed values: asc, desc. Default: desc for mtime, asc for name/size. |
lines | query | string | No | Extract specific lines from a file. Formats: 10-50 (range, 1-indexed inclusive), 100 (single line), -20 (last 20 lines / tail), 50- (line 50 to end). Returns text/plain with X-Line-Range header. X-Total-Lines header included when naturally known (scan reached EOF). Max 100,000 lines or 64MB per request. |
history | query | string | No | List all revisions of a file. Returns JSON with a revisions array; paginate via after_id. Mutually exclusive with at, revision, and diff. |
at | query | string | No | Read file content at a point in time. Accepts an RFC3339 timestamp or Unix milliseconds. Mutually exclusive with history, revision, and diff. Composable with lines, hash, and base64. |
revision | query | integer | No | Read file content by stable per-path sequence number. Mutually exclusive with history, at, and diff. Composable with lines, hash, and base64. |
diff | query | string | No | Compute a unified diff between two versions. Requires from_seq or from_ts. Optional to_seq or to_ts (defaults to current file). Mutually exclusive with history, at, and revision. |
from_seq | query | integer | No | Source revision sequence number for ?diff. Mutually exclusive with from_ts. |
from_ts | query | string | No | Source timestamp for ?diff (RFC3339 or Unix ms). Mutually exclusive with from_seq. |
to_seq | query | integer | No | Target revision sequence number for ?diff. Mutually exclusive with to_ts. Defaults to current file on disk. |
to_ts | query | string | No | Target timestamp for ?diff (RFC3339 or Unix ms). Mutually exclusive with to_seq. |
after_id | query | integer | No | Cursor for ?history pagination. Returns entries with id > after_id. |
limit | query | integer | No | Maximum entries to return for ?history. Default: 100. |
zip | query | string | No | Download a directory as a streaming zip archive (bare flag, e.g. ?zip). Local directories only; requires --allow-archive. Same behavior as the WebDAV-style /{directory}?zip. |
Response
Section titled “Response”{ "auth": true, "user": "alice@example.com", "allow_archive": true, "allow_delete": true, "allow_search": true, "allow_upload": true, "dir_exists": true, "href": "/home/alice", "kind": "Index", "uri_prefix": "/", "paths": [ { "name": "documents", "path_type": "Dir", "size": 5, "mtime": 1700000000000, "revisions": null }, { "name": "README.md", "path_type": "File", "size": 2048, "mtime": 1700000000000, "revisions": 3 } ]}{ "error": "File does not exist at the requested point in time"}{ "error": "Content not stored for this revision (file was too large or binary at this point in time)"}The service returns no body for this status. Retry the request after backing off; the limit is on concurrent journal queries, not request rate.
Example request
Section titled “Example request”curl -X GET "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/v1/files/home/alice/README.md" \ -H "Authorization: Bearer <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.get('/home/alice/README.md');