Examples
Practical, copy-paste examples for the tasks most integrations need first. Every call goes to the fixed Drive host and carries your authentication key as a bearer token:
export OPTIWORK_KEY="opk_xxxxxxxxxxxxxxxxxxxxxxxx"export OPTIWORK_API="https://work.optidata.cloud/api"Get the key in Optiwork at
work.optidata.cloud/user/settings/security
(My account > Profile > Security). Keys are short-lived — when a call
returns 401, fetch a fresh one from that page and retry.
The examples use drive 1, which is the drive of a standard tenant. Read the
real id from
GET /drives/config.json rather
than hard-coding it. Ids and names below are fictional; responses are trimmed to
the fields each example is about.
Create a folder
Section titled “Create a folder”A folder is a node with type: 1. Post it to the folder you want it created
in — here, company folder 300754.
curl --request POST \ --url "$OPTIWORK_API/drives/1/nodes/300754" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json" \ --header "Content-Type: application/json" \ --data '{ "name": "Contracts 2026", "type": 1 }'{ "id": 665201, "parent_id": 300754, "drive_id": 1, "type": 1, "name": "Contracts 2026", "is_folder": true, "is_file": false, "created_at": "2026-08-19T12:41:02.000000Z"}To create at the top level of the drive instead — a new company folder — post to
/drives/1/nodes with no parent id.
Reference: POST /drives/{drive}/nodes/{node}
· POST /drives/{drive}/nodes
Upload a file
Section titled “Upload a file”Same endpoint, type: 2, sent as multipart/form-data with the bytes in
file. The response is the created node, with its content attributes filled in.
curl --request POST \ --url "$OPTIWORK_API/drives/1/nodes/665201" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json" \ --form "name=NDA.pdf" \ --form "type=2" \ --form "file=@./NDA.pdf"{ "id": 665198, "parent_id": 665201, "type": 2, "name": "NDA.pdf", "is_file": true, "content_mime_type": "application/pdf", "content_size_bytes": 148213}A name that collides with a sibling, or that contains characters the storage
layer forbids, comes back as 422 with a per-field errors map.
Reference: POST /drives/{drive}/nodes/{node}
List what is inside a folder
Section titled “List what is inside a folder”Two endpoints answer this, and which one you want depends on why you are asking.
Opening a folder in a UI — the node itself plus a page of its children, sorted and filterable:
curl --request GET \ --url "$OPTIWORK_API/drives/1/nodes/665201?pageSize=2&orderBy=name&order=asc" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json"{ "node": { "id": 665201, "name": "Contracts 2026", "is_folder": true }, "pagination": { "current_page": 1, "per_page": 2, "data": [ { "id": 665198, "name": "NDA.pdf", "type": 2, "content_size_bytes": 148213 }, { "id": 665199, "name": "Signed", "type": 1 } ] }}Walking the tree — a leaner payload ordered by id, with the caller’s effective permissions on the folder attached to the first page:
curl --request GET \ --url "$OPTIWORK_API/drives/1/nodes/665201/children?pageSize=100" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json"To find the folders you can start from, list the company folders of the drive
with GET /drives/{drive}/nodes/company/folders.
Reference: GET /drives/{drive}/nodes/{node}
· GET /drives/{drive}/nodes/{node}/children
Read a file
Section titled “Read a file”View it
Section titled “View it”Streams the bytes inline, with the file’s own MIME type — what you point an image or PDF preview at.
curl --request GET \ --url "$OPTIWORK_API/drives/1/nodes/665198/content" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --output NDA.pdfDownload it
Section titled “Download it”Same bytes, delivered as an attachment. This one is gated separately: a company policy can withhold downloading from users who may still view the file, and the download is written to the node’s audit trail.
curl --request GET \ --url "$OPTIWORK_API/drives/1/nodes/665198/content/download" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --output NDA.pdfCheck before you transfer
Section titled “Check before you transfer”To decide whether a download is needed at all, ask for the metadata instead — size, MIME type and hash, with no bytes on the wire.
curl --request GET \ --url "$OPTIWORK_API/drives/1/nodes/665198/content/meta" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json"Reference: GET …/content
· GET …/content/download
· GET …/content/meta
Replace the content of a file
Section titled “Replace the content of a file”Uploading a new version keeps the old one in the node’s history.
curl --request POST \ --url "$OPTIWORK_API/drives/1/nodes/665198/content/file" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json" \ --form "file=@./NDA-signed.pdf"If another user could be editing the same file, take a
lock first and pass its id as
node_lock_id; a stale or foreign lock is rejected instead of silently
overwriting their work.
To make sure you do not overwrite a version you never saw, send the
hash_sha256 you last read on node.content as base_content_hash:
curl --request POST \ --url "$OPTIWORK_API/drives/1/nodes/665198/content/file" \ --header "Authorization: Bearer $OPTIWORK_KEY" \ --header "Accept: application/json" \ --form "file=@./NDA-signed.pdf" \ --form "base_content_hash=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"The upload is accepted only if that is still the hash of the file’s current
content; otherwise it answers 409 and writes nothing. A file with no stored
hash yet matches no base, so leave the field out for its first content. The
accepted base comes back on the new version as node.content.base_content_hash. An
upload of the same bytes as the current content creates no new version, so it
returns the base already stored on that version, not the one you sent.
Reference: POST /drives/{drive}/nodes/{node}/content/file
Errors you should expect
Section titled “Errors you should expect”| Status | Shape | When |
|---|---|---|
401 |
{"error": "…"} |
Missing, malformed or expired authentication key |
403 |
{"message": "This action is unauthorized."} |
The caller lacks the permission level the operation needs |
404 |
{"message": "…"} |
No such node, or it does not belong to the given drive |
409 |
{"error": "…", "status": 409, "help": ""} |
base_content_hash is not the file’s current content — someone saved a newer version; or a repeated chunk finish of committed content with a different or missing fileHash |
422 |
{"message": "…", "errors": { … }} |
Validation failed; errors is keyed by field |
423 |
{"error": "…", "status": 423, "help": ""} |
Another write of the same file held it too long (a base-carrying write or a chunk finish); nothing was written — retry the same request after the Retry-After seconds |
429 |
{"message": "Too Many Attempts."} |
Rate limit exceeded — retry after the window resets |
Note the asymmetry: authentication failures and Drive’s own domain errors (such as
the 409 and 423) answer with error, everything else with message.