The Reading Files API provides two endpoints for listing directory contents and downloading files. The WebDAV-style /{path} endpoint returns HTML by default and integrates with the Web UI, while /api/v1/files/{path} returns JSON and supports advanced features like grep, glob, and zip downloads.
List directory or download file
Section titled “List directory or download file”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. Supports revision history via ?history, point-in-time reads via ?at or ?revision, and unified diffs via ?diff.
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, 1, or true. For directory paths, ?download 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. Default: 100. |
Response
Section titled “Response”{ "allow_archive": true, "allow_delete": true, "allow_search": true, "allow_upload": true, "auth": true, "dir_exists": true, "href": "/projects/web-app", "kind": "Index", "paths": [ { "mtime": 1706000000000, "name": "src", "path_type": "Dir", "revisions": null, "size": 42 }, { "mtime": 1706100000000, "name": "README.md", "path_type": "File", "revisions": 7, "size": 2048 } ], "uri_prefix": "/api/v1/files/", "user": "alice"}{ "error": "Access 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": "Path not found: /projects/missing", "success": false}SDK usage
Section titled “SDK usage”// List a directory in JSON formatawait client.files.listDirectory({ path: "/projects/web-app", json: ""});
// Get the SHA256 hash of a fileawait client.files.listDirectory({ path: "/projects/web-app/README.md", hash: ""});
// Force a browser downloadawait client.files.listDirectory({ path: "/projects/web-app/README.md", download: "1"});
// Read a file at a specific point in timeawait client.files.listDirectory({ path: "/projects/web-app/README.md", at: "2024-01-15T10:30:00Z"});
// Compute a unified diff between two revisionsawait client.files.listDirectory({ path: "/projects/web-app/README.md", diff: "", from_seq: 3, to_seq: 5});Get file or directory (API v1)
Section titled “Get file or directory (API v1)”GET /api/v1/files/{path}
Section titled “GET /api/v1/files/{path}”Returns a directory listing, file content, search results, or a streaming archive. This endpoint exposes the full feature set including ?grep, ?glob, ?lines, and ?zip. Append ?zip to download an entire directory as a streaming zip archive (requires --allow-archive).
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. Default: "mtime". |
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. |
Response
Section titled “Response”For directory listings, file content, grep results, glob results, or line-range content depending on the query string. The response body is application/json for listings/searches, application/octet-stream for raw files, or application/zip for ?zip downloads.
{ "allow_archive": true, "allow_delete": true, "allow_search": true, "allow_upload": true, "auth": true, "dir_exists": true, "href": "/projects/web-app", "kind": "Index", "paths": [ { "mtime": 1706000000000, "name": "src", "path_type": "Dir", "revisions": null, "size": 42 }, { "mtime": 1706100000000, "name": "README.md", "path_type": "File", "revisions": 7, "size": 2048 } ], "uri_prefix": "/api/v1/files/", "user": "alice"}For a ?grep query, the response matches files_GrepResults:
{ "duration_ms": 42, "matches": [ { "column_byte": 12, "context_after": [], "context_before": [], "line": "function handleAuth(token: string) {", "line_number": 38, "path": "/projects/web-app/src/auth.ts" } ], "path": "/projects/web-app", "pattern": "handleAuth", "total_files_matched": 1, "total_files_searched": 18, "total_matches": 1, "truncated": false}{ "error": "File /projects/web-app/src/old.ts was deleted or moved at the requested point in time"}{ "error": "Content blob not stored for revision 12 (file was larger than the retained size limit at that revision)"}Too many concurrent journal queries. Retry the request after a short delay.
SDK usage
Section titled “SDK usage”// List a directory in JSON formatawait client.files.get({ path: "/projects/web-app"});
// Search file contents with grepawait client.files.get({ path: "/projects/web-app/src", grep: "handleAuth", ignore_case: true, context: 2});
// Find files matching a globawait client.files.get({ path: "/projects/web-app", glob: "**/*.rs"});
// Extract a specific line rangeawait client.files.get({ path: "/projects/web-app/src/auth.ts", lines: "10-50"});
// Get SHA256 hash of a file via remote backendawait client.files.get({ path: "/projects/web-app/README.md", backend: "s3-primary", hash: ""});
// Download a directory as a streaming zipawait client.files.get({ path: "/projects/web-app", zip: ""});