:::endpoint GET /v1/admin/tickets

Every support ticket of the firm's traders. The same list as Tickets on the
website, with the same search and the same filters. Where the website reads a
value it does not know as the default, because its addresses get bookmarked,
this refuses it: a client that thinks it filtered and got everything shows the
wrong list.

One ticket, with what it takes to answer it, is [a ticket](/docs/api/admin/ticket).
The counters above the list are the [summary](/docs/api/admin/tickets-summary),
and the agents, teams and tags to filter on are the
[options](/docs/api/admin/ticket-options).

Needs a firm. Our own staff name one with the `Propper-Workspace` header.

## Request

| Parameter        | Description |
| ---------------- | ----------- |
| `status`         | `waiting` (for the team), `open` (not ended), `ai` (the assistant is answering), `trader` (waiting on the trader), `ended` (resolved or closed), or `all` (the default) |
| `assignee`       | `anyone` (the default), `me` (yours and your teams'), `none` (no agent and no team), or the `id` of an agent |
| `team`           | `any` (the default), `none`, or the `id` of a [team](/docs/api/admin/support-teams) |
| `priority`       | `urgent`, `high`, `normal`, `low`, or `all` (the default) |
| `tag`            | Only tickets with this [tag](/docs/api/admin/ticket-tags), or `all` (the default). A tag that no longer exists finds nothing |
| `q`              | Search, up to 100 characters. See below |
| `sort`           | `queue` (the default), `-last_message_at` latest activity first, `-created_at` newest first, `created_at` oldest first, or `-priority` most urgent first |
| `limit`          | How many, see [pagination](/docs/api/pagination) |
| `starting_after` | The `next_cursor` of the page before. A cursor only works with the `sort` it was handed out with |

`queue` is the order the website opens on. First what waits for the team, the
most urgent on top and then whoever has waited longest since the trader last
wrote. Then what the assistant is answering, then what waits on a trader, then
everything that ended, each with the latest activity first.

`q` takes what a trader or a colleague has in hand. A whole ticket id or
trader id finds exactly that one. Anything else is split into words, and every
word has to match somewhere: the subject, the trader's name or email address,
or any message of the conversation, the team's internal notes included. A word
of six letters and digits also finds the ticket with that `number`. A word
starting with `#` looks only at the number, so `#Q45CA7` does not also find a
message holding those letters.

```bash
curl "https://api.proppertrading.com/v1/admin/tickets?status=waiting&limit=2" \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
  -H "Propper-Workspace: acme"
```

## Response

```json
{
    "data": [
        {
            "object": "ticket",
            "id": "tkt_tattwr6c8dunw3f9",
            "number": "#UNW3F9",
            "subject": "Spread on gold looked wrong at the open",
            "status": "awaiting_admin",
            "priority": "high",
            "ai_enabled": false,
            "ai_blocked": false,
            "unread": 1,
            "last_from": "trader",
            "last_message_at": "2026-10-07T05:00:26+00:00",
            "created_at": "2026-10-07T05:00:26+00:00",
            "closed_at": null,
            "trader": {
                "id": "usr_5t9et623ep5cygcm",
                "name": "Ines Rossi",
                "email": "ines.rossi.661@example.com",
                "avatar_url": null,
                "deleted": false
            },
            "assignee": null,
            "team": null,
            "tags": [],
            "action_url": "/admin/tickets/tkt_tattwr6c8dunw3f9"
        },
        {
            "object": "ticket",
            "id": "tkt_ebcgbewt26spv54q",
            "number": "#SPV54Q",
            "subject": "Payout still pending after five days",
            "status": "awaiting_admin",
            "priority": "high",
            "ai_enabled": false,
            "ai_blocked": false,
            "unread": 1,
            "last_from": "trader",
            "last_message_at": "2026-10-08T19:23:11+00:00",
            "created_at": "2026-10-08T19:23:11+00:00",
            "closed_at": null,
            "trader": {
                "id": "usr_c3jpdarm9q2wndhs",
                "name": "Julia Nilsson",
                "email": "julia.nilsson.112@example.com",
                "avatar_url": null,
                "deleted": false
            },
            "assignee": null,
            "team": null,
            "tags": [],
            "action_url": "/admin/tickets/tkt_ebcgbewt26spv54q"
        }
    ],
    "meta": {
        "request_id": "req_01m50va7n21xvavmhds6n2p3a7",
        "has_more": true,
        "next_cursor": "eyJzIjoicXVldWUiLCJ2IjpbMCwtMiwiMTc5MTQ4NzM5MS4wMDAwMDAiXSwiaWQiOiJ0a3RfZWJjZ2Jld3QyNnNwdjU0cSJ9"
    }
}
```

| Field             | Description |
| ----------------- | ----------- |
| `number`          | What people read out: the last six characters of the id |
| `status`          | `open` (the assistant is answering), `awaiting_admin` (waits for the team), `awaiting_trader`, `resolved` or `closed`. The last two are final |
| `priority`        | `low`, `normal`, `high` or `urgent` |
| `ai_enabled`      | The assistant answers this ticket now. It goes off for good at the team's first answer |
| `ai_blocked`      | The trader may not call the assistant back in. See [block the assistant](/docs/api/admin/ticket-ai-block) |
| `unread`          | Messages from the trader and the assistant that the team has not [read](/docs/api/admin/ticket-read) |
| `last_from`       | Who wrote the last message the trader can see: `trader`, `admin`, `ai` or `system`. Says whose turn it is. Null without one |
| `last_message_at` | The last message the trader can see. A note does not move it |
| `closed_at`       | When it was resolved or closed. Null while it is open |
| `trader`          | Who asked. `deleted` is true for a trader who deleted their account, whose ticket stays in the firm's history |
| `assignee`        | The agent who holds it, with `id`, `name` and `avatar_url`. Null for nobody |
| `team`            | The team it was given to, with `id` and `name`. Null for none |
| `tags`            | The team's own labels, each with `id`, `name` and `color` |
| `action_url`      | Where the website shows the ticket, a path inside the web application |

## Errors

| Status | Code                      | Meaning                                                                         |
| ------ | ------------------------- | ------------------------------------------------------------------------------- |
| 400    | `workspace_required`      | Asked by our own staff without naming a firm                                    |
| 400    | `validation_failed`       | `status`, `assignee`, `team`, `priority` or `tag` is not one of its values or an id of the right kind, or `q` is not text |
| 400    | `invalid_sort`            | `sort` is not one of the five orders                                            |
| 400    | `invalid_limit`           | `limit` is not a positive integer                                               |
| 400    | `invalid_cursor`          | `starting_after` is not a cursor handed out for this `sort`                     |
| 401    | `invalid_token`           | Not a token, or the secret does not match                                       |
| 401    | `revoked_token`           | Signed out here or from another device                                          |
| 401    | `expired_token`           | Ninety days without use, or a set expiry passed                                 |
| 403    | `admin_access_required`   | This account no longer helps run the environment                                |
| 403    | `insufficient_scope`      | This device does not hold `admin:read`                                          |
| 403    | `workspace_not_permitted` | The `Propper-Workspace` header names an environment this account cannot act in |
| 403    | `forbidden`               | Without `view_tickets`                                                          |