Overview
Section titled “Overview”The Reading Files endpoints let you browse, download, and inspect files via HTTP GET requests. Use them to enumerate directory contents, download file payloads, retrieve hashes, run content searches (grep) and filename searches (glob), extract specific line ranges, and read historical revisions from the file journal. Two endpoint variants are available: a basic form at /{path} and a richer v1 form at /api/v1/files/{path} that exposes the full search and journal surface.
GET /{path}
Section titled “GET /{path}”Returns a directory listing in HTML or JSON format, or downloads a file. For file paths, append ?download (or ?download=true) to force a Content-Disposition: attachment response. Use ?json for a machine-readable listing, ?hash for a SHA-256 digest, and ?base64 for base64-encoded content.
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 |
simple | query | string | No | Return simple text listing |
sort | query | string | No | Sort by field. Accepted values: name, mtime, size |
order | query | string | No | Sort order. Accepted 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 only: force browser download (Content-Disposition: attachment). Accepted values: empty (?download), 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 revisions array, pagination via after_id. Mutually exclusive with at/revision/diff. |
at | query | string | No | Read file content at a point in time. Accepts RFC3339 timestamp or Unix milliseconds. Mutually exclusive with history/revision/diff. Composable with ?lines, ?hash, ?base64. |
revision | query | integer | No | Read file content by stable per-path sequence number. Mutually exclusive with history/at/diff. Composable with ?lines, ?hash, ?base64. |
diff | query | string | No | Compute 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/revision. |
from_seq | query | integer | No | Source revision seq 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 seq number for ?diff. Mutually exclusive with to_ts. Default: 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 | Max entries to return for ?history. |
Example request
Section titled “Example request”curl "https://api.hoody.com/workspace/projects?json&sort=name&order=asc"const listing = await client.files.listDirectory({ path: "workspace/projects", json: "", sort: "name", order: "asc"});Response
Section titled “Response”Directory listings return JSON matching the DirectoryListing schema. File downloads return application/octet-stream with the raw binary content.
{ "allow_archive": true, "allow_delete": false, "allow_search": true, "allow_upload": true, "auth": true, "dir_exists": true, "href": "/workspace/projects", "kind": "Index", "paths": [ { "mtime": 1716400000000, "name": "README.md", "path_type": "File", "revisions": 12, "size": 4321 }, { "mtime": 1716390000000, "name": "src", "path_type": "Dir", "revisions": null, "size": 24 }, { "mtime": 1716300000000, "name": "package.json", "path_type": "File", "revisions": 5, "size": 1208 } ], "uri_prefix": "/api/v1/files", "user": "alice"}{ "error": "Access to /workspace/secret is forbidden", "success": false}| 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 different account |
{ "error": "File or directory not found: /workspace/missing.txt", "success": false}GET /api/v1/files/{path}
Section titled “GET /api/v1/files/{path}”Get a directory listing in JSON format, download a file, run grep/glob searches, extract a line range, or read historical revisions from the journal. The optional backend query parameter routes the request to a remote backend.
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 | Generate thumbnail (not yet implemented in API v1, returns 501) |
grep | query | string | No | Search file/directory contents for 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 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: mtime (default), name, or size |
order | query | string | No | Sort order for glob results. Default: desc for mtime, asc for name/size. Accepted values: asc, desc |
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 revisions array, pagination via after_id. Mutually exclusive with at/revision/diff. |
at | query | string | No | Read file content at a point in time. Accepts RFC3339 timestamp or Unix milliseconds. Mutually exclusive with history/revision/diff. Composable with ?lines, ?hash, ?base64. |
revision | query | integer | No | Read file content by stable per-path sequence number. Mutually exclusive with history/at/diff. Composable with ?lines, ?hash, ?base64. |
diff | query | string | No | Compute 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/revision. |
from_seq | query | integer | No | Source revision seq 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 seq number for ?diff. Mutually exclusive with to_ts. Default: 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 | Max 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. |
Example request
Section titled “Example request”curl "https://api.hoody.com/api/v1/files/workspace/api-docs?grep=export+function&ignore_case=true&context=2&max_count=50"const results = await client.files.get({ path: "workspace/api-docs", grep: "export function", ignore_case: true, context: 2, max_count: 50});Response
Section titled “Response”Returns a directory listing, grep/glob results, line-range content, file revision history, historical content, or a unified diff depending on the query parameters used. File downloads return application/octet-stream.
Directory listing:
{ "allow_archive": true, "allow_delete": false, "allow_search": true, "allow_upload": true, "auth": true, "dir_exists": true, "href": "/workspace/api-docs", "kind": "Index", "paths": [ { "mtime": 1716400000000, "name": "README.md", "path_type": "File", "revisions": 12, "size": 4321 }, { "mtime": 1716390000000, "name": "src", "path_type": "Dir", "revisions": null, "size": 24 } ], "uri_prefix": "/api/v1/files", "user": "alice"}Grep results:
{ "duration_ms": 142, "matches": [ { "column_byte": 6, "context_after": ["function foo() {"], "context_before": ["// utility module"], "line": "export function greet(name) {", "line_number": 12, "path": "/workspace/api-docs/src/utils.ts" } ], "path": "/workspace/api-docs", "pattern": "export function", "total_files_matched": 1, "total_files_searched": 42, "total_matches": 1, "truncated": false}Glob results:
{ "count": 2, "duration_ms": 18, "entries": [ { "is_dir": false, "modified": 1716400000, "name": "/workspace/api-docs/src/index.ts", "size": 2104 }, { "is_dir": false, "modified": 1716350000, "name": "/workspace/api-docs/src/utils.ts", "size": 872 } ], "path": "/workspace/api-docs", "pattern": "src/**/*.ts", "total_scanned": 87, "truncated": false}{ "error": "File /workspace/old-report.txt was deleted or moved at the requested point in time"}{ "error": "Content for revision 47 of /workspace/large.bin is not stored (file exceeded journal size limit)"}Too many concurrent journal queries are in flight. Retry after a short delay. The response has no body.