SpedySpedy Docs

Tickets

Create, update, assign, and transition tickets -- the core work items in Spedy.

Tickets are the fundamental work items in Spedy. Every task, bug, feature request, or piece of work lives as a ticket on a board. Tickets support statuses, priorities, assignments, labels, due dates, time estimates, and more.

List Tickets

GET /api/v1/boards/{boardId}/tickets

Returns a paginated list of tickets on the board.

Query Parameters

ParameterTypeRequiredDescription
pagenumberNoPage number (default: 1)
limitnumberNoItems per page (default: 20, max: 100)
statusIdstringNoFilter by status ID
assigneeIdstringNoFilter by assignee user ID
customerIdstringNoFilter by customer ID
needsReassignmentbooleanNoFilter tickets needing reassignment
typeIdstringNoFilter by ticket type ID (comma-separated for multiple)
labelIdstringNoFilter by label ID (comma-separated for multiple)
searchstringNoSearch in title and description
includePlanningbooleanNoInclude tickets in PLANNING statuses (default: false)
includeArchivedbooleanNoInclude archived/done tickets
overduebooleanNoOnly overdue tickets
noDueDatebooleanNoOnly tickets without a due date
dueBeforestringNoTickets due on or before this date (ISO 8601)
dueAfterstringNoTickets due on or after this date (ISO 8601)
impactLevelstringNoFilter by impact level (comma-separated)
externalReferencestringNoFilter by external reference (partial match)

Example Response

{
  "data": [
    {
      "id": "tkt_abc123",
      "displayId": "WEB-42",
      "title": "Fix login page styling",
      "status": {
        "id": "sts_def456",
        "name": "In Progress",
        "category": "ACTIVE"
      },
      "priority": "high",
      "assignee": {
        "id": "usr_abc123",
        "name": "Alex Smith"
      },
      "type": {
        "id": "typ_abc123",
        "name": "Bug"
      },
      "labels": [],
      "dueDate": "2025-04-01T00:00:00Z",
      "createdAt": "2025-03-15T10:00:00Z"
    }
  ],
  "total": 42,
  "page": 1,
  "pageSize": 20,
  "totalPages": 3
}

Create Ticket

POST /api/v1/boards/{boardId}/tickets

Request Body

FieldTypeRequiredDescription
titlestringYesTicket title (max 200 characters)
descriptionstringNoDetailed description (max 50,000 characters)
statusIdstringNoInitial status ID (defaults to Backlog)
assigneeIdstringNoAssignee user ID
customerIdstringNoCustomer ID
prioritystringNolow, medium, high, or critical
typeIdstringNoTicket type ID
labelIdsstring[]NoLabel IDs to attach
dueDatestringNoDue date (ISO 8601)
startDatestringNoPlanned start date (ISO 8601)
estimatedHoursnumberNoEstimated hours (min 0.1)
storyPointsnumberNoStory points
externalReferencestringNoExternal reference ID (max 200 characters)
impactLevelstringNolow, medium, high, or critical

Example Request

{
  "title": "Fix login page styling",
  "description": "The login button is misaligned on mobile devices.",
  "priority": "high",
  "typeId": "typ_bug123",
  "assigneeId": "usr_abc123",
  "labelIds": ["lbl_frontend"],
  "dueDate": "2025-04-01T00:00:00Z"
}

Get Ticket

GET /api/v1/boards/{boardId}/tickets/{ticketId}

Returns full ticket details including description, comments count, attachment count, and related data.

Update Ticket

PATCH /api/v1/boards/{boardId}/tickets/{ticketId}

All fields are optional. Send only the fields you want to change. Set a field to null to clear it.

Request Body

FieldTypeRequiredDescription
titlestringNoTicket title
descriptionstringNoDetailed description
assigneeIdstring | nullNoAssignee (null to unassign)
customerIdstring | nullNoCustomer (null to remove)
prioritystring | nullNolow, medium, high, critical (null to remove)
typeIdstringNoTicket type ID
statusIdstringNoStatus ID
statusChangeReasonstringNoReason for status change (for explainable-status logging, max 500 chars)
isArchivedbooleanNoArchive status (true to archive, false to restore)
labelIdsstring[]NoLabel IDs (replaces existing labels)
dueDatestring | nullNoDue date (null to remove)
startDatestring | nullNoStart date (null to remove)
estimatedHoursnumber | nullNoEstimated hours (null to remove)
timeSpentnumber | nullNoTime spent in hours (null to remove)
storyPointsnumber | nullNoStory points (null to remove)
externalReferencestring | nullNoExternal reference (null to remove)
impactLevelstring | nullNolow, medium, high, critical (null to remove)
milestoneIdstring | nullNoMilestone ID (null to unassign)
resolutionstring | nullNoResolution description
resolutionTypestring | nullNofixed, wont_fix, duplicate, cannot_reproduce, or by_design

Delete Ticket

DELETE /api/v1/boards/{boardId}/tickets/{ticketId}

Soft-deletes the ticket (marks as deleted but retains data). Returns 204 No Content.

Update Ticket Status

PATCH /api/v1/boards/{boardId}/tickets/{ticketId}/status

Change the ticket's workflow status.

Request Body

FieldTypeRequiredDescription
statusIdstringYesTarget status ID
reasonstringNoReason for status change (for explainable-status logging, max 500 chars)

