{ "openapi": "3.1.0", "info": { "title": "Kaneo API", "version": "1.0.0", "description": "Kaneo Project Management API - Manage projects, tasks, labels, and more" }, "servers": [ { "url": "https://cloud.kaneo.app/api", "description": "Kaneo API Server" } ], "security": [ { "bearerAuth": [] } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "API key or session token (Bearer)" } }, "schemas": { "InstanceStatus": { "type": "object", "properties": { "hasUsers": { "type": "boolean" }, "hasAdmin": { "type": "boolean" } }, "required": [ "hasUsers", "hasAdmin" ] }, "PublicBoardPage": { "allOf": [ { "$ref": "#/components/schemas/Board" }, { "type": "object", "properties": { "pagination": { "$ref": "#/components/schemas/BoardPagination" } }, "required": [ "pagination" ] } ] }, "BoardColumn": { "type": "object", "properties": { "id": { "type": "string", "description": "The column slug, same as `slug`." }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": [ "string", "null" ] }, "isFinal": { "type": "boolean" }, "position": { "type": "number" }, "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" } } }, "required": [ "id", "slug", "name", "icon", "isFinal", "tasks" ] }, "BoardTask": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "number": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "descriptionDeferred": { "type": "boolean", "description": "True when the list omits a large description; load the task detail or description pages to read it. Do not replace stored text with this null summary." }, "status": { "type": "string" }, "priority": { "type": "string", "description": "One of: no-priority, low, medium, high, urgent." }, "startDate": { "type": [ "string", "null" ], "format": "date-time" }, "dueDate": { "type": [ "string", "null" ], "format": "date-time" }, "position": { "type": [ "number", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "userId": { "type": [ "string", "null" ] }, "assigneeName": { "type": [ "string", "null" ] }, "assigneeId": { "type": [ "string", "null" ] }, "assigneeImage": { "type": [ "string", "null" ] }, "projectId": { "type": "string" }, "subtaskCounts": { "type": "object", "properties": { "completed": { "type": "integer", "minimum": 0 }, "total": { "type": "integer", "minimum": 0 } }, "required": [ "completed", "total" ], "description": "Direct subtasks in the workspace; completed means a final column in the child project. Public boards count only children in public projects." }, "labels": { "type": "array", "items": { "$ref": "#/components/schemas/TaskLabel" } }, "externalLinks": { "type": "array", "items": { "$ref": "#/components/schemas/TaskExternalLink" } } }, "required": [ "id", "title", "number", "description", "status", "priority", "startDate", "dueDate", "position", "createdAt", "userId", "assigneeName", "assigneeId", "assigneeImage", "projectId", "subtaskCounts", "labels", "externalLinks" ] }, "TaskLabel": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "color": { "type": "string" } }, "required": [ "id", "name", "color" ] }, "TaskExternalLink": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "integrationId": { "type": [ "string", "null" ] }, "resourceType": { "type": "string" }, "externalId": { "type": "string" }, "url": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "metadata": { "type": [ "object", "null" ], "additionalProperties": {}, "description": "Provider-specific payload, already parsed from the stored JSON string." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "taskId", "integrationId", "resourceType", "externalId", "url", "title", "metadata", "createdAt", "updatedAt" ] }, "BoardPagination": { "type": "object", "properties": { "total": { "type": "number" }, "page": { "type": "number" }, "pageSize": { "type": "number" }, "totalPages": { "type": "number" }, "relatedPage": { "type": "number" }, "relatedPageSize": { "type": "number" }, "relatedTotalPages": { "type": "number" }, "relatedRevision": { "type": "string", "description": "Public board labels and external links revision for this task page. Restart pagination if it changes during related-page continuations." }, "revision": { "type": "string", "description": "Public board content, membership and ordering revision, including related records and visible subtask progress. Restart pagination if it changes between task or related pages." } }, "required": [ "total", "page", "pageSize", "totalPages", "relatedPage", "relatedPageSize", "relatedTotalPages" ], "description": "Always paginated: 50 tasks by default, at most 100 per page. Continue through totalPages to retrieve all tasks. For each task page, follow relatedPage through relatedTotalPages to retrieve all labels, external links and columns (100 related rows per kind per request, plus up to 100 columns needed to represent the tasks)." }, "Board": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "icon": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "descriptionDeferred": { "type": "boolean", "description": "True when a project description above 64 KiB is omitted; use project detail or public project description pages for full text." }, "isPublic": { "type": [ "boolean", "null" ] }, "workspaceId": { "type": "string" }, "backgroundVersion": { "type": [ "string", "null" ] }, "columns": { "type": "array", "items": { "$ref": "#/components/schemas/BoardColumn" } }, "archivedTasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" } }, "plannedTasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" } } }, "required": [ "id", "name", "slug", "icon", "description", "isPublic", "workspaceId", "backgroundVersion", "columns", "archivedTasks", "plannedTasks" ] }, "TaskDescriptionPage": { "type": "object", "properties": { "content": { "type": "string" }, "version": { "type": "string" }, "nextOffset": { "type": [ "number", "null" ] } }, "required": [ "content", "version", "nextOffset" ] }, "Config": { "type": "object", "properties": { "isCloud": { "type": "boolean" }, "disableRegistration": { "type": "boolean" }, "disablePasswordRegistration": { "type": "boolean" }, "disableEmailOtpSignIn": { "type": "boolean" }, "disableWorkspaceCreation": { "type": "boolean" }, "isDemoMode": { "type": "boolean" }, "hasSmtp": { "type": "boolean" }, "hasGithubSignIn": { "type": "boolean" }, "hasGoogleSignIn": { "type": "boolean" }, "hasDiscordSignIn": { "type": "boolean" }, "hasCustomOAuth": { "type": "boolean" }, "hasGuestAccess": { "type": "boolean" }, "disableLoginForm": { "type": "boolean" }, "customOAuthAutoLogin": { "type": "boolean" }, "customOAuthLogoutUrl": { "type": [ "string", "null" ] }, "billingEnabled": { "type": "boolean" } }, "required": [ "isCloud", "disableRegistration", "disablePasswordRegistration", "disableEmailOtpSignIn", "disableWorkspaceCreation", "isDemoMode", "hasSmtp", "hasGithubSignIn", "hasGoogleSignIn", "hasDiscordSignIn", "hasCustomOAuth", "hasGuestAccess", "disableLoginForm", "customOAuthAutoLogin", "customOAuthLogoutUrl", "billingEnabled" ] }, "McpClientRegistration": { "type": "object", "properties": { "client_id": { "type": "string" }, "client_id_issued_at": { "type": "number" }, "redirect_uris": { "type": "array", "items": { "type": "string" } }, "client_name": { "type": "string" }, "token_endpoint_auth_method": { "type": "string", "enum": [ "none" ] }, "grant_types": { "type": "array", "items": { "type": "string", "enum": [ "authorization_code" ] } }, "response_types": { "type": "array", "items": { "type": "string", "enum": [ "code" ] } } }, "required": [ "client_id", "client_id_issued_at", "redirect_uris", "token_endpoint_auth_method", "grant_types", "response_types" ] }, "OAuthError": { "type": "object", "properties": { "error": { "type": "string" }, "error_description": { "type": "string" } }, "required": [ "error" ] }, "McpAuthorizationRequest": { "type": "object", "properties": { "client_name": { "type": "string" }, "redirect_uri": { "type": "string" } }, "required": [ "client_name", "redirect_uri" ] }, "McpAuthorizationDecision": { "type": "object", "properties": { "redirect": { "type": "string", "description": "Where to send the browser next: back to the client with a code on approval, or with an error on denial." } }, "required": [ "redirect" ] }, "OAuthIdToken": { "type": "object", "properties": { "idToken": { "type": [ "string", "null" ], "description": "The stored id_token for the user's `custom` OAuth account, or null when they have no such account." } }, "required": [ "idToken" ] }, "MovedProject": { "allOf": [ { "$ref": "#/components/schemas/Project" }, { "type": "object", "properties": { "unassignedTaskCount": { "type": "number" } }, "required": [ "unassignedTaskCount" ] } ] }, "Project": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "backgroundVersion": { "type": [ "string", "null" ] }, "slug": { "type": "string", "description": "Short prefix used in task identifiers, e.g. KAN-12." }, "icon": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "description": { "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "isPublic": { "type": [ "boolean", "null" ], "description": "When true the project's board is readable without signing in, via /api/public-project/{id}." }, "archivedAt": { "type": [ "string", "null" ], "format": "date-time", "description": "Non-null once archived; archived projects are hidden by default." }, "position": { "type": "number", "description": "Sidebar order, ascending." }, "lastTaskNumber": { "type": "number", "description": "Highest task number issued in this project; the next task gets this plus one." } }, "required": [ "id", "workspaceId", "backgroundVersion", "slug", "icon", "name", "description", "createdAt", "isPublic", "archivedAt", "position", "lastTaskNumber" ] }, "ProjectListItem": { "allOf": [ { "$ref": "#/components/schemas/Project" }, { "type": "object", "properties": { "statistics": { "$ref": "#/components/schemas/ProjectStatistics" }, "archivedTasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" }, "description": "Always empty." }, "plannedTasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" }, "description": "Always empty." }, "columns": { "type": "array", "items": { "$ref": "#/components/schemas/BoardColumn" }, "description": "Always empty." } }, "required": [ "statistics", "archivedTasks", "plannedTasks", "columns" ] } ] }, "ProjectStatistics": { "type": "object", "properties": { "completionPercentage": { "type": "number" }, "totalTasks": { "type": "number" }, "dueDate": { "type": [ "string", "null" ], "format": "date-time", "description": "The soonest due date among the project's open tasks." } }, "required": [ "completionPercentage", "totalTasks", "dueDate" ] }, "ProjectBackgroundUpload": { "type": "object", "properties": { "key": { "type": "string" }, "uploadUrl": { "type": "string" }, "version": { "type": "string" }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "key", "uploadUrl", "version", "headers" ] }, "ProjectBackgroundFinalize": { "type": "object", "properties": { "url": { "type": "string" } }, "required": [ "url" ] }, "CalendarFeed": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "token": { "type": "string" }, "labelIds": { "type": "array", "items": { "type": "string" } }, "timeZone": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "token", "labelIds", "timeZone", "createdAt" ] }, "TaskDescriptionMatches": { "type": "object", "properties": { "ids": { "type": "array", "items": { "type": "string" } }, "nextCursor": { "type": [ "string", "null" ] } }, "required": [ "ids", "nextCursor" ] }, "AssignedTasks": { "type": "object", "properties": { "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/AssignedTask" } }, "total": { "type": "number", "description": "All open tasks assigned to the caller, including any beyond the first 100 returned." } }, "required": [ "tasks", "total" ] }, "AssignedTask": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "number": { "type": [ "number", "null" ] }, "title": { "type": "string" }, "status": { "type": "string", "description": "The slug of the column the task sits in." }, "statusName": { "type": [ "string", "null" ], "description": "The column's display name. Null for tasks outside a column, such as planned ones." }, "statusIcon": { "type": [ "string", "null" ] }, "priority": { "type": "string", "description": "One of: no-priority, low, medium, high, urgent." }, "dueDate": { "type": [ "string", "null" ], "format": "date-time" }, "projectName": { "type": "string" }, "projectSlug": { "type": "string" }, "projectIcon": { "type": [ "string", "null" ] }, "labels": { "type": "array", "items": { "$ref": "#/components/schemas/TaskLabel" } } }, "required": [ "id", "projectId", "number", "title", "status", "statusName", "statusIcon", "priority", "dueDate", "projectName", "projectSlug", "projectIcon", "labels" ] }, "BoardResponse": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Board" }, "pagination": { "$ref": "#/components/schemas/BoardPagination" } }, "required": [ "data", "pagination" ] }, "BulkTaskResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "updatedCount": { "type": "number" } }, "required": [ "success", "updatedCount" ] }, "TaskImageUpload": { "type": "object", "properties": { "key": { "type": "string", "description": "Object key to send back to the finalize route." }, "uploadUrl": { "type": "string", "description": "Presigned URL to PUT the image bytes to." }, "headers": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Headers that must accompany the upload request, including Content-Type." } }, "required": [ "key", "uploadUrl", "headers" ] }, "TaskImageAsset": { "type": "object", "properties": { "id": { "type": "string" }, "url": { "type": "string", "description": "Where the stored image can be read back from." } }, "required": [ "id", "url" ] }, "Task": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "position": { "type": [ "number", "null" ], "description": "Order within its column, ascending." }, "number": { "type": [ "number", "null" ], "description": "Per-project counter shown as {projectSlug}-{number}." }, "userId": { "type": [ "string", "null" ], "description": "The assignee, if any." }, "title": { "type": "string" }, "description": { "type": [ "string", "null" ] }, "descriptionDeferred": { "type": "boolean", "description": "True when the list omits a large description; load the task detail or description pages to read it. Do not replace stored text with this null summary." }, "status": { "type": "string", "description": "The slug of the column the task sits in." }, "priority": { "type": "string", "description": "One of: no-priority, low, medium, high, urgent." }, "startDate": { "type": [ "string", "null" ], "format": "date-time" }, "dueDate": { "type": [ "string", "null" ], "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "customFields": { "type": "array", "items": { "type": "object", "properties": { "fieldId": { "type": "string" }, "value": { "type": "string" } }, "required": [ "fieldId", "value" ] } } }, "required": [ "id", "projectId", "position", "number", "userId", "title", "description", "status", "priority", "startDate", "dueDate", "createdAt" ] }, "TaskWithAssignee": { "allOf": [ { "$ref": "#/components/schemas/Task" }, { "type": "object", "properties": { "subtaskCounts": { "type": "object", "properties": { "completed": { "type": "number" }, "total": { "type": "number" } }, "required": [ "completed", "total" ] }, "parentSubtaskCounts": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "completed": { "type": "number" }, "total": { "type": "number" } }, "required": [ "taskId", "completed", "total" ] } }, "assigneeName": { "type": [ "string", "null" ] }, "assigneeId": { "type": [ "string", "null" ] } }, "required": [ "assigneeName", "assigneeId" ] } ] }, "MoveTaskResult": { "type": "object", "properties": { "task": { "$ref": "#/components/schemas/Task" }, "sourceProjectId": { "type": "string" }, "destinationProjectId": { "type": "string" } }, "required": [ "task", "sourceProjectId", "destinationProjectId" ] }, "TaskExport": { "type": "object", "properties": { "project": { "$ref": "#/components/schemas/TaskExportProject" }, "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/ExportedTask" } } }, "required": [ "project", "tasks" ] }, "TaskExportProject": { "type": "object", "properties": { "name": { "type": "string" }, "slug": { "type": "string" }, "description": { "type": [ "string", "null" ] }, "exportedAt": { "type": "string", "format": "date-time" } }, "required": [ "name", "slug", "description", "exportedAt" ] }, "ExportedTask": { "type": "object", "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string" }, "priority": { "type": "string" }, "dueDate": { "type": [ "string", "null" ], "format": "date-time" }, "startDate": { "type": [ "string", "null" ], "format": "date-time" }, "userId": { "type": [ "string", "null" ] }, "labels": { "type": "array", "items": { "$ref": "#/components/schemas/ExportedTaskLabel" }, "description": "Label names and colors, without their ids." } }, "required": [ "title", "description", "status", "priority", "dueDate", "startDate", "userId", "labels" ] }, "ExportedTaskLabel": { "type": "object", "properties": { "name": { "type": "string" }, "color": { "type": "string" } }, "required": [ "name", "color" ] }, "TaskImportResult": { "type": "object", "properties": { "results": { "$ref": "#/components/schemas/TaskImportSummary" } }, "required": [ "results" ] }, "TaskImportSummary": { "type": "object", "properties": { "total": { "type": "number" }, "successful": { "type": "number" }, "failed": { "type": "number" }, "tasks": { "type": "array", "items": {}, "description": "Per-task outcome, each carrying a success flag." } }, "required": [ "total", "successful", "failed", "tasks" ] }, "Column": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string", "description": "Stable identifier derived from the name; tasks store this as their status." }, "position": { "type": "number", "description": "Board order, ascending. Columns are always returned sorted by it." }, "icon": { "type": [ "string", "null" ] }, "color": { "type": [ "string", "null" ] }, "isFinal": { "type": "boolean", "description": "Marks the column as a done state, which stops overdue reminders for tasks in it." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "name", "slug", "position", "icon", "color", "isFinal", "createdAt", "updatedAt" ] }, "WorkspaceActivity": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "description": "One of: comment, task, create, status_changed, priority_changed, assignee_changed, unassigned, due_date_changed, title_changed, description_changed." }, "createdAt": { "type": "string", "format": "date-time" }, "eventData": { "description": "Type-specific payload, e.g. { oldStatus, newStatus } for status_changed." }, "excerpt": { "type": [ "string", "null" ], "description": "Plain-text preview of the stored content, at most 240 characters: the comment body, or the description older system events carry instead of eventData." }, "userId": { "type": [ "string", "null" ] }, "userName": { "type": [ "string", "null" ] }, "userImage": { "type": [ "string", "null" ] }, "externalUserName": { "type": [ "string", "null" ] }, "externalUserAvatar": { "type": [ "string", "null" ] }, "taskId": { "type": "string" }, "taskTitle": { "type": "string" }, "taskNumber": { "type": [ "number", "null" ] }, "projectId": { "type": "string" }, "projectSlug": { "type": "string" } }, "required": [ "id", "type", "createdAt", "excerpt", "userId", "userName", "userImage", "externalUserName", "externalUserAvatar", "taskId", "taskTitle", "taskNumber", "projectId", "projectSlug" ] }, "Activity": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "type": { "type": "string", "description": "One of: comment, task, create, status_changed, priority_changed, assignee_changed, unassigned, due_date_changed, title_changed, description_changed." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "userId": { "type": [ "string", "null" ] }, "content": { "type": [ "string", "null" ] }, "eventData": { "description": "Type-specific payload, e.g. { oldStatus, newStatus } for status_changed. Null for plain comments." }, "externalUserName": { "type": [ "string", "null" ], "description": "Set when the activity was imported from another tool." }, "externalUserAvatar": { "type": [ "string", "null" ] }, "externalSource": { "type": [ "string", "null" ], "description": "The tool it was imported from, e.g. planka, trello, jira." }, "externalUrl": { "type": [ "string", "null" ] } }, "required": [ "id", "taskId", "type", "createdAt", "updatedAt", "userId", "content", "externalUserName", "externalUserAvatar", "externalSource", "externalUrl" ] }, "Comment": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "userId": { "type": "string" }, "content": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "user": { "$ref": "#/components/schemas/CommentAuthor" } }, "required": [ "id", "taskId", "userId", "content", "createdAt", "updatedAt", "user" ] }, "CommentAuthor": { "type": "object", "properties": { "name": { "type": "string" }, "image": { "type": [ "string", "null" ] } }, "required": [ "name", "image" ] }, "TimeEntryWithUser": { "allOf": [ { "$ref": "#/components/schemas/TimeEntry" }, { "type": "object", "properties": { "userName": { "type": [ "string", "null" ] } }, "required": [ "userName" ] } ] }, "TimeEntry": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "userId": { "type": [ "string", "null" ], "description": "Null once the user who logged the time has been removed." }, "description": { "type": [ "string", "null" ] }, "startTime": { "type": "string", "format": "date-time" }, "endTime": { "type": [ "string", "null" ], "format": "date-time", "description": "Null while the timer is still running." }, "duration": { "type": [ "number", "null" ], "description": "Elapsed seconds, filled in once the entry has an endTime." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "taskId", "userId", "description", "startTime", "endTime", "duration", "createdAt", "updatedAt" ] }, "Label": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "color": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "deletionStartedAt": { "type": "string", "format": "date-time" }, "taskId": { "type": [ "string", "null" ] }, "workspaceId": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "color", "createdAt", "updatedAt", "taskId", "workspaceId" ] }, "PendingLabelDeletion": { "allOf": [ { "$ref": "#/components/schemas/Label" }, { "type": "object", "properties": { "pendingDeletion": { "type": "boolean", "enum": [ true ] } }, "required": [ "pendingDeletion" ] } ] }, "Notification": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "content": { "type": [ "string", "null" ], "description": "Free-text body. Null for generated notifications, whose text the client renders from type and eventData." }, "type": { "type": "string", "description": "One of: info, task_created, workspace_created, task_status_changed, task_assignee_changed, time_entry_created, due_date_reminder, task_overdue, task_mention, task_comment." }, "eventData": { "description": "Type-specific payload, e.g. { taskTitle, oldStatus, newStatus, projectId, workspaceId }." }, "isRead": { "type": [ "boolean", "null" ] }, "resourceId": { "type": [ "string", "null" ], "description": "The id of the task or workspace the notification points at." }, "resourceType": { "type": [ "string", "null" ], "description": "`task` or `workspace`." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "userId", "title", "content", "type", "isRead", "resourceId", "resourceType", "createdAt", "updatedAt" ] }, "NotificationBulkResult": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] }, "NotificationPreferences": { "type": "object", "properties": { "emailAddress": { "type": [ "string", "null" ] }, "emailEnabled": { "type": "boolean" }, "ntfyEnabled": { "type": "boolean" }, "ntfyConfigured": { "type": "boolean" }, "ntfyServerUrl": { "type": [ "string", "null" ] }, "ntfyTopic": { "type": [ "string", "null" ] }, "ntfyTokenConfigured": { "type": "boolean" }, "maskedNtfyToken": { "type": [ "string", "null" ] }, "gotifyEnabled": { "type": "boolean" }, "gotifyConfigured": { "type": "boolean" }, "gotifyServerUrl": { "type": [ "string", "null" ] }, "gotifyTokenConfigured": { "type": "boolean" }, "maskedGotifyToken": { "type": [ "string", "null" ] }, "webhookEnabled": { "type": "boolean" }, "webhookConfigured": { "type": "boolean" }, "webhookUrl": { "type": [ "string", "null" ] }, "webhookSecretConfigured": { "type": "boolean" }, "maskedWebhookSecret": { "type": [ "string", "null" ] }, "taskAssignmentEnabled": { "type": "boolean" }, "taskCommentEnabled": { "type": "boolean" }, "taskStatusChangeEnabled": { "type": "boolean" }, "dueDateReminderEnabled": { "type": "boolean" }, "dueDateReminderLeadTimeMinutes": { "type": "number", "description": "How long before a due date the reminder fires, in minutes." }, "workspaces": { "type": "array", "items": { "$ref": "#/components/schemas/NotificationPreferenceWorkspaceRule" }, "description": "Per-workspace overrides. A workspace with no rule follows the global settings." }, "createdAt": { "type": [ "string", "null" ], "format": "date-time" }, "updatedAt": { "type": [ "string", "null" ], "format": "date-time" } }, "required": [ "emailAddress", "emailEnabled", "ntfyEnabled", "ntfyConfigured", "ntfyServerUrl", "ntfyTopic", "ntfyTokenConfigured", "maskedNtfyToken", "gotifyEnabled", "gotifyConfigured", "gotifyServerUrl", "gotifyTokenConfigured", "maskedGotifyToken", "webhookEnabled", "webhookConfigured", "webhookUrl", "webhookSecretConfigured", "maskedWebhookSecret", "taskAssignmentEnabled", "taskCommentEnabled", "taskStatusChangeEnabled", "dueDateReminderEnabled", "dueDateReminderLeadTimeMinutes", "workspaces", "createdAt", "updatedAt" ] }, "NotificationPreferenceWorkspaceRule": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "workspaceName": { "type": "string" }, "isActive": { "type": "boolean", "description": "Turn all notifications for this workspace on or off." }, "emailEnabled": { "type": "boolean" }, "ntfyEnabled": { "type": "boolean" }, "gotifyEnabled": { "type": "boolean" }, "webhookEnabled": { "type": "boolean" }, "projectMode": { "type": "string", "enum": [ "all", "selected" ], "description": "`all` notifies for every project in the workspace; `selected` restricts it to selectedProjectIds." }, "selectedProjectIds": { "type": "array", "items": { "type": "string" } }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "workspaceId", "workspaceName", "isActive", "emailEnabled", "ntfyEnabled", "gotifyEnabled", "webhookEnabled", "projectMode", "selectedProjectIds", "createdAt", "updatedAt" ] }, "SearchResponse": { "type": "object", "properties": { "results": { "type": "array", "items": { "$ref": "#/components/schemas/SearchResult" } }, "totalCount": { "type": "number", "description": "Total matches found before the `limit` slice, so a caller can tell that more exist." }, "searchQuery": { "type": "string", "description": "The query that was run." } }, "required": [ "results", "totalCount", "searchQuery" ] }, "SearchResult": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": [ "task", "project", "workspace", "comment", "activity" ] }, "title": { "type": "string" }, "description": { "type": "string" }, "content": { "type": "string", "description": "Matched body text, for comment and activity results. Activities get a rendered summary such as `changed status from Todo to In Progress`." }, "projectId": { "type": "string" }, "projectName": { "type": "string" }, "projectSlug": { "type": "string" }, "workspaceId": { "type": "string" }, "workspaceName": { "type": "string" }, "userId": { "type": "string" }, "userName": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "relevanceScore": { "type": "number", "description": "Higher is a better match. Results are sorted by score, then by createdAt descending." }, "taskNumber": { "type": "number" }, "priority": { "type": "string" }, "status": { "type": "string" } }, "required": [ "id", "type", "title", "createdAt", "relevanceScore" ] }, "GitHubAppInfo": { "type": "object", "properties": { "accountConnected": { "type": "boolean" }, "accountLinkingAvailable": { "type": "boolean" }, "appName": { "type": [ "string", "null" ], "description": "The configured GitHub App slug, or null when this instance has no App set up." } }, "required": [ "accountConnected", "accountLinkingAvailable", "appName" ] }, "GitHubRepositoryList": { "type": "object", "properties": { "repositories": { "type": "array", "items": { "$ref": "#/components/schemas/GitHubRepository" }, "description": "Deduplicated across installations, most recently updated first." }, "installations": { "type": "array", "items": { "$ref": "#/components/schemas/GitHubInstallation" } }, "total": { "type": "number" }, "nextPage": { "type": [ "object", "null" ], "properties": { "installationPage": { "type": "number" }, "repositoryPage": { "type": "number" } }, "required": [ "installationPage", "repositoryPage" ] } }, "required": [ "repositories", "installations", "total", "nextPage" ] }, "GitHubRepository": { "type": "object", "properties": { "id": { "type": "number" }, "name": { "type": "string" }, "full_name": { "type": "string" }, "private": { "type": "boolean" }, "owner": { "$ref": "#/components/schemas/GitHubRepositoryOwner" }, "description": { "type": [ "string", "null" ] }, "html_url": { "type": "string" }, "permissions": { "$ref": "#/components/schemas/GitHubRepositoryPermissions" }, "updated_at": { "type": "string", "format": "date-time" }, "installation_id": { "type": "number", "description": "Which App installation this repository came through." } }, "required": [ "id", "name", "full_name", "private", "owner", "description", "html_url", "updated_at", "installation_id" ] }, "GitHubRepositoryOwner": { "type": "object", "properties": { "login": { "type": "string" }, "avatar_url": { "type": "string" }, "type": { "type": "string" } }, "required": [ "login", "avatar_url", "type" ] }, "GitHubRepositoryPermissions": { "type": "object", "properties": { "admin": { "type": "boolean" }, "push": { "type": "boolean" }, "pull": { "type": "boolean" } }, "required": [ "admin", "push", "pull" ] }, "GitHubInstallation": { "type": "object", "properties": { "id": { "type": "number" }, "account": { "$ref": "#/components/schemas/GitHubInstallationAccount" }, "repositories": { "type": "array", "items": { "type": "string" }, "description": "Full names of the repositories under this installation. Empty when listing them failed." } }, "required": [ "id", "account", "repositories" ] }, "GitHubInstallationAccount": { "type": [ "object", "null" ], "properties": { "login": { "type": "string" }, "type": { "type": "string" } }, "required": [ "login", "type" ] }, "GitHubVerificationResult": { "type": "object", "properties": { "isInstalled": { "type": "boolean" }, "installationId": { "type": [ "number", "null" ] }, "repositoryExists": { "type": [ "boolean", "null" ] }, "repositoryPrivate": { "type": [ "boolean", "null" ] }, "permissions": { "type": [ "object", "null" ], "additionalProperties": { "type": "string" }, "description": "The permissions the installation currently grants." }, "hasRequiredPermissions": { "type": "boolean" }, "missingPermissions": { "type": "array", "items": { "type": "string" }, "description": "Permissions that must be granted before the link will work." }, "message": { "type": "string", "description": "A human-readable summary to show the user." }, "settingsUrl": { "type": "string", "description": "Where to adjust the installation, when one exists." }, "installationUrl": { "type": "string", "description": "Where to install the App, when it is not installed yet." } }, "required": [ "isInstalled", "installationId", "repositoryExists", "repositoryPrivate", "permissions", "hasRequiredPermissions", "missingPermissions", "message" ] }, "GitHubIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "repositoryOwner": { "type": "string" }, "repositoryName": { "type": "string" }, "installationId": { "type": [ "number", "null" ], "description": "The GitHub App installation that grants access to the repository." }, "requiresVerification": { "type": "boolean" }, "importProgress": { "$ref": "#/components/schemas/IssueImportResult" }, "branchPattern": { "type": "string", "description": "Template used to name branches created for a task." }, "commentTaskLinkOnGitHubIssue": { "type": "boolean", "description": "When on, Kaneo comments a link back to the task on the linked GitHub issue." }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "repositoryOwner", "repositoryName", "installationId", "requiresVerification", "isActive", "createdAt", "updatedAt" ] }, "IssueImportResult": { "type": "object", "properties": { "runId": { "type": "string" }, "pending": { "type": "boolean" }, "imported": { "type": "number" }, "updated": { "type": "number" }, "skipped": { "type": "number", "description": "Issues whose linked task or source disappeared or belongs to another project." } }, "required": [ "runId", "pending", "imported", "updated", "skipped" ] }, "CreatedGitHubIntegration": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "repositoryOwner": { "type": "string" }, "repositoryName": { "type": "string" }, "installationId": { "type": [ "number", "null" ], "description": "The GitHub App installation that grants access to the repository." }, "requiresVerification": { "type": "boolean" }, "importProgress": { "$ref": "#/components/schemas/IssueImportResult" }, "branchPattern": { "type": "string", "description": "Template used to name branches created for a task." }, "commentTaskLinkOnGitHubIssue": { "type": "boolean", "description": "When on, Kaneo comments a link back to the task on the linked GitHub issue." }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "repositoryOwner", "repositoryName", "installationId", "requiresVerification" ] }, "GitHubIntegrationNotFound": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] }, "GitHubDeleteResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "success", "message" ] }, "GiteaRepositoryList": { "type": "object", "properties": { "repositories": { "type": "array", "items": { "$ref": "#/components/schemas/GiteaRepository" } } }, "required": [ "repositories" ] }, "GiteaRepository": { "type": "object", "properties": { "id": { "type": "number" }, "name": { "type": "string" }, "full_name": { "type": "string" }, "owner": { "$ref": "#/components/schemas/GiteaRepositoryOwner" }, "private": { "type": "boolean" }, "html_url": { "type": "string" } }, "required": [ "id", "name", "full_name", "owner", "private", "html_url" ] }, "GiteaRepositoryOwner": { "type": "object", "properties": { "login": { "type": "string" } }, "required": [ "login" ] }, "GiteaVerificationResult": { "type": "object", "properties": { "isInstalled": { "type": "boolean" }, "hasRequiredPermissions": { "type": "boolean" }, "repositoryExists": { "type": "boolean" }, "repositoryPrivate": { "type": [ "boolean", "null" ] }, "missingPermissions": { "type": "array", "items": { "type": "string" } }, "message": { "type": "string", "description": "A human-readable summary to show the user." }, "failureReason": { "type": [ "string", "null" ], "enum": [ "not_a_gitea_instance", "redirected", "repository_not_found", null ], "description": "Why verification failed, when it did. `redirected` usually means the base URL is behind a proxy that rewrites it." } }, "required": [ "isInstalled", "hasRequiredPermissions", "repositoryExists", "repositoryPrivate", "missingPermissions", "message", "failureReason" ] }, "GiteaIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "baseUrl": { "type": "string", "description": "Root URL of the Gitea instance." }, "repositoryOwner": { "type": "string" }, "repositoryName": { "type": "string" }, "maskedAccessToken": { "type": "string" }, "webhookUrl": { "type": "string", "description": "Where Gitea should POST events for this project." }, "webhookSecret": { "type": "string", "description": "Only returned to callers with workspace:manage_settings, so the value can be pasted into Gitea." }, "branchPattern": { "type": "string" }, "commentTaskLinkOnGiteaIssue": { "type": "boolean", "description": "When on, Kaneo comments a link back to the task on the linked Gitea issue." }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "baseUrl", "repositoryOwner", "repositoryName", "maskedAccessToken", "isActive", "createdAt", "updatedAt" ] }, "GiteaIntegrationNotFound": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] }, "GiteaDeleteResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "success", "message" ] }, "GiteaImportResult": { "type": "object", "properties": { "imported": { "type": "number" }, "updated": { "type": "number", "description": "Existing tasks that were refreshed from their issue." }, "skipped": { "type": "number" }, "errors": { "type": "array", "items": { "type": "string" } } }, "required": [ "imported", "updated", "skipped" ] }, "GitlabProjectList": { "type": "object", "properties": { "projects": { "type": "array", "items": { "$ref": "#/components/schemas/GitlabProject" } } }, "required": [ "projects" ] }, "GitlabProject": { "type": "object", "properties": { "id": { "type": "number" }, "name": { "type": "string" }, "path_with_namespace": { "type": "string" }, "name_with_namespace": { "type": "string" }, "visibility": { "type": "string" }, "web_url": { "type": "string" } }, "required": [ "id", "name", "path_with_namespace", "name_with_namespace", "visibility", "web_url" ] }, "GitlabVerificationResult": { "type": "object", "properties": { "isInstalled": { "type": "boolean", "description": "The base URL answered as a GitLab instance for this token." }, "hasRequiredPermissions": { "type": "boolean" }, "projectExists": { "type": "boolean" }, "projectVisibility": { "type": [ "string", "null" ] }, "missingPermissions": { "type": "array", "items": { "type": "string" } }, "message": { "type": "string", "description": "A human-readable summary to show the user." }, "failureReason": { "type": [ "string", "null" ], "enum": [ "not_a_gitlab_instance", "redirected", "project_not_found", null ], "description": "Why verification failed, when it did. `redirected` usually means the base URL is behind a proxy that rewrites it." } }, "required": [ "isInstalled", "hasRequiredPermissions", "projectExists", "projectVisibility", "missingPermissions", "message", "failureReason" ] }, "GitlabIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "baseUrl": { "type": "string", "description": "Root URL of the GitLab instance." }, "projectPath": { "type": "string", "description": "Full path of the linked project, nested groups included." }, "tokenType": { "type": "string", "enum": [ "private", "bearer" ] }, "maskedAccessToken": { "type": "string", "description": "First and last characters of the stored token, only returned to callers with workspace:manage_settings." }, "webhookUrl": { "type": "string", "description": "Where GitLab should POST events for this project." }, "webhookSecret": { "type": "string", "description": "Only returned to callers with workspace:manage_settings, so the value can be pasted into GitLab." }, "branchPattern": { "type": "string" }, "commentTaskLinkOnGitlabIssue": { "type": "boolean", "description": "When on, Kaneo comments a link back to the task on each issue opened in GitLab. Issues Kaneo creates from tasks are not commented on." }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "baseUrl", "projectPath", "tokenType", "maskedAccessToken", "isActive", "createdAt", "updatedAt" ] }, "GitlabIntegrationNotFound": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] }, "GitlabDeleteResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "success", "message" ] }, "GitlabImportResult": { "type": "object", "properties": { "imported": { "type": "number" }, "updated": { "type": "number", "description": "Existing tasks that were refreshed from their issue." }, "skipped": { "type": "number" }, "errors": { "type": "array", "items": { "type": "string" } } }, "required": [ "imported", "updated", "skipped" ] }, "GenericWebhookIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "webhookConfigured": { "type": "boolean" }, "maskedWebhookUrl": { "type": [ "string", "null" ] }, "secretConfigured": { "type": "boolean" }, "maskedSecret": { "type": [ "string", "null" ], "description": "A preview of the HMAC signing secret used to sign outgoing deliveries." }, "events": { "$ref": "#/components/schemas/GenericWebhookEvents" }, "dueDateReminderLeadTimeMinutes": { "type": "number", "description": "How long before a due date the dueDateReminder event fires, in minutes." }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "webhookConfigured", "maskedWebhookUrl", "secretConfigured", "maskedSecret", "events", "dueDateReminderLeadTimeMinutes", "isActive", "createdAt", "updatedAt" ] }, "GenericWebhookEvents": { "allOf": [ { "$ref": "#/components/schemas/IntegrationEvents" }, { "type": "object", "properties": { "taskDeleted": { "type": "boolean" }, "taskMoved": { "type": "boolean" }, "taskDueDateChanged": { "type": "boolean" }, "taskAssigneeChanged": { "type": "boolean" }, "taskUnassigned": { "type": "boolean" }, "dueDateReminder": { "type": "boolean" } }, "required": [ "taskDeleted", "taskMoved", "taskDueDateChanged", "taskAssigneeChanged", "taskUnassigned", "dueDateReminder" ] } ] }, "IntegrationEvents": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } }, "required": [ "taskCreated", "taskStatusChanged", "taskPriorityChanged", "taskTitleChanged", "taskDescriptionChanged", "taskCommentCreated" ] }, "DiscordIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "webhookConfigured": { "type": "boolean" }, "maskedWebhookUrl": { "type": "string", "description": "The webhook URL with its secret path segment masked, or an empty string when none is set." }, "events": { "$ref": "#/components/schemas/IntegrationEvents" }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "channelName", "webhookConfigured", "maskedWebhookUrl", "events", "isActive", "createdAt", "updatedAt" ] }, "MattermostIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "webhookConfigured": { "type": "boolean" }, "maskedWebhookUrl": { "type": "string", "description": "The webhook URL with its secret path segment masked, or an empty string when none is set." }, "events": { "$ref": "#/components/schemas/IntegrationEvents" }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "channelName", "webhookConfigured", "maskedWebhookUrl", "events", "isActive", "createdAt", "updatedAt" ] }, "SlackIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "webhookConfigured": { "type": "boolean" }, "maskedWebhookUrl": { "type": "string", "description": "The webhook URL with its secret path segment masked, or an empty string when none is set." }, "events": { "$ref": "#/components/schemas/IntegrationEvents" }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "channelName", "webhookConfigured", "maskedWebhookUrl", "events", "isActive", "createdAt", "updatedAt" ] }, "TelegramIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "chatId": { "type": "string", "description": "The Telegram chat, group, or channel messages are sent to." }, "threadId": { "type": [ "number", "null" ], "description": "Forum topic id, when the target group uses topics." }, "chatLabel": { "type": [ "string", "null" ], "description": "A human-readable name for the chat, shown in the UI." }, "botTokenConfigured": { "type": "boolean" }, "maskedBotToken": { "type": "string" }, "events": { "$ref": "#/components/schemas/IntegrationEvents" }, "isActive": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "chatId", "threadId", "chatLabel", "botTokenConfigured", "maskedBotToken", "events", "isActive", "createdAt", "updatedAt" ] }, "TaskRelationWithTasks": { "allOf": [ { "$ref": "#/components/schemas/TaskRelation" }, { "type": "object", "properties": { "sourceTask": { "$ref": "#/components/schemas/RelatedTask" }, "targetTask": { "$ref": "#/components/schemas/RelatedTask" } }, "required": [ "sourceTask", "targetTask" ] } ] }, "RelatedTask": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "status": { "type": "string" }, "isCompleted": { "type": "boolean", "description": "Whether the task is in a final column of its own project." }, "priority": { "type": [ "string", "null" ] }, "number": { "type": [ "number", "null" ] }, "projectId": { "type": "string" }, "userId": { "type": [ "string", "null" ] }, "assigneeName": { "type": [ "string", "null" ] } }, "required": [ "id", "title", "status", "isCompleted", "priority", "number", "projectId", "userId", "assigneeName" ] }, "TaskRelation": { "type": "object", "properties": { "id": { "type": "string" }, "sourceTaskId": { "type": "string" }, "targetTaskId": { "type": "string" }, "relationType": { "type": "string", "description": "How the two tasks relate: `subtask`, `blocks`, or `related`." }, "createdAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "sourceTaskId", "targetTaskId", "relationType", "createdAt" ] }, "CreatedExternalLink": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "integrationId": { "type": [ "string", "null" ] }, "resourceType": { "type": "string", "description": "The resource kind: `url` for a manual link, or an integration resource such as `issue` or `pull_request`." }, "externalId": { "type": "string", "description": "The provider's resource identifier, or the URL for a manual link." }, "url": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "metadata": { "description": "Provider-specific payload, parsed from the stored JSON string. Null when the link has no metadata." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "taskId", "integrationId", "resourceType", "externalId", "url", "title", "createdAt", "updatedAt" ] }, "DeletedExternalLink": { "type": "object", "properties": { "id": { "type": "string" } }, "required": [ "id" ] }, "ExternalLink": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "integrationId": { "type": [ "string", "null" ] }, "resourceType": { "type": "string", "description": "The resource kind: `url` for a manual link, or an integration resource such as `issue` or `pull_request`." }, "externalId": { "type": "string", "description": "The provider's resource identifier, or the URL for a manual link." }, "url": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "metadata": { "description": "Provider-specific payload, parsed from the stored JSON string. Null when the link has no metadata." }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "integration": { "$ref": "#/components/schemas/ExternalLinkIntegration" } }, "required": [ "id", "taskId", "integrationId", "resourceType", "externalId", "url", "title", "createdAt", "updatedAt", "integration" ] }, "ExternalLinkIntegration": { "type": [ "object", "null" ], "properties": { "id": { "type": "string" }, "type": { "type": "string" } }, "required": [ "id", "type" ] }, "WorkflowRule": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "integrationType": { "type": "string", "description": "The integration that emits the event, e.g. `github`." }, "eventType": { "type": "string", "description": "The provider event that triggers the move, e.g. `pull_request.opened`." }, "columnId": { "type": "string", "description": "The column tasks are moved to when the event fires." }, "columnName": { "type": [ "string", "null" ] }, "columnSlug": { "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "integrationType", "eventType", "columnId", "columnName", "columnSlug", "createdAt", "updatedAt" ] }, "WorkflowRuleRow": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "integrationType": { "type": "string" }, "eventType": { "type": "string" }, "columnId": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "integrationType", "eventType", "columnId", "createdAt", "updatedAt" ] }, "PendingInvitation": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "workspaceId": { "type": "string" }, "workspaceName": { "type": "string" }, "inviterName": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "status": { "type": "string", "description": "Always `pending` here; expired and accepted ones are filtered out." } }, "required": [ "id", "email", "workspaceId", "workspaceName", "inviterName", "expiresAt", "createdAt", "status" ] }, "InvitationDetails": { "type": "object", "properties": { "valid": { "type": "boolean", "description": "True only when the invitation can still be accepted." }, "invitation": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "workspaceName": { "type": "string" }, "inviterName": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" }, "status": { "type": "string" }, "expired": { "type": "boolean" } }, "required": [ "id", "email", "workspaceName", "inviterName", "expiresAt", "status", "expired" ], "description": "Omitted when the invitation does not exist, was already accepted, or was canceled -- the details are withheld rather than leaked." }, "error": { "type": "string", "description": "Why the invitation is unusable, when valid is false." } }, "required": [ "valid" ] }, "WorkspaceMember": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "email": { "type": "string" }, "image": { "type": [ "string", "null" ] }, "role": { "type": "string", "description": "The member's workspace role: a built-in role (owner, admin, member, guest) or a custom role name." } }, "required": [ "id", "name", "email", "image", "role" ] }, "CustomFieldDefinition": { "type": "object", "properties": { "id": { "type": "string" }, "projectId": { "type": "string" }, "name": { "type": "string" }, "type": { "type": "string" }, "required": { "type": "boolean" }, "defaultValue": { "type": [ "string", "null" ] }, "options": {}, "position": { "type": "number" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "projectId", "name", "type", "required", "defaultValue", "position", "createdAt", "updatedAt" ] }, "CustomFieldValue": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "fieldId": { "type": "string" }, "value": { "type": [ "string", "null" ] }, "fieldName": { "type": "string" }, "fieldPosition": { "type": "number" }, "fieldType": { "type": "string" }, "fieldOptions": {} }, "required": [ "id", "taskId", "fieldId", "value", "fieldName", "fieldPosition", "fieldType" ] }, "CustomFieldFilterValues": { "type": "object", "properties": { "fieldId": { "type": "string" }, "fieldName": { "type": "string" }, "fieldType": { "type": "string" }, "values": { "type": "array", "items": { "type": "string" } } }, "required": [ "fieldId", "fieldName", "fieldType", "values" ] }, "ReorderCustomFieldsResponse": {}, "SetCustomFieldValueResponse": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "fieldId": { "type": "string" }, "value": { "type": [ "string", "null" ] } }, "required": [ "id", "taskId", "fieldId", "value" ] }, "CurrentUser": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "email": { "type": "string" }, "image": { "type": [ "string", "null" ] }, "role": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "email", "image", "role" ] }, "UserAvatar": { "type": "object", "properties": { "id": { "type": "string" }, "url": { "type": "string", "description": "Public URL for the stored avatar, served from /api/user/avatar/{id}." }, "size": { "type": "number", "description": "Decoded size in bytes." } }, "required": [ "id", "url", "size" ] }, "UserAvatarDeleted": { "type": "object", "properties": { "deleted": { "type": "boolean", "description": "False when the user had no uploaded avatar to remove." } }, "required": [ "deleted" ] }, "AdminUserList": { "type": "object", "properties": { "users": { "type": "array", "items": { "$ref": "#/components/schemas/AdminUser" } }, "total": { "type": "integer", "description": "Number of users matching the search, across all pages." } }, "required": [ "users", "total" ] }, "AdminUser": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "email": { "type": "string" }, "emailVerified": { "type": "boolean" }, "image": { "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "role": { "type": [ "string", "null" ] }, "banned": { "type": "boolean" }, "banReason": { "type": [ "string", "null" ] }, "banExpires": { "type": [ "string", "null" ], "format": "date-time" } }, "required": [ "id", "name", "email", "emailVerified", "image", "createdAt", "updatedAt", "role", "banned", "banReason", "banExpires" ] } }, "parameters": {} }, "paths": { "/instance/status": { "get": { "operationId": "getInstanceStatus", "tags": [ "Instance" ], "summary": "Get instance status", "description": "Public instance setup status. When hasUsers is false the next signup becomes the instance admin.", "security": [], "responses": { "200": { "description": "Instance status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstanceStatus" } } } } } } }, "/public-project/{id}": { "get": { "operationId": "getPublicProject", "tags": [ "Projects" ], "summary": "Get a public project board", "description": "Read a public board in bounded task pages. Visibility is checked before loading tasks. Continue through pagination.totalPages for all tasks and through relatedPage/pagination.relatedTotalPages for their complete related records.", "security": [], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "priority", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "assigneeId", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000000 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000000 }, "required": false, "name": "relatedPage", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "enum": [ "createdAt", "priority", "dueDate", "position", "title", "number" ] }, "required": false, "name": "sortBy", "in": "query" }, { "schema": { "type": "string", "enum": [ "asc", "desc" ] }, "required": false, "name": "sortOrder", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "dueBefore", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "dueAfter", "in": "query" } ], "responses": { "200": { "description": "A public board page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicBoardPage" } } } }, "400": { "description": "Invalid pagination or filters", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "Project is not public", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Task list request timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/public-project/{id}/description": { "get": { "operationId": "getPublicProjectDescriptionPage", "tags": [ "Projects" ], "summary": "Read a public project description page", "security": [], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 0, "maximum": 2000000000, "default": 0 }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "pattern": "^[0-9]{1,10}$" }, "required": false, "name": "version", "in": "query" } ], "responses": { "200": { "description": "Public project description page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskDescriptionPage" } } } }, "400": { "description": "Invalid description cursor", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Public project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Description changed or no longer public", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Description request timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/public-project/{id}/task/{taskId}/description": { "get": { "operationId": "getPublicTaskDescriptionPage", "tags": [ "Projects" ], "summary": "Read a public task description page", "security": [], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "integer", "minimum": 0, "maximum": 2000000000, "default": 0 }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "pattern": "^[0-9]{1,10}$" }, "required": false, "name": "version", "in": "query" } ], "responses": { "200": { "description": "Public task description page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskDescriptionPage" } } } }, "400": { "description": "Invalid description cursor", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Public task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Description changed or no longer public", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Description request timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/calendar-feed/{token}/calendar.ics": { "get": { "operationId": "getCalendarFeed", "tags": [ "Calendar feeds" ], "summary": "Subscribe to a calendar feed", "description": "Read scheduled project tasks using a secret calendar feed link. Anyone with the link can read matching task titles, descriptions, and dates. Responses are streamed; descriptions longer than 4096 characters and titles or calendar names longer than 1024 characters are truncated with an ellipsis.", "security": [], "parameters": [ { "schema": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "required": true, "name": "token", "in": "path" } ], "responses": { "200": { "description": "iCalendar feed", "content": { "text/calendar": { "schema": { "type": "string" } } } }, "400": { "description": "Invalid feed token", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Calendar feed not found or revoked", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/auth/get-session": { "get": { "operationId": "getSession", "tags": [ "Authentication" ], "summary": "Get session", "description": "Get the current authenticated session, or null when the caller is not signed in. Served by Better Auth.", "security": [], "responses": { "200": { "description": "Current session details, or null when unauthenticated" } } } }, "/asset/{id}": { "get": { "operationId": "getAsset", "tags": [ "Assets" ], "summary": "Download asset", "description": "Download an uploaded asset. Readable without signing in only when it belongs to a public project; image types are served inline, everything else as an attachment.", "security": [], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The requested asset binary stream", "content": { "*/*": { "schema": { "type": "string", "format": "binary" } } } }, "304": { "description": "Not modified" }, "403": { "description": "No access to this asset" }, "404": { "description": "Asset not found" } } } }, "/user/avatar/{id}": { "get": { "operationId": "getUserAvatar", "tags": [ "User" ], "summary": "Download avatar", "description": "Download a user avatar by its avatar ID. Public, immutable, and cache-friendly: the id changes whenever the avatar is replaced.", "security": [], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The avatar image", "content": { "image/*": { "schema": { "type": "string", "format": "binary" } } } }, "304": { "description": "Not modified" }, "404": { "description": "Avatar not found" } } } }, "/config": { "get": { "operationId": "getConfig", "tags": [ "Config" ], "summary": "Get config", "description": "Public instance settings: which sign-in methods, registration paths, and features are enabled.", "security": [], "responses": { "200": { "description": "Application settings", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Config" } } } } } } }, "/auth/organization/accept-invitation": { "post": { "tags": [ "Organization Management" ], "operationId": "acceptOrganizationInvitation", "summary": "Accept Organization Invitation", "description": "Accept an invitation to an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "invitationId": { "type": "string", "description": "The ID of the invitation to accept" } }, "required": [ "invitationId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "invitation": { "type": "object", "additionalProperties": {} }, "member": { "type": "object", "additionalProperties": {} } } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/add-team-member": { "post": { "tags": [ "Organization Management" ], "operationId": "addOrganizationTeamMember", "summary": "Add Organization Team Member", "description": "The newly created member", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "teamId": { "type": "string", "description": "The team the user should be a member of." }, "userId": { "type": "string", "description": "The user Id which represents the user to be added as a member." }, "organizationId": { "type": "string", "description": "The organization ID which the team falls under. If not provided, it will default to the user's active organization." } }, "required": [ "teamId", "userId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier of the team member" }, "userId": { "type": "string", "description": "The user ID of the team member" }, "teamId": { "type": "string", "description": "The team ID of the team the team member is in" }, "createdAt": { "type": "string", "description": "Timestamp when the team member was created" } }, "required": [ "id", "userId", "teamId", "createdAt" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/cancel-invitation": { "post": { "tags": [ "Organization Management" ], "operationId": "cancelOrganizationInvitation", "summary": "Cancel Organization Invitation", "description": "Cancel Organization Invitation", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "invitationId": { "type": "string", "description": "The ID of the invitation to cancel" } }, "required": [ "invitationId" ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/check-slug": { "post": { "tags": [ "Organization Management" ], "operationId": "checkOrganizationSlug", "summary": "Check Organization Slug", "description": "Check Organization Slug", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "slug": { "type": "string", "description": "The organization slug to check. Eg: \"my-org\"" } }, "required": [ "slug" ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/create": { "post": { "tags": [ "Organization Management" ], "operationId": "createOrganization", "summary": "Create Organization", "description": "Create an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the organization" }, "slug": { "type": "string", "description": "The slug of the organization" }, "userId": { "type": "string", "description": "The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: \"user-id\"" }, "logo": { "type": [ "string", "null" ], "description": "The logo of the organization" }, "metadata": { "type": "object", "additionalProperties": {}, "description": "The metadata of the organization" }, "keepCurrentActiveOrganization": { "type": "boolean", "description": "Whether to keep the current active organization active after creating a new one. Eg: true" }, "description": { "type": [ "string", "null" ] } }, "required": [ "name", "slug" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/create-role": { "post": { "tags": [ "Organization Management" ], "operationId": "createOrganizationRole", "summary": "Create Organization Role", "description": "Create Organization Role", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "organizationId": { "type": "string" }, "role": { "type": "string", "description": "The name of the role to create" }, "permission": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "The permission to assign to the role" }, "additionalFields": { "type": "object", "additionalProperties": {} } }, "required": [ "role", "permission" ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/create-team": { "post": { "tags": [ "Organization Management" ], "operationId": "createOrganizationTeam", "summary": "Create Organization Team", "description": "Create a new team within an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the team. Eg: \"my-team\"" }, "organizationId": { "type": "string", "description": "The organization ID which the team will be created in. Defaults to the active organization. Eg: \"organization-id\"" } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier of the created team" }, "name": { "type": "string", "description": "Name of the team" }, "organizationId": { "type": "string", "description": "ID of the organization the team belongs to" }, "createdAt": { "type": "string", "description": "Timestamp when the team was created" }, "updatedAt": { "type": "string", "description": "Timestamp when the team was last updated" } }, "required": [ "id", "name", "organizationId", "createdAt", "updatedAt" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/delete": { "post": { "tags": [ "Organization Management" ], "operationId": "deleteOrganization", "summary": "Delete Organization", "description": "Delete an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "The organization id to delete" } }, "required": [ "organizationId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/delete-role": { "post": { "tags": [ "Organization Management" ], "operationId": "deleteOrganizationRole", "summary": "Delete Organization Role", "description": "Delete Organization Role", "requestBody": { "required": true, "content": { "application/json": { "schema": { "allOf": [ { "type": "object", "properties": { "organizationId": { "type": "string" } } }, { "anyOf": [ { "type": "object", "properties": { "roleName": { "type": "string", "description": "The name of the role to delete" } }, "required": [ "roleName" ] }, { "type": "object", "properties": { "roleId": { "type": "string", "description": "The id of the role to delete" } }, "required": [ "roleId" ] } ] } ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/get-active-member": { "get": { "tags": [ "Organization Management" ], "operationId": "getOrganizationActiveMember", "summary": "Get Organization Active Member", "description": "Get the member details of the active organization", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "organizationId": { "type": "string" }, "role": { "type": "string" } }, "required": [ "id", "userId", "organizationId", "role" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/get-active-member-role": { "get": { "tags": [ "Organization Management" ], "operationId": "getOrganizationActiveMemberRole", "summary": "Get Organization Active Member Role", "description": "Get Organization Active Member Role", "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/get-full-organization": { "get": { "tags": [ "Organization Management" ], "operationId": "getOrganizationFullOrganization", "summary": "Get Organization Full Organization", "description": "Get the full organization", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/get-invitation": { "get": { "tags": [ "Organization Management" ], "operationId": "getOrganizationInvitation", "summary": "Get Organization Invitation", "description": "Get an invitation by ID", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "query" } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "role": { "type": "string" }, "organizationId": { "type": "string" }, "inviterId": { "type": "string" }, "status": { "type": "string" }, "expiresAt": { "type": "string" }, "organizationName": { "type": "string" }, "organizationSlug": { "type": "string" }, "inviterEmail": { "type": "string" } }, "required": [ "id", "email", "role", "organizationId", "inviterId", "status", "expiresAt", "organizationName", "organizationSlug", "inviterEmail" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/get-role": { "get": { "tags": [ "Organization Management" ], "operationId": "getOrganizationRole", "summary": "Get Organization Role", "description": "Get Organization Role", "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/has-permission": { "post": { "tags": [ "Organization Management" ], "operationId": "hasOrganizationPermission", "summary": "Check Organization Permission", "description": "Check if the user has permission", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "permission": { "type": "object", "additionalProperties": {}, "description": "The permission to check" }, "permissions": { "type": "object", "additionalProperties": {}, "description": "The permission to check" } }, "required": [ "permissions" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" }, "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/invite-member": { "post": { "tags": [ "Organization Management" ], "operationId": "inviteOrganizationMember", "summary": "Invite Organization Member", "description": "Create or resend an invitation. Email delivery failures return 502; the invitation remains pending and can be resent after correcting SMTP settings.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "The email address of the user to invite" }, "role": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ], "description": "The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: \"member\"" }, "organizationId": { "type": "string", "description": "The organization ID to invite the user to" }, "resend": { "type": "boolean", "description": "Resend the invitation email, if the user is already invited. Eg: true" }, "teamId": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ] } }, "required": [ "email", "role" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "role": { "type": "string" }, "organizationId": { "type": "string" }, "inviterId": { "type": "string" }, "status": { "type": "string" }, "expiresAt": { "type": "string" }, "createdAt": { "type": "string" } }, "required": [ "id", "email", "role", "organizationId", "inviterId", "status", "expiresAt", "createdAt" ] } } } }, "401": { "description": "Missing or invalid credentials" }, "502": { "description": "Invitation saved, but email delivery failed", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "INVITATION_EMAIL_FAILED" ] }, "message": { "type": "string" } }, "required": [ "code", "message" ] } } } } } } }, "/auth/organization/leave": { "post": { "tags": [ "Organization Management" ], "operationId": "leaveOrganization", "summary": "Leave Organization", "description": "Leave Organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "The organization Id for the member to leave. Eg: \"organization-id\"" } }, "required": [ "organizationId" ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganization", "summary": "List Organization", "description": "List all organizations", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": {} } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-invitations": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationInvitations", "summary": "List Organization Invitations", "description": "List Organization Invitations", "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-members": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationMembers", "summary": "List Organization Members", "description": "List Organization Members", "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-roles": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationRoles", "summary": "List Organization Roles", "description": "List Organization Roles", "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-team-members": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationTeamMembers", "summary": "List Organization Team Members", "description": "List the members of the given team.", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier of the team member" }, "userId": { "type": "string", "description": "The user ID of the team member" }, "teamId": { "type": "string", "description": "The team ID of the team the team member is in" }, "createdAt": { "type": "string", "description": "Timestamp when the team member was created" } }, "required": [ "id", "userId", "teamId", "createdAt" ] } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-teams": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationTeams", "summary": "List Organization Teams", "description": "List all teams in an organization", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier of the team" }, "name": { "type": "string", "description": "Name of the team" }, "organizationId": { "type": "string", "description": "ID of the organization the team belongs to" }, "createdAt": { "type": "string", "description": "Timestamp when the team was created" }, "updatedAt": { "type": "string", "description": "Timestamp when the team was last updated" } }, "required": [ "id", "name", "organizationId", "createdAt", "updatedAt" ] } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-user-invitations": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationUserInvitations", "summary": "List Organization User Invitations", "description": "List all invitations a user has received", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "role": { "type": "string" }, "organizationId": { "type": "string" }, "organizationName": { "type": "string" }, "inviterId": { "type": "string", "description": "The ID of the user who created the invitation" }, "teamId": { "type": [ "string", "null" ], "description": "The ID of the team associated with the invitation" }, "status": { "type": "string" }, "expiresAt": { "type": "string" }, "createdAt": { "type": "string" } }, "required": [ "id", "email", "role", "organizationId", "organizationName", "inviterId", "status", "expiresAt", "createdAt" ] } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/list-user-teams": { "get": { "tags": [ "Organization Management" ], "operationId": "listOrganizationUserTeams", "summary": "List Organization User Teams", "description": "List all teams that the current user is a part of.", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": {} } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/reject-invitation": { "post": { "tags": [ "Organization Management" ], "operationId": "rejectOrganizationInvitation", "summary": "Reject Organization Invitation", "description": "Reject an invitation to an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "invitationId": { "type": "string", "description": "The ID of the invitation to reject" } }, "required": [ "invitationId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "invitation": { "type": "object", "additionalProperties": {} }, "member": { "type": [ "object", "null" ], "additionalProperties": {} } } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/remove-member": { "post": { "tags": [ "Organization Management" ], "operationId": "removeOrganizationMember", "summary": "Remove Organization Member", "description": "Remove a member from an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "memberIdOrEmail": { "type": "string", "description": "The ID or email of the member to remove" }, "organizationId": { "type": "string", "description": "The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: \"org-id\"" } }, "required": [ "memberIdOrEmail" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "member": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "organizationId": { "type": "string" }, "role": { "type": "string" } }, "required": [ "id", "userId", "organizationId", "role" ] } }, "required": [ "member" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/remove-team": { "post": { "tags": [ "Organization Management" ], "operationId": "removeOrganizationTeam", "summary": "Remove Organization Team", "description": "Remove a team from an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "teamId": { "type": "string", "description": "The team ID of the team to remove. Eg: \"team-id\"" }, "organizationId": { "type": "string", "description": "The organization ID which the team falls under. If not provided, it will default to the user's active organization. Eg: \"organization-id\"" } }, "required": [ "teamId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "enum": [ "Team removed successfully." ], "description": "Confirmation message indicating successful removal" } }, "required": [ "message" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/remove-team-member": { "post": { "tags": [ "Organization Management" ], "operationId": "removeOrganizationTeamMember", "summary": "Remove Organization Team Member", "description": "Remove a member from a team", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "teamId": { "type": "string", "description": "The team the user should be removed from." }, "userId": { "type": "string", "description": "The user which should be removed from the team." }, "organizationId": { "type": "string", "description": "The organization ID which the team falls under. If not provided, it will default to the user's active organization." } }, "required": [ "teamId", "userId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "enum": [ "Team member removed successfully." ], "description": "Confirmation message indicating successful removal" } }, "required": [ "message" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/set-active": { "post": { "tags": [ "Organization Management" ], "operationId": "setOrganizationActive", "summary": "Set Organization Active", "description": "Set the active organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "organizationId": { "type": [ "string", "null" ], "description": "The organization id to set as active. It can be null to unset the active organization. Eg: \"org-id\"" }, "organizationSlug": { "type": "string", "description": "The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: \"org-slug\"" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/set-active-team": { "post": { "tags": [ "Organization Management" ], "operationId": "setOrganizationActiveTeam", "summary": "Set Organization Active Team", "description": "Set the active team for the current active organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "teamId": { "type": [ "string", "null" ], "description": "The team id to set as active. It can be null to unset the active team" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/update": { "post": { "tags": [ "Organization Management" ], "operationId": "updateOrganization", "summary": "Update Organization", "description": "Update an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "description": { "type": [ "string", "null" ] }, "name": { "type": "string", "description": "The name of the organization" }, "slug": { "type": "string", "description": "The slug of the organization" }, "logo": { "type": [ "string", "null" ], "description": "The logo of the organization" }, "metadata": { "type": "object", "additionalProperties": {}, "description": "The metadata of the organization" } } }, "organizationId": { "type": "string", "description": "The organization ID. Eg: \"org-id\"" } }, "required": [ "data" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/update-member-role": { "post": { "tags": [ "Organization Management" ], "operationId": "updateOrganizationMemberRole", "summary": "Update Organization Member Role", "description": "Update the role of a member in an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "role": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ], "description": "The new role to be applied. This can be a string or array of strings representing the roles. Eg: [\"admin\", \"sale\"]" }, "memberId": { "type": "string", "description": "The member id to apply the role update to. Eg: \"member-id\"" }, "organizationId": { "type": "string", "description": "An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: \"organization-id\"" } }, "required": [ "role", "memberId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "member": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "organizationId": { "type": "string" }, "role": { "type": "string" } }, "required": [ "id", "userId", "organizationId", "role" ] } }, "required": [ "member" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/update-role": { "post": { "tags": [ "Organization Management" ], "operationId": "updateOrganizationRole", "summary": "Update Organization Role", "description": "Update Organization Role", "requestBody": { "required": true, "content": { "application/json": { "schema": { "allOf": [ { "type": "object", "properties": { "organizationId": { "type": "string" }, "data": { "type": "object", "properties": { "permission": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } }, "roleName": { "type": "string" } } } }, "required": [ "data" ] }, { "anyOf": [ { "type": "object", "properties": { "roleName": { "type": "string", "description": "The name of the role to update" } }, "required": [ "roleName" ] }, { "type": "object", "properties": { "roleId": { "type": "string", "description": "The id of the role to update" } }, "required": [ "roleId" ] } ] } ] } } } }, "responses": { "200": { "description": "Success" }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/organization/update-team": { "post": { "tags": [ "Organization Management" ], "operationId": "updateOrganizationTeam", "summary": "Update Organization Team", "description": "Update an existing team in an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "teamId": { "type": "string", "description": "The ID of the team to be updated. Eg: \"team-id\"" }, "data": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "organizationId": { "type": "string" }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } } } }, "required": [ "teamId", "data" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier of the updated team" }, "name": { "type": "string", "description": "Updated name of the team" }, "organizationId": { "type": "string", "description": "ID of the organization the team belongs to" }, "createdAt": { "type": "string", "description": "Timestamp when the team was created" }, "updatedAt": { "type": "string", "description": "Timestamp when the team was last updated" } }, "required": [ "id", "name", "organizationId", "createdAt", "updatedAt" ] } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/auth/device": { "get": { "operationId": "getDeviceAuthorizationPage", "tags": [ "Authentication" ], "summary": "Device authorization page", "description": "Better Auth serves this as JSON. A top-level browser navigation is redirected to the web app's device screen instead, so opening the URL by hand shows a page rather than a JSON blob.", "security": [], "parameters": [ { "schema": { "type": "string", "description": "The device authorization user code." }, "required": false, "description": "The device authorization user code.", "name": "user_code", "in": "query" }, { "schema": { "type": "string", "enum": [ "1" ], "description": "Force a redirect to the web UI, for clients that do not send Sec-Fetch-* headers." }, "required": false, "description": "Force a redirect to the web UI, for clients that do not send Sec-Fetch-* headers.", "name": "ui", "in": "query" } ], "responses": { "200": { "description": "Device authorization payload from Better Auth" }, "302": { "description": "Redirects the browser to the web app device screen" } } } }, "/mcp/register": { "post": { "operationId": "registerMcpOAuthClient", "tags": [ "MCP" ], "summary": "Register MCP OAuth client", "description": "Dynamically register a public OAuth client for the MCP endpoint. Public clients hold no secret, so authorization is protected by PKCE and an explicit consent step.", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "redirect_uris": { "type": "array", "items": { "type": "string", "maxLength": 2048 }, "minItems": 1, "maxItems": 10 }, "client_name": { "type": "string", "maxLength": 100 }, "token_endpoint_auth_method": { "type": "string", "enum": [ "none" ] }, "grant_types": { "type": "array", "items": { "type": "string", "enum": [ "authorization_code", "refresh_token" ] }, "maxItems": 2 }, "response_types": { "type": "array", "items": { "type": "string", "enum": [ "code" ] }, "minItems": 1, "maxItems": 1 } }, "required": [ "redirect_uris" ] } } } }, "responses": { "200": { "description": "Registered OAuth client", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/McpClientRegistration" } } } }, "400": { "description": "Invalid client metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } } } } }, "/mcp/authorize": { "get": { "operationId": "authorizeMcpOAuthClient", "tags": [ "MCP" ], "summary": "Start MCP authorization", "description": "Begin an MCP OAuth authorization. Redirects the browser to the Kaneo consent page, which then approves or denies the request.", "security": [], "parameters": [ { "schema": { "type": "string", "enum": [ "code" ] }, "required": true, "name": "response_type", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 128 }, "required": true, "name": "client_id", "in": "query" }, { "schema": { "type": "string", "maxLength": 2048 }, "required": true, "name": "redirect_uri", "in": "query" }, { "schema": { "type": "string", "pattern": "^[A-Za-z0-9_-]{43}$", "description": "PKCE challenge; only S256 is accepted." }, "required": true, "description": "PKCE challenge; only S256 is accepted.", "name": "code_challenge", "in": "query" }, { "schema": { "type": "string", "enum": [ "S256" ] }, "required": true, "name": "code_challenge_method", "in": "query" }, { "schema": { "type": "string", "maxLength": 1024 }, "required": false, "name": "state", "in": "query" } ], "responses": { "302": { "description": "Redirect to the Kaneo consent page" }, "400": { "description": "Invalid authorization request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } } } } }, "/mcp/authorize/request/{requestId}": { "get": { "operationId": "getMcpAuthorizationRequest", "tags": [ "MCP" ], "summary": "Get consent request", "description": "Get the client name and redirect URI for a pending consent request, so the consent page can show who is asking.", "security": [], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 128 }, "required": true, "name": "requestId", "in": "path" } ], "responses": { "200": { "description": "Authorization request details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/McpAuthorizationRequest" } } } }, "400": { "description": "Invalid OAuth client", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } }, "404": { "description": "Unknown or expired authorization request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } } } }, "post": { "operationId": "decideMcpAuthorizationRequest", "tags": [ "MCP" ], "summary": "Decide consent request", "description": "Approve or deny a pending consent request and get the URL to send the browser back to.", "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 128 }, "required": true, "name": "requestId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "approved": { "type": "boolean" } }, "required": [ "approved" ] } } } }, "responses": { "200": { "description": "OAuth client redirect", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/McpAuthorizationDecision" } } } }, "400": { "description": "Invalid request or OAuth client", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } }, "401": { "description": "Authentication required", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } }, "403": { "description": "Untrusted request origin", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } }, "404": { "description": "Unknown or expired authorization request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } } } } } }, "/oauth/id-token": { "get": { "operationId": "getOAuthIdToken", "tags": [ "Authentication" ], "summary": "Get OAuth id token", "description": "Get the id_token for the current user's custom OAuth account. Returns null when the user signed in another way.", "responses": { "200": { "description": "The id_token if available", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthIdToken" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/project/{id}/move": { "put": { "operationId": "moveProject", "tags": [ "Projects" ], "summary": "Move a project to another workspace", "description": "Move a project and its tasks. Requires update and delete permission in the source, plus project creation and workspace settings management permission in the destination. Remove cross-project task relationships before moving.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1 } }, "required": [ "workspaceId" ] } } } }, "responses": { "200": { "description": "Project moved", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MovedProject" } } } }, "400": { "description": "Invalid destination or same workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Unauthorized", "content": { "text/plain": { "schema": { "type": "string" } } } }, "402": { "description": "Destination workspace plan has expired", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "Missing workspace access or permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found in the source workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Project key conflict or cross-project task relationships", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project": { "get": { "operationId": "listProjects", "tags": [ "Projects" ], "summary": "List projects", "description": "List a workspace's projects in sidebar order, each with rollup task statistics. Archived projects are excluded unless includeArchived is set.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "query" }, { "schema": { "type": "string", "description": "Pass \"true\" to include archived projects in the list." }, "required": false, "description": "Pass \"true\" to include archived projects in the list.", "name": "includeArchived", "in": "query" } ], "responses": { "200": { "description": "List of projects", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectListItem" } } } } }, "400": { "description": "Workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createProject", "tags": [ "Projects" ], "summary": "Create project", "description": "Create a project in a workspace. The slug becomes the prefix of its task identifiers.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "workspaceId": { "type": "string" }, "icon": { "type": "string" }, "slug": { "type": "string" } }, "required": [ "name", "workspaceId", "icon", "slug" ] } } } }, "responses": { "200": { "description": "The created project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Invalid body, or workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}": { "get": { "operationId": "getProject", "tags": [ "Projects" ], "summary": "Get project", "description": "Get a single project by ID.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Project details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "updateProject", "tags": [ "Projects" ], "summary": "Update project", "description": "Replace a project's name, icon, slug, description, and visibility.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "icon": { "type": "string" }, "slug": { "type": "string" }, "description": { "type": "string" }, "isPublic": { "type": "boolean" } }, "required": [ "name", "icon", "slug", "description", "isPublic" ] } } } }, "responses": { "200": { "description": "The updated project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, missing project:update, or missing project:share when visibility changes", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteProject", "tags": [ "Projects" ], "summary": "Delete project", "description": "Permanently delete a project and everything in it. Archive it instead to keep the data.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:delete permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}/background": { "get": { "operationId": "getProjectBackground", "tags": [ "Projects" ], "summary": "Download project background", "description": "Download the current project board background image.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The project background image", "content": { "image/*": { "schema": { "type": "string", "format": "binary" } } } }, "304": { "description": "Not modified" }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project background not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteProjectBackground", "tags": [ "Projects" ], "summary": "Delete project background", "description": "Remove the current project board background image.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Project background removed" }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/reorder": { "put": { "operationId": "reorderProjects", "tags": [ "Projects" ], "summary": "Reorder projects", "description": "Set the sidebar order of a workspace's projects. The given positions express relative order only -- the workspace is renumbered to 0..n-1.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "query" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projects": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": "integer", "minimum": 0 } }, "required": [ "id", "position" ] }, "minItems": 1 } }, "required": [ "projects" ] } } } }, "responses": { "200": { "description": "The reordered projects", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Project" } } } } }, "400": { "description": "Invalid body, or workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}/archive": { "put": { "operationId": "archiveProject", "tags": [ "Projects" ], "summary": "Archive project", "description": "Hide a project from the default list without deleting it. Reversible with unarchive.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The archived project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}/unarchive": { "put": { "operationId": "unarchiveProject", "tags": [ "Projects" ], "summary": "Unarchive project", "description": "Return an archived project to the default list.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The restored project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}/background-upload": { "put": { "operationId": "uploadProjectBackground", "tags": [ "Projects" ], "summary": "Prepare project background upload", "description": "Create a presigned background image upload URL for a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "contentType": { "type": "string" }, "size": { "type": "number" } }, "required": [ "contentType", "size" ] } } } }, "responses": { "200": { "description": "Background image upload URL", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectBackgroundUpload" } } } }, "400": { "description": "Invalid image upload request, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Image uploads are not configured", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/project/{id}/background-upload/finalize": { "post": { "operationId": "finalizeProjectBackgroundUpload", "tags": [ "Projects" ], "summary": "Finalize project background upload", "description": "Save an uploaded image as the project's board background.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string" }, "contentType": { "type": "string" }, "version": { "type": "string" }, "size": { "type": "number" } }, "required": [ "key", "contentType", "version", "size" ] } } } }, "responses": { "200": { "description": "Finalized project background", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectBackgroundFinalize" } } } }, "400": { "description": "Invalid image upload request, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "500": { "description": "Failed to save the project background", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/calendar-feed/project/{projectId}": { "get": { "operationId": "listCalendarFeeds", "tags": [ "Calendar feeds" ], "summary": "List project calendar feeds", "description": "List secret calendar subscription links. Requires project sharing permission.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Calendar feeds", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CalendarFeed" } } } } }, "400": { "description": "Invalid request or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Authentication required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access or missing project sharing permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createCalendarFeed", "tags": [ "Calendar feeds" ], "summary": "Create a calendar feed", "description": "Create a calendar subscription matching any selected label. Tasks need a start or due date. All-day dates use the supplied time zone. Creating a missing workspace label definition also requires label:create permission.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "labelIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1, "maxItems": 100 }, "timeZone": { "type": "string", "default": "UTC" } }, "required": [ "labelIds" ] } } } }, "responses": { "201": { "description": "Calendar feed created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CalendarFeed" } } } }, "400": { "description": "Invalid request or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Authentication required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access, missing project:share permission, or missing label:create permission for a new workspace label definition", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/calendar-feed/project/{projectId}/{id}": { "delete": { "operationId": "revokeCalendarFeed", "tags": [ "Calendar feeds" ], "summary": "Revoke a calendar feed", "description": "Revoke a calendar subscription link, preventing further access through it.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Calendar feed revoked", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Invalid request or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Authentication required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access or missing project sharing permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Calendar feed not found in this project", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/{id}/description": { "get": { "operationId": "getTaskDescriptionPage", "tags": [ "Tasks" ], "summary": "Read a description page", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 0, "maximum": 2000000000, "default": 0 }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "pattern": "^[0-9]{1,10}$" }, "required": false, "name": "version", "in": "query" } ], "responses": { "200": { "description": "Description page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskDescriptionPage" } } } }, "400": { "description": "Invalid offset or version", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Description changed; reload from offset zero", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Description request timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/description-matches/{projectId}": { "get": { "operationId": "findDeferredTaskDescriptions", "tags": [ "Tasks" ], "summary": "Search descriptions omitted from task lists", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 256 }, "required": true, "name": "query", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 128 }, "required": false, "name": "after", "in": "query" } ], "responses": { "200": { "description": "Matching task IDs", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskDescriptionMatches" } } } }, "400": { "description": "Invalid search query or cursor", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Description search timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/assigned": { "get": { "operationId": "listAssignedTasks", "tags": [ "Tasks" ], "summary": "List my assigned tasks", "description": "Get the open tasks assigned to the caller across a workspace's active projects. Completed and archived tasks are excluded. Ordered by due date (undated last), then priority. At most 100 tasks are returned; total counts all of them.", "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "workspaceId", "in": "query" } ], "responses": { "200": { "description": "Open tasks assigned to the caller", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignedTasks" } } } }, "400": { "description": "Workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/tasks/{projectId}": { "get": { "operationId": "listTasks", "tags": [ "Tasks" ], "summary": "List tasks", "description": "Get a project's board: its columns, each with the tasks in it, plus the archived and planned buckets. Responses always contain at most 100 tasks (50 by default). Continue through pagination.totalPages for the whole board, and for each task page follow relatedPage through pagination.relatedTotalPages for all labels, links and column metadata. Filters and sorting apply before pagination. Descriptions larger than 64 KiB are omitted with descriptionDeferred=true; read the task detail or description pages for full text.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "priority", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "assigneeId", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000000 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000000 }, "required": false, "name": "relatedPage", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "enum": [ "createdAt", "priority", "dueDate", "position", "title", "number" ] }, "required": false, "name": "sortBy", "in": "query" }, { "schema": { "type": "string", "enum": [ "asc", "desc" ] }, "required": false, "name": "sortOrder", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "dueBefore", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "dueAfter", "in": "query" } ], "responses": { "200": { "description": "The project board", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BoardResponse" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Task list request timed out", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/bulk": { "patch": { "operationId": "bulkUpdateTasks", "tags": [ "Tasks" ], "summary": "Bulk update tasks", "description": "Apply one operation to many tasks at once. Every task must be in the same workspace.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskIds": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "operation": { "type": "string", "enum": [ "updateStatus", "updatePriority", "updateAssignee", "delete", "addLabel", "removeLabel", "updateDueDate" ] }, "value": { "type": [ "string", "null" ], "description": "The new value for the chosen operation. Unused by `delete`; null clears an assignee or due date." } }, "required": [ "taskIds", "operation" ] } } } }, "responses": { "200": { "description": "Bulk operation result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkTaskResult" } } } }, "400": { "description": "Invalid body, or the tasks span more than one workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing the permission the operation needs", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "No tasks found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Tasks changed projects; retry the operation", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/draft-upload/{projectId}": { "post": { "operationId": "stageTaskAssetUpload", "tags": [ "Tasks" ], "summary": "Stage a task attachment", "description": "Upload an attachment before submitting a task. Staged assets are private to the uploader and expire after 24 hours.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "filename": { "type": "string" }, "contentType": { "type": "string" }, "size": { "type": "number" }, "surface": { "type": "string", "enum": [ "description" ] } }, "required": [ "filename", "contentType", "size", "surface" ] } } } }, "responses": { "200": { "description": "Presigned upload", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskImageUpload" } } } }, "400": { "description": "Invalid upload", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Missing task:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Storage unavailable", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/draft-upload/{projectId}/finalize": { "post": { "operationId": "finalizeStagedTaskAsset", "tags": [ "Tasks" ], "summary": "Finalize a staged task attachment", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "description": "The key returned when the URL was issued." }, "filename": { "type": "string" }, "contentType": { "type": "string" }, "size": { "type": "number" }, "surface": { "type": "string", "enum": [ "description" ] } }, "required": [ "key", "filename", "contentType", "size", "surface" ] } } } }, "responses": { "200": { "description": "Staged attachment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskImageAsset" } } } }, "400": { "description": "Invalid upload", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Missing task:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Upload already attached", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Storage unavailable", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/reorder": { "post": { "operationId": "reorderTasks", "tags": [ "Tasks" ], "summary": "Reorder or move cards", "description": "Atomically update positions and optional column status for cards in one project. Other task fields are preserved.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string" }, "expectedTasks": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": [ "integer", "null" ], "minimum": 0, "maximum": 2147483646 }, "status": { "type": "string" } }, "required": [ "id", "position", "status" ] }, "description": "Previous complete contents of the affected columns; stale snapshots return 409" }, "tasks": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": "integer", "minimum": 0, "maximum": 2147483646 }, "status": { "type": "string" } }, "required": [ "id", "position" ] }, "minItems": 1 } }, "required": [ "projectId", "tasks" ] } } } }, "responses": { "200": { "description": "Updated card positions and statuses", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": "number" }, "status": { "type": "string" } }, "required": [ "id", "position", "status" ] } } } } }, "400": { "description": "Invalid positions or column", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Tasks do not belong to the project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Board changed or task moved; refresh before reordering", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/{projectId}": { "post": { "operationId": "createTask", "tags": [ "Tasks" ], "summary": "Create task", "description": "Add a task to a project. It is placed in the column named by `status`.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "startDate": { "type": "string" }, "dueDate": { "type": "string" }, "priority": { "type": "string", "enum": [ "no-priority", "low", "medium", "high", "urgent" ] }, "status": { "type": "string", "description": "The target column's slug." }, "userId": { "type": "string", "description": "Assignee, if any." }, "draftAssetIds": { "type": "array", "items": { "type": "string" }, "maxItems": 100 }, "customFields": { "type": "array", "items": { "type": "object", "properties": { "fieldId": { "type": "string" }, "value": { "type": "string" } }, "required": [ "fieldId", "value" ] } } }, "required": [ "title", "description", "priority", "status" ] } } } }, "responses": { "200": { "description": "The created task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/duplicate/{id}": { "post": { "operationId": "duplicateTask", "tags": [ "Tasks" ], "summary": "Duplicate a task", "description": "Copy a task into the same project and column, including custom fields, labels, description assets and same-workspace parent links. Copying parent links also requires task:update. Comments, time entries and child tasks are not copied.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" } } } } } }, "responses": { "200": { "description": "The duplicated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid task fields or request", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Unauthorized", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access, missing task:create, or missing task:update when copying parent links", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task or project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Task column has reached its capacity", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Unable to copy task attachments", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/by-ticket-id/{ticketId}": { "get": { "operationId": "getTaskByTicketId", "tags": [ "Tasks" ], "summary": "Get task by ticket ID", "description": "Get a single task by its project key and number, such as KAN-12. If the ticket ID matches multiple accessible tasks, provide workspaceId or projectId to select one.", "parameters": [ { "schema": { "type": "string", "maxLength": 128, "description": "Project key and task number, e.g. KAN-12." }, "required": true, "description": "Project key and task number, e.g. KAN-12.", "name": "ticketId", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "description": "Select a workspace if the ticket ID exists in more than one." }, "required": false, "description": "Select a workspace if the ticket ID exists in more than one.", "name": "workspaceId", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "description": "Select a project if the ticket ID exists more than once." }, "required": false, "description": "Select a project if the ticket ID exists more than once.", "name": "projectId", "in": "query" } ], "responses": { "200": { "description": "Task details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskWithAssignee" } } } }, "400": { "description": "Invalid ticket ID", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "404": { "description": "No accessible task has this ticket ID", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Ticket ID matches multiple accessible tasks", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/{id}": { "get": { "operationId": "getTask", "tags": [ "Tasks" ], "summary": "Get task", "description": "Get a single task by ID, with its assignee name. The board view omits descriptions above 64 KiB and includes task and same-project parent subtask progress.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "detail", "board" ] }, "required": false, "name": "view", "in": "query" } ], "responses": { "200": { "description": "Task details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskWithAssignee" } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "updateTask", "tags": [ "Tasks" ], "summary": "Update task", "description": "Replace every field of a task. Use the single-field routes for narrower edits.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" }, "description": { "type": "string", "description": "Omit to preserve the existing description when updating a list summary." }, "startDate": { "type": "string" }, "dueDate": { "type": "string" }, "priority": { "type": "string", "enum": [ "no-priority", "low", "medium", "high", "urgent" ] }, "status": { "type": "string" }, "projectId": { "type": "string" }, "position": { "type": "integer", "minimum": 0, "maximum": 2147483646 }, "userId": { "type": "string" } }, "required": [ "title", "priority", "status", "projectId", "position" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update or task:assign permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteTask", "tags": [ "Tasks" ], "summary": "Delete task", "description": "Permanently delete a task and its comments, labels, and time entries.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:delete permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Task changed projects; retry the operation", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/move/{id}": { "put": { "operationId": "moveTask", "tags": [ "Tasks" ], "summary": "Move task", "description": "Move a task to another project, optionally into a named column. Both projects must be in the same workspace.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "destinationProjectId": { "type": "string" }, "destinationStatus": { "type": "string", "description": "Defaults to the destination project's first column." } }, "required": [ "destinationProjectId" ] } } } }, "responses": { "200": { "description": "The moved task, with both project ids", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MoveTaskResult" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task or destination project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Task or project moved concurrently; retry the move", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/export/{projectId}": { "get": { "operationId": "exportTasks", "tags": [ "Tasks" ], "summary": "Export tasks", "description": "Export a project's tasks, with their labels, as a JSON document.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The exported project and tasks", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskExport" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/import/{projectId}": { "post": { "operationId": "importTasks", "tags": [ "Tasks" ], "summary": "Import tasks", "description": "Import tasks into a project. Each task is reported individually, so a partial import still returns 200.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "tasks": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string" }, "priority": { "type": "string" }, "startDate": { "type": [ "string", "null" ] }, "dueDate": { "type": [ "string", "null" ] }, "userId": { "type": [ "string", "null" ] } }, "required": [ "title", "status" ] } } }, "required": [ "tasks" ] } } } }, "responses": { "200": { "description": "Per-task import outcome", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskImportResult" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/status/{id}": { "put": { "operationId": "updateTaskStatus", "tags": [ "Tasks" ], "summary": "Update task status", "description": "Move a task to another column in the same project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string" } }, "required": [ "status" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/priority/{id}": { "put": { "operationId": "updateTaskPriority", "tags": [ "Tasks" ], "summary": "Update task priority", "description": "Set a task's priority.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "priority": { "type": "string", "enum": [ "no-priority", "low", "medium", "high", "urgent" ] } }, "required": [ "priority" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid priority, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/assignee/{id}": { "put": { "operationId": "updateTaskAssignee", "tags": [ "Tasks" ], "summary": "Update task assignee", "description": "Assign a task to a workspace member, or send null to unassign it.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "userId": { "type": [ "string", "null" ], "description": "Null unassigns." } }, "required": [ "userId" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:assign permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Assignee is not a member of the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/due-date/{id}": { "put": { "operationId": "updateTaskDueDate", "tags": [ "Tasks" ], "summary": "Update task due date", "description": "Set or clear a task's due date.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "dueDate": { "type": "string" } } } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid date, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/title/{id}": { "put": { "operationId": "updateTaskTitle", "tags": [ "Tasks" ], "summary": "Update task title", "description": "Rename a task.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" } }, "required": [ "title" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/image-upload/{id}": { "put": { "operationId": "createTaskImageUpload", "tags": [ "Tasks" ], "summary": "Create image upload URL", "description": "Get a presigned URL for uploading an image used in a task description or comment. PUT the bytes to it, then call the finalize route.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "filename": { "type": "string" }, "contentType": { "type": "string" }, "size": { "type": "number" }, "surface": { "type": "string", "enum": [ "description", "comment" ], "description": "Where the image is used, which decides how it is scoped." } }, "required": [ "filename", "contentType", "size", "surface" ] } } } }, "responses": { "200": { "description": "The presigned upload", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskImageUpload" } } } }, "400": { "description": "Unsupported content type, or the file is too large", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "503": { "description": "Image uploads are not configured on this instance", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/image-upload/{id}/finalize": { "post": { "operationId": "finalizeTaskImageUpload", "tags": [ "Tasks" ], "summary": "Finalize image upload", "description": "Record an uploaded image as a private asset and return the URL to reference it by.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "description": "The key returned when the URL was issued." }, "filename": { "type": "string" }, "contentType": { "type": "string" }, "size": { "type": "number" }, "surface": { "type": "string", "enum": [ "description", "comment" ], "description": "Where the image is used, which decides how it is scoped." } }, "required": [ "key", "filename", "contentType", "size", "surface" ] } } } }, "responses": { "200": { "description": "The stored asset", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskImageAsset" } } } }, "400": { "description": "Invalid upload, or the key does not belong to this task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task/description/{id}": { "put": { "operationId": "updateTaskDescription", "tags": [ "Tasks" ], "summary": "Update task description", "description": "Replace a task's description.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "description": { "type": "string" } }, "required": [ "description" ] } } } }, "responses": { "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/column/{projectId}": { "get": { "operationId": "getColumns", "tags": [ "Columns" ], "summary": "Get columns", "description": "Get a project's board columns, ordered by position.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "List of columns ordered by position", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Column" } } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createColumn", "tags": [ "Columns" ], "summary": "Create column", "description": "Add a column to the end of a project's board. The slug is derived from the name.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "isFinal": { "type": "boolean" } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "The created column", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Column" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "The slug is reserved, or already used in this project", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/column/reorder/{projectId}": { "put": { "operationId": "reorderColumns", "tags": [ "Columns" ], "summary": "Reorder columns", "description": "Set new positions for a project's columns and return the whole board in its new order.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "columns": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": "number" } }, "required": [ "id", "position" ] }, "description": "Every column keeps its new position. Columns from another project are rejected." } }, "required": [ "columns" ] } } } }, "responses": { "200": { "description": "The reordered columns", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Column" } } } } }, "400": { "description": "A column does not belong to this project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/column/{id}": { "put": { "operationId": "updateColumn", "tags": [ "Columns" ], "summary": "Update column", "description": "Update a column. Omitted fields are left unchanged; icon and color accept null to clear them.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "icon": { "type": [ "string", "null" ] }, "color": { "type": [ "string", "null" ] }, "isFinal": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "The updated column", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Column" } } } }, "400": { "description": "Invalid body, or unknown column", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteColumn", "tags": [ "Columns" ], "summary": "Delete column", "description": "Delete an empty column. A column holding tasks is refused until they are moved or deleted.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted column", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Column" } } } }, "400": { "description": "Unknown column, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "The column still contains tasks", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/activity/workspace/{workspaceId}": { "get": { "operationId": "getWorkspaceActivities", "tags": [ "Activity" ], "summary": "Get recent workspace activity", "description": "Get the 20 most recent task events across a workspace's active projects from the last 30 days, newest first. Each event carries a short plain-text excerpt instead of its full content.", "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "Recent activity in the workspace", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/WorkspaceActivity" } } } } }, "400": { "description": "Workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/activity/{taskId}": { "get": { "operationId": "getActivities", "tags": [ "Activity" ], "summary": "Get task activity", "description": "Get a task's full activity feed, newest first: comments alongside system events such as status and assignee changes.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "List of activities for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Activity" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/activity/create": { "post": { "operationId": "createActivity", "tags": [ "Activity" ], "summary": "Create activity", "description": "Record a system-generated event on a task. Most events are written by the server itself; this exists for importers and integrations.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskId": { "type": "string" }, "message": { "type": [ "string", "null" ], "description": "Free-text body. Null for events whose meaning is in eventData." }, "type": { "type": "string", "description": "The event kind, e.g. status_changed or assignee_changed." }, "eventData": { "type": [ "object", "null" ], "additionalProperties": {}, "description": "Type-specific payload stored alongside the event." } }, "required": [ "taskId", "message", "type" ] } } } }, "responses": { "200": { "description": "The created activity", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, unknown task, or comment activity submitted through the generic endpoint", "content": { "text/plain": { "schema": { "type": "string" } }, "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/activity/comment": { "post": { "operationId": "createComment", "tags": [ "Activity" ], "summary": "Create comment", "description": "Add a comment to a task. Equivalent to POST /comment/{taskId}, kept for the activity-feed client.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskId": { "type": "string" }, "comment": { "type": "string", "maxLength": 10000 } }, "required": [ "taskId", "comment" ] } } } }, "responses": { "200": { "description": "The created comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "updateComment", "tags": [ "Activity" ], "summary": "Update comment", "description": "Edit a comment. Only the comment's author may do this.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "activityId": { "type": "string" }, "comment": { "type": "string", "maxLength": 10000 } }, "required": [ "activityId", "comment" ] } } } }, "responses": { "200": { "description": "The updated comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, or unknown activity", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not the author, or no access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Comment not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteComment", "tags": [ "Activity" ], "summary": "Delete comment", "description": "Delete a comment. Only the comment's author may do this.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "activityId": { "type": "string" } }, "required": [ "activityId" ] } } } }, "responses": { "200": { "description": "The deleted comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, or unknown activity", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not the author, or no access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Comment not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/comment/{taskId}": { "get": { "operationId": "getTaskComments", "tags": [ "Comments" ], "summary": "Get task comments", "description": "Get every comment on a task, oldest first, each with its author's name and avatar.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "List of comments for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createTaskComment", "tags": [ "Comments" ], "summary": "Create task comment", "description": "Add a comment to a task. Mentions in the content notify the mentioned users, and the assignee is notified too. Returns the stored activity row, which carries no author object -- read the list route for that.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000 }, "externalUserName": { "type": "string", "maxLength": 120, "description": "Attribution for an imported comment. Requires workspace:manage_settings and externalSource; otherwise ignored." }, "externalSource": { "type": "string", "enum": [ "planka", "trello", "jira" ], "description": "The tool the comment was imported from. Supplying external attribution requires workspace:manage_settings." } }, "required": [ "content" ] } } } }, "responses": { "200": { "description": "The created comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, missing task:update permission, or external attribution without workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/comment/{id}": { "put": { "operationId": "updateTaskComment", "tags": [ "Comments" ], "summary": "Update task comment", "description": "Edit a comment. Only the comment's author may do this.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000 } }, "required": [ "content" ] } } } }, "responses": { "200": { "description": "The updated comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Invalid body, or unknown comment", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not the author, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Comment not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteTaskComment", "tags": [ "Comments" ], "summary": "Delete task comment", "description": "Delete a comment. Only the comment's author may do this.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted comment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Activity" } } } }, "400": { "description": "Unknown comment, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not the author, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Comment not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/time-entry/task/{taskId}": { "get": { "operationId": "getTaskTimeEntries", "tags": [ "Time Entries" ], "summary": "Get task time entries", "description": "Get every time entry logged against a task.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "List of time entries for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TimeEntryWithUser" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/time-entry/{id}": { "get": { "operationId": "getTimeEntry", "tags": [ "Time Entries" ], "summary": "Get time entry", "description": "Get a single time entry by ID.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Time entry details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TimeEntry" } } } }, "400": { "description": "Unknown entry, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the entry's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "updateTimeEntry", "tags": [ "Time Entries" ], "summary": "Update time entry", "description": "Replace a time entry's start, end, and description. Setting endTime closes a running entry and fills in its duration.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "startTime": { "type": "string", "format": "date-time", "example": "2026-01-31T09:00:00Z" }, "endTime": { "type": "string", "format": "date-time", "example": "2026-01-31T09:00:00Z" }, "description": { "type": "string" } }, "required": [ "startTime" ] } } } }, "responses": { "200": { "description": "The updated time entry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TimeEntry" } } } }, "400": { "description": "Invalid timestamps, or unknown entry", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/time-entry": { "post": { "operationId": "createTimeEntry", "tags": [ "Time Entries" ], "summary": "Create time entry", "description": "Log time against a task. Omit endTime to start a running entry that can be closed later with an update.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskId": { "type": "string" }, "startTime": { "type": "string", "format": "date-time", "example": "2026-01-31T09:00:00Z" }, "endTime": { "type": "string", "format": "date-time", "example": "2026-01-31T09:00:00Z", "description": "Omit to start an open-ended entry that is still running." }, "description": { "type": "string" } }, "required": [ "taskId", "startTime" ] } } } }, "responses": { "200": { "description": "The created time entry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TimeEntry" } } } }, "400": { "description": "Invalid timestamps, or unknown task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/label/task/{taskId}": { "get": { "operationId": "getTaskLabels", "tags": [ "Labels" ], "summary": "Get task labels", "description": "Get all labels assigned to a specific task", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "List of labels for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Label" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/label/workspace/{workspaceId}": { "get": { "operationId": "getWorkspaceLabels", "tags": [ "Labels" ], "summary": "Get workspace labels", "description": "Get all labels for a specific workspace", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "List of labels in the workspace", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Label" } } } } }, "400": { "description": "Workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/label": { "post": { "operationId": "createLabel", "tags": [ "Labels" ], "summary": "Create label", "description": "Create a new label in a workspace", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "color": { "type": "string" }, "workspaceId": { "type": "string" }, "taskId": { "type": "string" } }, "required": [ "name", "color", "workspaceId" ] } } } }, "responses": { "200": { "description": "Label created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid body, or workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing label:create permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "The workspace label is being deleted", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/label/{id}": { "get": { "operationId": "getLabel", "tags": [ "Labels" ], "summary": "Get label", "description": "Get a specific label by ID", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Label details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Unknown label, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the label's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "updateLabel", "tags": [ "Labels" ], "summary": "Update label", "description": "Update an existing label", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "color": { "type": "string" } }, "required": [ "name", "color" ] } } } }, "responses": { "200": { "description": "Label updated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid body, or unknown label", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing label:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "The workspace label is being deleted", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteLabel", "tags": [ "Labels" ], "summary": "Delete label", "description": "Delete a label by ID. Large workspace cascades remove at most 25 task copies per request. Repeat DELETE with the same ID after HTTP 202 until HTTP 200 completes the operation. The persisted start boundary allows safe resumption after a disconnect. HTTP 429 asks the caller to retry later.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Label deleted successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "202": { "description": "Deletion has more batches; repeat the same request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PendingLabelDeletion" } } } }, "400": { "description": "Unknown label, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing label:delete permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "The label's task no longer exists", "content": { "text/plain": { "schema": { "type": "string" } } } }, "429": { "description": "Deletion capacity is busy; retry after Retry-After", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/label/{id}/task": { "put": { "operationId": "attachLabelToTask", "tags": [ "Labels" ], "summary": "Attach label to task", "description": "Attach an existing label to a task", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskId": { "type": "string" } }, "required": [ "taskId" ] } } } }, "responses": { "200": { "description": "Label attached to task successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Unknown label, or label and task belong to different workspaces", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing label:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "The workspace label is being deleted", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "detachLabelFromTask", "tags": [ "Labels" ], "summary": "Detach label from task", "description": "Detach a label from its current task", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Label detached from task successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Unknown label, or label is not assigned to a task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing label:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/notification": { "get": { "operationId": "listNotifications", "tags": [ "Notifications" ], "summary": "List notifications", "description": "Get up to 50 notifications for the current user, read and unread. Optionally limit them to one workspace before applying the limit.", "parameters": [ { "schema": { "type": "string", "minLength": 1, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces." }, "required": false, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces.", "name": "workspaceId", "in": "query" } ], "responses": { "200": { "description": "List of notifications", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Notification" } } } } }, "401": { "description": "Missing or invalid credentials" } } }, "post": { "operationId": "createNotification", "tags": [ "Notifications" ], "summary": "Create notification", "description": "Create a notification for the current user. Most notifications are raised by the server from task and workspace events; this exists for integrations. Returns null when the user has turned off this notification category in their preferences.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": [ "string", "null" ] }, "message": { "type": [ "string", "null" ], "description": "Stored as the notification's content." }, "type": { "type": "string" }, "eventData": { "type": [ "object", "null" ], "additionalProperties": {} }, "relatedEntityId": { "type": "string", "description": "Stored as resourceId: the task or workspace being pointed at." }, "relatedEntityType": { "type": "string", "description": "Stored as resourceType: `task` or `workspace`." } }, "required": [ "type" ] } } } }, "responses": { "200": { "description": "The created notification, or null when the user has muted this notification type", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/Notification" }, { "type": [ "object", "null" ] } ] } } } }, "400": { "description": "Invalid request", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/notification/{id}/read": { "patch": { "operationId": "markNotificationAsRead", "tags": [ "Notifications" ], "summary": "Mark notification read", "description": "Mark one notification as read. Scoped to the current user, so another user's notification is not found.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The updated notification", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Notification" } } } }, "401": { "description": "Missing or invalid credentials" }, "404": { "description": "Notification not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/notification/read-all": { "patch": { "operationId": "markAllNotificationsAsRead", "tags": [ "Notifications" ], "summary": "Mark all read", "description": "Mark notifications for the current user as read, optionally limited to one workspace.", "parameters": [ { "schema": { "type": "string", "minLength": 1, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces." }, "required": false, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces.", "name": "workspaceId", "in": "query" } ], "responses": { "200": { "description": "All notifications marked as read", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationBulkResult" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/notification/clear-all": { "delete": { "operationId": "clearAllNotifications", "tags": [ "Notifications" ], "summary": "Clear all", "description": "Permanently delete notifications for the current user, optionally limited to one workspace. This cannot be undone.", "parameters": [ { "schema": { "type": "string", "minLength": 1, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces." }, "required": false, "description": "Limit notifications to resources currently in this workspace. Omit to include all workspaces.", "name": "workspaceId", "in": "query" } ], "responses": { "200": { "description": "All notifications cleared", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationBulkResult" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/notification-preferences": { "get": { "operationId": "getNotificationPreferences", "tags": [ "Notification Preferences" ], "summary": "Get notification preferences", "description": "Get how the current user is notified, globally and per workspace. Configured secrets are reported as booleans plus a masked preview, never in full.", "responses": { "200": { "description": "Notification preferences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } }, "401": { "description": "Missing or invalid credentials" } } }, "put": { "operationId": "updateNotificationPreferences", "tags": [ "Notification Preferences" ], "summary": "Update notification preferences", "description": "Update the global delivery settings. Omitted fields are left unchanged; a secret sent as null is cleared.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "emailEnabled": { "type": "boolean" }, "ntfyEnabled": { "type": "boolean" }, "ntfyServerUrl": { "type": [ "string", "null" ] }, "ntfyTopic": { "type": [ "string", "null" ] }, "ntfyToken": { "type": [ "string", "null" ] }, "gotifyEnabled": { "type": "boolean" }, "gotifyServerUrl": { "type": [ "string", "null" ] }, "gotifyToken": { "type": [ "string", "null" ] }, "webhookEnabled": { "type": "boolean" }, "webhookUrl": { "type": [ "string", "null" ] }, "webhookSecret": { "type": [ "string", "null" ] }, "taskAssignmentEnabled": { "type": "boolean" }, "taskCommentEnabled": { "type": "boolean" }, "taskStatusChangeEnabled": { "type": "boolean" }, "dueDateReminderEnabled": { "type": "boolean" }, "dueDateReminderLeadTimeMinutes": { "type": "integer", "minimum": 5, "maximum": 43200, "description": "Between 5 minutes and 30 days." } } } } } }, "responses": { "200": { "description": "The updated preferences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } }, "400": { "description": "Invalid request", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/notification-preferences/workspaces/{workspaceId}": { "put": { "operationId": "upsertNotificationPreferenceWorkspaceRule", "tags": [ "Notification Preferences" ], "summary": "Upsert workspace rule", "description": "Create or replace the notification rule for one workspace, overriding the global settings there.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "isActive": { "type": "boolean" }, "emailEnabled": { "type": "boolean" }, "ntfyEnabled": { "type": "boolean" }, "gotifyEnabled": { "type": "boolean" }, "webhookEnabled": { "type": "boolean" }, "projectMode": { "type": "string", "enum": [ "all", "selected" ] }, "selectedProjectIds": { "type": "array", "items": { "type": "string" }, "description": "Required in practice when projectMode is `selected`." } }, "required": [ "isActive", "emailEnabled", "ntfyEnabled", "gotifyEnabled", "webhookEnabled", "projectMode" ] } } } }, "responses": { "200": { "description": "The updated preferences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } }, "400": { "description": "Invalid request", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteNotificationPreferenceWorkspaceRule", "tags": [ "Notification Preferences" ], "summary": "Delete workspace rule", "description": "Remove a workspace's rule so the workspace falls back to the global settings.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "The updated preferences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Workspace rule not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/search": { "get": { "operationId": "globalSearch", "tags": [ "Search" ], "summary": "Global search", "description": "Search across tasks, projects, workspaces, comments, and activities in one workspace. Results are ranked by relevance and returned as a single flat list, each entry tagged with its `type`.", "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512 }, "required": true, "name": "q", "in": "query" }, { "schema": { "type": "string", "enum": [ "all", "tasks", "projects", "workspaces", "comments", "activities" ], "default": "all" }, "required": false, "name": "type", "in": "query" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "workspaceId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "projectId", "in": "query" }, { "schema": { "type": "string", "default": "20" }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "format": "email" }, "required": false, "name": "userEmail", "in": "query" } ], "responses": { "200": { "description": "Ranked search results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" } } } }, "400": { "description": "Invalid query, or workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/github-integration/app-info": { "get": { "operationId": "getGitHubAppInfo", "tags": [ "GitHub" ], "summary": "Get GitHub app info", "description": "Get the GitHub App this instance is configured with, so the client can build an install link.", "responses": { "200": { "description": "GitHub app information", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubAppInfo" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/github-integration/repositories/{projectId}": { "get": { "operationId": "listGitHubRepositories", "tags": [ "GitHub" ], "summary": "List GitHub repositories", "description": "List the repositories reachable through the installed GitHub App, for picking one to link.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" }, { "schema": { "type": "string", "pattern": "^[1-9][0-9]{0,5}$", "default": "1" }, "required": false, "name": "installationPage", "in": "query" }, { "schema": { "type": "string", "pattern": "^[1-9][0-9]{0,5}$", "default": "1" }, "required": false, "name": "repositoryPage", "in": "query" } ], "responses": { "200": { "description": "Repositories reachable through the installed App", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubRepositoryList" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/github-integration/verify": { "post": { "operationId": "verifyGitHubInstallation", "tags": [ "GitHub" ], "summary": "Verify GitHub installation", "description": "Check that the GitHub App is installed on a repository and holds the permissions Kaneo needs. Always 200 -- problems are reported in the body so the client can guide the user.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1 }, "repositoryOwner": { "type": "string", "minLength": 1, "maxLength": 100 }, "repositoryName": { "type": "string", "minLength": 1, "maxLength": 100 } }, "required": [ "projectId", "repositoryOwner", "repositoryName" ] } } } }, "responses": { "200": { "description": "Verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubVerificationResult" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/github-integration/project/{projectId}": { "get": { "operationId": "getGitHubIntegration", "tags": [ "GitHub" ], "summary": "Get GitHub integration", "description": "Get the GitHub integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "GitHub integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createGitHubIntegration", "tags": [ "GitHub" ], "summary": "Create GitHub integration", "description": "Link a project to a GitHub repository. Disconnect first to switch repositories; existing issue and pull request links cannot be reused for another repository.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "repositoryOwner": { "type": "string", "minLength": 1, "maxLength": 100 }, "repositoryName": { "type": "string", "minLength": 1, "maxLength": 100 } }, "required": [ "repositoryOwner", "repositoryName" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedGitHubIntegration" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Integration changed or another repository is already linked", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateGitHubIntegration", "tags": [ "GitHub" ], "summary": "Update GitHub integration", "description": "Update the GitHub integration. Omitted fields keep their current value.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "isActive": { "type": "boolean" }, "commentTaskLinkOnGitHubIssue": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Integration not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubIntegrationNotFound" } } } }, "409": { "description": "Integration changed or another repository is already linked", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteGitHubIntegration", "tags": [ "GitHub" ], "summary": "Delete GitHub integration", "description": "Unlink a project from its GitHub repository.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitHubDeleteResult" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "GitHub integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/github-integration/import-issues": { "post": { "operationId": "importGitHubIssues", "tags": [ "GitHub" ], "summary": "Import GitHub issues", "description": "Import open issues and link open pull requests in bounded steps. Existing tasks are updated. Continue 202 responses with the returned runId until 200; the same runId safely retries completion. Progress is saved after each page. New calls without runId resume an unfinished import or start a new one after completion.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1, "maxLength": 128 }, "runId": { "type": "string", "minLength": 1, "maxLength": 128 } }, "required": [ "projectId" ] } } } }, "responses": { "200": { "description": "Completed import summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueImportResult" } } } }, "202": { "description": "Saved import progress; continue with runId", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueImportResult" } } } }, "400": { "description": "projectId is required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:create or task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "Integration or import changed; refresh before resuming", "content": { "text/plain": { "schema": { "type": "string" } } } }, "429": { "description": "Import busy; retry after one second", "content": { "text/plain": { "schema": { "type": "string" } } } }, "502": { "description": "Provider unavailable or invalid page; progress is saved", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitea-integration/repositories": { "post": { "operationId": "listGiteaRepositories", "tags": [ "Gitea" ], "summary": "List Gitea repositories", "description": "List the repositories a Gitea token can reach, for picking one to link. Sent as a POST because the token travels in the body rather than the URL.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1 }, "baseUrl": { "type": "string", "format": "uri" }, "accessToken": { "type": "string", "minLength": 1 } }, "required": [ "projectId", "baseUrl", "accessToken" ] } } } }, "responses": { "200": { "description": "Accessible repositories", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaRepositoryList" } } } }, "400": { "description": "Invalid body, unknown project, or invalid Gitea credentials", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitea-integration/verify": { "post": { "operationId": "verifyGiteaAccess", "tags": [ "Gitea" ], "summary": "Verify Gitea access", "description": "Check that the base URL is a Gitea instance and that the token can reach the repository with the permissions Kaneo needs. Repository permission failures are reported in the body; invalid credentials and upstream errors return an error status. Omit accessToken to use the saved token for the unchanged base URL.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1 }, "baseUrl": { "type": "string", "format": "uri" }, "accessToken": { "type": "string", "minLength": 1, "description": "Omit to verify with this project's saved token. The base URL must match the saved integration." }, "repositoryOwner": { "type": "string", "minLength": 1 }, "repositoryName": { "type": "string", "minLength": 1 } }, "required": [ "projectId", "baseUrl", "repositoryOwner", "repositoryName" ] } } } }, "responses": { "200": { "description": "Verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaVerificationResult" } } } }, "400": { "description": "Invalid body, unknown project, or invalid Gitea credentials", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Kaneo authentication required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "500": { "description": "Gitea verification failed", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitea-integration/project/{projectId}": { "get": { "operationId": "getGiteaIntegration", "tags": [ "Gitea" ], "summary": "Get Gitea integration", "description": "Get the Gitea integration for a project, or null when none is configured. The webhook secret is included only for callers with workspace:manage_settings.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Gitea integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createGiteaIntegration", "tags": [ "Gitea" ], "summary": "Create Gitea integration", "description": "Link a project to a Gitea repository, creating the webhook Gitea will post events to. Use the verify route first to confirm the token really reaches the repository.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "baseUrl": { "type": "string", "minLength": 1 }, "accessToken": { "type": "string", "description": "Omit to keep the token already stored for this project." }, "repositoryOwner": { "type": "string", "minLength": 1 }, "repositoryName": { "type": "string", "minLength": 1 } }, "required": [ "baseUrl", "repositoryOwner", "repositoryName" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaIntegration" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateGiteaIntegration", "tags": [ "Gitea" ], "summary": "Update Gitea integration", "description": "Update the Gitea integration. Omitted fields keep their current value.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "isActive": { "type": "boolean" }, "commentTaskLinkOnGiteaIssue": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Integration not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaIntegrationNotFound" } } } } } }, "delete": { "operationId": "deleteGiteaIntegration", "tags": [ "Gitea" ], "summary": "Delete Gitea integration", "description": "Unlink a project from its Gitea repository.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaDeleteResult" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Gitea integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitea-integration/import-issues": { "post": { "operationId": "importGiteaIssues", "tags": [ "Gitea" ], "summary": "Import Gitea issues", "description": "Import the linked repository's issues as tasks. Issues that already have a task are refreshed rather than duplicated.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string" } }, "required": [ "projectId" ] } } } }, "responses": { "200": { "description": "Import summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaImportResult" } } } }, "400": { "description": "projectId is required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:create or task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitlab-integration/projects": { "post": { "operationId": "listGitlabProjects", "tags": [ "GitLab" ], "summary": "List GitLab projects", "description": "List the projects a GitLab token is a member of, for picking one to link. Sent as a POST because the token travels in the body rather than the URL.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1 }, "baseUrl": { "type": "string", "format": "uri" }, "accessToken": { "type": "string", "minLength": 1 }, "tokenType": { "type": "string", "enum": [ "private", "bearer" ], "description": "`private` sends the token in PRIVATE-TOKEN, which is what personal, project and group access tokens expect. `bearer` sends it in Authorization, for an OAuth2 token you already hold. Defaults to `private`." } }, "required": [ "projectId", "baseUrl", "accessToken" ] } } } }, "responses": { "200": { "description": "Accessible projects", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabProjectList" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "GitLab rejected the token, or the instance is unreachable", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitlab-integration/verify": { "post": { "operationId": "verifyGitlabAccess", "tags": [ "GitLab" ], "summary": "Verify GitLab access", "description": "Check that the base URL is a GitLab instance and that the token can reach the project with the permissions Kaneo needs. An unreachable instance, a missing project, or insufficient permissions are reported in a 200 body so the form can explain them; a token GitLab rejects outright is a 401.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string", "minLength": 1 }, "baseUrl": { "type": "string", "format": "uri" }, "accessToken": { "type": "string", "minLength": 1 }, "tokenType": { "type": "string", "enum": [ "private", "bearer" ], "description": "`private` sends the token in PRIVATE-TOKEN, which is what personal, project and group access tokens expect. `bearer` sends it in Authorization, for an OAuth2 token you already hold. Defaults to `private`." }, "projectPath": { "type": "string", "minLength": 1, "description": "Full path of the GitLab project, including any nested groups, for example acme/platform/web." } }, "required": [ "projectId", "baseUrl", "accessToken", "projectPath" ] } } } }, "responses": { "200": { "description": "Verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabVerificationResult" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "GitLab rejected the token", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitlab-integration/project/{projectId}": { "get": { "operationId": "getGitlabIntegration", "tags": [ "GitLab" ], "summary": "Get GitLab integration", "description": "Get the GitLab integration for a project, or null when none is configured. The masked access token and the webhook secret are included only for callers with workspace:manage_settings.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "GitLab integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createGitlabIntegration", "tags": [ "GitLab" ], "summary": "Create GitLab integration", "description": "Link a project to a GitLab project. Kaneo generates the secret GitLab must send with each webhook; add the webhook in GitLab afterwards. Use the verify route first to confirm the token really reaches the project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "baseUrl": { "type": "string", "format": "uri" }, "accessToken": { "type": "string", "description": "Omit to keep the stored token only when the GitLab base URL is unchanged. A changed URL requires a new token." }, "tokenType": { "type": "string", "enum": [ "private", "bearer" ], "description": "`private` sends the token in PRIVATE-TOKEN, which is what personal, project and group access tokens expect. `bearer` sends it in Authorization, for an OAuth2 token you already hold. Defaults to `private`." }, "projectPath": { "type": "string", "minLength": 1 } }, "required": [ "baseUrl", "projectPath" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabIntegration" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "That GitLab project is already linked to another Kaneo project", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateGitlabIntegration", "tags": [ "GitLab" ], "summary": "Update GitLab integration", "description": "Update the GitLab integration. Omitted fields keep their current value.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "isActive": { "type": "boolean" }, "commentTaskLinkOnGitlabIssue": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Integration not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabIntegrationNotFound" } } } } } }, "delete": { "operationId": "deleteGitlabIntegration", "tags": [ "GitLab" ], "summary": "Delete GitLab integration", "description": "Unlink a project from its GitLab project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabDeleteResult" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "GitLab integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/gitlab-integration/import-issues": { "post": { "operationId": "importGitlabIssues", "tags": [ "GitLab" ], "summary": "Import GitLab issues", "description": "Import the linked project's open issues as tasks. Issues that already have a task are refreshed rather than duplicated. Requires task:create and task:update permissions.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string" } }, "required": [ "projectId" ] } } } }, "responses": { "200": { "description": "Import summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitlabImportResult" } } } }, "400": { "description": "projectId is required", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:create or task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/generic-webhook-integration/project/{projectId}": { "get": { "operationId": "getGenericWebhookIntegration", "tags": [ "Generic Webhook" ], "summary": "Get webhook integration", "description": "Get the outgoing webhook integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Webhook integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenericWebhookIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createGenericWebhookIntegration", "tags": [ "Generic Webhook" ], "summary": "Create webhook integration", "description": "Create or replace the outgoing webhook for a project. Kaneo POSTs the selected task events to this URL, signed with the secret when one is set.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string", "minLength": 1 }, "secret": { "type": "string", "description": "Optional HMAC secret used to sign outgoing deliveries." }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" }, "taskDeleted": { "type": "boolean" }, "taskMoved": { "type": "boolean" }, "taskDueDateChanged": { "type": "boolean" }, "taskAssigneeChanged": { "type": "boolean" }, "taskUnassigned": { "type": "boolean" }, "dueDateReminder": { "type": "boolean" } } }, "dueDateReminderLeadTimeMinutes": { "type": "integer", "minimum": 5, "maximum": 43200, "description": "Between 5 minutes and 30 days." } }, "required": [ "webhookUrl" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenericWebhookIntegration" } } } }, "400": { "description": "The webhook URL failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateGenericWebhookIntegration", "tags": [ "Generic Webhook" ], "summary": "Update webhook integration", "description": "Update the outgoing webhook. Omitted fields keep their current value, event toggles merge into the existing set, and a null secret clears it.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string" }, "secret": { "type": [ "string", "null" ], "description": "Send null to remove the signing secret." }, "isActive": { "type": "boolean" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" }, "taskDeleted": { "type": "boolean" }, "taskMoved": { "type": "boolean" }, "taskDueDateChanged": { "type": "boolean" }, "taskAssigneeChanged": { "type": "boolean" }, "taskUnassigned": { "type": "boolean" }, "dueDateReminder": { "type": "boolean" } } }, "dueDateReminderLeadTimeMinutes": { "type": "integer", "minimum": 5, "maximum": 43200, "description": "Between 5 minutes and 30 days." } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenericWebhookIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Webhook integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteGenericWebhookIntegration", "tags": [ "Generic Webhook" ], "summary": "Delete webhook integration", "description": "Remove the outgoing webhook from a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Webhook integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/discord-integration/project/{projectId}": { "get": { "operationId": "getDiscordIntegration", "tags": [ "Discord" ], "summary": "Get Discord integration", "description": "Get the Discord integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Discord integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DiscordIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createDiscordIntegration", "tags": [ "Discord" ], "summary": "Create Discord integration", "description": "Create or replace the Discord integration for a project. The webhook URL is checked for shape only; delivery failures surface later.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string", "minLength": 1 }, "channelName": { "type": "string" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } }, "required": [ "webhookUrl" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DiscordIntegration" } } } }, "400": { "description": "The webhook URL failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateDiscordIntegration", "tags": [ "Discord" ], "summary": "Update Discord integration", "description": "Update the Discord integration. Omitted fields keep their current value, and event toggles are merged into the existing set.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "isActive": { "type": "boolean" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DiscordIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Discord integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteDiscordIntegration", "tags": [ "Discord" ], "summary": "Delete Discord integration", "description": "Remove the Discord integration from a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Discord integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/mattermost-integration/project/{projectId}": { "get": { "operationId": "getMattermostIntegration", "tags": [ "Mattermost" ], "summary": "Get Mattermost integration", "description": "Get the Mattermost integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Mattermost integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MattermostIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createMattermostIntegration", "tags": [ "Mattermost" ], "summary": "Create Mattermost integration", "description": "Create or replace the Mattermost integration for a project. The webhook URL must use HTTPS and pass destination validation; delivery failures surface later.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string", "minLength": 1 }, "channelName": { "type": "string" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } }, "required": [ "webhookUrl" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MattermostIntegration" } } } }, "400": { "description": "The webhook URL failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateMattermostIntegration", "tags": [ "Mattermost" ], "summary": "Update Mattermost integration", "description": "Update the Mattermost integration. Omitted fields keep their current value, and event toggles are merged into the existing set.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "isActive": { "type": "boolean" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MattermostIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Mattermost integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteMattermostIntegration", "tags": [ "Mattermost" ], "summary": "Delete Mattermost integration", "description": "Remove the Mattermost integration from a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Mattermost integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/slack-integration/project/{projectId}": { "get": { "operationId": "getSlackIntegration", "tags": [ "Slack" ], "summary": "Get Slack integration", "description": "Get the Slack integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Slack integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SlackIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createSlackIntegration", "tags": [ "Slack" ], "summary": "Create Slack integration", "description": "Create or replace the Slack integration for a project. The webhook URL is checked for shape only; delivery failures surface later.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string", "minLength": 1 }, "channelName": { "type": "string" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } }, "required": [ "webhookUrl" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SlackIntegration" } } } }, "400": { "description": "The webhook URL failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateSlackIntegration", "tags": [ "Slack" ], "summary": "Update Slack integration", "description": "Update the Slack integration. Omitted fields keep their current value, and event toggles are merged into the existing set.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookUrl": { "type": "string" }, "channelName": { "type": [ "string", "null" ] }, "isActive": { "type": "boolean" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SlackIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Slack integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteSlackIntegration", "tags": [ "Slack" ], "summary": "Delete Slack integration", "description": "Remove the Slack integration from a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Slack integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/telegram-integration/project/{projectId}": { "get": { "operationId": "getTelegramIntegration", "tags": [ "Telegram" ], "summary": "Get Telegram integration", "description": "Get the Telegram integration for a project, or null when none is configured.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Telegram integration details, or null", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelegramIntegration" } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "post": { "operationId": "createTelegramIntegration", "tags": [ "Telegram" ], "summary": "Create Telegram integration", "description": "Create or replace the Telegram integration for a project. The bot token and chat are checked for shape only, not against Telegram.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "botToken": { "type": "string", "minLength": 1, "description": "A Telegram bot token, in the form 123456789:AA..." }, "chatId": { "type": "string", "minLength": 1 }, "threadId": { "type": "number" }, "chatLabel": { "type": "string" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } }, "required": [ "botToken", "chatId" ] } } } }, "responses": { "200": { "description": "The stored integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelegramIntegration" } } } }, "400": { "description": "The bot token or chat failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "patch": { "operationId": "updateTelegramIntegration", "tags": [ "Telegram" ], "summary": "Update Telegram integration", "description": "Update the Telegram integration. Omitted fields keep their current value; threadId and chatLabel accept null to clear them.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "botToken": { "type": "string" }, "chatId": { "type": "string" }, "threadId": { "type": [ "number", "null" ] }, "chatLabel": { "type": [ "string", "null" ] }, "isActive": { "type": "boolean" }, "events": { "type": "object", "properties": { "taskCreated": { "type": "boolean" }, "taskStatusChanged": { "type": "boolean" }, "taskPriorityChanged": { "type": "boolean" }, "taskTitleChanged": { "type": "boolean" }, "taskDescriptionChanged": { "type": "boolean" }, "taskCommentCreated": { "type": "boolean" } } } } } } } }, "responses": { "200": { "description": "The updated integration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelegramIntegration" } } } }, "400": { "description": "The resulting config failed validation", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Telegram integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteTelegramIntegration", "tags": [ "Telegram" ], "summary": "Delete Telegram integration", "description": "Remove the Telegram integration from a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "The integration was removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing workspace:manage_settings", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Telegram integration not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task-relation/{taskId}": { "get": { "operationId": "getTaskRelations", "tags": [ "Task Relations" ], "summary": "Get task relations", "description": "Get every relation where the task is the source or the target, each with a summary of both linked tasks. Relations pointing outside the caller's workspace are omitted.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "Task relations with the linked task summaries", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TaskRelationWithTasks" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task-relation": { "post": { "operationId": "createTaskRelation", "tags": [ "Task Relations" ], "summary": "Create task relation", "description": "Link two tasks. Authorization is scoped to the source task's workspace.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "sourceTaskId": { "type": "string" }, "targetTaskId": { "type": "string" }, "relationType": { "type": "string", "enum": [ "subtask", "blocks", "related" ] } }, "required": [ "sourceTaskId", "targetTaskId", "relationType" ] } } } }, "responses": { "200": { "description": "The created relation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskRelation" } } } }, "400": { "description": "Invalid body", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Source or target task not found", "content": { "text/plain": { "schema": { "type": "string" } } } }, "409": { "description": "This relation already exists", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/task-relation/{id}": { "delete": { "operationId": "deleteTaskRelation", "tags": [ "Task Relations" ], "summary": "Delete task relation", "description": "Remove a link between two tasks. Returns the deleted relation.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted relation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskRelation" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Task relation not found, or its source task is gone", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/external-link/task/{taskId}": { "post": { "operationId": "createExternalLink", "tags": [ "External Links" ], "summary": "Create an external link", "description": "Add a resource link to a task", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri", "description": "An HTTP or HTTPS URL" }, "title": { "type": "string", "maxLength": 200 } }, "required": [ "url" ] } } } }, "responses": { "200": { "description": "External link created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedExternalLink" } } } }, "400": { "description": "Invalid external link data", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Unauthorized", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No permission to update the task", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "get": { "operationId": "getExternalLinksByTask", "tags": [ "External Links" ], "summary": "Get task external links", "description": "Get manually added resource links and links from connected integrations, such as GitHub or Gitea issues.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "External links for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExternalLink" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the task's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/external-link/task/{taskId}/{id}": { "delete": { "operationId": "deleteExternalLink", "tags": [ "External Links" ], "summary": "Remove a manual resource link", "description": "Remove a manually added link from a task. Integration-managed links cannot be removed through this endpoint.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Resource link removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeletedExternalLink" } } } }, "400": { "description": "Unknown task or invalid link data", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Unauthorized", "content": { "text/plain": { "schema": { "type": "string" } } } }, "403": { "description": "No permission to update the task", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Manual resource link not found on this task", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/workflow-rule/{projectId}": { "get": { "operationId": "getWorkflowRules", "tags": [ "Workflow Rules" ], "summary": "Get workflow rules", "description": "Get every workflow rule for a project. A rule moves a task to a column when an integration event fires.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "List of workflow rules", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/WorkflowRule" } } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the project's workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "put": { "operationId": "upsertWorkflowRule", "tags": [ "Workflow Rules" ], "summary": "Upsert workflow rule", "description": "Create a workflow rule, or update the target column of the existing rule for the same integration and event.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "integrationType": { "type": "string" }, "eventType": { "type": "string" }, "columnId": { "type": "string" } }, "required": [ "integrationType", "eventType", "columnId" ] } } } }, "responses": { "200": { "description": "The created or updated rule", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkflowRuleRow" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/workflow-rule/{id}": { "delete": { "operationId": "deleteWorkflowRule", "tags": [ "Workflow Rules" ], "summary": "Delete workflow rule", "description": "Delete a workflow rule. Returns the rule that was removed.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted rule", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkflowRuleRow" } } } }, "400": { "description": "Unknown rule, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/invitation/pending": { "get": { "operationId": "getUserPendingInvitations", "tags": [ "Invitations" ], "summary": "Get pending invitations", "description": "Get the current user's unexpired, unaccepted invitations. Returns an empty list until the user's email is verified.", "responses": { "200": { "description": "List of pending invitations", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PendingInvitation" } } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/invitation/{id}": { "get": { "operationId": "getInvitationDetails", "tags": [ "Invitations" ], "summary": "Get invitation details", "description": "Look up an invitation by ID. Always 200 -- an unusable invitation is reported with valid: false and a reason rather than an error status.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Invitation details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvitationDetails" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/workspace/{workspaceId}/members": { "get": { "operationId": "getWorkspaceMembers", "tags": [ "Workspaces" ], "summary": "Get workspace members", "description": "Get all members of a workspace, with their role.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "List of workspace members", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/WorkspaceMember" } } } } }, "400": { "description": "Workspace ID could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/project/{projectId}": { "get": { "operationId": "getCustomFieldsByProject", "tags": [ "Custom Fields" ], "summary": "Get custom fields", "description": "Get all custom field definitions for a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "List of custom field definitions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CustomFieldDefinition" } } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access or missing read permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/project/{projectId}/values": { "get": { "operationId": "getCustomFieldValuesByProject", "tags": [ "Custom Fields" ], "summary": "Get project custom field values", "description": "Get all custom field values for every task in a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "List of custom field values for the project", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CustomFieldValue" } } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access or missing read permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/task/{taskId}": { "get": { "operationId": "getCustomFieldValuesByTask", "tags": [ "Custom Fields" ], "summary": "Get task custom field values", "description": "Get all custom field values for a task with their definitions.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "List of custom field values for the task", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CustomFieldValue" } } } } }, "400": { "description": "Unknown task, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access or missing task:read permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/project/{projectId}/filter-values": { "get": { "operationId": "getCustomFieldFilterValues", "tags": [ "Custom Fields" ], "summary": "Get custom field filter values", "description": "Get distinct values used by tasks for each custom field of a project.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Distinct values used for each custom field", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CustomFieldFilterValues" } } } } }, "400": { "description": "Unknown project, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access or missing read permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field": { "post": { "operationId": "createCustomField", "tags": [ "Custom Fields" ], "summary": "Create custom field", "description": "Create a custom field definition for a project.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "projectId": { "type": "string" }, "name": { "type": "string" }, "type": { "type": "string", "enum": [ "text", "number", "date", "dropdown", "boolean", "multiselect" ] }, "required": { "type": "boolean", "default": false }, "defaultValue": { "type": "string" }, "options": { "type": "array", "items": { "type": "string" } } }, "required": [ "projectId", "name", "type" ] } } } }, "responses": { "200": { "description": "The created custom field", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CustomFieldDefinition" } } } }, "400": { "description": "Invalid body, or unknown project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/reorder/{projectId}": { "put": { "operationId": "reorderCustomFields", "tags": [ "Custom Fields" ], "summary": "Reorder custom fields", "description": "Set new positions for a project's custom fields.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "fields": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "position": { "type": "number" } }, "required": [ "id", "position" ] } } }, "required": [ "fields" ] } } } }, "responses": { "200": { "description": "The reordered custom fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderCustomFieldsResponse" } } } }, "400": { "description": "A custom field does not belong to this project", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/value": { "put": { "operationId": "setCustomFieldValue", "tags": [ "Custom Fields" ], "summary": "Set custom field value", "description": "Create or update a custom field value for a task.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "taskId": { "type": "string" }, "fieldId": { "type": "string" }, "value": { "type": "string" } }, "required": [ "taskId", "fieldId", "value" ] } } } }, "responses": { "200": { "description": "The saved custom field value", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetCustomFieldValueResponse" } } } }, "400": { "description": "Invalid body, unknown task, or unknown custom field", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing task:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/custom-field/{id}": { "delete": { "operationId": "deleteCustomField", "tags": [ "Custom Fields" ], "summary": "Delete custom field", "description": "Delete a custom field definition by ID.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "The deleted custom field", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CustomFieldDefinition" } } } }, "400": { "description": "Unknown custom field, or its workspace could not be determined", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No workspace access, or missing project:update permission", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/user/me": { "get": { "operationId": "getCurrentUser", "tags": [ "User" ], "summary": "Get current user", "description": "Return the currently authenticated user.", "responses": { "200": { "description": "Current user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CurrentUser" } } } }, "401": { "description": "Unauthorized", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "User not found", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/user/avatar": { "put": { "operationId": "uploadUserAvatar", "tags": [ "User" ], "summary": "Upload avatar", "description": "Store a base64 encoded avatar (PNG, JPEG, or WebP, up to 512KB) for the current user and return its public URL. Replaces any existing avatar.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "contentType": { "type": "string", "maxLength": 64, "description": "One of image/png, image/jpeg, or image/webp.", "example": "image/png" }, "data": { "type": "string", "maxLength": 700076, "description": "Base64 encoded image bytes." } }, "required": [ "contentType", "data" ] } } } }, "responses": { "200": { "description": "Avatar stored", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserAvatar" } } } }, "400": { "description": "Unsupported content type, malformed base64, or too large", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "408": { "description": "Request body timed out", "content": { "text/plain": { "schema": { "type": "string" } } } }, "413": { "description": "Request body exceeds the upload limit", "content": { "text/plain": { "schema": { "type": "string" } } } } } }, "delete": { "operationId": "deleteUserAvatar", "tags": [ "User" ], "summary": "Delete avatar", "description": "Remove the uploaded avatar of the current user. Succeeds even when there was nothing to remove.", "responses": { "200": { "description": "Avatar removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserAvatarDeleted" } } } }, "401": { "description": "Missing or invalid credentials" } } } }, "/admin/users": { "get": { "operationId": "listAdminUsers", "tags": [ "Admin" ], "summary": "List instance users", "description": "Page through every user account on this instance, optionally filtered by a case-insensitive name or email search. Requires an instance administrator session; API keys are rejected.", "parameters": [ { "schema": { "type": "string", "maxLength": 200, "description": "Case-insensitive match against user name or email." }, "required": false, "description": "Case-insensitive match against user name or email.", "name": "search", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000000, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Users matching the search", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminUserList" } } } }, "400": { "description": "Invalid search, page, or limit", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "The caller is not an instance administrator or is authenticated with an API key", "content": { "text/plain": { "schema": { "type": "string" } } } } } } } }, "webhooks": {} }