Skip to content

Issues API

Issues are the core work items in kendo. Each issue belongs to a project and has a unique key (e.g., KD-42).

Permissions

ActionRequired PermissionScope
List / search / viewIssues: ReadIssues within accessible projects
CreateIssues: CreateIn accessible projects
UpdateIssues: Update (Own/All)Own: only issues you created. All: any issue in accessible projects
DeleteIssues: Delete (Own/All)Own: only issues you created. All: any issue in accessible projects

Admins and project owners bypass all permission checks for project-scoped resources.

Endpoints

MethodEndpointDescription
GET/api/projects/{projectId}/issuesList all issues
POST/api/projects/{projectId}/issuesCreate an issue
GET/api/projects/{projectId}/issues/{issueId}Get an issue
PUT/api/projects/{projectId}/issues/{issueId}Update an issue
DELETE/api/projects/{projectId}/issues/{issueId}Delete an issue
GET/api/projects/{projectId}/issues/search?q=Search issues (within project)
GET/api/issues/searchSearch issues (cross-project)
GET/api/issues/myList issues assigned to the authenticated user

Create Issue

POST /api/projects/{projectId}/issues

Request Fields

FieldTypeRequiredDescription
titlestringYesIssue title, max 255 characters
descriptionstringYesMarkdown description, max 65,535 characters
lane_idintegerYesBoard lane ID (must belong to the project)
priorityintegerYes0 Highest, 1 High, 2 Medium, 3 Low, 4 Lowest
typeintegerYes0 Feature, 1 Bug
orderintegerYesPosition within the lane
assignee_idintegerNoUser ID (must be a project member)
sprint_idintegerNoSprint ID (must belong to the project)
epic_idintegerNoEpic ID (must belong to the project)
estimated_minutesintegerNoTime estimate in minutes, min 0
blocked_by_idsinteger[]NoIssue IDs that block this issue
blocks_idsinteger[]NoIssue IDs that this issue blocks
promptstringNoAI prompt context, max 10,000 characters
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Add pagination to issues list",
    "description": "The issues overview needs cursor-based pagination for large projects.",
    "lane_id": 1,
    "priority": 2,
    "type": 0,
    "order": 0,
    "assignee_id": 3,
    "estimated_minutes": 240
  }'
json
{
  "id": 42,
  "key": "KD-42",
  "title": "Add pagination to issues list",
  "description": "The issues overview needs cursor-based pagination for large projects.",
  "prompt": null,
  "user_id": 1,
  "assignee_id": 3,
  "project_id": 1,
  "lane_id": 1,
  "sprint_id": null,
  "epic_id": null,
  "comment_ids": [],
  "priority": 2,
  "type": 0,
  "order": 0,
  "estimated_minutes": 240,
  "blocked_by_ids": [],
  "blocks_ids": [],
  "branch_link_statuses": [],
  "created_at": "2026-03-13T10:30:00.000000Z"
}

Update Issue

PUT /api/projects/{projectId}/issues/{issueId}

Accepts the same fields as create. All required fields must be included in every update.

bash
curl -X PUT https://{tenant}.kendo.dev/api/projects/1/issues/42 \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Add pagination to issues list",
    "description": "The issues overview needs cursor-based pagination for large projects.",
    "lane_id": 2,
    "priority": 1,
    "type": 0,
    "order": 0,
    "sprint_id": 5,
    "blocked_by_ids": [38, 40]
  }'
json
{
  "id": 42,
  "key": "KD-42",
  "title": "Add pagination to issues list",
  "description": "The issues overview needs cursor-based pagination for large projects.",
  "prompt": null,
  "user_id": 1,
  "assignee_id": 3,
  "project_id": 1,
  "lane_id": 2,
  "sprint_id": 5,
  "epic_id": null,
  "comment_ids": [],
  "priority": 1,
  "type": 0,
  "order": 0,
  "estimated_minutes": 240,
  "blocked_by_ids": [38, 40],
  "blocks_ids": [],
  "branch_link_statuses": [],
  "created_at": "2026-03-13T10:30:00.000000Z"
}

