WebDAV Operations
Section titled “WebDAV Operations”The WebDAV operations expose RFC 4918-compliant file management endpoints for accessing, copying, moving, locking, and inspecting properties on container files. Use these endpoints when integrating with WebDAV-aware clients such as Nextcloud, ownCloud, Cyberduck, macOS Finder, and Windows Explorer.
All endpoints operate on paths relative to the container’s workspace. Authentication uses a container-scoped token. LOCK and UNLOCK are compatibility stubs — the server does not enforce locking semantics, but responds with valid tokens so WebDAV clients can complete their workflows.
Connection and Capability Discovery
Section titled “Connection and Capability Discovery”GET /api/files/webdav/{path}
Section titled “GET /api/files/webdav/{path}”Connect to a remote WebDAV server (Nextcloud, ownCloud, etc.) through this container. Returns the file content or a directory listing proxied from the upstream endpoint. Use this endpoint to provide WebDAV access when clients cannot reach the upstream server directly.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
type | query | string | Yes | Must be webdav |
server | query | string | Yes | Target WebDAV server hostname |
user | query | string | No | Username for WebDAV authentication |
pass | query | string | No | Password for WebDAV authentication |
webdav_path | query | string | No | WebDAV endpoint path. Default: "/" |
curl -X GET "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/remote.php/webdav/Documents?type=webdav&server=cloud.example.com&user=alice&pass=$WEBDAV_PASS&webdav_path=/"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.webdav.access('/remote.php/webdav/Documents', { type: 'webdav', server: 'cloud.example.com', user: 'alice', pass: process.env.WEBDAV_PASS, webdav_path: '/',});Responses
Section titled “Responses”File content or directory listing returned from the upstream WebDAV server.
{ "description": "File content or directory listing"}OPTIONS /api/files/webdav/{path}
Section titled “OPTIONS /api/files/webdav/{path}”Returns supported HTTP methods and WebDAV capabilities in the Allow header. WebDAV clients call this endpoint first to discover which verbs they can use.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
curl -X OPTIONS "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/report.pdf" \ -iimport { 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.webdav.getOptions('/Documents/report.pdf');Responses
Section titled “Responses”Capability discovery per RFC 4918 §10.1. No response body. The advertised methods and DAV class are returned in response headers:
Allow— comma-separated list of supported HTTP methods. WebDAV-root paths advertise the full WebDAV verb set;/api/v1/*paths advertise the simple HTTP set.DAV— WebDAV compliance class. Set to1on WebDAV-root OPTIONS responses; absent on/api/v1/*OPTIONS responses.MS-Author-Via— authoring-protocol hint for Microsoft WebDAV clients. Set toDAVon WebDAV-root OPTIONS responses.
File Operations
Section titled “File Operations”COPY /api/files/webdav/{path}
Section titled “COPY /api/files/webdav/{path}”WebDAV COPY: copy a file or directory to a new location specified by the Destination header. Use Depth: 0 to copy a single file, or Depth: infinity to recursively copy a directory.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Source file or directory path |
Destination | header | string | Yes | Destination URL for the copy |
Depth | header | string | No | Copy depth. Allowed values: 0 (file only) or infinity (recursive for directories). Default: "infinity" |
curl -X COPY "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/report.pdf" \ -H "Destination: https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Archive/report.pdf" \ -H "Depth: 0"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.webdav.copyResource('/Documents/report.pdf', { Destination: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Archive/report.pdf', Depth: '0',});Responses
Section titled “Responses”Resource copied successfully.
Resource overwritten at destination.
Copy not allowed.
{ "success": false, "error": "Copy not allowed: insufficient permissions on source resource"}Source resource not found.
Destination parent does not exist.
MOVE /api/files/webdav/{path}
Section titled “MOVE /api/files/webdav/{path}”WebDAV MOVE: move or rename a file or directory to a new location specified by the Destination header. The caller must hold both upload and delete permissions on the source and destination.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Source file or directory path |
Destination | header | string | Yes | Destination URL for the move |
curl -X MOVE "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/draft.txt" \ -H "Destination: https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/final.txt"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.webdav.moveResource('/Documents/draft.txt', { Destination: 'https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/final.txt',});Responses
Section titled “Responses”Resource moved successfully.
Resource overwritten at destination.
Move not allowed. The caller must hold both upload and delete permissions.
{ "success": false, "error": "Move requires both upload and delete permissions"}Source resource not found.
Destination parent does not exist.
Locking
Section titled “Locking”LOCK /api/files/webdav/{path}
Section titled “LOCK /api/files/webdav/{path}”WebDAV LOCK: returns a lock token for WebDAV client compatibility. This is a compatibility stub — locks are not enforced server-side.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
Depth | header | string | No | Allowed values: 0 or infinity |
Request Body
Section titled “Request Body”The optional request body is a WebDAV lock XML document describing the requested lock scope, type, and owner. Omit the body to request a default exclusive write lock.
curl -X LOCK "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/report.pdf" \ -H "Depth: infinity" \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0" encoding="utf-8"?><D:lockinfo xmlns:D="DAV:"> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> <D:owner><D:href>mailto:alice@example.com</D:href></D:owner></D:lockinfo>'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.webdav.lockResource('/Documents/report.pdf', `<?xml version="1.0" encoding="utf-8"?><D:lockinfo xmlns:D="DAV:"> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> <D:owner><D:href>mailto:alice@example.com</D:href></D:owner></D:lockinfo>`, { Depth: 'infinity' });Responses
Section titled “Responses”Lock token issued for compatibility. The response body is a WebDAV XML prop document containing a lockdiscovery element with the issued token.
<?xml version="1.0" encoding="utf-8"?><D:prop xmlns:D="DAV:"> <D:lockdiscovery> <D:activelock> <D:locktype><D:write/></D:locktype> <D:lockscope><D:exclusive/></D:lockscope> <D:depth>infinity</D:depth> <D:timeout>Second-3600</D:timeout> <D:locktoken> <D:href>urn:uuid:e71d3c20-3e3f-11ec-8d3d-0242ac130004</D:href> </D:locktoken> </D:activelock> </D:lockdiscovery></D:prop>File not found.
UNLOCK /api/files/webdav/{path}
Section titled “UNLOCK /api/files/webdav/{path}”WebDAV UNLOCK: release a previously issued lock token. This is a no-op compatibility stub — the server does not track lock state.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
Lock-Token | header | string | Yes | Lock token to release |
curl -X UNLOCK "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/report.pdf" \ -H "Lock-Token: <urn:uuid:e71d3c20-3e3f-11ec-8d3d-0242ac130004>"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.webdav.unlockResource('/Documents/report.pdf', { 'Lock-Token': 'urn:uuid:e71d3c20-3e3f-11ec-8d3d-0242ac130004',});Responses
Section titled “Responses”Lock released (no-op).
Resource not found.
Properties
Section titled “Properties”PROPFIND /api/files/webdav/{path}
Section titled “PROPFIND /api/files/webdav/{path}”WebDAV PROPFIND: retrieve properties (metadata) for files or directories. Returns a 207 Multi-Status response containing resource type, size, modification date, ETag, and other properties in WebDAV XML format. Use the Depth header to control recursion into directories.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
Depth | header | string | No | Depth of property retrieval. Allowed values: 0 (resource only), 1 (immediate children), infinity (recursive). Default: "1" |
Request Body
Section titled “Request Body”The optional request body is a PROPFIND XML document specifying which properties to retrieve. Omit the body to retrieve the standard set of properties.
curl -X PROPFIND "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents" \ -H "Depth: 1" \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"> <D:prop> <D:resourcetype/> <D:getcontentlength/> <D:getlastmodified/> <D:getetag/> </D:prop></D:propfind>'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.webdav.propfindResource('/Documents', `<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"> <D:prop> <D:resourcetype/> <D:getcontentlength/> <D:getlastmodified/> <D:getetag/> </D:prop></D:propfind>`, { Depth: '1' });Responses
Section titled “Responses”Multi-Status response with resource properties in WebDAV XML format.
<?xml version="1.0" encoding="utf-8"?><D:multistatus xmlns:D="DAV:"> <D:response> <D:href>/Documents</D:href> <D:propstat> <D:prop> <D:resourcetype><D:collection/></D:resourcetype> <D:getcontentlength>0</D:getcontentlength> <D:getlastmodified>Mon, 01 Jan 2024 12:00:00 GMT</D:getlastmodified> <D:creationdate>2024-01-01T12:00:00Z</D:creationdate> <D:getetag>"d41d8cd98f00b204e9800998ecf8427e"</D:getetag> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response> <D:href>/Documents/report.pdf</D:href> <D:propstat> <D:prop> <D:resourcetype/> <D:getcontentlength>1048576</D:getcontentlength> <D:getlastmodified>Fri, 12 Jan 2024 09:30:00 GMT</D:getlastmodified> <D:creationdate>2024-01-12T09:30:00Z</D:creationdate> <D:getetag>"a1b2c3d4e5f67890"</D:getetag> <D:getcontenttype>application/pdf</D:getcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response></D:multistatus>Resource not found.
PROPPATCH /api/files/webdav/{path}
Section titled “PROPPATCH /api/files/webdav/{path}”WebDAV PROPPATCH: modify dead properties on a file or directory. Returns a 207 Multi-Status response confirming the property changes.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Resource path inside the container |
Request Body
Section titled “Request Body”The request body is a PROPPATCH XML document with set and/or remove instructions for the target properties.
curl -X PROPPATCH "https://{projectId}-{containerId}-files-1.{server}.containers.hoody.com/api/files/webdav/Documents/report.pdf" \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0" encoding="utf-8"?><D:propertyupdate xmlns:D="DAV:"> <D:set> <D:prop> <D:displayname>Annual Report 2024</D:displayname> </D:prop> </D:set></D:propertyupdate>'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.webdav.proppatchResource('/Documents/report.pdf', `<?xml version="1.0" encoding="utf-8"?><D:propertyupdate xmlns:D="DAV:"> <D:set> <D:prop> <D:displayname>Annual Report 2024</D:displayname> </D:prop> </D:set></D:propertyupdate>`);Responses
Section titled “Responses”Multi-Status response confirming property changes.
<?xml version="1.0" encoding="utf-8"?><D:multistatus xmlns:D="DAV:"> <D:response> <D:href>/Documents/report.pdf</D:href> <D:propstat> <D:prop> <D:displayname>Annual Report 2024</D:displayname> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response></D:multistatus>File not found.