---
title: "Send a message to VetsGPT"
method: POST
path: "/workspaces/{workspaceId}/vetsgpt/ask"
tags: ["vetsgpt"]
---

# Send a message to VetsGPT

`POST /workspaces/{workspaceId}/vetsgpt/ask`

## Request

- Base URL: `https://vetnio.com/api/v2`
- URL: `https://vetnio.com/api/v2/workspaces/{workspaceId}/vetsgpt/ask`
- Auth: HTTP bearer

Sends one message to VetsGPT, waits for the complete answer and returns both stored messages as JSON (no streaming). It runs the same engine as the web app: the message is classified as clinical or administrative, clinical questions are answered from web and clinic-knowledge search with inline citations, and the chat's consultation, patient and file context is included. An answer involves several model calls and searches, so expect responses to take a while and use a long client timeout.

Omit `chatId` to start a chat (its id is derived from `idempotencyKey`), or pass an existing chat's id to continue it. The caller must own the chat or have contribute access. Only the owner can send `consultationIds` or `patientId` to update its context before a new question; contributors must omit both.

**Idempotency:** every request needs an `idempotencyKey`. Repeating a request with the same key returns the stored answer without generating again. With server-coordinated turns, changing the prompt, files or generation options under the same key is a conflict. If an earlier request with that key is still generating, the call waits for it, and returns `409 CONFLICT` if it does not finish. If generation fails, the question stays stored and requires an explicit `retry: true` action by the original sender to restart the latest interrupted request before later messages. The question retains its original linked context. Ordinary network replay never restarts it. `409 CHAT_BUSY` means another question is generating; `REQUEST_MISMATCH` means the payload changed under the same key; `RETRY_NOT_ALLOWED` means an explicit retry can no longer restart.

Deep Research, streaming, and the consultation editor actions of the web app are not available through this endpoint. The first VetsGPT use in a workspace without a subscription can start its free trial. Errors: `403` when VetsGPT is disabled for the caller, `404` for an unknown chat, insufficient chat permission or an unreadable consultation, `500` when generation fails.

## Path parameters

- `workspaceId` string, required: Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.

## Request body

- object
  - `chatId` string: Existing chat the caller owns or has contribute access to; `404` if it does not exist. Omit to start a new chat, whose id is derived from `idempotencyKey`. A chat must already exist to upload attachments, so create it first when the first message carries files.
  - `title` string: Initial title for a chat created by this call; ignored when `chatId` is given. VetsGPT replaces it with a generated title after the first message on a topic. Defaults to `New Chat <date>`.
  - `message` string, required: The vet's question or instruction, as plain text (1 to 50,000 characters).
  - `retry` boolean: Explicitly retry the latest interrupted turn; network replays must omit this.
  - `idempotencyKey` string, required: Client-generated unique key for this message (8 to 128 characters, for example a UUID). Retrying with the same key never sends the question twice: if the answer is already stored it is returned immediately, and if another request with this key is still generating, this one waits for it. Use a new key for every new message.
  - `consultationIds` string[]: Owner only: consultations to use for a new question (up to 50). A non-empty list replaces the chat's stored consultation context; when omitted or empty, the existing context is kept. Contributors must omit this field. Replays and explicit retries retain the original question's context. VetsGPT sees each consultation's name, date, transcript, clinical note, client communication and linked patient. Every id must be readable by the caller, otherwise `404`.
  - `patientId` string: Owner only: patient to store as context for a new question, replacing any previous one. Contributors must omit this field. VetsGPT uses the patient's basic details, up to five recent clinical notes and analysed patient files only while no consultations are attached. The id is not validated; an unknown id gives no context. Omit to keep the stored patient. Replays and explicit retries retain the original question's context.
  - `imageKeys` string[]: Keys of images uploaded to this chat through the upload-url endpoint. VetsGPT reads each file for this message only; send the keys again to use a file in a later message. Keys from another chat or user are ignored, as are files with an unsupported `Content-Type`.
  - `pdfKeys` string[]: Keys of PDF documents uploaded to this chat through the upload-url endpoint. Handled exactly like `imageKeys` (the stored `Content-Type` decides how the file is read).
  - `categoryHint` 'clinical' | 'administrative': Overrides VetsGPT's automatic classification of the question: - `clinical` — answer as a clinical question, with web and clinic-knowledge search and citations. - `administrative` — answer as a practice-administration task (for example drafting a summary or referral) without web search. Omit to let VetsGPT classify the message itself.

