:::endpoint POST /v1/admin/tickets

A ticket the team opens with a trader, for a question the team has rather than
one the trader asked. The team spoke first, so it starts waiting on the
trader, held by whoever opened it, with the assistant off and blocked: the
trader cannot hand it to the assistant until somebody on the team
[allows that again](/docs/api/admin/ticket-ai-block). The trader is told the
way any reply tells them: the bell, a toast, and an email when they are away.

Only one of the firm's own traders. Somebody on the team is not, because a
conversation with a colleague does not belong in the support queue. The
traders to pick from are [listed here](/docs/api/admin/ticket-traders).

A trader has one open ticket at a time, so this is refused when they have one,
and the error names it in `ticket` so the app can offer that one instead.

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

## Request

| Field      | Description |
| ---------- | ----------- |
| `user_id`  | The trader's `id`. Required |
| `subject`  | Up to 150 characters. Required. The trader reads it in their list of tickets |
| `message`  | The first message, up to 5000 characters. Required |
| `priority` | `low`, `normal` (the default), `high` or `urgent` |

```bash
curl -X POST "https://api.proppertrading.com/v1/admin/tickets" \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
  -H "Propper-Workspace: acme" \
  -H "Idempotency-Key: 7b9d1f3a-5c7e-4e9b-8d1f-3a5c7e9b1d3f" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "usr_ec8dc3bqfsuh2p5r", "subject": "Your trades on Friday", "message": "Hi Zara, we noticed a few trades on Friday that we would like to go through with you. Do you have a moment this week?", "priority": "high"}'
```

## Response

`201`, with the [ticket](/docs/api/admin/ticket):

```json
{
    "data": {
        "object": "ticket",
        "id": "tkt_wm9qfkgsnpfhtzfj",
        "number": "#FHTZFJ",
        "subject": "Your trades on Friday",
        "status": "awaiting_trader",
        "priority": "high",
        "ai_enabled": false,
        "ai_blocked": true,
        "created_at": "2026-10-15T22:30:22+00:00",
        "last_message_at": "2026-10-15T22:30:22+00:00",
        "last_trader_message_at": null,
        "last_admin_message_at": "2026-10-15T22:30:22+00:00",
        "closed_at": null,
        "closed_by": null,
        "idle_warning_sent_at": null,
        "trader": {
            "id": "usr_ec8dc3bqfsuh2p5r",
            "name": "Zara Fontaine",
            "email": "zara.fontaine.2600@example.com",
            "avatar_url": null,
            "is_active": true,
            "deleted": false,
            "on_team": false,
            "online": false,
            "last_seen_at": null
        },
        "assignee": {
            "id": "usr_pj68ba8tmrbb7fxb",
            "name": "Ios Tester",
            "avatar_url": null,
            "me": true
        },
        "team": null,
        "tags": [],
        "counts": {
            "messages": 1,
            "notes": 0,
            "unread": 0,
            "tickets": 1,
            "payouts": 0
        },
        "tabs": [
            "conversation",
            "trader",
            "activity"
        ],
        "can": {
            "manage": true,
            "teams": true,
            "traders": true,
            "accounts": true,
            "payouts": true,
            "fraud": true,
            "activity": true,
            "ai": true
        },
        "channel": "private-ticket.tkt_wm9qfkgsnpfhtzfj",
        "action_url": "/admin/tickets/tkt_wm9qfkgsnpfhtzfj"
    },
    "meta": {
        "request_id": "req_01m50v06daqssxzggkt9ptrzhr"
    }
}
```

When the trader already has an open ticket:

```json
{
    "error": {
        "type": "invalid_request_error",
        "code": "trader_has_open_ticket",
        "message": "The trader already has an open ticket. Answer in that one instead.",
        "param": "user_id",
        "doc_url": "https://proppertrading.com/docs/api/errors#trader_has_open_ticket",
        "ticket": {
            "id": "tkt_tattwr6c8dunw3f9",
            "subject": "Spread on gold looked wrong at the open"
        },
        "request_id": "req_01m50tx6zmy9bj6vvayz6vnhz1"
    }
}
```

## Errors

| Status | Code                      | Meaning                                                                         |
| ------ | ------------------------- | ------------------------------------------------------------------------------- |
| 400    | `workspace_required`      | Asked by our own staff without naming a firm                                    |
| 400    | `missing_idempotency_key` | A POST without an `Idempotency-Key` header                                      |
| 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:write`                                         |
| 403    | `workspace_not_permitted` | The `Propper-Workspace` header names an environment this account cannot act in |
| 403    | `forbidden`               | Without `view_tickets` and `manage_tickets`                                     |
| 409    | `trader_has_open_ticket`  | The trader has an open ticket already. `ticket` names it, with `id` and `subject` |
| 422    | `validation_failed`       | No `user_id`, or not one of the firm's traders, somebody on the team for instance. No `subject` or `message`, one that is too long, or an unknown `priority` |