Ask a new question

.md

Start a conversation with its first question. The answer follows over the websocket.

Scopesai:write
POST/v1/me/ai/conversations

Makes a conversation, stores the question in it and queues the answer. The response comes back at once, before the assistant has written a word: the question as it was stored, and the answer as an empty message with status streaming.

Draw both straight away, subscribe to the conversation's channel, and let the websocket events fill the answer in. Match them by the answer's id, which is the message_id of every turn_state.

Request

curl -X POST https://api.proppertrading.com/v1/me/ai/conversations \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6c1f0d52-3a8e-4b7d-9e21-5f4a8c3b2d10" \
  -d '{
    "message": "What is the maximum daily loss on my account?",
    "attachments": [
      { "name": "chart.png", "data": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAI..." }
    ]
  }'
FieldRequiredDescription
messageyesThe question, at most 4000 characters
attachmentsnoUp to five files
attachments[].nameyesThe file's name as the person sees it, at most 255 characters. Never used as a path on our side
attachments[].datayesThe file, base64. At most 10 MB once decoded. JPEG, PNG, GIF, WebP, PDF, plain text or CSV, worked out from the bytes

Response

201:

{
    "data": {
        "object": "ai_turn",
        "conversation": {
            "id": "01a16152-7e42-70cd-91a4-b6b80ee47daa",
            "object": "ai_conversation",
            "title": null,
            "pinned": false,
            "surface": "trader_chat",
            "channel": "private-ai-chat.01a16152-7e42-70cd-91a4-b6b80ee47daa",
            "last_message_at": "2026-10-22T01:55:58+00:00",
            "created_at": "2026-10-22T01:55:58+00:00"
        },
        "question": {
            "id": "aimsg_dkr8n8ctvh9qtmce",
            "object": "ai_message",
            "role": "user",
            "content": "What is the maximum daily loss on my account?",
            "status": "complete",
            "attachments": [
                {
                    "index": 0,
                    "name": "chart.png",
                    "content_type": "image/png",
                    "size_bytes": 90,
                    "url": "https://api.proppertrading.com/v1/me/ai/messages/aimsg_dkr8n8ctvh9qtmce/attachments/0"
                }
            ],
            "actions": [],
            "created_at": "2026-10-22T01:55:58+00:00"
        },
        "answer": {
            "id": "aimsg_tjqupx579w3cpx9m",
            "object": "ai_message",
            "role": "assistant",
            "content": "",
            "status": "streaming",
            "attachments": [],
            "actions": [],
            "created_at": "2026-10-22T01:55:58+00:00"
        }
    },
    "meta": {
        "request_id": "req_01m5gn4zh3jdhfxy2bxdyg8q29"
    }
}

A message is the same shape everywhere:

FieldDescription
idA public id such as aimsg_dkr8n8ctvh9qtmce
roleuser for the question, assistant for the answer
contentThe text. Markdown in an answer
statuscomplete, streaming, cancelled or failed
attachmentsThe files on a question. content_type is the image type for an image and application/octet-stream for anything else. url downloads it with the same token
actionsThe action cards an answer proposed, oldest first, as they stand now. Always empty on a question

What the answer uses counts against the firm's AI allowance and, for a trader, against a limit per day when the firm set one. A stopped answer counts for what it wrote.

Errors

StatusCodeMeaning
400invalid_attachmentA file's data is not base64, or it is empty. param says which, such as attachments.0.data
400attachment_too_largeA file over 10 MB once decoded
400missing_idempotency_keyEvery POST needs one
400workspace_requiredOur own staff, without a firm in Propper-Workspace
403ai_unavailableThe firm has the assistant switched off for this chat
403ai_kyc_requiredA trader whose account is locked until the identity check is done
403forbiddenStaff whose role does not include use_ai_chat
403insufficient_scopeThis device does not hold ai:write
422validation_failedNo message, one over 4000 characters, more than five files, or a file of a type that is not allowed
429ai_limit_reachedAn allowance is used up. state says which and resets_at when it comes back
429rate_limit_exceededTwenty questions and deletions a minute, shared with the website

A refusal from the allowance looks like this:

{
    "error": {
        "type": "rate_limit_error",
        "code": "ai_limit_reached",
        "message": "You have asked as many questions today as this firm allows. Ask again after resets_at.",
        "doc_url": "https://proppertrading.com/docs/api/errors#ai_limit_reached",
        "state": "daily_limit",
        "resets_at": "2026-10-23T00:00:00+02:00",
        "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey"
    }
}

state is session or week for the firm's AI allowance, none for a package without AI, platform when our own capacity is used up, and daily_limit for the limit per trader the firm set. resets_at is left out when waiting will not help.