:::endpoint POST /v1/admin/tickets/{ticket}/ai

The `/ai` command of the website's reply box: the assistant writes the next
reply to the trader, following your instruction. The instruction itself stays
behind as an internal note, so the team can see what was asked for, while the
trader only ever sees the answer.

That note is what this answers with. The reply follows a few seconds later:
it is written on the ticket's `channel` as `text_delta`, and lands in
[the conversation](/docs/api/admin/ticket-messages) as a message `from` `ai`
once it is done. See [listen on a websocket](/docs/api/apps/realtime#the-ticket-channels).

The ticket stays with whoever holds it. The assistant does not take the
conversation over, and the status moves to `awaiting_trader` like any other
reply. It works on a ticket where the assistant is
[blocked](/docs/api/admin/ticket-ai-block): the block is about the trader
calling it in, not about the team using it.

When the assistant cannot answer, because the firm's AI allowance is used up
or the AI is down, a note with the event `ai_command_failed` follows instead,
and nothing reaches the trader.

:::warning Every call is a reply written by the AI
It counts against the firm's AI allowance like any answer of the assistant.
Retrying with the same `Idempotency-Key` asks once.
:::

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

## Request

| Field         | Description |
| ------------- | ----------- |
| `instruction` | What the assistant should write, up to 2000 characters. Required |

```bash
curl -X POST "https://api.proppertrading.com/v1/admin/tickets/tkt_rqfzx8upvc24x5sg/ai" \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
  -H "Propper-Workspace: acme" \
  -H "Idempotency-Key: 9c1e3a5b-7d9f-4b2d-8e4a-6c8e0a2b4d6f" \
  -H "Content-Type: application/json" \
  -d '{"instruction": "Ask politely which device they trade from, in one sentence."}'
```

## Response

`201`, with the note:

```json
{
    "data": {
        "object": "ticket_message",
        "id": "tmsg_uhvtxfdk5kx28qmh",
        "ticket_id": "tkt_rqfzx8upvc24x5sg",
        "from": "admin",
        "author": "Ios Tester",
        "body": "/ai Ask politely which device they trade from, in one sentence.",
        "image_url": null,
        "image_name": null,
        "internal": true,
        "streaming": false,
        "via_email": false,
        "event": "ai_command",
        "read_at": null,
        "created_at": "2026-10-15T22:20:47+00:00"
    },
    "meta": {
        "request_id": "req_01m50sxk3v8q2r7hm4tn6wd9fa"
    }
}
```

## 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`                                     |
| 404    | `resource_not_found`      | No ticket with that id in this firm                                             |
| 409    | `ticket_ended`            | The ticket was resolved or closed                                               |
| 409    | `assistant_unavailable`   | The firm switched the assistant off for its team. The ticket's `can.ai` says so in advance |
| 422    | `validation_failed`       | No `instruction`, or one longer than 2000 characters                            |