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}/ticketsReturns a paginated list of tickets on the board.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20, max: 100) |
| statusId | string | No | Filter by status ID |
| assigneeId | string | No | Filter by assignee user ID |
| customerId | string | No | Filter by customer ID |
| needsReassignment | boolean | No | Filter tickets needing reassignment |
| typeId | string | No | Filter by ticket type ID (comma-separated for multiple) |
| labelId | string | No | Filter by label ID (comma-separated for multiple) |
| search | string | No | Search in title and description |
| includePlanning | boolean | No | Include tickets in PLANNING statuses (default: false) |
| includeArchived | boolean | No | Include archived/done tickets |
| overdue | boolean | No | Only overdue tickets |
| noDueDate | boolean | No | Only tickets without a due date |
| dueBefore | string | No | Tickets due on or before this date (ISO 8601) |
| dueAfter | string | No | Tickets due on or after this date (ISO 8601) |
| impactLevel | string | No | Filter by impact level (comma-separated) |
| externalReference | string | No | Filter 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}/ticketsRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Ticket title (max 200 characters) |
| description | string | No | Detailed description (max 50,000 characters) |
| statusId | string | No | Initial status ID (defaults to Backlog) |
| assigneeId | string | No | Assignee user ID |
| customerId | string | No | Customer ID |
| priority | string | No | low, medium, high, or critical |
| typeId | string | No | Ticket type ID |
| labelIds | string[] | No | Label IDs to attach |
| dueDate | string | No | Due date (ISO 8601) |
| startDate | string | No | Planned start date (ISO 8601) |
| estimatedHours | number | No | Estimated hours (min 0.1) |
| storyPoints | number | No | Story points |
| externalReference | string | No | External reference ID (max 200 characters) |
| impactLevel | string | No | low, 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
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | No | Ticket title |
| description | string | No | Detailed description |
| assigneeId | string | null | No | Assignee (null to unassign) |
| customerId | string | null | No | Customer (null to remove) |
| priority | string | null | No | low, medium, high, critical (null to remove) |
| typeId | string | No | Ticket type ID |
| statusId | string | No | Status ID |
| statusChangeReason | string | No | Reason for status change (for explainable-status logging, max 500 chars) |
| isArchived | boolean | No | Archive status (true to archive, false to restore) |
| labelIds | string[] | No | Label IDs (replaces existing labels) |
| dueDate | string | null | No | Due date (null to remove) |
| startDate | string | null | No | Start date (null to remove) |
| estimatedHours | number | null | No | Estimated hours (null to remove) |
| timeSpent | number | null | No | Time spent in hours (null to remove) |
| storyPoints | number | null | No | Story points (null to remove) |
| externalReference | string | null | No | External reference (null to remove) |
| impactLevel | string | null | No | low, medium, high, critical (null to remove) |
| milestoneId | string | null | No | Milestone ID (null to unassign) |
| resolution | string | null | No | Resolution description |
| resolutionType | string | null | No | fixed, 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}/statusChange the ticket's workflow status.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| statusId | string | Yes | Target status ID |
| reason | string | No | Reason for status change (for explainable-status logging, max 500 chars) |
Assign Ticket
PATCH /api/v1/boards/{boardId}/tickets/{ticketId}/assignAssign or unassign a user from the ticket.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| assigneeId | string | null | Yes | User ID to assign, or null to unassign |
Move Ticket
POST /api/v1/boards/{boardId}/tickets/{ticketId}/moveMove a ticket to a different board. Subtickets and tickets with subtickets cannot be moved.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| targetBoardId | string | Yes | Destination 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}/transitionTransition a ticket to a new status with validation of transition rules.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| toStatusId | string | Yes | Target status ID |
| reason | string | No | Reason for the transition (required when explainable-status feature is enabled) |
| blockerInfo | object | No | Blocker information (required when transitioning to BLOCKED status) |
| blockerInfo.reason | string | Yes* | Reason for blocking (*required inside blockerInfo) |
| blockerInfo.blockedBy | string | No | User 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}/approveApprove 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-reassignmentReturns 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/reorderReorder a ticket within or across columns (statuses) on a board.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| ticketId | string | Yes | Ticket ID to reorder |
| position | number | Yes | New position (float) |
| statusId | string | No | Optional new status ID (for cross-column drag) |
Inline Update Ticket
PATCH /api/v1/boards/{boardId}/tickets/{ticketId}/inlineUpdate multiple ticket fields at once with optimistic locking for conflict detection.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | No | Ticket title (max 200 characters) |
| description | string | No | Ticket description |
| statusId | string | No | Status ID |
| assigneeId | string | null | No | Assignee user ID (null to unassign) |
| dueDate | string | null | No | Due date (null to remove) |
| expectedUpdatedAt | string | No | Expected updatedAt timestamp for conflict detection |
Set Custom Field Values
PUT /api/v1/boards/{boardId}/tickets/{ticketId}/custom-fieldsPermission required: custom-fields:manage
Set custom field values for a ticket.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| values | array | Yes | Array of custom field value objects |
| values[].customFieldId | string | Yes | Custom field ID |
| values[].value | string | null | No | Value 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-checkCheck 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}/blockerGet 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-requestsGet 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"
}
]
}