Assign Ticket

PATCH /api/v1/boards/{boardId}/tickets/{ticketId}/assign

Assign or unassign a user from the ticket.

Request Body

FieldTypeRequiredDescription
assigneeIdstring | nullYesUser ID to assign, or null to unassign

Move Ticket

POST /api/v1/boards/{boardId}/tickets/{ticketId}/move

Move a ticket to a different board. Subtickets and tickets with subtickets cannot be moved.

Request Body

FieldTypeRequiredDescription
targetBoardIdstringYesDestination board ID

Example Response

{
  "data": {
    "id": "tkt_abc123",
    "displayId": "NEW-1",
    "title": "Fix login page styling",
    "boardId": "brd_newboard"
  }
}

Transition Ticket

POST /api/v1/boards/{boardId}/tickets/{ticketId}/transition

Transition a ticket to a new status with validation of transition rules.

Request Body

FieldTypeRequiredDescription
toStatusIdstringYesTarget status ID
reasonstringNoReason for the transition (required when explainable-status feature is enabled)
blockerInfoobjectNoBlocker information (required when transitioning to BLOCKED status)
blockerInfo.reasonstringYes*Reason for blocking (*required inside blockerInfo)
blockerInfo.blockedBystringNoUser ID who blocked the ticket

Example Request

{
  "toStatusId": "sts_blocked123",
  "reason": "Waiting for design approval",
  "blockerInfo": {
    "reason": "Design team needs to review mockups",
    "blockedBy": "usr_designer456"
  }
}

Approve Ticket

POST /api/v1/boards/{boardId}/tickets/{ticketId}/approve

Approve a ticket that's in a planning/backlog status, moving it into the active workflow.

Tickets Needing Reassignment

GET /api/v1/boards/{boardId}/tickets/needing-reassignment

Returns tickets that have been flagged as needing reassignment (e.g., after a team member is removed from a board).

Reorder Ticket

PATCH /api/v1/boards/{boardId}/tickets/reorder

Reorder a ticket within or across columns (statuses) on a board.

Request Body

FieldTypeRequiredDescription
ticketIdstringYesTicket ID to reorder
positionnumberYesNew position (float)
statusIdstringNoOptional new status ID (for cross-column drag)

Inline Update Ticket

PATCH /api/v1/boards/{boardId}/tickets/{ticketId}/inline

Update multiple ticket fields at once with optimistic locking for conflict detection.

Request Body

FieldTypeRequiredDescription
titlestringNoTicket title (max 200 characters)
descriptionstringNoTicket description
statusIdstringNoStatus ID
assigneeIdstring | nullNoAssignee user ID (null to unassign)
dueDatestring | nullNoDue date (null to remove)
expectedUpdatedAtstringNoExpected updatedAt timestamp for conflict detection

Set Custom Field Values

PUT /api/v1/boards/{boardId}/tickets/{ticketId}/custom-fields

Permission required: custom-fields:manage

Set custom field values for a ticket.

Request Body

FieldTypeRequiredDescription
valuesarrayYesArray of custom field value objects
values[].customFieldIdstringYesCustom field ID
values[].valuestring | nullNoValue to set (null to clear)

Example Request

{
  "values": [
    { "customFieldId": "cf_abc123", "value": "Enterprise" },
    { "customFieldId": "cf_def456", "value": null }
  ]
}

Completion Check

GET /api/v1/boards/{boardId}/tickets/{ticketId}/completion-check

Check if a ticket is ready for completion. Returns blockers, requirements, and subticket status.

Example Response

{
  "data": {
    "canComplete": false,
    "hasOpenSubtickets": true,
    "openSubtickets": [
      { "id": "tkt_sub1", "title": "Design review", "displayId": "WEB-43" }
    ],
    "aggregation": {
      "total": 3,
      "completed": 1,
      "summary": "in_progress"
    },
    "blockers": [],
    "requirements": {
      "hasDescription": true,
      "hasAssignee": true,
      "hasCustomer": false,
      "hasNoActiveSubtickets": false
    }
  }
}

Blocker Info

GET /api/v1/boards/{boardId}/tickets/{ticketId}/blocker

Get information about what is blocking this ticket.

Example Response

{
  "data": {
    "isBlocked": true,
    "reason": "Waiting for API changes",
    "reasonText": "Waiting for API changes",
    "blockingTickets": [
      {
        "id": "tkt_other123",
        "ticketNumber": "API-15",
        "title": "Refactor auth module",
        "status": { "id": "sts_1", "name": "In Progress", "color": "#3B82F6" },
        "createdAt": "2025-03-01T10:00:00Z"
      }
    ],
    "blockerCount": 1
  }
}

Pull Requests

GET /api/v1/boards/{boardId}/tickets/{ticketId}/pull-requests

Get pull requests linked to a ticket via branch name or PR title.

Example Response

{
  "data": [
    {
      "id": "pr_abc123",
      "prNumber": 42,
      "title": "Fix login styling",
      "url": "https://github.com/org/repo/pull/42",
      "branchName": "fix/WEB-42-login-styling",
      "state": "open",
      "authorName": "alex",
      "provider": "github",
      "repoFullName": "org/repo",
      "createdAt": "2025-03-20T10:00:00Z",
      "updatedAt": "2025-03-20T14:00:00Z"
    }
  ]
}