openapi: 3.2.0 info: title: Taskfolk Workflows 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: Workflows paths: /v1/workspaces/{slug}/workflows: get: summary: List workflows. tags: - Workflows security: - bearerAuth: - workflows: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/Workflow' 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 workflow (draft; admin-tier scope). tags: - Workflows security: - bearerAuth: - workflows: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/WorkflowCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/Workflow' 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}/workflows/{id}: get: summary: Get a workflow with its nodes and edges. tags: - Workflows security: - bearerAuth: - workflows:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WorkflowDetail' 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: Update name/description, or enable/disable (enabling enforces the plan cap and graph validity). tags: - Workflows security: - bearerAuth: - workflows:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WorkflowPatchInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/Workflow' 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: Soft-delete a workflow. Refuses while runs are in flight unless ?cancel_runs=true. tags: - Workflows security: - bearerAuth: - workflows:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id 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}/workflows/{id}/graph: put: summary: Replace a workflow's nodes and edges atomically (referential + acyclicity checked). tags: - Workflows security: - bearerAuth: - workflows:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WorkflowGraphInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WorkflowDetail' 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}/workflows/{id}/runs: get: summary: List a workflow's runs (newest first). tags: - Workflows security: - bearerAuth: - workflows:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id 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/WorkflowRun' 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' /v1/workspaces/{slug}/workflow-runs/{id}: get: summary: Get a workflow run with its stage states. tags: - Workflows security: - bearerAuth: - workflows:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WorkflowRunDetail' 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}/workflow-runs/{id}/advance: post: summary: Force-advance a run's state machine. tags: - Workflows security: - bearerAuth: - workflows:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WorkflowRunDetail' 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}/workflow-runs/{id}/complete-stage: post: summary: Complete the current active stage(s) of a run (member-tier workflow.run). tags: - Workflows security: - bearerAuth: - issues:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WorkflowCompleteStageInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WorkflowRunDetail' 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}/projects/{key}/issues/{issueKey}/workflow: post: summary: Route an issue through an enabled workflow (member-tier workflow.run). tags: - Workflows security: - bearerAuth: - issues:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: web description: Project key. required: true description: Project key. name: key in: path - schema: type: string example: WEB-39 description: Issue key (KEY-N). required: true description: Issue key (KEY-N). name: issueKey in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WorkflowStartInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: type: object properties: run_id: type: string required: - run_id 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: Cancel the issue's active workflow run (member-tier workflow.run). tags: - Workflows security: - bearerAuth: - issues:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: web description: Project key. required: true description: Project key. name: key in: path - schema: type: string example: WEB-39 description: Issue key (KEY-N). required: true description: Issue key (KEY-N). name: issueKey in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: issue_key: type: string cancelled: type: boolean enum: - true required: - issue_key - cancelled 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: WorkflowStartInput: type: object properties: workflow_id: type: string minLength: 1 required: - workflow_id Pagination: type: object properties: next_cursor: type: - string - 'null' example: null required: - next_cursor WorkflowGraphInput: type: object properties: nodes: type: array items: type: object properties: id: type: string minLength: 1 kind: type: string enum: - start - agent - person - condition - parallel - end assignee_user_id: type: - string - 'null' config: {} label: type: - string - 'null' maxLength: 120 pos_x: type: integer pos_y: type: integer required: - id - kind - pos_x - pos_y maxItems: 200 edges: type: array items: type: object properties: id: type: string minLength: 1 source_node_id: type: string minLength: 1 target_node_id: type: string minLength: 1 branch_label: type: - string - 'null' maxLength: 120 required: - id - source_node_id - target_node_id maxItems: 400 required: - nodes - edges WorkflowCompleteStageInput: type: object properties: node_id: type: string minLength: 1 description: Complete this active stage; omit to complete all active stages. WorkflowEdge: type: object properties: id: type: string source_node_id: type: string target_node_id: type: string branch_label: type: - string - 'null' description: '"true"|"false" on a condition node''s out-edges; null otherwise.' required: - id - source_node_id - target_node_id - branch_label Workflow: type: object properties: id: type: string name: type: string example: Triage and build description: type: - string - 'null' status: type: string enum: - draft - enabled created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' updated_at: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - id - name - description - status - created_at - updated_at WorkflowRunNode: type: object properties: node_id: type: string state: type: string enum: - pending - active - done - skipped - failed branch_taken: type: - string - 'null' required: - node_id - state - branch_taken WorkflowRun: type: object properties: id: type: string issue_id: type: string status: type: string enum: - running - completed - failed - cancelled current_summary: type: - string - 'null' started_at: type: string format: date-time example: '2026-05-28T14:30:00Z' ended_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' required: - id - issue_id - status - current_summary - started_at - ended_at WorkflowCreateInput: type: object properties: name: type: string minLength: 1 maxLength: 120 description: type: string maxLength: 500 required: - name WorkflowNode: type: object properties: id: type: string kind: type: string enum: - start - agent - person - condition - parallel - end assignee_user_id: type: - string - 'null' description: The agent (isAgent user) or person for agent/person nodes; null otherwise. config: description: 'Kind-specific config. condition: { match, rules } (AutomationConditions shape). agent: { title?, instructions? }. parallel: { join: "all"|"any" }.' label: type: - string - 'null' pos_x: type: integer pos_y: type: integer required: - id - kind - assignee_user_id - label - pos_x - pos_y WorkflowRunDetail: type: object properties: id: type: string workflow_id: type: string workflow_name: type: string issue_id: type: string status: type: string enum: - running - completed - failed - cancelled current_summary: type: - string - 'null' nodes: type: array items: $ref: '#/components/schemas/WorkflowRunNode' started_at: type: string format: date-time example: '2026-05-28T14:30:00Z' ended_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' required: - id - workflow_id - workflow_name - issue_id - status - current_summary - nodes - started_at - ended_at 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 WorkflowDetail: type: object properties: id: type: string name: type: string description: type: - string - 'null' status: type: string enum: - draft - enabled nodes: type: array items: $ref: '#/components/schemas/WorkflowNode' edges: type: array items: $ref: '#/components/schemas/WorkflowEdge' created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' updated_at: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - id - name - description - status - nodes - edges - created_at - updated_at WorkflowPatchInput: type: object properties: name: type: string minLength: 1 maxLength: 120 description: type: - string - 'null' maxLength: 500 status: type: string enum: - draft - enabled 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.'