Optidata — Optiwork Platform Team
Overview
Files, folders, sharing and synchronisation for the Optiwork suite.
Optiwork Drive API v2026.08.18.0924
Section titled “Optiwork Drive API v2026.08.18.0924”Optiwork Drive is the file service of the Optiwork suite: company folders, files and folders (nodes), content upload and download, versioning, locks, approvals, sharing and audit — plus a change journal that lets an integration keep an external copy of the drive up to date.
Drive shares its host and its authentication key with the rest of the suite. The account layer — users, groups, notifications, multi-factor authentication — is documented in the Optiwork reference.
Base URL
All endpoints are served under the fixed Optiwork host:
https://work.optidata.cloud/api.
Authentication
Every endpoint (except GET /ping) requires a Bearer JWT passport. Your
personal passport is available in Optiwork at
https://work.optidata.cloud/user/settings/security
(My account > Profile > Security), where it is shown as the
authentication key. Send it on every request:
Authorization: Bearer opk_xxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Passports are short-lived; when a request returns 401, get a fresh
authentication key from the same settings page and retry.
Drives and nodes
Files and folders are nodes. A node is either a folder (type: 1) or a file
(type: 2), and every node lives in a drive — the tenant’s file space. Most
installations have a single drive, whose numeric id you can read from
GET /drives/config.json in the Optiwork reference; it is 1 unless your tenant
was configured otherwise.
Nodes form a tree. A node with parent_id: null is a company folder: the
top-level shared spaces of the tenant. GET /drives/{drive}/nodes/company/folders
lists the company folders the caller can reach, and everything below them is
navigated with GET /drives/{drive}/nodes/{node}.
Permissions
Access to a node is governed by the share permissions granted on it or on one
of its ancestors. A permission carries an actions level:
none < view < edit < manage. Operations note the level they require;
requests by users without it return 403. share and owner are legacy aliases
of manage and may still appear on older permissions.
Concurrent edits of a file
The four operations that replace a file’s content —
POST .../content/file, POST .../content/base64, and the prepare and
finish of a chunked replacement — accept an optional base_content_hash:
the hash_sha256 of the content the caller edited, exactly as the server
returned it on node.content.hash_sha256. With it, the write behaves like an
If-Match:
- The write is accepted only when
base_content_hashis equal to thehash_sha256stored on the node’s current content. That includes the SHA-256 of empty content when the current version is an empty file. - When the node’s current content has no stored hash — the file has no
content yet, or its current version has a
nullor empty hash — no base can match, and anybase_content_hashis refused. - A refused write answers
409 Conflictand writes nothing: no new content version, no history entry, no journal entry. Read the node again and keep your version as a copy instead of overwriting. - Two base-carrying writes, or chunk finishes, of the same file run one at a time, and the second is checked against the hash the first one left. It is refused when that hash differs from its base; a first write that stored the same bytes leaves the hash unchanged, so the second still passes. The check compares content hashes: it does not detect every intervening version.
- A write that carries a base, and every chunk finish, waits for another
such write of the same file to finish, 30 seconds by default. Past that,
or when the write could not keep its turn, it answers
423 Lockedwith aRetry-Afterheader (5 seconds by default; read the header rather than assume the value) and writes nothing. Its base was not checked, so retry the same request after the delay; do not keep a copy as for a409. - A write whose bytes equal the current content creates no new version: the
answer’s
node.content.base_content_hashis the one already stored on that version, not the one the request sent. - Without
base_content_hashthe write is unconditional, as before. For a chunked replacement that means neither step sent one: a base sent atprepareis still checked atfinish.
The accepted base is stored on the new version as
node.content.base_content_hash, returned on the node and on every
journal row of GET /drives/{drive}/wal/nodes/since/{nodeWalEntryId}. A
sync client compares it with the hash it last committed: equal means the
other side edited its version (a sequential edit); different, or null,
means it cannot tell, so it keeps a conflict copy.
Conventions
- Identifiers in paths (
{drive},{node}, …) are the numericidof the resource. Nested resources are scope-checked: referencing a node that does not belong to the given drive returns404. - Timestamps are ISO-8601 UTC strings (e.g.
2026-03-10T17:09:05.000000Z). - Validation failures return
422with a per-fielderrorsmap. - List endpoints are paginated with Laravel’s paginator envelope. Endpoints that
use the simple paginator omit
totalandlast_page. - Requests are rate limited per authenticated user; exceeding the limit returns
429.
Authentication
Section titled “ Authentication ”bearerAuth
Section titled “bearerAuth”The authentication key (JWT passport) from My account > Profile > Security at work.optidata.cloud/user/settings/security.
Security scheme type: http
Bearer format: JWT