File metadata
Section titled “File metadata”A HEAD /{path} request returns a file’s metadata through response headers (Content-Length, Last-Modified, ETag, Content-Type) and carries no payload body. Use it to test whether a file is present, fetch an ETag for conditional requests, or read a file’s size and modification time without downloading the file.
The same WebDAV-style path also accepts the history, at, revision, and diff query parameters. On a HEAD request those parameters are accepted but still produce a headers-only response. To receive the revision list, point-in-time content, or unified diff, send the same path as GET instead (see the examples below).
The service is addressed at https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com.
Get file metadata
Section titled “Get file metadata”HEAD /{path}
Section titled “HEAD /{path}”Returns the headers that the matching GET would send for the file at {path}. The path is the URL-encoded file path under the served directory.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | URL-encoded file path under the served directory. |
history | query | string | No | List all revisions of a file. Returns JSON with a revisions array, pagination via after_id. Mutually exclusive with at/revision/diff. Pass history= (no value) to enable. |
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 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/revision. Pass diff= (no value) to enable. |
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 headers
Section titled “Response headers”The successful response carries the following headers:
| Header | Description |
|---|---|
Content-Length | Size in bytes. |
Content-Type | The file’s type, guessed from its name. |
ETag | Entity tag of this version. |
Last-Modified | Modification time. |
Responses
Section titled “Responses”The response carries the headers listed above for the existing file.
{ "code": "INVALID_PATH", "error": "Invalid path", "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 |
{ "code": "ACCESS_FORBIDDEN", "error": "Access forbidden", "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 |
{ "code": "RESOURCE_NOT_FOUND", "error": "Not found", "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 backend named by the type query parameter still has uploads from before a service restart pending. The response includes a Retry-After header with the number of seconds to wait before retrying.
{ "error": "Uploads from before a service restart are still pending on this backend; retry later", "success": false}The server cannot connect to the backend named by the type query parameter, or a journal read could not verify its paths in time. The response includes a Retry-After header with the number of seconds to wait before retrying.
{ "code": "MOUNT_STORAGE_UNAVAILABLE", "error": "Mounts unavailable", "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 (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. 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. | Retry after the time given in Retry-After |
Examples
Section titled “Examples”Check whether a file exists
Section titled “Check whether a file exists”curl -I "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/data/report.json"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: '<the operation Base URL>', token: process.env.HOODY_TOKEN });
await client.files.exists('data/report.json');List a file’s revisions
Section titled “List a file’s revisions”Use ?history on a GET to the same path to receive the revision list as JSON. Pass history with no value to enable; pair with after_id to paginate.
curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/data/report.json?history=&limit=20"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: '<the operation Base URL>', token: process.env.HOODY_TOKEN });
await client.files.get('data/report.json', { history: '', limit: 20 });Read content at a point in time
Section titled “Read content at a point in time”Use ?at on a GET to the same path to read the file content as of a given timestamp.
curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/data/report.json?at=2025-09-17T14:30:00Z"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: '<the operation Base URL>', token: process.env.HOODY_TOKEN });
await client.files.get('data/report.json', { at: '2025-09-17T14:30:00Z' });Computing a diff
Section titled “Computing a diff”Use ?diff on a GET to the same path to compute a unified diff between two revisions. Specify the source with from_seq or from_ts; the target defaults to the current file on disk if to_seq or to_ts is omitted.
curl "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/data/report.json?diff=&from_seq=10&to_seq=12"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: '<the operation Base URL>', token: process.env.HOODY_TOKEN });
await client.files.get('data/report.json', { diff: '', from_seq: 10, to_seq: 12 });