# Optiwork Projects API - **Version:** v2026.07.23.1005 - **Base URL:** `https://projects.work.optidata.cloud/api` - **OpenAPI spec (YAML):** https://docs.work.optidata.cloud/specs/optiwork-projects.openapi.yaml Kanban project management (boards, columns, tasks) for the Optiwork suite. The **Optiwork Projects** service provides kanban-style project management: hierarchical **boards** (projects), **columns** (task lists), **cards** (tasks), plus tags, checklists, comments, time tracking, file attachments, custom fields and recurring tasks. ### Base URL All endpoints are served under the fixed Projects host: `https://projects.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](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. ### Permissions Board access is governed by board membership. Each member has one permission level: `view` < `interact` < `edit` < `manage`. Operations note the level they require; requests by users without the required level return `403`. Boards may also be `public` (visible to every user of the tenant) or `private` (members only). ### Conventions - Identifiers in paths (`{board}`, `{card}`, ...) are the numeric `id` of the resource unless stated otherwise. Nested resources are **scope-checked**: referencing a card that does not belong to the given board returns `404`. - Timestamps are ISO-8601 UTC strings (e.g. `2026-03-10T17:09:05.000000Z`). - Validation failures return `422` with a per-field `errors` map. - Responses are serialized with numeric-string coercion: numeric fields are emitted as JSON numbers. ## Operations ### Service - [Health check](operations/ping.md) — `GET /ping` ### Boards - [List boards the caller is a member of](operations/listboards.md) — `GET /boards` - [Create a board](operations/createboard.md) — `POST /boards` - [Get the caller's boards as a tree](operations/getboardtree.md) — `GET /boards/tree` - [Reorder the caller's board list](operations/updateboardorder.md) — `PATCH /boards/order` - [Get selected fields for a batch of boards](operations/getboardsinfobatch.md) — `GET /boards/info/batch` - [Get a board with its full working set](operations/getboard.md) — `GET /boards/{board}` - [Delete a board](operations/deleteboard.md) — `DELETE /boards/{board}` - [Update a board](operations/updateboard.md) — `PATCH /boards/{board}` - [Search cards and columns within a board](operations/searchboard.md) — `GET /boards/{board}/search` - [Archive a board](operations/archiveboard.md) — `POST /boards/{board}/archive` - [Unarchive a board](operations/unarchiveboard.md) — `POST /boards/{board}/unarchive` - [Duplicate a board](operations/duplicateboard.md) — `POST /boards/{board}/duplicate` - [Import cards into a board from an external tool](operations/importboard.md) — `POST /boards/{board}/import` - [Export a board as a file download](operations/exportboard.md) — `GET /boards/{board}/export` - [Export a board to Optiwork Drive](operations/exportboardtodrive.md) — `POST /boards/{board}/export/drive` - [Change a board's visibility](operations/updateboardvisibility.md) — `PUT /boards/{board}/visibility` ### Board Members - [List the members of a board](operations/listboardmembers.md) — `GET /boards/{board}/members` - [Search users that could be added to the board](operations/listassignableusers.md) — `GET /boards/{board}/members/assignables` - [Search users that can be @-mentioned on the board](operations/listmentionableusers.md) — `GET /boards/{board}/members/mentionables` - [Set the caller's view mode for this board](operations/updatemyviewmode.md) — `PATCH /boards/{board}/members/myself/view-mode` - [Set the caller's notification preferences for this board](operations/updatemynotificationpreferences.md) — `PATCH /boards/{board}/members/myself/notifications/preferences` ### Columns - [List the columns of a board](operations/listcolumns.md) — `GET /boards/{board}/columns` - [Create a column](operations/createcolumn.md) — `POST /boards/{board}/columns` - [Reorder the board's columns](operations/reordercolumns.md) — `PATCH /boards/{board}/columns/order` - [Delete several columns at once](operations/batchdeletecolumns.md) — `POST /boards/{board}/columns/delete/batch` - [Unarchive several columns at once](operations/batchunarchivecolumns.md) — `POST /boards/{board}/columns/unarchive/batch` - [Delete a column](operations/deletecolumn.md) — `DELETE /boards/{board}/columns/{column}` - [Update a column](operations/updatecolumn.md) — `PATCH /boards/{board}/columns/{column}` - [List the cards of a column (slim)](operations/listcolumncards.md) — `GET /boards/{board}/columns/{column}/cards` - [Archive a column](operations/archivecolumn.md) — `POST /boards/{board}/columns/{column}/archive` - [Unarchive a column](operations/unarchivecolumn.md) — `POST /boards/{board}/columns/{column}/unarchive` - [Sort a column's cards by a predefined criterion](operations/sortcolumncards.md) — `POST /boards/{board}/columns/{column}/order` - [Move / reorder cards within or into a column](operations/movecards.md) — `PATCH /boards/{board}/columns/{column}/cards/order` ### Cards - [Create a card](operations/createcard.md) — `POST /boards/{board}/cards` - [Delete several cards at once](operations/batchdeletecards.md) — `POST /boards/{board}/cards/delete/batch` - [Unarchive several cards at once](operations/batchunarchivecards.md) — `POST /boards/{board}/cards/unarchive/batch` - [Get a card](operations/getcard.md) — `GET /boards/{board}/cards/{card}` - [Delete a card](operations/deletecard.md) — `DELETE /boards/{board}/cards/{card}` - [Update a card](operations/updatecard.md) — `PATCH /boards/{board}/cards/{card}` - [Archive a card](operations/archivecard.md) — `POST /boards/{board}/cards/{card}/archive` - [Unarchive a card](operations/unarchivecard.md) — `POST /boards/{board}/cards/{card}/unarchive` - [Duplicate a card in place](operations/copycard.md) — `POST /boards/{board}/cards/{card}/copy` - [Get selected fields for a batch of cards (cross-board)](operations/getcardsinfobatch.md) — `GET /cards/info/batch` ### Card Files - [Upload a file to a card](operations/uploadcardfile.md) — `POST /boards/{board}/cards/{card}/files` - [Attach an existing Optiwork Drive file to a card](operations/attachdrivefiletocard.md) — `POST /boards/{board}/cards/{card}/files/attach` - [Download a card file](operations/downloadcardfile.md) — `GET /boards/{board}/cards/{card}/files/{file}/download` - [Get a signed view URL for a card file](operations/getcardfileviewurl.md) — `GET /boards/{board}/cards/{card}/files/{file}/view` - [Delete a card file](operations/deletecardfile.md) — `DELETE /boards/{board}/cards/{card}/files/{file}` ### Card Assignees & Tags - [Attach/detach card assignees](operations/synccardassignees.md) — `POST /boards/{board}/cards/{card}/assignees/sync` - [Attach/detach card tags](operations/synccardtags.md) — `POST /boards/{board}/cards/{card}/tags/sync` ### Card Recurrence - [Get a card's recurrence rule](operations/getcardrecurrence.md) — `GET /boards/{board}/cards/{card}/recurrence` - [Create or update a card's recurrence rule](operations/upsertcardrecurrence.md) — `POST /boards/{board}/cards/{card}/recurrence` - [Stop a card's recurrence](operations/stopcardrecurrence.md) — `DELETE /boards/{board}/cards/{card}/recurrence` ### Comments - [Add a comment to a card](operations/addcomment.md) — `POST /boards/{board}/cards/{card}/comments` - [Delete a comment](operations/deletecomment.md) — `DELETE /boards/{board}/cards/{card}/comments/{comment}` - [Edit a comment](operations/updatecomment.md) — `PATCH /boards/{board}/cards/{card}/comments/{comment}` ### Time Tracking - [Start a timer on a card](operations/starttimetracking.md) — `POST /boards/{board}/cards/{card}/time-tracks/start` - [Stop the running timer on a card](operations/stoptimetracking.md) — `POST /boards/{board}/cards/{card}/time-tracks/stop` - [Delete a time entry](operations/deletetimetrack.md) — `DELETE /boards/{board}/cards/{card}/time-tracks/{timeTrack}` - [Edit a time entry](operations/updatetimetrack.md) — `PATCH /boards/{board}/cards/{card}/time-tracks/{timeTrack}` ### Checklists - [Create a checklist on a card](operations/createchecklist.md) — `POST /boards/{board}/cards/{card}/checklists` - [Reorder the checklists of a card](operations/reorderchecklists.md) — `POST /boards/{board}/cards/{card}/checklists/reorder` - [Reorder checklist items (within and across checklists)](operations/reorderchecklistitems.md) — `POST /boards/{board}/cards/{card}/checklists/items/reorder` - [Get a checklist with its items](operations/getchecklist.md) — `GET /boards/{board}/cards/{card}/checklists/{checklist}` - [Delete a checklist](operations/deletechecklist.md) — `DELETE /boards/{board}/cards/{card}/checklists/{checklist}` - [Rename a checklist](operations/updatechecklist.md) — `PATCH /boards/{board}/cards/{card}/checklists/{checklist}` - [Add an item to a checklist](operations/createchecklistitem.md) — `POST /boards/{board}/cards/{card}/checklists/{checklist}/items` - [Get a checklist item](operations/getchecklistitem.md) — `GET /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - [Delete a checklist item](operations/deletechecklistitem.md) — `DELETE /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - [Update a checklist item](operations/updatechecklistitem.md) — `PATCH /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - [Convert a checklist item into a card](operations/convertchecklistitemtocard.md) — `POST /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/conversion` - [Attach/detach assignees on a checklist item](operations/syncchecklistitemassignees.md) — `POST /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/assignees/sync` ### Custom Fields - [List a card's custom field values](operations/listcardcustomfields.md) — `GET /boards/{board}/cards/{card}/custom-fields` - [Set several custom field values on a card](operations/bulkupdatecardcustomfields.md) — `PUT /boards/{board}/cards/{card}/custom-fields` - [Clear a custom field value from a card](operations/clearcardcustomfield.md) — `DELETE /boards/{board}/cards/{card}/custom-fields/{definition}` - [Set one custom field value on a card](operations/updatecardcustomfield.md) — `PATCH /boards/{board}/cards/{card}/custom-fields/{definition}` ### Custom Field Definitions - [List a board's custom field definitions](operations/listboardcustomfielddefinitions.md) — `GET /boards/{board}/custom-fields/definitions` - [Create a custom field definition on a board](operations/createboardcustomfielddefinition.md) — `POST /boards/{board}/custom-fields/definitions` - [Reorder a board's custom field definitions](operations/reorderboardcustomfielddefinitions.md) — `PATCH /boards/{board}/custom-fields/definitions/reorder` - [Delete a custom field definition](operations/deleteboardcustomfielddefinition.md) — `DELETE /boards/{board}/custom-fields/definitions/{definition}` - [Update a custom field definition](operations/updateboardcustomfielddefinition.md) — `PATCH /boards/{board}/custom-fields/definitions/{definition}` - [List global custom field definitions](operations/listglobalcustomfielddefinitions.md) — `GET /custom-fields/definitions/global` - [Create a global custom field definition](operations/createglobalcustomfielddefinition.md) — `POST /custom-fields/definitions/global` - [Reorder global custom field definitions](operations/reorderglobalcustomfielddefinitions.md) — `PATCH /custom-fields/definitions/global/reorder` - [Delete a global custom field definition](operations/deleteglobalcustomfielddefinition.md) — `DELETE /custom-fields/definitions/global/{definition}` - [Update a global custom field definition](operations/updateglobalcustomfielddefinition.md) — `PATCH /custom-fields/definitions/global/{definition}` ### Tags - [Create a board tag](operations/createboardtag.md) — `POST /boards/{board}/tags` - [Get a board tag](operations/getboardtag.md) — `GET /boards/{board}/tags/{tag}` - [Delete a board tag](operations/deleteboardtag.md) — `DELETE /boards/{board}/tags/{tag}` - [Update a board tag](operations/updateboardtag.md) — `PATCH /boards/{board}/tags/{tag}` - [Create a common (tenant-wide) tag](operations/createcommontag.md) — `POST /tags/common` - [Get a common tag](operations/getcommontag.md) — `GET /tags/common/{tag}` - [Delete a common tag](operations/deletecommontag.md) — `DELETE /tags/common/{tag}` - [Update a common tag](operations/updatecommontag.md) — `PATCH /tags/common/{tag}` ### Contact Links - [List contacts linked to a board](operations/listboardcontactlinks.md) — `GET /boards/{board}/link/contacts` - [Link/unlink contacts on a board](operations/updateboardcontactlinks.md) — `PATCH /boards/{board}/link/contacts` - [List contacts linked to a card](operations/listcardcontactlinks.md) — `GET /boards/{board}/cards/{card}/link/contacts` - [Link/unlink contacts on a card](operations/updatecardcontactlinks.md) — `PATCH /boards/{board}/cards/{card}/link/contacts` ### Dashboard - [Get a user's upcoming tasks](operations/getuserdashboard.md) — `GET /users/{user}/dashboard` --- # Health check `GET /ping` - **Operation ID:** `ping` - **Tags:** Service - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/ping`) Public liveness probe. Requires no authentication. ## Authentication None (public endpoint). ## Responses ### 200 — Service is up. **Content type:** `application/json` ```yaml # object pong: boolean ``` **Example:** ```json { "pong": true } ``` --- # List boards the caller is a member of `GET /boards` - **Operation ID:** `listBoards` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards`) Returns every board the authenticated user is a member of, as a flat array. When `board_id` is given, that board and all of its descendants are excluded from the result (useful to pick a new parent for a board without creating a cycle). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board_id` | query | integer | no | Exclude this board and all of its descendant boards from the result. Must reference an existing board. | ## Responses ### 200 — Boards the user belongs to. **Content type:** `application/json` ```yaml # array # each item: # object id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` **Example:** ```json [ { "id": 42, "user_id": 7, "group_id": null, "cuid": "a1b2c3d4-0000-4111-8222-333344445555", "name": "Website Redesign", "description": "Q3 marketing site refresh", "icon": "🎨", "parent_id": null, "archived_at": null, "visibility": "private", "order_cards_by": "order", "order_cards_direction": "asc", "created_at": "2026-03-10T17:09:05.000000Z", "updated_at": "2026-03-10T17:09:05.000000Z", "deleted_at": null } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` --- # Create a board `POST /boards` - **Operation ID:** `createBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards`) Creates a board owned by the authenticated user, attaches the listed members with their permission levels, and optionally seeds columns from a project template. Members receive an in-app notification. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 80 description: string|null # maxLength: 600 icon: string|null # maxLength: 14. Emoji used as the board icon. parent_id: integer|null # Id of an existing board to nest this board under. user_permissions: object # required. Map of user id → permission level for the initial members. Use `none` to skip a user. The creator is always the owner. template: string|null # Optional project template used to seed the board's columns. ``` **Example:** ```json { "name": "Website Redesign", "description": "Q3 marketing site refresh", "icon": "🎨", "parent_id": null, "user_permissions": { "8": "edit", "9": "manage" } } ``` ## Responses ### 200 — The created board. **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get the caller's boards as a tree `GET /boards/tree` - **Operation ID:** `getBoardTree` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/tree`) Returns the boards the user can edit or manage (including owned boards) as a nested tree of `{id, name, icon, children}` nodes. Useful to render a project picker. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Nested board tree. **Content type:** `application/json` ```yaml # object data: array # each item: id: integer name: string icon: string|null children: array ``` **Example:** ```json { "data": [ { "id": 42, "name": "Website Redesign", "icon": "🎨", "children": [ { "id": 51, "name": "Landing pages", "icon": "📄", "children": [] } ] } ] } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` --- # Reorder the caller's board list `PATCH /boards/order` - **Operation ID:** `updateBoardOrder` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/order`) Persists the personal display order of the caller's boards (the sidebar order). Affects only the authenticated user. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object board_ids: array # required. Board ids in the desired display order. ``` **Example:** ```json { "board_ids": [ 42, 51, 12 ] } ``` ## Responses ### 204 — Order saved. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get selected fields for a batch of boards `GET /boards/info/batch` - **Operation ID:** `getBoardsInfoBatch` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/info/batch`) Returns lightweight info for up to a batch of boards by id, restricted to boards the caller is a member of (inaccessible ids are silently omitted). By default returns `id`, `name`, `icon` and `cuid`; use `options[fields][]` to choose fields and `options[with][]=parent` to embed the parent board's `{id, name, icon}`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `ids[]` | query | array | yes | Board ids to fetch. | | `options[fields][]` | query | array | no | Fields to include (id is always included). | | `options[with][]` | query | array | no | Relations to embed. | ## Responses ### 200 — Requested boards (accessible ones only). **Content type:** `application/json` ```yaml # object boards: array ``` **Example:** ```json { "boards": [ { "id": 42, "name": "Website Redesign", "icon": "🎨", "cuid": "a1b2c3d4-0000-4111-8222-333344445555" } ] } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a board with its full working set `GET /boards/{board}` - **Operation ID:** `getBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}`) Returns the board with its members, tags, columns, cards, custom field definitions, plus the caller's permissions and per-board preferences — everything needed to render the kanban view. When `attributes[]` is given, returns only those board attributes instead (wrapped in a `board` key). Requires `view` permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `attributes[]` | query | array | no | Return only these board attributes (must be valid board attribute names). | ## Responses ### 200 — Full board payload (or partial when `attributes[]` was used). **Content type:** `application/json` ```yaml # any of: # option 1: object id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null members: object # Map of user id → member (with `pivot` membership info). tags: object # Map of tag id → tag (board tags plus common tags). columns: object # Map of column id → column. cards: array # The board's cards (listing attributes). # each item: id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean cards_summary: object # Per-card counters (present on search responses). custom_field_definitions: array # each item: id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null permissions: object # The caller's effective abilities on this board (ability → boolean). preferences: object # The caller's per-board preferences. view_mode: string # enum: "view_kanban", "view_list" notification: object notification_mode: string # enum: "all", "assignee", "mentions", "silent" is_notified_through_app: boolean is_notified_through_email: boolean # option 2: object board: object # required ``` **Example (full):** ```json { "id": 42, "user_id": 7, "group_id": null, "cuid": "a1b2c3d4-0000-4111-8222-333344445555", "name": "Website Redesign", "description": null, "icon": "🎨", "parent_id": null, "archived_at": null, "visibility": "private", "order_cards_by": "order", "order_cards_direction": "asc", "created_at": "2026-03-10T17:09:05.000000Z", "updated_at": "2026-03-10T17:09:05.000000Z", "deleted_at": null, "members": { "7": { "id": 7, "uuid": "0b0d2f1e-6a3c-4f7d-9a21-7c1f2e3d4a5b", "name": "Jane Doe", "avatar_url": "https://cdn.example/avatars/jane.webp", "pivot": { "board_id": 42, "user_id": 7, "permission": "manage", "view_mode": "view_kanban" } } }, "tags": { "88": { "id": 88, "name": "frontend", "description": null, "color": "#52eb00" } }, "columns": { "301": { "id": 301, "board_id": 42, "name": "To do", "description": "", "icon": null, "order": 1, "archived_at": null, "sort_order": null, "color": null } }, "cards": [ { "id": 9001, "board_id": 42, "column_id": 301, "title": "Draft homepage copy", "number": 1, "order": 1, "status": null, "due_date": null } ], "custom_field_definitions": [], "permissions": { "view": true, "interact": true, "edit": true, "manage": true }, "preferences": { "view_mode": "view_kanban", "notification": { "notification_mode": "all", "is_notified_through_app": true, "is_notified_through_email": true } } } ``` **Example (partial):** ```json { "board": { "name": "Website Redesign", "icon": "🎨" } } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a board `DELETE /boards/{board}` - **Operation ID:** `deleteBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}`) Soft-deletes the board **and all of its descendant boards**, recursively. Requires `manage` permission (delete policy). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted board. **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a board `PATCH /boards/{board}` - **Operation ID:** `updateBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}`) Partially updates the board's attributes. Requires `edit` permission; changing `members` or `visibility` requires `manage`. When `members` is sent the full member list is synchronized (users omitted from the list are removed). `visibility` and `members` must be sent together. Attribute changes may notify board members. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # maxLength: 14 parent_id: integer|null # New parent board (must exist; cycles are rejected). visibility: string # enum: "private", "public". Required when `members` is present. Requires `manage` permission. members: array # Full member list to synchronize. Required when `visibility` is present. Requires `manage` permission. # each item: id: integer # required. User id. permission: string # required. enum: "view", "interact", "edit", "manage" ``` **Example:** ```json { "name": "Website Redesign (Q3)", "visibility": "private", "members": [ { "id": 7, "permission": "manage" }, { "id": 8, "permission": "edit" } ] } ``` ## Responses ### 200 — The updated board. **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Search cards and columns within a board `GET /boards/{board}/search` - **Operation ID:** `searchBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/search`) Filters the board's cards and columns by free-text query, tags, assignees, statuses, due-date buckets and custom field values. The response has the same shape as *Get a board* but with `columns` and `cards` restricted to the matches (plus a `cards_summary` with per-card counters). Requires `view` permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `query` | query | string|null | no | Free-text search over card titles/content. | | `by[tags][]` | query | array | no | Only cards having any of these tag ids. | | `by[assignees][]` | query | array | no | Only cards assigned to any of these user ids. | | `by[statuses][]` | query | array | no | Only cards in any of these statuses / due-date statuses. | | `by[dueDate][]` | query | array | no | Due-date buckets to match. | | `by[customFields]` | query | array | no | Custom-field filters, e.g. `by[customFields][0][definitionId]=12&by[customFields][0][operator]=equals&by[customFields][0][value]=High`. | | `scope[archived]` | query | boolean | no | Include archived cards/columns. | | `target` | query | string | no | Restrict matching to one entity type; omit to search cards and columns.. enum: "App\\Models\\Card", "App\\Models\\Column", "App\\Models\\CardTemplate" | ## Responses ### 200 — Board payload restricted to matching columns/cards. **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null members: object # Map of user id → member (with `pivot` membership info). tags: object # Map of tag id → tag (board tags plus common tags). columns: object # Map of column id → column. cards: array # The board's cards (listing attributes). # each item: id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean cards_summary: object # Per-card counters (present on search responses). custom_field_definitions: array # each item: id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null permissions: object # The caller's effective abilities on this board (ability → boolean). preferences: object # The caller's per-board preferences. view_mode: string # enum: "view_kanban", "view_list" notification: object notification_mode: string # enum: "all", "assignee", "mentions", "silent" is_notified_through_app: boolean is_notified_through_email: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Archive a board `POST /boards/{board}/archive` - **Operation ID:** `archiveBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/archive`) Archives the board and, recursively, all of its descendant boards. Requires archive permission (`manage`). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Responses ### 200 — The archived board (`archived_at` set). **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Unarchive a board `POST /boards/{board}/unarchive` - **Operation ID:** `unarchiveBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/unarchive`) Restores an archived board and the descendants archived with it. If the board's parent is still archived, the board is detached to root level. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Responses ### 200 — The restored board (`archived_at` null). **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Duplicate a board `POST /boards/{board}/duplicate` - **Operation ID:** `duplicateBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/duplicate`) Creates a copy of the board (structure and content) owned by the caller. Requires duplicate permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Responses ### 200 — The newly created copy. **Content type:** `application/json` ```yaml # object — A project (kanban board). Boards nest via `parent_id`. id: integer user_id: integer|null # Owner user id. group_id: integer|null cuid: string # Tenant/company identifier the board belongs to. parent_id: integer|null # Parent board id (null for root boards). name: string # maxLength: 80 description: string|null # maxLength: 600 icon: string|null # Emoji icon. visibility: string # enum: "private", "public" order_cards_by: string|null # Default card sort field for new columns. order_cards_direction: string|null # enum: "asc", "desc", null archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Import cards into a board from an external tool `POST /boards/{board}/import` - **Operation ID:** `importBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/import`) Imports a project exported from an external source (currently Trello JSON exports) into this board. Send the export file as multipart form-data. Requires import permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `multipart/form-data` ```yaml # object file: string # required. The export file (`.json` or `.txt`). source: string # required. enum: "TRELLO". Source tool of the export. ``` ## Responses ### 200 — Import result. **Content type:** `application/json` ```yaml # object message: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Export a board as a file download `GET /boards/{board}/export` - **Operation ID:** `exportBoard` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/export`) Exports the board's cards to CSV, Excel or JSON and streams the file as a download. Requires export permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `format` | query | string | yes | enum: "csv", "excel", "json" | | `fields[]` | query | array | yes | Card fields to include in the export. | ## Responses ### 200 — The exported file (content type depends on `format`). **Content type:** `text/csv` ```yaml # string ``` **Content type:** `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` ```yaml # string ``` **Content type:** `application/json` ```yaml # object ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Export a board to Optiwork Drive `POST /boards/{board}/export/drive` - **Operation ID:** `exportBoardToDrive` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/export/drive`) Exports the board (same formats and fields as *Export a board*) and uploads the resulting file to a folder (node) in Optiwork Drive instead of streaming it back. Requires export permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object format: string # required. enum: "csv", "excel", "json" fields: array # required node: object # required. Target Optiwork Drive node (folder) descriptor where the file is uploaded. ``` **Example:** ```json { "format": "csv", "fields": [ "task_title", "list_name", "due_date", "assignees" ], "node": { "id": 12345, "drive_id": 1 } } ``` ## Responses ### 200 — Upload result with the created Drive file metadata. **Content type:** `application/json` ```yaml # object — Drive upload result (file metadata as returned by Optiwork Drive). ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Change a board's visibility `PUT /boards/{board}/visibility` - **Operation ID:** `updateBoardVisibility` - **Tags:** Boards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/visibility`) Switches the board between `private` (members only) and `public` (all tenant users can view). Requires `manage` permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object visibility: string # enum: "private", "public" ``` **Example:** ```json { "visibility": "public" } ``` ## Responses ### 200 — New visibility. **Content type:** `application/json` ```yaml # object visibility: string # enum: "private", "public" ``` **Example:** ```json { "visibility": "public" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List the members of a board `GET /boards/{board}/members` - **Operation ID:** `listBoardMembers` - **Tags:** Board Members - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/members`) Returns all users who are members of the board, including soft-deleted users (so past activity can still be attributed). Membership metadata is in each user's `pivot`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Responses ### 200 — Board members. **Content type:** `application/json` ```yaml # array # each item: # object id: integer uuid: string name: string email: string avatar_url: string|null username: string company_name: string|null role: string|null status: string|null deleted_at: string|null pivot: object # Membership metadata. board_id: integer user_id: integer permission: string # enum: "view", "interact", "edit", "manage" view_mode: string|null # enum: "view_kanban", "view_list", null created_at: string updated_at: string ``` **Example:** ```json [ { "id": 7, "uuid": "0b0d2f1e-6a3c-4f7d-9a21-7c1f2e3d4a5b", "username": "jane.doe@acme.example", "email": "jane.doe@acme.example", "name": "Jane Doe", "company_name": "Acme Corp", "role": "user", "status": "active", "avatar_url": "https://cdn.example/avatars/jane.webp", "deleted_at": null, "pivot": { "board_id": 42, "user_id": 7, "permission": "manage", "view_mode": "view_kanban" } } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Search users that could be added to the board `GET /boards/{board}/members/assignables` - **Operation ID:** `listAssignableUsers` - **Tags:** Board Members - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/members/assignables`) Searches the tenant's users by name or email (excluding the caller) so they can be invited as board members. Returns at most 50 users ordered by name. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `query` | query | string | yes | Name/email search string. | ## Responses ### 200 — Matching users. **Content type:** `application/json` ```yaml # object assignable: array # each item: id: integer uuid: string name: string email: string avatar_url: string|null ``` **Example:** ```json { "assignable": [ { "id": 8, "uuid": "9f8e7d6c-5b4a-3f2e-1d0c-b9a8c7d6e5f4", "name": "John Smith", "email": "john.smith@acme.example" } ] } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Search users that can be @-mentioned on the board `GET /boards/{board}/members/mentionables` - **Operation ID:** `listMentionableUsers` - **Tags:** Board Members - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/members/mentionables`) Returns the board's members (max 50, ordered by name), optionally filtered by a name/email substring — the candidates for @-mentions in card content and comments. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `filter` | query | string|null | no | Name/email substring filter. | ## Responses ### 200 — Mentionable users. **Content type:** `application/json` ```yaml # array # each item: # object id: integer uuid: string name: string email: string avatar_url: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Set the caller's view mode for this board `PATCH /boards/{board}/members/myself/view-mode` - **Operation ID:** `updateMyViewMode` - **Tags:** Board Members - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/members/myself/view-mode`) Persists whether the caller sees this board as a kanban or a list. Affects only the authenticated member. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object viewMode: string # enum: "view_kanban", "view_list" ``` **Example:** ```json { "viewMode": "view_list" } ``` ## Responses ### 200 — The stored view mode. **Content type:** `application/json` ```yaml # object view_mode: string # enum: "view_kanban", "view_list" ``` **Example:** ```json { "view_mode": "view_list" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Set the caller's notification preferences for this board `PATCH /boards/{board}/members/myself/notifications/preferences` - **Operation ID:** `updateMyNotificationPreferences` - **Tags:** Board Members - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/members/myself/notifications/preferences`) Updates which events on this board notify the caller (`all` activity, only cards where they are an `assignee`, only `mentions`, or `silent`) and through which channels (in-app, email). Affects only the authenticated member. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object notification_mode: string # enum: "all", "assignee", "mentions", "silent" is_notified_through_app: boolean is_notified_through_email: boolean ``` **Example:** ```json { "notification_mode": "assignee", "is_notified_through_app": true, "is_notified_through_email": false } ``` ## Responses ### 200 — The stored preference. **Content type:** `application/json` ```yaml # object notification_mode: string # enum: "all", "assignee", "mentions", "silent" is_notified_through_app: boolean is_notified_through_email: boolean ``` **Example:** ```json { "notification_mode": "assignee", "is_notified_through_app": true, "is_notified_through_email": false } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List the columns of a board `GET /boards/{board}/columns` - **Operation ID:** `listColumns` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns`) Returns the board's active (non-archived) columns ordered by position. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Columns. **Content type:** `application/json` ```yaml # array # each item: # object id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` **Example:** ```json [ { "id": 301, "board_id": 42, "name": "To do", "description": "", "icon": null, "order": 1, "sort_order": null, "color": null, "archived_at": null, "created_at": "2026-03-10T17:09:05.000000Z", "updated_at": "2026-03-10T17:09:05.000000Z", "deleted_at": null }, { "id": 302, "board_id": 42, "name": "Doing", "description": "", "icon": null, "order": 2, "sort_order": null, "color": "#3b82f6", "archived_at": null, "created_at": "2026-03-10T17:09:05.000000Z", "updated_at": "2026-03-10T17:09:05.000000Z", "deleted_at": null } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Create a column `POST /boards/{board}/columns` - **Operation ID:** `createColumn` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns`) Adds a column at the end of the board. Requires `edit` permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null ``` **Example:** ```json { "name": "Review", "description": "Awaiting code review", "color": "#8b5cf6" } ``` ## Responses ### 200 — The created column. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Reorder the board's columns `PATCH /boards/{board}/columns/order` - **Operation ID:** `reorderColumns` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/order`) Bulk-updates the position of the board's columns. Every referenced id must belong to the board, otherwise the request fails with `400`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object columnsOrder: array # required # each item: id: integer # required order: integer # required ``` **Example:** ```json { "columnsOrder": [ { "id": 302, "order": 1 }, { "id": 301, "order": 2 } ] } ``` ## Responses ### 200 — The applied order (echo of the request). **Content type:** `application/json` ```yaml # array # each item: # object id: integer order: integer ``` ### 400 — A referenced column does not belong to the board. **Content type:** `application/json` ```yaml # object message: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete several columns at once `POST /boards/{board}/columns/delete/batch` - **Operation ID:** `batchDeleteColumns` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/delete/batch`) Soft-deletes the listed columns. Requires the batch-delete permission on the board. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object ids: array # required. Ids to operate on. ``` **Example:** ```json { "ids": [ 301, 305 ] } ``` ## Responses ### 200 — The deleted columns. **Content type:** `application/json` ```yaml # array # each item: # object id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Unarchive several columns at once `POST /boards/{board}/columns/unarchive/batch` - **Operation ID:** `batchUnarchiveColumns` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/unarchive/batch`) Restores the listed archived columns. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object ids: array # required. Ids to operate on. ``` **Example:** ```json { "ids": [ 303, 304 ] } ``` ## Responses ### 200 — The restored columns. **Content type:** `application/json` ```yaml # array # each item: # object id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete a column `DELETE /boards/{board}/columns/{column}` - **Operation ID:** `deleteColumn` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}`) Soft-deletes the column and its cards from the board view. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted column. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a column `PATCH /boards/{board}/columns/{column}` - **Operation ID:** `updateColumn` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}`) Updates the column's name, description, icon or color. Requires `edit` permission. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null ``` **Example:** ```json { "name": "In review", "color": "#f59e0b" } ``` ## Responses ### 200 — The updated column. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List the cards of a column (slim) `GET /boards/{board}/columns/{column}/cards` - **Operation ID:** `listColumnCards` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}/cards`) Returns the column's cards in display order (pinned first) with a minimal payload — id, column, title, icon and number. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `column` | path | integer | yes | Column id (must belong to the board). | ## Responses ### 200 — Slim card list. **Content type:** `application/json` ```yaml # object data: array # each item: id: integer column_id: integer title: string icon: string|null number: integer ``` **Example:** ```json { "data": [ { "id": 9001, "column_id": 301, "title": "Draft homepage copy", "icon": null, "number": 1 }, { "id": 9002, "column_id": 301, "title": "Choose hero image", "icon": "🖼️", "number": 2 } ] } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Archive a column `POST /boards/{board}/columns/{column}/archive` - **Operation ID:** `archiveColumn` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}/archive`) Archives the column (and hides its cards from the active board view). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `column` | path | integer | yes | Column id (must belong to the board). | ## Responses ### 200 — The archived column. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Unarchive a column `POST /boards/{board}/columns/{column}/unarchive` - **Operation ID:** `unarchiveColumn` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}/unarchive`) Restores an archived column to the active board view. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `column` | path | integer | yes | Column id (must belong to the board). | ## Responses ### 200 — The restored column. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Sort a column's cards by a predefined criterion `POST /boards/{board}/columns/{column}/order` - **Operation ID:** `sortColumnCards` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}/order`) Re-ranks all ordinary cards in the column by the chosen criterion (`oldest`/`newest` creation date, or `due_date`). Pinned cards keep their pinned status. Broadcasts the new order to other connected clients. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `column` | path | integer | yes | Column id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object order_option: string # required. enum: "oldest", "newest", "due_date" ``` **Example:** ```json { "order_option": "due_date" } ``` ## Responses ### 200 — The column after sorting. **Content type:** `application/json` ```yaml # object — A task list within a board. id: integer board_id: integer name: string # maxLength: 80 description: string|null # maxLength: 300 icon: string|null # maxLength: 255 color: string|null # enum: "#ef4444", "#f97316", "#f59e0b", "#84cc16", "#10b981", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", null. Column accent color (fixed palette). order: integer # Position within the board. sort_order: string|null # Sticky automatic card sort applied to this column, when set. archived_at: string|null created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Move / reorder cards within or into a column `PATCH /boards/{board}/columns/{column}/cards/order` - **Operation ID:** `moveCards` - **Tags:** Columns - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/columns/{column}/cards/order`) Bulk-positions cards inside the column identified in the path — this is the drag-and-drop endpoint, used both for reordering within a column and for moving a card from another column of the same board (send the card's id with its new `order` and `column_id`). All referenced cards must exist and belong to a single board, otherwise the request fails with `400`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `column` | path | integer | yes | Column id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object cardsOrder: array # required # each item: id: integer # required. Card id. order: integer # required. New position within the column. column_id: integer # Target column (when moving between columns). ``` **Example:** ```json { "cardsOrder": [ { "id": 9002, "order": 1, "column_id": 302 }, { "id": 9001, "order": 2, "column_id": 302 } ] } ``` ## Responses ### 200 — The applied order (echo of the request). **Content type:** `application/json` ```yaml # array # items: object ``` ### 400 — Referenced cards missing or spanning multiple boards. **Content type:** `application/json` ```yaml # object message: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Create a card `POST /boards/{board}/cards` - **Operation ID:** `createCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards`) Creates a card (task) in one of the board's columns. Optionally applies a card template, sets a due date, cover color and rich-text content. @-mentions inside `content` trigger notifications. Requires `edit` permission (create policy). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object column_id: integer # required. Target column (must exist). title: string # required. maxLength: 255 content: string|null # Rich-text card description (serialized editor document, JSON string). type: string|null # enum: "ORDINARY", null. Card type; only `ORDINARY` can be created directly. status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer|null # Position within the column. due_date: string|null template_id: integer|null # Card template to apply (must be visible on this board). cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null source: string|null # Originating Optiwork app nickname when the card is created from another app (e.g. `mail`). ``` **Example:** ```json { "column_id": 301, "title": "Draft homepage copy", "content": "{}", "due_date": "2026-08-01T12:00:00Z", "cover_color": "#3b82f6" } ``` ## Responses ### 200 — The created card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete several cards at once `POST /boards/{board}/cards/delete/batch` - **Operation ID:** `batchDeleteCards` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/delete/batch`) Soft-deletes the listed cards. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object ids: array # required. Ids to operate on. ``` **Example:** ```json { "ids": [ 9001, 9002 ] } ``` ## Responses ### 204 — Cards deleted. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Unarchive several cards at once `POST /boards/{board}/cards/unarchive/batch` - **Operation ID:** `batchUnarchiveCards` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/unarchive/batch`) Restores the listed archived cards. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object ids: array # required. Ids to operate on. ``` **Example:** ```json { "ids": [ 9003 ] } ``` ## Responses ### 204 — Cards restored. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a card `GET /boards/{board}/cards/{card}` - **Operation ID:** `getCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}`) Returns the full card, including derived attributes: tag/assignee id lists, comment/file/custom-field counters, due-date status and human-readable due-date strings, and whether the caller has a running timer on it. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` **Example:** ```json { "id": 9001, "board_id": 42, "column_id": 301, "user_id": 7, "title": "Draft homepage copy", "content": "{}", "type": "ORDINARY", "status": null, "icon": null, "order": 1, "number": 1, "due_date": "2026-08-01T12:00:00.000000Z", "due_date_hash": "b2c3d4e5-1111-4222-8333-444455556666", "pinned_at": null, "completed_at": null, "archived_at": null, "deleted_at": null, "checklist_id": null, "checklist_items": null, "checklist_items_completed": null, "card_recurrence_id": null, "cover_color": null, "created_at": "2026-03-10T17:09:49.000000Z", "updated_at": "2026-03-10T17:14:28.000000Z", "tags_ids": [ "88" ], "assignees_ids": [ "7" ], "is_time_tracking": null, "comments_count": 0, "files_count": 0, "custom_fields_count": 0, "human_due_date": "Aug 1, 2026", "short_locale_date": "08/01/2026", "human_verbose_due_date": "August 1, 2026 12:00 PM", "due_date_status": "FAR", "is_completed": false, "is_recurrent": false } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a card `DELETE /boards/{board}/cards/{card}` - **Operation ID:** `deleteCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}`) Soft-deletes the card. If the card is part of a recurrence series, pass `stop_recurrence: true` to also stop the series. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body **Content type:** `application/json` ```yaml # object stop_recurrence: boolean|null # Also stop the card's recurrence series. ``` **Example:** ```json { "stop_recurrence": true } ``` ## Responses ### 200 — The deleted card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Update a card `PATCH /boards/{board}/cards/{card}` - **Operation ID:** `updateCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}`) Partially updates the card. Moving the card is possible by sending `column_id` (and `board_id` for cross-board moves). Setting `completed_at` marks the card complete. @-mentions added to `content` trigger notifications. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object title: string # maxLength: 255 content: string|null board_id: integer|null # Target board when moving across boards. column_id: integer|null # Target column when moving. status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer|null due_date: string|null completed_at: string|null template_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null ``` **Example:** ```json { "title": "Draft homepage copy (v2)", "due_date": "2026-08-05T12:00:00Z" } ``` ## Responses ### 200 — The updated card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Archive a card `POST /boards/{board}/cards/{card}/archive` - **Operation ID:** `archiveCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/archive`) Sets the card's status to `ARCHIVED` and hides it from the active board view. Broadcast to other connected clients. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Responses ### 200 — The archived card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Unarchive a card `POST /boards/{board}/cards/{card}/unarchive` - **Operation ID:** `unarchiveCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/unarchive`) Restores an archived card to its column. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Responses ### 200 — The restored card. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Duplicate a card in place `POST /boards/{board}/cards/{card}/copy` - **Operation ID:** `copyCard` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/copy`) Creates a copy of the card in the same column (content, tags, assignees and checklists included). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Responses ### 200 — The new copy. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Get selected fields for a batch of cards (cross-board) `GET /cards/info/batch` - **Operation ID:** `getCardsInfoBatch` - **Tags:** Cards - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/cards/info/batch`) Returns lightweight info for cards by id across all boards the caller is a member of (inaccessible ids are silently omitted). By default returns `id`, `title` and `number`; use `options[fields][]` to choose fields and `options[with][]` to embed the parent `board` (`{id, name, icon}`) or `column` (`{id, name}`). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `ids[]` | query | array | yes | Card ids to fetch. | | `options[fields][]` | query | array | no | Fields to include (id is always included). | | `options[with][]` | query | array | no | Relations to embed. | ## Responses ### 200 — Requested cards (accessible ones only). **Content type:** `application/json` ```yaml # object cards: array ``` **Example:** ```json { "cards": [ { "id": 9001, "title": "Draft homepage copy", "number": 1, "board_id": 42, "board": { "id": 42, "name": "Website Redesign", "icon": "🎨" } } ] } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Upload a file to a card `POST /boards/{board}/cards/{card}/files` - **Operation ID:** `uploadCardFile` - **Tags:** Card Files - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/files`) Attaches a file to the card by uploading the binary from the caller's machine (multipart form-data with `blob`). The file is stored in the tenant's Optiwork Drive. Editor media uploads (`is_editor_upload: true`) are restricted to an image/video allow-list with per-type size limits. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `multipart/form-data` ```yaml # object name: string # required. File name. size_bytes: integer # required. File size in bytes. mime_type: string # required. File MIME type. blob: string # required. The file content. is_editor_upload: boolean # Set when uploading media from the card's rich-text editor (enables the media allow-list and size limits). ``` ## Responses ### 200 — The created file with access URLs. **Content type:** `application/json` ```yaml # object file: object id: integer identifier: string # Opaque file identifier used in file URLs. download_url: string content_url: string # Inline-content URL (renders in the editor). view_url: string|null # Signed Optiwork Drive viewer URL. ``` **Example:** ```json { "file": { "id": 5001, "identifier": "f0e1d2c3-7777-4888-9999-aaaabbbbcccc", "download_url": "https://projects.work.optidata.cloud/projects/boards/42/cards/9001/files/f0e1d2c3-7777-4888-9999-aaaabbbbcccc/download", "content_url": "https://projects.work.optidata.cloud/projects/boards/42/cards/9001/files/f0e1d2c3-7777-4888-9999-aaaabbbbcccc/content", "view_url": "https://drive.work.optidata.cloud/view/abc123" } } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Attach an existing Optiwork Drive file to a card `POST /boards/{board}/cards/{card}/files/attach` - **Operation ID:** `attachDriveFileToCard` - **Tags:** Card Files - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/files/attach`) Links a file that already lives in the tenant's Optiwork Drive to the card, without uploading new content. Provide the Drive node metadata in `meta` instead of a binary `blob`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required size_bytes: integer # required mime_type: string # required meta: object # required. Optiwork Drive node metadata identifying the file to link. ``` **Example:** ```json { "name": "brand-guidelines.pdf", "size_bytes": 482133, "mime_type": "application/pdf", "meta": { "node_id": 7788, "drive_id": 1 } } ``` ## Responses ### 200 — The linked file with access URLs. **Content type:** `application/json` ```yaml # object file: object id: integer identifier: string # Opaque file identifier used in file URLs. download_url: string content_url: string # Inline-content URL (renders in the editor). view_url: string|null # Signed Optiwork Drive viewer URL. ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Download a card file `GET /boards/{board}/cards/{card}/files/{file}/download` - **Operation ID:** `downloadCardFile` - **Tags:** Card Files - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/files/{file}/download`) Streams the file content from Optiwork Drive as an attachment download. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `file` | path | string | yes | File **identifier** (opaque string, not the numeric id). | ## Responses ### 200 — The file content (Content-Disposition attachment). **Content type:** `application/octet-stream` ```yaml # string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Get a signed view URL for a card file `GET /boards/{board}/cards/{card}/files/{file}/view` - **Operation ID:** `getCardFileViewUrl` - **Tags:** Card Files - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/files/{file}/view`) Returns a short-lived signed URL that renders the file in the Optiwork Drive viewer. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `file` | path | string | yes | File **identifier** (opaque string, not the numeric id). | ## Responses ### 200 — Signed viewer URL. **Content type:** `application/json` ```yaml # object url: string ``` **Example:** ```json { "url": "https://drive.work.optidata.cloud/view/abc123?signature=..." } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a card file `DELETE /boards/{board}/cards/{card}/files/{file}` - **Operation ID:** `deleteCardFile` - **Tags:** Card Files - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/files/{file}`) Removes the file from the card. Blocked with `422` while the card has unsatisfied required custom fields. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `file` | path | string | yes | File **identifier** (opaque string, not the numeric id). | ## Responses ### 200 — Confirmation message. **Content type:** `application/json` ```yaml # string ``` **Example:** ```json "File deleted successfully" ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Attach/detach card assignees `POST /boards/{board}/cards/{card}/assignees/sync` - **Operation ID:** `syncCardAssignees` - **Tags:** Card Assignees & Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/assignees/sync`) Synchronizes the card's assignees from a map of user id → boolean (`true` attaches, `false` detaches). Users not present in the map are left unchanged. Newly attached assignees are notified. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object assignees: object|null # Map of user id → attach (true) / detach (false). ``` **Example:** ```json { "assignees": { "7": true, "8": false } } ``` ## Responses ### 200 — The card after the sync. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Attach/detach card tags `POST /boards/{board}/cards/{card}/tags/sync` - **Operation ID:** `syncCardTags` - **Tags:** Card Assignees & Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/tags/sync`) Synchronizes the card's tags from a map of tag id → boolean (`true` attaches, `false` detaches). Tags not present in the map are left unchanged. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object tags: object|null # Map of tag id → attach (true) / detach (false). ``` **Example:** ```json { "tags": { "88": true, "97": false } } ``` ## Responses ### 200 — The card with its `tags` relation loaded. **Content type:** `application/json` ```yaml # object — A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean tags: array # each item: id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a card's recurrence rule `GET /boards/{board}/cards/{card}/recurrence` - **Operation ID:** `getCardRecurrence` - **Tags:** Card Recurrence - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/recurrence`) Returns the card's active recurrence rule, or `null` when the card does not repeat. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The recurrence (or null). **Content type:** `application/json` ```yaml # object recurrence: oneOf # one of: # option 1: object id: integer original_card_id: integer target_column_id: integer frequency: string # enum: "daily", "weekly", "monthly", "yearly" interval: integer|null # min: 1. max: 99 by_day: array|null by_month_day: array|null by_month: array|null by_set_pos: array|null last_occurrence_at: string|null next_occurrence_at: string|null created_at: string updated_at: string deleted_at: string|null # option 2: null # null ``` **Example:** ```json { "recurrence": null } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Create or update a card's recurrence rule `POST /boards/{board}/cards/{card}/recurrence` - **Operation ID:** `upsertCardRecurrence` - **Tags:** Card Recurrence - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/recurrence`) Defines how often a new occurrence of this card is generated and into which column. If the card already has a rule (even a stopped one), it is updated; otherwise a new rule is created. iCal-style refinements are supported: weekdays (`by_day`), month days (`by_month_day`), months (`by_month`) and monthly positions such as "first Monday" (`by_set_pos`). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object target_column_id: integer # required. Column of this board where generated occurrences are placed. frequency: string # required. enum: "daily", "weekly", "monthly", "yearly" interval: integer|null # min: 1. max: 99. Repeat every N periods (default 1). by_day: array|null # Weekdays the rule fires on. by_month_day: array|null # Days of the month the rule fires on. by_month: array|null # Months the rule fires in (1 = January). by_set_pos: array|null # Position within the month (1 = first ... -1 = last), combined with `by_day`. ``` **Example:** ```json { "target_column_id": 301, "frequency": "weekly", "interval": 1, "by_day": [ "MO", "TH" ] } ``` ## Responses ### 200 — The stored rule. **Content type:** `application/json` ```yaml # object message: string recurrence: object # Repeat rule for a card. id: integer original_card_id: integer target_column_id: integer frequency: string # enum: "daily", "weekly", "monthly", "yearly" interval: integer|null # min: 1. max: 99 by_day: array|null by_month_day: array|null by_month: array|null by_set_pos: array|null last_occurrence_at: string|null next_occurrence_at: string|null created_at: string updated_at: string deleted_at: string|null ``` **Example:** ```json { "message": "Card repetition created successfully.", "recurrence": { "id": 15, "original_card_id": 9001, "target_column_id": 301, "frequency": "weekly", "interval": 1, "by_day": [ "MO", "TH" ], "by_month_day": null, "by_month": null, "by_set_pos": null, "last_occurrence_at": null, "next_occurrence_at": "2026-07-27T00:00:00.000000Z" } } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Stop a card's recurrence `DELETE /boards/{board}/cards/{card}/recurrence` - **Operation ID:** `stopCardRecurrence` - **Tags:** Card Recurrence - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/recurrence`) Stops generating new occurrences. Returns `422` when the card has no active recurrence. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Recurrence stopped. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Card repetition stopped successfully." } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — The card has no active recurrence. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This card does not have an active repetition." } ``` --- # Add a comment to a card `POST /boards/{board}/cards/{card}/comments` - **Operation ID:** `addComment` - **Tags:** Comments - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/comments`) Adds a comment authored by the caller. Requires `interact` permission (comment-create policy). Blocked with `422` while the card has unsatisfied required custom fields. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object content: string # required. Comment body (may contain @-mention markup). ``` **Example:** ```json { "content": "Looks good — ship it 🚀" } ``` ## Responses ### 200 — The created comment. **Content type:** `application/json` ```yaml # object id: integer card_id: integer user_id: integer # Author user id. content: string created_at: string updated_at: string ``` **Example:** ```json { "id": 7001, "card_id": 9001, "user_id": 7, "content": "Looks good — ship it 🚀", "created_at": "2026-07-20T14:05:00.000000Z", "updated_at": "2026-07-20T14:05:00.000000Z" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete a comment `DELETE /boards/{board}/cards/{card}/comments/{comment}` - **Operation ID:** `deleteComment` - **Tags:** Comments - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/comments/{comment}`) Deletes the comment. Only the author (or a board manager) may delete. Blocked with `422` while the card has unsatisfied required custom fields. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted comment. **Content type:** `application/json` ```yaml # object id: integer card_id: integer user_id: integer # Author user id. content: string created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Edit a comment `PATCH /boards/{board}/cards/{card}/comments/{comment}` - **Operation ID:** `updateComment` - **Tags:** Comments - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/comments/{comment}`) Updates the comment body. Only the author (or a board manager) may edit. New @-mentions are notified. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object content: string # required. minLength: 1 ``` **Example:** ```json { "content": "Looks good — ship it today 🚀" } ``` ## Responses ### 200 — The updated comment. **Content type:** `application/json` ```yaml # object id: integer card_id: integer user_id: integer # Author user id. content: string created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Start a timer on a card `POST /boards/{board}/cards/{card}/time-tracks/start` - **Operation ID:** `startTimeTracking` - **Tags:** Time Tracking - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/time-tracks/start`) Starts a running time entry for the caller on this card. Blocked with `422` while the card has unsatisfied required custom fields. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Responses ### 200 — Timer started. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Time tracking started" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Stop the running timer on a card `POST /boards/{board}/cards/{card}/time-tracks/stop` - **Operation ID:** `stopTimeTracking` - **Tags:** Time Tracking - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/time-tracks/stop`) Stops the card's open time entry, computes the tracked seconds and logs a "clocked" interaction on the card. Returns `404` when no timer is running. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Responses ### 200 — Timer stopped. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Time tracking stopped" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — No running timer on this card (or board/card not found). **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Time tracking not found" } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete a time entry `DELETE /boards/{board}/cards/{card}/time-tracks/{timeTrack}` - **Operation ID:** `deleteTimeTrack` - **Tags:** Time Tracking - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/time-tracks/{timeTrack}`) Deletes the time entry and returns the card's recomputed total. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted entry plus the card's recomputed total. **Content type:** `application/json` ```yaml # object time_track: object # A time entry on a card. `end_at` null means the timer is running. id: integer board_id: integer card_id: integer user_id: integer start_at: string end_at: string|null amount_seconds: integer|null # Tracked duration in seconds (set when stopped). description: string|null # maxLength: 255 created_at: string updated_at: string total_time_spent: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Edit a time entry `PATCH /boards/{board}/cards/{card}/time-tracks/{timeTrack}` - **Operation ID:** `updateTimeTrack` - **Tags:** Time Tracking - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/time-tracks/{timeTrack}`) Adjusts a finished time entry's start/end (and optional description). The entry must stay in the past, start before it ends, and must not overlap the caller's neighbouring entries on the same card — violations return `422`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object start_at: string # required end_at: string # required description: string|null # maxLength: 255 ``` **Example:** ```json { "start_at": "2026-07-20T09:00:00Z", "end_at": "2026-07-20T10:30:00Z", "description": "Homepage wireframes" } ``` ## Responses ### 200 — The updated entry plus the card's recomputed total. **Content type:** `application/json` ```yaml # object time_track: object # A time entry on a card. `end_at` null means the timer is running. id: integer board_id: integer card_id: integer user_id: integer start_at: string end_at: string|null amount_seconds: integer|null # Tracked duration in seconds (set when stopped). description: string|null # maxLength: 255 created_at: string updated_at: string total_time_spent: string # Human-readable total tracked time on the card. ``` **Example:** ```json { "time_track": { "id": 610, "board_id": 42, "card_id": 9001, "user_id": 7, "start_at": "2026-07-20T09:00:00.000000Z", "end_at": "2026-07-20T10:30:00.000000Z", "amount_seconds": 5400, "description": "Homepage wireframes" }, "total_time_spent": "1h 30min" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Create a checklist on a card `POST /boards/{board}/cards/{card}/checklists` - **Operation ID:** `createChecklist` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists`) Adds a titled checklist to the card. All checklist endpoints require `update` permission on the card. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object title: string # required. maxLength: 255 ``` **Example:** ```json { "title": "Launch checklist" } ``` ## Responses ### 201 — The created checklist (with empty items). **Content type:** `application/json` ```yaml # object id: integer card_id: integer title: string # maxLength: 255 items: array # each item: id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string items_count: integer items_completed_count: integer created_at: string ``` **Example:** ```json { "id": 120, "card_id": 9001, "title": "Launch checklist", "items": [], "items_count": 0, "items_completed_count": 0, "created_at": "2026-07-20T14:00:00.000000Z" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Reorder the checklists of a card `POST /boards/{board}/cards/{card}/checklists/reorder` - **Operation ID:** `reorderChecklists` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/reorder`) Persists the display order of the card's checklists. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object checklist_ids: array # required. Checklist ids in the desired order (no duplicates). ``` **Example:** ```json { "checklist_ids": [ 121, 120 ] } ``` ## Responses ### 204 — Order saved. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Reorder checklist items (within and across checklists) `POST /boards/{board}/cards/{card}/checklists/items/reorder` - **Operation ID:** `reorderChecklistItems` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/items/reorder`) Bulk-positions checklist items; an item may be moved to a different checklist of the same card by sending a new `checklist_id`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | ## Request body (required) **Content type:** `application/json` ```yaml # object items: array # required # each item: id: integer # required. Checklist item id. checklist_id: integer # required. Target checklist. order: integer # required. min: 0 ``` **Example:** ```json { "items": [ { "id": 501, "checklist_id": 120, "order": 0 }, { "id": 502, "checklist_id": 121, "order": 0 } ] } ``` ## Responses ### 204 — Order saved. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a checklist with its items `GET /boards/{board}/cards/{card}/checklists/{checklist}` - **Operation ID:** `getChecklist` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}`) Returns the checklist with its items and completion counters. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The checklist. **Content type:** `application/json` ```yaml # object id: integer card_id: integer title: string # maxLength: 255 items: array # each item: id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string items_count: integer items_completed_count: integer created_at: string ``` **Example:** ```json { "id": 120, "card_id": 9001, "title": "Launch checklist", "items": [ { "id": 501, "checklist_id": 120, "title": "Update DNS records", "is_completed": false, "completed_at": null, "due_date": null, "due_date_status": null, "human_due_date": null, "short_locale_date": null, "assignees": [], "created_at": "2026-07-20T14:02:00.000000Z" } ], "items_count": 1, "items_completed_count": 0, "created_at": "2026-07-20T14:00:00.000000Z" } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a checklist `DELETE /boards/{board}/cards/{card}/checklists/{checklist}` - **Operation ID:** `deleteChecklist` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}`) Deletes the checklist and all of its items. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 204 — Checklist deleted. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Rename a checklist `PATCH /boards/{board}/cards/{card}/checklists/{checklist}` - **Operation ID:** `updateChecklist` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}`) Updates the checklist title. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object title: string # required. maxLength: 255 ``` **Example:** ```json { "title": "Go-live checklist" } ``` ## Responses ### 200 — The updated checklist. **Content type:** `application/json` ```yaml # object id: integer card_id: integer title: string # maxLength: 255 items: array # each item: id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string items_count: integer items_completed_count: integer created_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Add an item to a checklist `POST /boards/{board}/cards/{card}/checklists/{checklist}/items` - **Operation ID:** `createChecklistItem` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items`) Appends an item, optionally with a due date and assignees (map of user id → boolean). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `checklist` | path | integer | yes | Checklist id (must belong to the card). | ## Request body (required) **Content type:** `application/json` ```yaml # object title: string # required. maxLength: 255 due_date: string|null assignees: object|null # Map of user id → attach (true) / detach (false). ``` **Example:** ```json { "title": "Update DNS records", "due_date": "2026-08-01T12:00:00Z", "assignees": { "8": true } } ``` ## Responses ### 201 — The created item. **Content type:** `application/json` ```yaml # object id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a checklist item `GET /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - **Operation ID:** `getChecklistItem` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}`) Returns a single checklist item. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The item. **Content type:** `application/json` ```yaml # object id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a checklist item `DELETE /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - **Operation ID:** `deleteChecklistItem` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}`) Removes the item from the checklist. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 204 — Item deleted. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a checklist item `PATCH /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}` - **Operation ID:** `updateChecklistItem` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}`) Updates the item's title, completion state, due date and/or assignees. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object title: string # maxLength: 255 is_completed: boolean due_date: string|null assignees: object|null ``` **Example:** ```json { "is_completed": true } ``` ## Responses ### 200 — The updated item. **Content type:** `application/json` ```yaml # object id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Convert a checklist item into a card `POST /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/conversion` - **Operation ID:** `convertChecklistItemToCard` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/conversion`) Promotes the checklist item to a standalone card on the board and links it to the original card with a parent-task relationship. Returns `422` when the target is not a checklist item. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `checklist` | path | integer | yes | Checklist id (must belong to the card). | | `checklistItem` | path | integer | yes | Checklist item id (must belong to the checklist). | ## Responses ### 200 — The promoted card and the created relationship. **Content type:** `application/json` ```yaml # object card: object # A task. Derived attributes (`tags_ids`, `assignees_ids`, `*_count`, `human_*`, `due_date_status`, `is_time_tracking`) are present on single card reads; list contexts may return a subset of attributes. id: integer board_id: integer column_id: integer user_id: integer|null # Creator user id. title: string # maxLength: 255 content: string|null # Rich-text description (serialized editor document, JSON string). type: string # enum: "ORDINARY", "CHECKLIST_ITEM" status: string|null # enum: "OPEN", "CLOSED", "ARCHIVED", null icon: string|null order: integer # Position within its column. number: integer # Sequential card number within the board. due_date: string|null due_date_hash: string|null # Opaque id tied to the current due date (used for calendar sync). pinned_at: string|null completed_at: string|null archived_at: string|null deleted_at: string|null checklist_id: integer|null # Owning checklist (checklist-item cards only). checklist_items: integer|null # Cached count of checklist items on this card. checklist_items_completed: integer|null card_recurrence_id: integer|null cover_color: string|null # enum: "#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#6b7280", "#000000", null created_at: string updated_at: string tags_ids: array|null # Ids of the card's tags (as strings; may contain null when empty). assignees_ids: array|null # Ids of the card's assignees (as strings; may contain null when empty). is_time_tracking: boolean|integer|null # Truthy when the caller has a running timer on this card. comments_count: integer files_count: integer custom_fields_count: integer due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null # Localized short due date (e.g. Aug 1, 2026). short_locale_date: string|null human_verbose_due_date: string|null is_completed: boolean is_recurrent: boolean relationship: object # The parent-task relationship created between the original card and the new card. ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Attach/detach assignees on a checklist item `POST /boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/assignees/sync` - **Operation ID:** `syncChecklistItemAssignees` - **Tags:** Checklists - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/checklists/{checklist}/items/{checklistItem}/assignees/sync`) Same contract as card assignee sync — a map of user id → boolean. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | | `card` | path | integer | yes | Card id (must belong to the board). | | `checklist` | path | integer | yes | Checklist id (must belong to the card). | | `checklistItem` | path | integer | yes | Checklist item id (must belong to the checklist). | ## Request body (required) **Content type:** `application/json` ```yaml # object assignees: object|null ``` **Example:** ```json { "assignees": { "8": true } } ``` ## Responses ### 200 — The item with its assignees. **Content type:** `application/json` ```yaml # object id: integer checklist_id: integer title: string # maxLength: 255 is_completed: boolean completed_at: string|null due_date: string|null due_date_status: string|null # enum: "OVERDUE", "NEAR", "FAR", null human_due_date: string|null short_locale_date: string|null assignees: array # each item: id: integer uuid: string name: string avatar_url: string|null created_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List a card's custom field values `GET /boards/{board}/cards/{card}/custom-fields` - **Operation ID:** `listCardCustomFields` - **Tags:** Custom Fields - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/custom-fields`) Returns the card's stored custom field values (active definitions only), each with its `definition` embedded. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Custom field values. **Content type:** `application/json` ```yaml # array # each item: # object id: integer card_id: integer definition_id: integer value_text: string|null value_integer: integer|null value_decimal: number|null value_datetime: string|null value_boolean: boolean|null value_json: any definition: object # Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null created_at: string updated_at: string ``` **Example:** ```json [ { "id": 800, "card_id": 9001, "definition_id": 12, "value_text": "High", "value_integer": null, "value_decimal": null, "value_datetime": null, "value_boolean": null, "value_json": null, "definition": { "id": 12, "board_id": 42, "name": "Priority", "type": "select", "description": null, "config": { "options": [ { "id": "opt-1", "label": "High", "color": "#ef4444" }, { "id": "opt-2", "label": "Low", "color": "#22c55e" } ] }, "order": 0, "is_required": false, "is_active": true, "is_global": false } } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Set several custom field values on a card `PUT /boards/{board}/cards/{card}/custom-fields` - **Operation ID:** `bulkUpdateCardCustomFields` - **Tags:** Custom Fields - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/custom-fields`) Upserts multiple custom field values in one call. Each `definition_id` must be an active definition of this board. Value types are validated against each definition's field type (text, number, select option id, checkbox boolean, date, person user id). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object fields: array # required # each item: definition_id: integer # required value: any # New value; type depends on the definition's field type. Null clears the value. ``` **Example:** ```json { "fields": [ { "definition_id": 12, "value": "opt-1" }, { "definition_id": 13, "value": 8 } ] } ``` ## Responses ### 200 — The updated values. **Content type:** `application/json` ```yaml # array # each item: # object id: integer card_id: integer definition_id: integer value_text: string|null value_integer: integer|null value_decimal: number|null value_datetime: string|null value_boolean: boolean|null value_json: any definition: object # Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Clear a custom field value from a card `DELETE /boards/{board}/cards/{card}/custom-fields/{definition}` - **Operation ID:** `clearCardCustomField` - **Tags:** Custom Fields - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/custom-fields/{definition}`) Removes the stored value for this definition from the card. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 204 — Value cleared. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Set one custom field value on a card `PATCH /boards/{board}/cards/{card}/custom-fields/{definition}` - **Operation ID:** `updateCardCustomField` - **Tags:** Custom Fields - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/custom-fields/{definition}`) Upserts the value of a single custom field. The value type must match the definition's field type; mismatches return `422`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object value: any # New value; type depends on the definition's field type. Null clears the value. ``` **Example:** ```json { "value": "opt-1" } ``` ## Responses ### 200 — The stored value. **Content type:** `application/json` ```yaml # object — A stored custom field value. Exactly one `value_*` column is populated, matching the definition's type. id: integer card_id: integer definition_id: integer value_text: string|null value_integer: integer|null value_decimal: number|null value_datetime: string|null value_boolean: boolean|null value_json: any definition: object # Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List a board's custom field definitions `GET /boards/{board}/custom-fields/definitions` - **Operation ID:** `listBoardCustomFieldDefinitions` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/custom-fields/definitions`) Returns the board's active custom field definitions in display order. Pass `include_inactive=1` to also return deactivated definitions. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `include_inactive` | query | boolean | no | default: false | ## Responses ### 200 — Definitions. **Content type:** `application/json` ```yaml # array # each item: # object id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Create a custom field definition on a board `POST /boards/{board}/custom-fields/definitions` - **Operation ID:** `createBoardCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/custom-fields/definitions`) Defines a new custom field for this board's cards. `name` must be unique within the board. `config` is type-specific (e.g. select options, number format, text max length) and is validated against the chosen `type`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 60. minLength: 1. Unique within the board (or among global definitions). type: string # required. enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration; validated against the chosen `type`. is_required: boolean # default: false ``` **Example:** ```json { "name": "Priority", "type": "select", "description": "Business priority of the task", "is_required": false, "config": { "options": [ { "label": "High", "color": "#ef4444" }, { "label": "Low", "color": "#22c55e" } ] } } ``` ## Responses ### 201 — The created definition. **Content type:** `application/json` ```yaml # object — Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Reorder a board's custom field definitions `PATCH /boards/{board}/custom-fields/definitions/reorder` - **Operation ID:** `reorderBoardCustomFieldDefinitions` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/custom-fields/definitions/reorder`) Persists the display order of the board's definitions. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object definition_ids: array # required ``` **Example:** ```json { "definition_ids": [ 13, 12 ] } ``` ## Responses ### 204 — Order saved. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete a custom field definition `DELETE /boards/{board}/custom-fields/definitions/{definition}` - **Operation ID:** `deleteBoardCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/custom-fields/definitions/{definition}`) Soft-deletes the definition; existing stored values stop being shown on cards. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 204 — Definition deleted. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a custom field definition `PATCH /boards/{board}/custom-fields/definitions/{definition}` - **Operation ID:** `updateBoardCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/custom-fields/definitions/{definition}`) Updates the definition's name, description, config, required flag or active flag. The field `type` (and `board_id`) cannot be changed — sending them returns `422`. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object — Partial update. `type` and `board_id` are immutable (sending them fails validation). name: string # maxLength: 60. minLength: 1 description: string|null # maxLength: 250 config: object|null is_required: boolean is_active: boolean ``` **Example:** ```json { "name": "Business priority", "is_required": true } ``` ## Responses ### 200 — The updated definition. **Content type:** `application/json` ```yaml # object — Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List global custom field definitions `GET /custom-fields/definitions/global` - **Operation ID:** `listGlobalCustomFieldDefinitions` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/custom-fields/definitions/global`) Returns tenant-wide (global) definitions that apply to every board. Pass `include_inactive=1` to include deactivated ones. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `include_inactive` | query | boolean | no | default: false | ## Responses ### 200 — Global definitions (`board_id` is null, `is_global` true). **Content type:** `application/json` ```yaml # array # each item: # object id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` **Example:** ```json [ { "id": 95, "board_id": null, "name": "Cost center", "type": "text", "description": null, "config": { "multiline": false, "max_length": 500, "placeholder": null, "default_value": null }, "order": 0, "is_required": false, "is_active": true, "is_global": true, "created_at": "2026-03-18T17:53:13.000000Z", "updated_at": "2026-03-31T20:01:55.000000Z", "deleted_at": null } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` --- # Create a global custom field definition `POST /custom-fields/definitions/global` - **Operation ID:** `createGlobalCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/custom-fields/definitions/global`) Defines a tenant-wide custom field, available on all boards. `name` must be unique among global definitions. Restricted to administrators. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 60. minLength: 1. Unique within the board (or among global definitions). type: string # required. enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration; validated against the chosen `type`. is_required: boolean # default: false ``` **Example:** ```json { "name": "Cost center", "type": "text", "config": { "multiline": false, "max_length": 500 } } ``` ## Responses ### 201 — The created definition. **Content type:** `application/json` ```yaml # object — Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Reorder global custom field definitions `PATCH /custom-fields/definitions/global/reorder` - **Operation ID:** `reorderGlobalCustomFieldDefinitions` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/custom-fields/definitions/global/reorder`) Persists the display order of the tenant's global definitions. Restricted to administrators. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object definition_ids: array # required ``` **Example:** ```json { "definition_ids": [ 152, 95 ] } ``` ## Responses ### 204 — Order saved. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Delete a global custom field definition `DELETE /custom-fields/definitions/global/{definition}` - **Operation ID:** `deleteGlobalCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/custom-fields/definitions/global/{definition}`) Soft-deletes the global definition across all boards. Restricted to administrators. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 204 — Definition deleted. No content. ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a global custom field definition `PATCH /custom-fields/definitions/global/{definition}` - **Operation ID:** `updateGlobalCustomFieldDefinition` - **Tags:** Custom Field Definitions - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/custom-fields/definitions/global/{definition}`) Same contract as the board-scoped update — `type` and `board_id` cannot be changed. Restricted to administrators. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object — Partial update. `type` and `board_id` are immutable (sending them fails validation). name: string # maxLength: 60. minLength: 1 description: string|null # maxLength: 250 config: object|null is_required: boolean is_active: boolean ``` **Example:** ```json { "is_active": false } ``` ## Responses ### 200 — The updated definition. **Content type:** `application/json` ```yaml # object — Definition of a custom field. `board_id` null (and `is_global` true) means tenant-wide. id: integer board_id: integer|null name: string # maxLength: 60. minLength: 1 type: string # enum: "text", "number", "select", "checkbox", "date", "person" description: string|null # maxLength: 250 config: object|null # Type-specific configuration. Examples — text: `{multiline, max_length, placeholder, default_value}`; select: `{options: [{id, label, color}]}`; checkbox: `{default_value}`. order: integer is_required: boolean # Required fields block card interactions (comments, files, timers) until filled. is_active: boolean is_global: boolean created_at: string updated_at: string deleted_at: string|null ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Create a board tag `POST /boards/{board}/tags` - **Operation ID:** `createBoardTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/tags`) Creates a tag scoped to this board. The response also includes a rendered HTML snippet used by the Optiwork web client (safe to ignore in API integrations). ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `board` | path | integer | yes | Board id. | ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 40. minLength: 2 color: string # required. Hex color. description: string|null # maxLength: 250. minLength: 3 ``` **Example:** ```json { "name": "frontend", "color": "#52eb00", "description": "Front-end work" } ``` ## Responses ### 200 — The created tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string tag_list_item_html: string # Server-rendered HTML snippet for the Optiwork web client. Safe to ignore. ``` **Example:** ```json { "tag": { "id": 88, "board_id": 42, "name": "frontend", "description": "Front-end work", "color": "#52eb00", "created_at": "2026-07-20T14:00:00.000000Z", "updated_at": "2026-07-20T14:00:00.000000Z" }, "tag_list_item_html": "
  • " } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a board tag `GET /boards/{board}/tags/{tag}` - **Operation ID:** `getBoardTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/tags/{tag}`) Returns a single board-scoped tag. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a board tag `DELETE /boards/{board}/tags/{tag}` - **Operation ID:** `deleteBoardTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/tags/{tag}`) Deletes the tag and detaches it from every card of the board. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a board tag `PATCH /boards/{board}/tags/{tag}` - **Operation ID:** `updateBoardTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/tags/{tag}`) Updates the tag's name, color and/or description. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 40. minLength: 2 color: string # required. Hex color. description: string|null # maxLength: 250. minLength: 3 ``` **Example:** ```json { "name": "front-end", "color": "#22c55e" } ``` ## Responses ### 200 — The updated tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string tag_list_item_html: string # Server-rendered HTML snippet for the Optiwork web client. Safe to ignore. ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Create a common (tenant-wide) tag `POST /tags/common` - **Operation ID:** `createCommonTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/tags/common`) Creates a tag with no board scope — usable on every board of the tenant. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 40. minLength: 2 color: string # required. Hex color. description: string|null # maxLength: 250. minLength: 3 ``` **Example:** ```json { "name": "urgent", "color": "#ef4444" } ``` ## Responses ### 200 — The created tag (`board_id` null). **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string tag_list_item_html: string # Server-rendered HTML snippet for the Optiwork web client. Safe to ignore. ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a common tag `GET /tags/common/{tag}` - **Operation ID:** `getCommonTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/tags/common/{tag}`) Returns a single common tag. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Delete a common tag `DELETE /tags/common/{tag}` - **Operation ID:** `deleteCommonTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/tags/common/{tag}`) Deletes the common tag and detaches it from every card across all boards. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — The deleted tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Update a common tag `PATCH /tags/common/{tag}` - **Operation ID:** `updateCommonTag` - **Tags:** Tags - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/tags/common/{tag}`) Updates the common tag's name, color and/or description. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object name: string # required. maxLength: 40. minLength: 2 color: string # required. Hex color. description: string|null # maxLength: 250. minLength: 3 ``` **Example:** ```json { "name": "urgent", "color": "#f97316" } ``` ## Responses ### 200 — The updated tag. **Content type:** `application/json` ```yaml # object tag: object # A label. `board_id` null means a common (tenant-wide) tag. id: integer board_id: integer|null name: string # maxLength: 40. minLength: 2 description: string|null # maxLength: 250. minLength: 3 color: string # Hex color (e.g. #52eb00). created_at: string updated_at: string tag_list_item_html: string # Server-rendered HTML snippet for the Optiwork web client. Safe to ignore. ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List contacts linked to a board `GET /boards/{board}/link/contacts` - **Operation ID:** `listBoardContactLinks` - **Tags:** Contact Links - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/link/contacts`) Returns the Optiwork Contacts records linked to this board, enriched with contact data fetched from the Contacts app. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Linked contacts (empty array when none). **Content type:** `application/json` ```yaml # array # items: object — Contact record as provided by the Optiwork Contacts app. ``` **Example:** ```json [ { "id": 3301, "name": "Acme Procurement", "email": "procurement@acme.example" } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Link/unlink contacts on a board `PATCH /boards/{board}/link/contacts` - **Operation ID:** `updateBoardContactLinks` - **Tags:** Contact Links - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/link/contacts`) Adds and removes links to Optiwork Contacts records in one atomic call. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object external_modelable_ids_to_add: array # Optiwork Contacts record ids to link. external_modelable_ids_to_remove: array # Optiwork Contacts record ids to unlink. ``` **Example:** ```json { "external_modelable_ids_to_add": [ 3301 ], "external_modelable_ids_to_remove": [ 3105 ] } ``` ## Responses ### 200 — Counts of links changed. **Content type:** `application/json` ```yaml # object added_count: integer removed_count: integer ``` **Example:** ```json { "added_count": 1, "removed_count": 1 } ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # List contacts linked to a card `GET /boards/{board}/cards/{card}/link/contacts` - **Operation ID:** `listCardContactLinks` - **Tags:** Contact Links - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/link/contacts`) Returns the Optiwork Contacts records linked to this card. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Responses ### 200 — Linked contacts (empty array when none). **Content type:** `application/json` ```yaml # array # items: object ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` --- # Link/unlink contacts on a card `PATCH /boards/{board}/cards/{card}/link/contacts` - **Operation ID:** `updateCardContactLinks` - **Tags:** Contact Links - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/boards/{board}/cards/{card}/link/contacts`) Adds and removes links to Optiwork Contacts records on the card in one atomic call. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Request body (required) **Content type:** `application/json` ```yaml # object external_modelable_ids_to_add: array # Optiwork Contacts record ids to link. external_modelable_ids_to_remove: array # Optiwork Contacts record ids to unlink. ``` **Example:** ```json { "external_modelable_ids_to_add": [ 3301 ] } ``` ## Responses ### 200 — Counts of links changed. **Content type:** `application/json` ```yaml # object added_count: integer removed_count: integer ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 403 — The authenticated user lacks the required board permission. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "This action is unauthorized." } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ``` --- # Get a user's upcoming tasks `GET /users/{user}/dashboard` - **Operation ID:** `getUserDashboard` - **Tags:** Dashboard - **Server:** `https://projects.work.optidata.cloud/api` (full URL: `https://projects.work.optidata.cloud/api/users/{user}/dashboard`) Returns the user's cards due within the next 3 days across all active boards they belong to, ordered by nearest due date. Each card includes a deep `link` into the Optiwork web app. The user is addressed by UUID. ## Authentication HTTP bearer (JWT) — Optiwork **passport** — the JWT shown as the **authentication key** at `https://work.optidata.cloud/user/settings/security` (My account > Profile > Security). Send it as `Authorization: Bearer `. Passports expire; on `401`, get a fresh authentication key from that page and retry. ## Parameters | Name | In | Type | Required | Description | | ---- | -- | ---- | -------- | ----------- | | `user` | path | string | yes | The user's UUID. | | `limit` | query | integer | yes | Maximum number of cards to return. | ## Responses ### 200 — Upcoming cards. **Content type:** `application/json` ```yaml # array # each item: # object id: integer title: string due_date: string completed_at: string|null board_id: integer column_id: integer board: object id: integer name: string assignees: array # each item: id: integer uuid: string name: string email: string avatar_url: string|null link: string # Deep link to open the card in the Optiwork web app. ``` **Example:** ```json [ { "id": 9001, "title": "Draft homepage copy", "due_date": "2026-07-24T12:00:00.000000Z", "completed_at": null, "board_id": 42, "column_id": 301, "board": { "id": 42, "name": "Website Redesign" }, "assignees": [], "link": "https://projects.work.optidata.cloud/urn/acme/UkV..." } ] ``` ### 401 — Missing, invalid or expired bearer passport. **Content type:** `application/json` ```yaml # object error: string ``` **Example:** ```json { "error": "JWT passport exception: Missing bearer token in request" } ``` ### 404 — Resource not found, or a nested resource does not belong to its parent in the path. **Content type:** `application/json` ```yaml # object message: string ``` **Example:** ```json { "message": "Not found." } ``` ### 422 — Validation failed. **Content type:** `application/json` ```yaml # object message: string # First validation error message. errors: object # Map of field name → list of error messages. ``` **Example:** ```json { "message": "The name field is required.", "errors": { "name": [ "The name field is required." ] } } ```