{ "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" ] }, "Config": { "type": "object", "properties": { "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": [ "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" } }, "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" ] }, "BillingWebhookResult": { "type": "object", "properties": { "processed": { "type": "boolean" }, "duplicate": { "type": "boolean", "description": "True when this event id was already applied, so the delivery was a safe no-op." } }, "required": [ "processed", "duplicate" ] }, "WorkspaceBilling": { "type": "object", "properties": { "billingEnabled": { "type": "boolean", "description": "False when the instance has no billing configured." }, "entitlement": { "$ref": "#/components/schemas/BillingEntitlement" }, "foundingFree": { "type": "boolean" }, "trialEndsAt": { "type": [ "string", "null" ], "format": "date-time" }, "plan": { "type": [ "string", "null" ], "description": "`personal` or `team`." }, "billingInterval": { "type": [ "string", "null" ], "description": "`monthly` or `annual`." }, "status": { "type": [ "string", "null" ], "description": "The provider's subscription status." }, "seats": { "type": "number" }, "currentPeriodEnd": { "type": [ "string", "null" ], "format": "date-time" }, "canceledAt": { "type": [ "string", "null" ], "format": "date-time" }, "hasCustomer": { "type": "boolean", "description": "Whether a billing customer exists yet. The portal link requires one." } }, "required": [ "billingEnabled", "entitlement", "foundingFree", "trialEndsAt", "plan", "billingInterval", "status", "seats", "currentPeriodEnd", "canceledAt", "hasCustomer" ] }, "BillingEntitlement": { "type": "object", "properties": { "active": { "type": "boolean", "description": "Whether the workspace currently has paid-tier access." }, "reason": { "type": "string", "enum": [ "billing_disabled", "founding_free", "subscription", "trial", "expired" ], "description": "Why access is granted or denied. `billing_disabled` means the instance is not running billing at all, so everything is unlocked." } }, "required": [ "active", "reason" ] }, "BillingCheckout": { "type": "object", "properties": { "checkoutUrl": { "type": "string", "description": "Redirect the browser here to complete payment." } }, "required": [ "checkoutUrl" ] }, "BillingPortal": { "type": "object", "properties": { "portalUrl": { "type": "string", "description": "A short-lived link to the provider's customer portal." } }, "required": [ "portalUrl" ] }, "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" ] }, "BoardTask": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "number": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "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" }, "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", "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" }, "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" ] }, "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" }, "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/BoardTask" } } }, "required": [ "id", "slug", "name", "icon", "isFinal", "tasks" ] }, "Project": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "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", "slug", "icon", "name", "description", "createdAt", "isPublic", "archivedAt", "position", "lastTaskNumber" ] }, "BoardResponse": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Board" }, "pagination": { "$ref": "#/components/schemas/BoardPagination" } }, "required": [ "data", "pagination" ] }, "Board": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "icon": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "isPublic": { "type": [ "boolean", "null" ] }, "workspaceId": { "type": "string" }, "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", "columns", "archivedTasks", "plannedTasks" ] }, "BoardPagination": { "type": "object", "properties": { "total": { "type": "number" }, "page": { "type": "number" }, "pageSize": { "type": "number" }, "totalPages": { "type": "number" } }, "required": [ "total", "page", "pageSize", "totalPages" ], "description": "When no page/limit is given, everything is returned on a single page." }, "BulkTaskResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "updatedCount": { "type": "number" } }, "required": [ "success", "updatedCount" ] }, "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" ] }, "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" } }, "required": [ "id", "projectId", "position", "number", "userId", "title", "description", "status", "priority", "startDate", "dueDate", "createdAt" ] }, "TaskWithAssignee": { "allOf": [ { "$ref": "#/components/schemas/Task" }, { "type": "object", "properties": { "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" ] }, "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" ] }, "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" ] }, "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" ] }, "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" }, "taskId": { "type": [ "string", "null" ] }, "workspaceId": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "color", "createdAt", "updatedAt", "taskId", "workspaceId" ] }, "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": { "appName": { "type": [ "string", "null" ], "description": "The configured GitHub App slug, or null when this instance has no App set up." } }, "required": [ "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" } }, "required": [ "repositories", "installations", "total" ] }, "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." }, "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", "isActive", "createdAt", "updatedAt" ] }, "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." }, "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" ] }, "GitHubDeleteResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "success", "message" ] }, "IssueImportResult": { "type": "object", "properties": { "imported": { "type": "number" }, "skipped": { "type": "number", "description": "Issues that already had a task, or were not importable." }, "errors": { "type": "array", "items": { "type": "string" } } }, "required": [ "imported", "skipped" ] }, "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" ] }, "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" ] }, "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" ] }, "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" }, "priority": { "type": [ "string", "null" ] }, "number": { "type": [ "number", "null" ] }, "projectId": { "type": "string" }, "userId": { "type": [ "string", "null" ] }, "assigneeName": { "type": [ "string", "null" ] } }, "required": [ "id", "title", "status", "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" ] }, "ExternalLink": { "type": "object", "properties": { "id": { "type": "string" }, "taskId": { "type": "string" }, "integrationId": { "type": "string" }, "resourceType": { "type": "string", "description": "The kind of remote resource, e.g. `issue` or `pull_request`." }, "externalId": { "type": "string", "description": "The provider's own identifier for the linked resource." }, "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", "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" ] }, "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" ] } }, "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" } } } } } } }, "/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", "null" ], "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", "null" ], "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": [ "string", "null" ], "description": "The metadata of the organization" }, "keepCurrentActiveOrganization": { "type": [ "boolean", "null" ], "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": { "type": "object", "additionalProperties": {} } } } }, "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", "null" ] }, "role": { "type": "string", "description": "The name of the role to create" }, "permission": { "type": "string", "description": "The permission to assign to the role" }, "additionalFields": { "type": [ "object", "null" ], "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", "null" ], "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", "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": { "type": "object", "additionalProperties": {} } } } }, "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": "Has 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 an invitation to an organization", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "The email address of the user to invite" }, "role": { "type": "string", "description": "The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: \"member\"" }, "organizationId": { "type": [ "string", "null" ], "description": "The organization ID to invite the user to" }, "resend": { "type": [ "boolean", "null" ], "description": "Resend the invitation email, if the user is already invited. Eg: true" }, "teamId": { "type": "string" } }, "required": [ "email", "role", "teamId" ] } } } }, "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" } } } }, "/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": { "type": "object", "additionalProperties": {} } } } } }, "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", "null" ], "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", "null" ], "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", "null" ], "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" ] }, "organizationSlug": { "type": [ "string", "null" ], "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": { "type": "object", "additionalProperties": {} } } } }, "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" ] } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "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", "null" ], "description": "The name of the organization" }, "slug": { "type": [ "string", "null" ], "description": "The slug of the organization" }, "logo": { "type": [ "string", "null" ], "description": "The logo of the organization" }, "metadata": { "type": [ "string", "null" ], "description": "The metadata of the organization" } } }, "organizationId": { "type": [ "string", "null" ], "description": "The organization ID. Eg: \"org-id\"" } }, "required": [ "data" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "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": { "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", "null" ], "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", "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", "null" ] }, "name": { "type": [ "string", "null" ] }, "organizationId": { "type": [ "string", "null" ] }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } } } }, "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 }, "client_name": { "type": "string", "maxLength": 100 }, "token_endpoint_auth_method": { "type": "string", "enum": [ "none" ] }, "grant_types": { "type": "array", "prefixItems": [ { "type": "string", "enum": [ "authorization_code" ] } ] }, "response_types": { "type": "array", "prefixItems": [ { "type": "string", "enum": [ "code" ] } ] } }, "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" }, "required": true, "name": "client_id", "in": "query" }, { "schema": { "type": "string", "maxLength": 2048 }, "required": true, "name": "redirect_uri", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "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" }, "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" }, "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" }, "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" } } } }, "/billing/webhook": { "post": { "operationId": "handleBillingWebhook", "tags": [ "Billing" ], "summary": "Billing webhook", "description": "Receive a Creem subscription event. Authenticated by signature, not by session, and idempotent per event id.", "security": [], "responses": { "200": { "description": "The event was accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BillingWebhookResult" } } } }, "400": { "description": "Signature verification failed", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Billing is not enabled on this instance", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/billing/{workspaceId}": { "get": { "operationId": "getWorkspaceBilling", "tags": [ "Billing" ], "summary": "Get workspace billing", "description": "Get the billing state and entitlement for a workspace. When the instance has no billing configured this reports billingEnabled: false and an always-active entitlement.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "Billing state for the workspace", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkspaceBilling" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "No access to the workspace", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/billing/{workspaceId}/checkout": { "post": { "operationId": "createBillingCheckout", "tags": [ "Billing" ], "summary": "Create checkout", "description": "Create a Creem checkout session for a workspace plan and return the URL to redirect the browser to. Workspace owners and admins only.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "plan": { "type": "string", "enum": [ "personal", "team" ] }, "interval": { "type": "string", "enum": [ "monthly", "annual" ] } }, "required": [ "plan", "interval" ] } } } }, "responses": { "200": { "description": "The checkout session", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BillingCheckout" } } } }, "400": { "description": "Invalid plan or interval", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not a workspace owner or admin", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/billing/{workspaceId}/portal": { "post": { "operationId": "createBillingPortalSession", "tags": [ "Billing" ], "summary": "Create portal session", "description": "Generate a Creem customer portal link for the workspace subscription. Workspace owners and admins only, and only once a billing customer exists.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workspaceId", "in": "path" } ], "responses": { "200": { "description": "The portal link", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BillingPortal" } } } }, "400": { "description": "No billing customer exists for this workspace yet", "content": { "text/plain": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid credentials" }, "403": { "description": "Not a workspace owner or admin", "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, or missing project:update permission", "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/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" } } } } } } }, "/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. Filter and paginate with the query parameters.", "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": "string" }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "string" }, "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" } } } } } } }, "/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" } } } } } } }, "/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." } }, "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/{id}": { "get": { "operationId": "getTask", "tags": [ "Tasks" ], "summary": "Get task", "description": "Get a single task by ID, with its assignee's name resolved.", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "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" }, "startDate": { "type": "string" }, "dueDate": { "type": "string" }, "priority": { "type": "string", "enum": [ "no-priority", "low", "medium", "high", "urgent" ] }, "status": { "type": "string" }, "projectId": { "type": "string" }, "position": { "type": "number" }, "userId": { "type": "string" } }, "required": [ "title", "description", "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" } } } } } } }, "/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" } } } } } } }, "/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" } } } } } } }, "/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/{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, 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" } } } } } } }, "/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" } }, "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" } }, "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 }, "externalUserName": { "type": "string", "maxLength": 120, "description": "Attribution for an imported comment. Ignored unless externalSource is also given." }, "externalSource": { "type": "string", "enum": [ "planka", "trello", "jira" ], "description": "The tool the comment was imported from." } }, "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, or missing task:update permission", "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 } }, "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/TimeEntry" } } } } }, "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" } } } } } } }, "/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" } } } } } }, "delete": { "operationId": "deleteLabel", "tags": [ "Labels" ], "summary": "Delete label", "description": "Delete a label by ID", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Label deleted successfully", "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 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" } } } } } } }, "/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" } } } } } }, "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 every notification for the current user, read and unread.", "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 every notification for the current user as read.", "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 every notification for the current user. This cannot be undone.", "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 }, "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" } ], "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 }, "repositoryName": { "type": "string", "minLength": 1 } }, "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.", "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 }, "repositoryName": { "type": "string", "minLength": 1 } }, "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" } } } } } }, "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": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } }, "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 the linked repository's issues as tasks. Issues that already have a task are skipped.", "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/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 permission", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Project not found", "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, 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" } } } } } } }, "/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. Always 200 -- problems are reported in the body.", "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 }, "repositoryOwner": { "type": "string", "minLength": 1 }, "repositoryName": { "type": "string", "minLength": 1 } }, "required": [ "projectId", "baseUrl", "accessToken", "repositoryOwner", "repositoryName" ] } } } }, "responses": { "200": { "description": "Verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GiteaVerificationResult" } } } }, "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" } } } } } } }, "/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.", "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": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } }, "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 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 verified before it is stored.", "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" } } } } } } }, "/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 verified before it is stored.", "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 verified with Telegram before they are stored.", "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, or the relation already exists", "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 task not found", "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}": { "get": { "operationId": "getExternalLinksByTask", "tags": [ "External Links" ], "summary": "Get task external links", "description": "Get all links from a task to resources in 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" } } } } } } }, "/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" } } } } } } }, "/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", "description": "One of image/png, image/jpeg, or image/webp.", "example": "image/png" }, "data": { "type": "string", "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" } } }, "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" } } } } }, "webhooks": {} }