## Response `200`

The persisted user message and completed VetsGPT answer.

- object: The stored question and VetsGPT's completed answer.
  - `chat` object, required: The chat the exchange was stored in, including a newly created one.
    - `chatId` string, required: Chat id. Pass it as `chatId` to continue the conversation. Chats created by this endpoint without a `chatId` have ids of the form `rest-chat-<32 hex characters>`, derived from the caller and `idempotencyKey`.
    - `title` string, required: Chat title as shown in the VetsGPT sidebar, as stored when the answer was saved. A short title is generated in the background after the first message on a topic (also replacing a title supplied at creation, unless it was set with the update endpoint), so it can change shortly after this response; re-read it from the list endpoint. `Untitled` when no title is stored.
    - `createdAt` string, date-time, required: When the chat was created (ISO-8601 UTC).
    - `updatedAt` string, date-time, required: When the chat last changed, normally the time of the newest message (ISO-8601 UTC).
  - `userMessage` VetsgptMessage, required: One message in a VetsGPT chat, as returned by the ask endpoint.
    - `messageId` string, required: Message id. Messages written by the ask endpoint have stable ids derived from the actor, chat and `idempotencyKey`, so a retry returns the same ids. Use the assistant message id for feedback.
    - `timestamp` string, date-time, required: When the message was stored (ISO-8601 UTC).
    - `role` 'user' | 'assistant', required: Who wrote the message: - `user` — the vet's question. - `assistant` — VetsGPT's answer.
    - `content` string, required: Message text. Assistant answers are Markdown and may contain LaTeX math (`$…$`, `$$…$$`). Sources are cited inline, not in a separate list: web pages as `<https://…>` autolinks, clinic documents as `(Source: <title>, p. <page>)`, consultation data as `(Source: Consultation <n> - Clinical note)` and similar, uploaded files as `(Source: Attachment analysis)`.
    - `attachments` string[]: Attachment keys (from the upload-url endpoint) sent with this user message, as raw keys. The messages endpoint returns the same attachments as data URIs instead. Absent when there were none.
    - `feedback` 'positive' | 'negative' | 'none', required: The vet's rating of the message: - `positive` — rated helpful (thumbs up). - `negative` — rated unhelpful (thumbs down). - `none` — not rated, or the rating was cleared.
  - `assistantMessage` VetsgptMessage, required: One message in a VetsGPT chat, as returned by the ask endpoint.
    - `messageId` string, required: Message id. Messages written by the ask endpoint have stable ids derived from the actor, chat and `idempotencyKey`, so a retry returns the same ids. Use the assistant message id for feedback.
    - `timestamp` string, date-time, required: When the message was stored (ISO-8601 UTC).
    - `role` 'user' | 'assistant', required: Who wrote the message: - `user` — the vet's question. - `assistant` — VetsGPT's answer.
    - `content` string, required: Message text. Assistant answers are Markdown and may contain LaTeX math (`$…$`, `$$…$$`). Sources are cited inline, not in a separate list: web pages as `<https://…>` autolinks, clinic documents as `(Source: <title>, p. <page>)`, consultation data as `(Source: Consultation <n> - Clinical note)` and similar, uploaded files as `(Source: Attachment analysis)`.
    - `attachments` string[]: Attachment keys (from the upload-url endpoint) sent with this user message, as raw keys. The messages endpoint returns the same attachments as data URIs instead. Absent when there were none.
    - `feedback` 'positive' | 'negative' | 'none', required: The vet's rating of the message: - `positive` — rated helpful (thumbs up). - `negative` — rated unhelpful (thumbs down). - `none` — not rated, or the rating was cleared.
  - `progressEvents` string[], required: Progress phases VetsGPT went through while generating this answer, in order: - `analyzing_question` — preparing a clinical question for search. - `searching_sources` — searching the web and the clinic's knowledge material. - `generating_answer` — writing the answer. A clinical question normally reports all three; administrative and conversational messages may report none. Empty when the answer came from an earlier request with the same `idempotencyKey`. Informational only.

## Other responses

- `400`: Invalid input data
- `401`: Authorization not provided
- `403`: Insufficient access
- `500`: Internal server error

---

[API](https://skmtc.dev/vetnio/apis/vetnio-api.md) - [All operations](https://skmtc.dev/vetnio/apis/vetnio-api/llms.txt) - [OpenAPI document](https://skmtc.dev/vetnio/apis/vetnio-api/revisions/d004afd5617d?raw)
