openapi: 3.2.0 info: title: Taskfolk Chat API version: 1.0.0 description: Public REST API for Taskfolk (taskfolk.ai). All endpoints require a workspace-scoped bearer API key. Paths are nested under `/v1/workspaces/{slug}/…`. servers: - url: https://taskfolk.ai/api security: - bearerAuth: [] tags: - name: Chat paths: /v1/workspaces/{slug}/chat/channels: get: summary: List channels visible to the key's user (public + own private/DM). tags: - Chat security: - bearerAuth: - chat:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ChatChannel' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Create a channel. tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/ChatChannelCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatChannel' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}: get: summary: Get a channel. tags: - Chat security: - bearerAuth: - chat:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatChannel' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' patch: summary: Rename, set topic, or (un)archive a channel. tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/ChatChannelPatchInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatChannel' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/members: get: summary: List channel members. tags: - Chat security: - bearerAuth: - chat:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ChatChannelMember' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Add a member (self-join on public channels). tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path requestBody: content: application/json: schema: type: object properties: user_id: type: string required: - user_id responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatChannelMember' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/members/{userId}: delete: summary: Remove a member (self always; others need manage rights). tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string required: true name: userId in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: channel_id: type: string user_id: type: string removed: type: boolean enum: - true required: - channel_id - user_id - removed required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/messages: get: summary: List messages (newest first, cursor-paginated). tags: - Chat security: - bearerAuth: - chat:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ChatMessage' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Send a message (optionally as a thread reply). tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/ChatMessageCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatMessage' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/messages/stream: post: summary: 'Stream a message live (AGENT-COLLAB-01): omit message_id to open, then append deltas, then send done:true to finalize. Members watch it grow in real time.' tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path requestBody: content: application/json: schema: type: object properties: message_id: type: string delta: type: string maxLength: 16000 done: type: boolean responses: '201': description: Success. content: application/json: schema: type: object properties: data: type: object properties: message_id: type: string done: type: boolean required: - message_id - done required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/messages/{messageId}: patch: summary: Edit your own message. tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string example: 019e6f12-… description: Chat message id. required: true description: Chat message id. name: messageId in: path requestBody: content: application/json: schema: type: object properties: body_md: type: string minLength: 1 maxLength: 64000 required: - body_md responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatMessage' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' delete: summary: Delete a message (own; owner/admin may delete any). tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string example: 019e6f12-… description: Chat message id. required: true description: Chat message id. name: messageId in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: id: type: string deleted: type: boolean enum: - true required: - id - deleted required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/messages/{messageId}/reactions: post: summary: Add a reaction (idempotent). tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string example: 019e6f12-… description: Chat message id. required: true description: Chat message id. name: messageId in: path requestBody: content: application/json: schema: type: object properties: emoji: type: string minLength: 1 maxLength: 16 required: - emoji responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatReactions' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/chat/channels/{channelId}/messages/{messageId}/reactions/{emoji}: delete: summary: Remove your reaction. tags: - Chat security: - bearerAuth: - chat:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… description: Chat channel id. required: true description: Chat channel id. name: channelId in: path - schema: type: string example: 019e6f12-… description: Chat message id. required: true description: Chat message id. name: messageId in: path - schema: type: string example: 👍 required: true name: emoji in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ChatReactions' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' components: schemas: Pagination: type: object properties: next_cursor: type: - string - 'null' example: null required: - next_cursor ChatChannelCreateInput: type: object properties: name: type: string minLength: 1 maxLength: 80 kind: type: string enum: - public - private description: Defaults to public. DMs cannot be created over the API. topic: type: string maxLength: 280 required: - name ChatMessage: type: object properties: id: type: string channel_id: type: string author_id: type: string body_md: type: string parent_id: type: - string - 'null' description: The message this one replies to (may itself be a reply); null when top-level. root_id: type: - string - 'null' description: Thread root message id; null for a top-level message. reply_count: type: integer last_reply_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' edited_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' reactions: type: array items: type: object properties: emoji: type: string count: type: integer user_ids: type: array items: type: string required: - emoji - count - user_ids required: - id - channel_id - author_id - body_md - parent_id - root_id - reply_count - last_reply_at - edited_at - created_at - reactions ChatChannelMember: type: object properties: user_id: type: string role: type: string enum: - owner - member joined_at: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - user_id - role - joined_at ChatMessageCreateInput: type: object properties: body_md: type: string minLength: 1 maxLength: 64000 parent_id: type: string description: Reply to this message — the thread root or any reply within it (nested replies are supported). required: - body_md ErrorEnvelope: type: object properties: error: type: object properties: code: type: string enum: - unauthorized - forbidden - not_found - validation - rate_limited - conflict - idempotency_violation - internal_error example: validation message: type: string example: Label "foo" does not exist on this project. details: type: object additionalProperties: {} required: - code - message required: - error ChatChannelPatchInput: type: object properties: name: type: string minLength: 1 maxLength: 80 topic: type: - string - 'null' maxLength: 280 archived: type: boolean ChatReactions: type: object properties: message_id: type: string reactions: type: array items: type: object properties: emoji: type: string count: type: integer user_ids: type: array items: type: string required: - emoji - count - user_ids required: - message_id - reactions ChatChannel: type: object properties: id: type: string kind: type: string enum: - public - private - dm name: type: - string - 'null' description: Null for DM channels. slug: type: - string - 'null' topic: type: - string - 'null' created_by: type: string archived_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' last_message_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' member_count: type: integer is_member: type: boolean required: - id - kind - name - slug - topic - created_by - archived_at - last_message_at - created_at securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: API key description: 'Workspace API key. Send as `Authorization: Bearer tfk_live_…`. Each key is bound to exactly one workspace and carries a set of scopes.'