Get Issue

GET /api/projects/{projectId}/issues/{issueId}

bash
curl https://{tenant}.kendo.dev/api/projects/1/issues/42 \
  -H "Authorization: Bearer your-token"
json
{
  "id": 42,
  "key": "KD-42",
  "title": "Add pagination to issues list",
  "description": "The issues overview needs cursor-based pagination for large projects.",
  "prompt": null,
  "user_id": 1,
  "assignee_id": 3,
  "project_id": 1,
  "lane_id": 2,
  "sprint_id": 5,
  "epic_id": null,
  "comment_ids": [10, 11],
  "priority": 1,
  "type": 0,
  "order": 0,
  "estimated_minutes": 240,
  "blocked_by_ids": [38, 40],
  "blocks_ids": [],
  "branch_link_statuses": [1],
  "created_at": "2026-03-13T10:30:00.000000Z"
}

Delete Issue

DELETE /api/projects/{projectId}/issues/{issueId}

Returns 204 No Content on success.

bash
curl -X DELETE https://{tenant}.kendo.dev/api/projects/1/issues/42 \
  -H "Authorization: Bearer your-token"

List Issues

GET /api/projects/{projectId}/issues

Returns an array of all issues in the project.

bash
curl https://{tenant}.kendo.dev/api/projects/1/issues \
  -H "Authorization: Bearer your-token"
json
[
  {
    "id": 42,
    "key": "KD-42",
    "title": "Add pagination to issues list",
    "priority": 1,
    "type": 0,
    "lane_id": 2,
    "assignee_id": 3,
    "sprint_id": 5,
    "...": "..."
  },
  {
    "id": 43,
    "key": "KD-43",
    "title": "Fix email validation on login form",
    "priority": 0,
    "type": 1,
    "lane_id": 1,
    "assignee_id": null,
    "sprint_id": null,
    "...": "..."
  }
]

GET /api/issues/search

Search issues across all accessible projects. Admins can search all projects; non-admin users only see issues from projects they have access to.

Query Parameters

ParameterTypeRequiredDescription
querystringNoText search across title, description, and key (max 200 chars)
project_idintegerNoFilter by project ID
lane_idintegerNoFilter by lane ID
assignee_idintegerNoFilter by assignee user ID
sprint_idintegerNoFilter by sprint ID
epic_idintegerNoFilter by epic ID
priorityintegerNoFilter by priority (0-4, see enums below)
typeintegerNoFilter by type (0-1, see enums below)
exclude_final_lanebooleanNoExclude issues in each project's highest-order lane (typically Done)
limitintegerNoMax results to return (1-500, default 25)

Response Shape

Search responses use a {data, meta} envelope. The server caps result sets at 500 issues; when a query matches more, meta.truncated is true and callers should refine the filter set to see additional rows.

FieldTypeDescription
dataIssueSearchResource[]Matching issues (never more than meta.limit)
meta.truncatedbooleantrue when the result set was capped at meta.limit; refine filters to see more matches
meta.countintegerNumber of issues actually returned in data
meta.limitintegerServer-side cap applied to this request
bash
curl "https://{tenant}.kendo.dev/api/issues/search?query=login&priority=1&limit=10" \
  -H "Authorization: Bearer your-token"
json
{
  "data": [
    {
      "id": 42,
      "key": "KD-42",
      "title": "Fix login timeout bug",
      "project_id": 1,
      "project_name": "Backend",
      "lane_id": 2,
      "lane_title": "In Progress",
      "lane_color": 1,
      "epic_id": 7,
      "epic_title": "Authentication Overhaul",
      "user_id": 2,
      "assignee_id": 3,
      "priority": 1,
      "type": 1,
      "updated_at": "2026-03-13T10:30:00+00:00"
    }
  ],
  "meta": {
    "truncated": false,
    "count": 1,
    "limit": 10
  }
}

