Tickets API 🟡 BETA

Full-featured ticketing system with SLA tracking, canned responses, categories, and comments.


Base URL

/api/tickets

Authentication

All endpoints require a valid session token via Authorization: Bearer <token> header.


Ticket Management

List Tickets

GET /api/tickets/

Returns all tickets with optional filtering.

ParameterTypeRequiredDescription
statusstringNoFilter: open, in_progress, resolved, closed
prioritystringNoFilter: low, medium, high, critical
assigneestringNoFilter by assignee user ID
categoryIdstringNoFilter by category
searchstringNoSearch in title and description
pageintegerNoPage number (default: 1)
limitintegerNoResults per page (default: 50)

Request:

GET /api/tickets/?status=open&priority=high&limit=10

Response:

{
  "tickets": [
    {
      "id": "tkt-001",
      "title": "Login page returning 500 errors",
      "description": "Multiple users reporting 500 errors when attempting to log in via SSO.",
      "status": "open",
      "priority": "high",
      "categoryId": "cat-bug",
      "assigneeId": "user-support-01",
      "reporterId": "user-123",
      "createdAt": "2026-06-04T08:30:00Z",
      "updatedAt": "2026-06-04T09:15:00Z",
      "dueAt": "2026-06-05T17:00:00Z",
      "commentCount": 3
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 24,
    "totalPages": 3
  }
}

Create Ticket

POST /api/tickets/

Creates a new support ticket.

ParameterTypeRequiredDescription
titlestringYesTicket title
descriptionstringYesDetailed description
prioritystringNolow, medium, high, critical (default: medium)
categoryIdstringNoCategory identifier
assigneeIdstringNoAssignee user ID
tagsstring[]NoTag labels
dueAtstringNoDue date (ISO 8601)

Request:

{
  "title": "Dashboard charts not rendering",
  "description": "After the latest deploy, the analytics dashboard shows blank charts for all users.",
  "priority": "high",
  "categoryId": "cat-bug",
  "assigneeId": "user-dev-02",
  "tags": ["frontend", "analytics"],
  "dueAt": "2026-06-06T17:00:00Z"
}

Response:

{
  "id": "tkt-002",
  "title": "Dashboard charts not rendering",
  "description": "After the latest deploy, the analytics dashboard shows blank charts for all users.",
  "status": "open",
  "priority": "high",
  "categoryId": "cat-bug",
  "assigneeId": "user-dev-02",
  "reporterId": "user-123",
  "tags": ["frontend", "analytics"],
  "createdAt": "2026-06-04T12:00:00Z",
  "dueAt": "2026-06-06T17:00:00Z"
}

Get Ticket

GET /api/tickets/:id

Returns ticket details.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)

Request:

GET /api/tickets/tkt-001

Response:

{
  "id": "tkt-001",
  "title": "Login page returning 500 errors",
  "description": "Multiple users reporting 500 errors when attempting to log in via SSO.",
  "status": "open",
  "priority": "high",
  "categoryId": "cat-bug",
  "assigneeId": "user-support-01",
  "reporterId": "user-123",
  "tags": ["auth", "production"],
  "createdAt": "2026-06-04T08:30:00Z",
  "updatedAt": "2026-06-04T09:15:00Z",
  "dueAt": "2026-06-05T17:00:00Z",
  "resolvedAt": null,
  "closedAt": null,
  "commentCount": 3
}

Update Ticket

PUT /api/tickets/:id

Updates ticket fields.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
titlestringNoTicket title
descriptionstringNoDescription
prioritystringNoPriority level
categoryIdstringNoCategory
tagsstring[]NoTags
dueAtstringNoDue date

Request:

{
  "priority": "critical",
  "tags": ["auth", "production", "sso"]
}

Response:

{
  "id": "tkt-001",
  "priority": "critical",
  "tags": ["auth", "production", "sso"],
  "updatedAt": "2026-06-04T12:00:00Z"
}

Delete Ticket

DELETE /api/tickets/:id

Soft-deletes a ticket (sets status to closed).

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)

Request:

DELETE /api/tickets/tkt-002

Response:

{
  "deleted": true,
  "id": "tkt-002"
}

Get Full Ticket

GET /api/tickets/:id/full

Returns ticket with all associated data: comments, history, and metadata.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)

Request:

GET /api/tickets/tkt-001/full

Response:

{
  "id": "tkt-001",
  "title": "Login page returning 500 errors",
  "description": "Multiple users reporting 500 errors...",
  "status": "open",
  "priority": "high",
  "category": {
    "id": "cat-bug",
    "name": "Bug Report"
  },
  "assignee": {
    "id": "user-support-01",
    "name": "Maria Santos"
  },
  "reporter": {
    "id": "user-123",
    "name": "João Silva"
  },
  "tags": ["auth", "production"],
  "comments": [
    {
      "id": "cmt-001",
      "authorId": "user-support-01",
      "content": "Investigating the SSO endpoint logs.",
      "createdAt": "2026-06-04T09:00:00Z"
    }
  ],
  "history": [
    {
      "action": "created",
      "userId": "user-123",
      "at": "2026-06-04T08:30:00Z"
    },
    {
      "action": "assigned",
      "userId": "user-admin-01",
      "to": "user-support-01",
      "at": "2026-06-04T08:45:00Z"
    }
  ],
  "createdAt": "2026-06-04T08:30:00Z",
  "updatedAt": "2026-06-04T09:15:00Z"
}

