List tickets API

This article and the rest of the API documentation in this section are written for a technical audience — integrators and developers connecting external systems to Tickiti. Familiarity with HTTP, REST, JSON and bearer-token authentication is assumed.

The list endpoint returns the ticket list as Tickiti itself renders it — through a perspective. A perspective is a saved view (its filters, conditions and ordering) configured in the Tickiti interface; the API runs the same query the staff ticket browser does, so the results, ordering and permission filtering match exactly what the acting user would see on screen.

Use it to mirror a Tickiti queue into an external dashboard, to poll for tickets matching a saved filter, to look tickets up by number, subject or participant, or to reconcile state between Tickiti and another system.

Endpoint

POST /api/v1/tickets/query

Headers

  1. Authorization: Bearer YOUR_TOKEN — required. Token must have the tickets:read ability. A tickets:write token also works (write implies read).
  2. Content-Type: application/json — required. No Idempotency-Key is needed (this is a read).

Body

All fields are optional. With an empty body the endpoint returns the built-in All perspective.

  1. perspective_id — the numeric id of the perspective to list. This is the most direct selector when you are not searching.
  2. search_object.criteria — ad-hoc search filters; see Searching with criteria.
  3. search_object.search_perspective_id or search_object.search_perspective — the perspective a criteria search runs within, by id or by name (e.g. "All"). Defaults to All.
  4. row_limit — the maximum number of rows to return. Defaults to 100. Send it at the top level of the body; a row_limit inside search_object is used when there is none at the top level.

Tickiti chooses the perspective in this order:

  1. A token whose owner is not a staff account, and a lone ticket-number lookup (see below), always use All.
  2. When search_object.criteria holds at least one criterion with tokens, the search runs within search_perspective_id, else search_perspective, else All.
  3. Otherwise perspective_id is listed; with no perspective_id, All.

Results are always scoped by the permissions of the staff user the token acts as: a ticket is included only if that user can view its queue, is a participant on it, or belongs to the team it is assigned to. This means a token can never read tickets its owner could not read in the interface.

Searching with criteria

Pass search_object.criteria to apply ad-hoc filters — the same ones the ticket browser’s search bar builds. Each entry is a { "mode": ..., "tokens": [...], "match": ... } object: mode names the field to match, tokens is an array of values, and the optional match ("all" or "any") says how several tokens combine. A criterion with no tokens is ignored.

  1. Across criteria: criteria that share a mode are combined with OR; criteria of different modes are combined with AND. So [{"mode":"status","tokens":["open"]},{"mode":"queue","tokens":["Sales"]}] reads “open tickets in the Sales queue”.
  2. Within one criterion — text modes (subject, content, subject_content): every token must match, unless the criterion has "match": "any", in which case any one token is enough. {"mode":"subject","tokens":["Vapor","plate"]} finds subjects containing both words.
  3. Within one criterion — single-value modes (assigned, participant, priority, raised, queue, status, watchlist, ticket_number, hashtag): a ticket matches when it matches any of the tokens. {"mode":"ticket_number","tokens":["220009","220014"]} returns exactly those two tickets, and numbers that match nothing return nothing.
  4. Date modes take a single YYYY-MM-DD token and compare as UTC.

The modes:

ModeMatches
subjectTicket subject contains the token (substring).
contentAny response body or tag comment contains the token.
subject_contentSubject or any response body contains the token.
assignedThe assignee: a staff email (which also matches tickets assigned to that person’s teams), a team key team:<id> (the team’s own tickets), team-and-members:<id> (the team’s tickets and those assigned to any member personally), or Unassigned.
participantA participant email contains the token.
priorityPriority code — 10, 20, 30 or 40 (exact).
raisedOriginator (raiser) email contains the token.
queueQueue name (exact).
statusTicket status — open, closed, on-hold, … (exact).
watchlistId of a watchlist the ticket is on.
hashtagTicket carries the hashtag (a leading # is optional).
ticket_number6-digit ticket number (exact; a leading # is optional).
created_fromTicket raised on or after a YYYY-MM-DD date.
created_toTicket raised on or before a YYYY-MM-DD date.
updated_fromLast activity on or after a YYYY-MM-DD date.
updated_toLast activity on or before a YYYY-MM-DD date.

An unknown mode is refused with 422, and the message lists the valid modes. POST /api/v1/tickets/search-modes returns the same vocabulary and the combination rules at runtime, so a client can discover them rather than hard-coding the list — see the Ticket operations API. Team keys for assigned come from POST /api/v1/tickets/teams.

A lone criterion with a single 6-digit token — in ticket_number mode, or in any mode when written as #220009 — is a direct ticket lookup: it searches the All perspective for that number, whichever perspective the request names.

Example

List a saved perspective:

curl -X POST https://support.sole-provider.example/api/v1/tickets/query \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "perspective_id": 3
  }'

Or search with criteria — open Sales tickets, up to 50 rows:

curl -X POST https://support.sole-provider.example/api/v1/tickets/query \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "row_limit": 50,
    "search_object": {
      "criteria": [
        { "mode": "status", "tokens": ["open"] },
        { "mode": "queue", "tokens": ["Sales"] }
      ]
    }
  }'

Tickets whose subject mentions either of two quote references, in the Sales or Returns queue:

{
  "search_object": {
    "search_perspective": "All",
    "criteria": [
      { "mode": "subject", "tokens": ["Q-10068", "Q-10015"], "match": "any" },
      { "mode": "queue", "tokens": ["Sales", "Returns"] }
    ]
  }
}

Successful response

A tickets array of rows, each summarising one ticket in the perspective’s order, plus show_more (true when more rows matched than row_limit allowed) and total_count (the number of tickets that match, after permission and search filtering). The core row fields are stable; rows also carry the display fields the ticket browser uses, such as since_created, since_updated, opened and locked.

{
  "tickets": [
    {
      "ticket_id": 1,
      "number": 220009,
      "status": "open",
      "on_hold_until": null,
      "queue": "Returns",
      "priority": "20",
      "subject": "Carbon plate cracked on first marathon",
      "assigned_to_email": "[email protected]",
      "originator_email": "[email protected]",
      "created_at": "2026-05-01 09:14:02",
      "updated_at": "2026-05-02 11:30:48",
      "since_created": "1 day ago",
      "since_updated": "2 hours ago"
    }
  ],
  "show_more": false,
  "total_count": 1
}

The list is the same materialised, cached set the ticket browser uses, so it reflects the latest ticket state at query time. Poll it on a sensible interval rather than in a tight loop.

Error responses

  1. 422 — a criterion names an unknown mode. The body carries a message and, under errors["search_object.criteria"], the unknown modes and the list of valid ones.
  2. 404 — the requested perspective (by id or name) does not exist. The body carries a message.
  3. 401 unauthenticated — bad or missing token.
  4. 403 forbidden — token does not have the tickets:read (or tickets:write) ability.

To read a full conversation behind a row, follow up with the Show ticket API. See the API overview for the shared request and authentication conventions.