My Issues

GET /api/issues/my

List all issues assigned to the authenticated user across every project they can access, excluding issues in each project's final lane (typically Done). Returns up to 500 issues in the same {data, meta} envelope as /api/issues/search.

Query Parameters

None. Filtering is client-side.

bash
curl "https://{tenant}.kendo.dev/api/issues/my" \
  -H "Authorization: Bearer your-token"
json
{
  "data": [
    {
      "id": 42,
      "key": "KD-42",
      "title": "Fix login timeout bug",
      "project_id": 1,
      "project_name": "Backend",
      "lane_id": 2,
      "lane_title": "In Progress",
      "lane_color": 1,
      "epic_id": 7,
      "epic_title": "Authentication Overhaul",
      "user_id": 2,
      "assignee_id": 3,
      "priority": 1,
      "type": 1,
      "updated_at": "2026-03-13T10:30:00+00:00"
    }
  ],
  "meta": {
    "truncated": false,
    "count": 1,
    "limit": 500
  }
}

AI Story Generation

POST /api/projects/{projectId}/issues/agent-generate-story

Generates an AI-powered issue story using a multi-agent pipeline (Validate → Duplicate Check → Research → Classify → Write). Requires the generateStory permission. Rate-limited via throttle:story.

Real-time progress is broadcast via WebSocket on the user's private channel (Tenant.{tenantId}.App.Models.User.{userId}) as agent-progress events during processing.

Request Fields

FieldTypeRequiredDescription
descriptionstringYesThe input text describing the desired issue
contextstringNoAdditional context prepended to the description

Response Fields

FieldTypeDescription
titlestringAI-generated issue title
descriptionstringAI-generated issue description (Markdown)
typeintegerSuggested issue type (0 Feature, 1 Bug)
priorityintegerSuggested priority (0-4)
intentstringPipeline result intent: create, update, or respond
reasoningstring|nullExplanation when intent is update or respond
issue_idinteger|nullExisting issue ID when intent is update
pipelinearray|nullPipeline step summary (see below), null when empty

Pipeline Step Object

Each entry in the pipeline array describes the result of one agent step:

FieldTypeDescription
stepstringAgent name: validate, duplicate_check, research, classify, write
statusinteger0 Success, 1 Warning, 2 Skipped
messagestringHuman-readable result message (English)
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues/agent-generate-story \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Users can not reset their password when 2FA is enabled"
  }'
json
{
  "title": "Fix password reset flow when 2FA is enabled",
  "description": "## Problem\n\nUsers with two-factor authentication enabled cannot complete the password reset flow...",
  "type": 1,
  "priority": 1,
  "intent": "create",
  "reasoning": null,
  "issue_id": null,
  "pipeline": [
    {"step": "validate", "status": 0, "message": "Input is actionable"},
    {"step": "duplicate_check", "status": 0, "message": "No duplicates found"},
    {"step": "research", "status": 0, "message": "Found 3 relevant issues"},
    {"step": "classify", "status": 0, "message": "Classified as new bug report"},
    {"step": "write", "status": 0, "message": "Story generated successfully"}
  ]
}

WebSocket Progress Events

During generation, agent-progress events are broadcast on the user's private channel:

FieldTypeDescription
stepstringAgent name (same as pipeline step names)
phaseinteger0 Pending, 1 Started, 2 Completed
messagestringHuman-readable progress message (English)
stepIndexintegerZero-based step position (0-4)
totalStepsintegerTotal steps in the pipeline (5)

Events are best-effort — the pipeline works correctly even when WebSocket (Reverb) is unavailable. The HTTP response pipeline field is the authoritative result.

Enums

Priority

ValueLabel
0Highest
1High
2Medium
3Low
4Lowest

Type

ValueLabel
0Feature
1Bug

See Also