Status Transitions

Assign Ticket

PUT /api/tickets/:id/assign

Assigns a ticket to a user.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
assigneeIdstringYesUser ID to assign

Request:

{
  "assigneeId": "user-dev-03"
}

Response:

{
  "id": "tkt-001",
  "assigneeId": "user-dev-03",
  "updatedAt": "2026-06-04T12:00:00Z"
}

Update Status

PUT /api/tickets/:id/status

Changes the ticket status.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
statusstringYesNew status: open, in_progress, resolved, closed

Request:

{
  "status": "in_progress"
}

Response:

{
  "id": "tkt-001",
  "status": "in_progress",
  "updatedAt": "2026-06-04T12:00:00Z"
}

Resolve Ticket

PUT /api/tickets/:id/resolve

Marks a ticket as resolved.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
resolutionstringNoResolution notes

Request:

{
  "resolution": "Root cause: expired TLS certificate on SSO provider. Renewed and verified."
}

Response:

{
  "id": "tkt-001",
  "status": "resolved",
  "resolvedAt": "2026-06-04T14:30:00Z",
  "resolution": "Root cause: expired TLS certificate on SSO provider. Renewed and verified."
}

Close Ticket

PUT /api/tickets/:id/close

Closes a resolved ticket permanently.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)

Request:

PUT /api/tickets/tkt-001/close

Response:

{
  "id": "tkt-001",
  "status": "closed",
  "closedAt": "2026-06-04T15:00:00Z"
}

Reopen Ticket

PUT /api/tickets/:id/reopen

Reopens a closed or resolved ticket.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
reasonstringNoReason for reopening

Request:

{
  "reason": "Issue recurred for 3 additional users after initial fix."
}

Response:

{
  "id": "tkt-001",
  "status": "open",
  "reopenCount": 1,
  "updatedAt": "2026-06-04T16:00:00Z"
}

Comments

List Comments

GET /api/tickets/:id/comments

Returns all comments on a ticket.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)

Request:

GET /api/tickets/tkt-001/comments

Response:

[
  {
    "id": "cmt-001",
    "authorId": "user-support-01",
    "authorName": "Maria Santos",
    "content": "Investigating the SSO endpoint logs. Found TLS certificate warning.",
    "isInternal": false,
    "createdAt": "2026-06-04T09:00:00Z"
  },
  {
    "id": "cmt-002",
    "authorId": "user-support-01",
    "authorName": "Maria Santos",
    "content": "Internal note: certificate expires in 2 days, need renewal.",
    "isInternal": true,
    "createdAt": "2026-06-04T09:10:00Z"
  }
]

Add Comment

POST /api/tickets/:id/comments

Adds a comment to a ticket.

ParameterTypeRequiredDescription
idstringYesTicket identifier (path param)
contentstringYesComment text
isInternalbooleanNoInternal note (default: false)

Request:

{
  "content": "Certificate has been renewed. SSO login restored. Monitoring for recurrence.",
  "isInternal": false
}

Response:

{
  "id": "cmt-003",
  "authorId": "user-support-01",
  "authorName": "Maria Santos",
  "content": "Certificate has been renewed. SSO login restored. Monitoring for recurrence.",
  "isInternal": false,
  "createdAt": "2026-06-04T14:30:00Z"
}

Canned Responses

List Canned Responses

GET /api/tickets/canned

Returns saved response templates.

Response:

[
  {
    "id": "canned-001",
    "name": "Acknowledged",
    "content": "Thank you for reporting this issue. We are investigating and will update you within 24 hours.",
    "categoryId": "cat-bug"
  },
  {
    "id": "canned-002",
    "name": "Resolved - Fixed in Production",
    "content": "This issue has been resolved in the latest deployment. Please verify and let us know if the problem persists.",
    "categoryId": "cat-bug"
  }
]

Create Canned Response

POST /api/tickets/canned

Creates a new canned response template.

ParameterTypeRequiredDescription
namestringYesTemplate name
contentstringYesResponse content
categoryIdstringNoCategory association

Request:

{
  "name": "Out of Office",
  "content": "The assigned team member is currently unavailable. Your ticket will be reviewed upon their return.",
  "categoryId": "cat-general"
}

Response:

{
  "id": "canned-003",
  "name": "Out of Office",
  "content": "The assigned team member is currently unavailable. Your ticket will be reviewed upon their return.",
  "categoryId": "cat-general",
  "createdAt": "2026-06-04T12:00:00Z"
}

Categories

List Categories

GET /api/tickets/categories

Returns all ticket categories.

Response:

[
  {
    "id": "cat-bug",
    "name": "Bug Report",
    "color": "#e74c3c",
    "ticketCount": 45
  },
  {
    "id": "cat-feature",
    "name": "Feature Request",
    "color": "#3498db",
    "ticketCount": 22
  },
  {
    "id": "cat-general",
    "name": "General Inquiry",
    "color": "#95a5a6",
    "ticketCount": 12
  }
]

Create Category

POST /api/tickets/categories

Creates a new ticket category.

ParameterTypeRequiredDescription
namestringYesCategory name
colorstringNoHex color code
descriptionstringNoCategory description

Request:

{
  "name": "Security",
  "color": "#e67e22",
  "description": "Security-related issues and vulnerability reports"
}

Response:

{
  "id": "cat-security",
  "name": "Security",
  "color": "#e67e22",
  "description": "Security-related issues and vulnerability reports",
  "ticketCount": 0,
  "createdAt": "2026-06-04T12:00:00Z"
}

SLA & Tags

Get SLA Configuration

GET /api/tickets/sla

Returns SLA rules and current compliance status.

Response:

{
  "rules": [
    {
      "id": "sla-001",
      "name": "Critical Response",
      "priority": "critical",
      "responseTimeHours": 1,
      "resolutionTimeHours": 4,
      "currentlyBreached": 0
    },
    {
      "id": "sla-002",
      "name": "High Priority",
      "priority": "high",
      "responseTimeHours": 4,
      "resolutionTimeHours": 24,
      "currentlyBreached": 1
    },
    {
      "id": "sla-003",
      "name": "Medium Priority",
      "priority": "medium",
      "responseTimeHours": 8,
      "resolutionTimeHours": 72,
      "currentlyBreached": 0
    },
    {
      "id": "sla-004",
      "name": "Low Priority",
      "priority": "low",
      "responseTimeHours": 24,
      "resolutionTimeHours": 168,
      "currentlyBreached": 0
    }
  ],
  "overallCompliance": 96.5
}

List Tags

GET /api/tickets/tags

Returns all tags used across tickets.

Response:

[
  { "name": "auth", "ticketCount": 12 },
  { "name": "frontend", "ticketCount": 18 },
  { "name": "production", "ticketCount": 31 },
  { "name": "sso", "ticketCount": 5 },
  { "name": "analytics", "ticketCount": 7 }
]

Statistics

Get Ticket Stats

GET /api/tickets/stats

Returns aggregate ticket statistics.

Response:

{
  "total": 128,
  "byStatus": {
    "open": 24,
    "in_progress": 12,
    "resolved": 45,
    "closed": 47
  },
  "byPriority": {
    "critical": 2,
    "high": 8,
    "medium": 30,
    "low": 14
  },
  "avgResolutionTimeHours": 18.4,
  "avgResponseTimeHours": 2.1,
  "slaCompliance": 96.5,
  "lastUpdated": "2026-06-04T12:00:00Z"
}

Get Overdue Tickets

GET /api/tickets/overdue

Returns tickets that have exceeded their SLA or due date.

Response:

[
  {
    "id": "tkt-045",
    "title": "Payment gateway timeout",
    "priority": "critical",
    "status": "in_progress",
    "assigneeId": "user-dev-01",
    "dueAt": "2026-06-03T17:00:00Z",
    "overdueByHours": 19,
    "slaBreached": true
  }
]

See Also


ITSM Concepts (CMDB, KB, Record Types)

The Tickets app absorbs the former ITSM app. Every support_tickets row carries a record_type column (ticket | problem | change), enabling Problems/Changes to share the same lifecycle as tickets.

⚠️ Migration required: The record_type column plus the ticket_cis and ticket_kb_articles tables come from migration 6.5.33-tickets-itsm-unification. If your database predates it, run botserver/migrations/6.5.33-tickets-itsm-unification/up.sql — otherwise the Tickets list will appear empty (the diesel model queries record_type).

Create/Update with Record Type

POST /api/tickets
Content-Type: application/json
{
  "subject": "Payment API returning 500s",
  "record_type": "problem",
  "priority": "high",
  "category": "technical"
}

Configuration Items (CMDB)

GET  /api/tickets/cis            # list CIs
POST /api/tickets/cis            # create CI { name, ci_type, description, status }
GET  /api/tickets/cis/:id
PUT  /api/tickets/cis/:id
DELETE /api/tickets/cis/:id

HTMX fragment: GET /api/ui/tickets/cis

Knowledge Base Articles

GET  /api/tickets/kb            # list published articles
POST /api/tickets/kb            # create article { title, body, category, tags, is_published }
GET  /api/tickets/kb/:id
PUT  /api/tickets/kb/:id
DELETE /api/tickets/kb/:id

HTMX fragment: GET /api/ui/tickets/kb

List Fragment (with filters)

The suite list view is served as HTML fragments:

GET /api/ui/tickets?status=open
GET /api/ui/tickets?priority=high
GET /api/ui/tickets?category=billing
GET /api/ui/tickets?record_type=problem
GET /api/ui/tickets/:id                 # detail fragment
GET /api/ui/tickets/:id/comments        # comments fragment

Assign by email/name or UUID:

PUT /api/tickets/:id/assign
Content-Type: application/json
{ "assignee": "team@example.com" }   # or { "assignee_id": "<uuid>" }