API reference · Assistant
VetsGPT, Vetnio's clinical assistant: chats, messages, consultation and patient context, attachments and feedback.
Guides:Use VetsGPT
A VetsGPT conversation, private by default. Only its owner and explicitly granted current workspace members can access it; administrators have no implicit access.
chat_idstringrequiredChat id (UUID). Use it as chatId in the other VetsGPT endpoints.
user_idstringrequiredId of the Vetnio user who owns the chat, i.e. the caller.
workspace_idstringrequiredWorkspace the chat belongs to.
titlestringrequiredChat title. Without a supplied title the server stores New Chat <date> (date in the server's locale format). Either way, a short generated title replaces it in the background after the first message on a topic, unless the title is set with the update endpoint first.
created_atstringrequiredWhen the chat was created (ISO-8601 UTC).
last_updated_atstringrequiredWhen the chat last changed (ISO-8601 UTC).
messagesarray of objectsrequiredMessages in the chat, oldest first. Always empty for a newly created chat.
message_idstringrequiredMessage id, unique within the chat. Use it with the feedback endpoint.
timestampstringrequiredWhen the message was stored (ISO-8601 UTC).
typeenumrequiredWho wrote the message:
user_message — the vet.bot_message — VetsGPT.contentobjectrequiredText and attachments of a stored VetsGPT message.
textstringrequiredMessage text. Assistant answers are Markdown with inline source citations (see the ask endpoint).
attachmentsarray of stringsoptionalFiles attached to a user message. The messages endpoint returns each file inline as a base64 data URI (data:<mime>;name=<url-encoded file name>;base64,<bytes>), which can make responses large; files that can no longer be read are left out. Absent when the message has no attachments.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.isAttachmentAnalysisbooleanoptionalInternal marker for hidden messages that hold VetsGPT's analysis of uploaded files. Such messages are filtered out of the messages endpoint, so REST clients do not normally see this field.
copilotProposalsarray of objectsoptionalEdits to a consultation's clinical note or client communication that VetsGPT proposed while the vet chatted from the consultation page in the web app. Absent for chats that never used the consultation editor. Informational for REST clients; proposals can only be applied in the web app.
proposalIdstringrequiredId of the proposal, unique within the message.
at least 1 characters
toolenumrequiredThe editing tool VetsGPT used:
edit_clinical_note — edits the consultation's clinical note.edit_communication — edits the consultation's client communication.targetenumrequiredWhich document the edit applies to:
clinical_note — the clinical note.communication — the client communication.summarystringrequiredShort description of the change shown to the vet (up to 300 characters).
at least 1 characters · at most 300 characters
operationobjectrequiredThe edit itself, discriminated by kind: patch carries edits (1 to 20 {find, replace} pairs of lines in the document's HTML); replace_all carries html, the complete new document.
object (option 1)
kindenumrequiredPossible values:patch
editsarray of objectsrequiredat least 1 items · at most 20 items
findstringrequiredThe line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />.
at least 1 characters
replacestringrequiredWhat those lines become. Empty removes them.
object (option 2)
kindenumrequiredPossible values:replace_all
htmlstringrequiredat least 1 characters
sourceenumoptionalWhere the content of the edit came from:
consultation — this consultation's data.vetsgpt_knowledge — VetsGPT's own veterinary knowledge, flagged to the vet for review.
Absent on older proposals, which count as consultation.modeenumrequiredHow the vet had VetsGPT apply edits when the proposal was made:
auto — applied immediately ("Write it").manual — waits for the vet to accept ("Ask first").baseHashstringrequiredFingerprint of the document version the edit was written against. Used to detect that the document changed since.
at least 1 characters
statusenumrequiredReview state of the proposal:
pending — waiting for the vet.applied — applied automatically.accepted — accepted by the vet and applied.rejected — declined by the vet.undone — applied, then reverted.stale — could not be applied because the document changed (shown as Outdated).searchable_contentstringoptionalPlain-text log of message text (questions, extracted file text and most answers) that the list endpoint's search matches against. Not intended for display. Absent on a new chat.
{
"chat_id": "3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53",
"user_id": "6c1d2e3f-4a5b-4c7d-8e9f-0a1b2c3d4e5f",
"workspace_id": "furunculotic-loud-chihuahua",
"title": "NSAID dosing in a dog with CKD",
"created_at": "2026-10-04T09:12:31.000Z",
"last_updated_at": "2026-10-04T09:12:31.000Z",
"messages": [
{
"message_id": "rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b",
"timestamp": "2026-10-04T09:12:58.000Z",
"type": "bot_message",
"content": {
"text": "What is the meloxicam dose for a 24 kg dog?",
"attachments": [
"data:application/pdf;name=bloodwork.pdf;base64,JVBERi0xLjcK..."
]
},
"feedback": "positive",
"isAttachmentAnalysis": false,
"copilotProposals": [
{
"proposalId": "cp_7f3a9c21",
"tool": "edit_clinical_note",
"target": "clinical_note",
"summary": "Add the meloxicam dose to the treatment plan",
"operation": {
"kind": null,
"edits": null
},
"source": "consultation",
"mode": "manual",
"baseHash": "9b1e4c7a",
"status": "accepted"
}
]
}
],
"searchable_content": "string"
}One message in a VetsGPT chat, as returned by the ask endpoint.
messageIdstringrequiredMessage 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.
timestampstring (date-time)requiredWhen the message was stored (ISO-8601 UTC).
matches `^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$`
roleenumrequiredWho wrote the message:
user — the vet's question.assistant — VetsGPT's answer.contentstringrequiredMessage 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).
attachmentsarray of stringsoptionalAttachment 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.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.{
"messageId": "rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b",
"timestamp": "2026-10-04T09:12:58.000Z",
"role": "assistant",
"content": "Meloxicam is generally avoided in dogs with CKD unless the benefit outweighs the risk...",
"attachments": [
"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"
],
"feedback": "none"
}POST/workspaces/{workspaceId}/vetsgpt/ask
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.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringoptionalExisting 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.
titlestringoptionalInitial 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>.
messagestringrequiredThe vet's question or instruction, as plain text (1 to 50,000 characters).
at least 1 characters · at most 50000 characters
retrybooleanoptionalExplicitly retry the latest interrupted turn; network replays must omit this.
idempotencyKeystringrequiredClient-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.
at least 8 characters · at most 128 characters
consultationIdsarray of stringsoptionalOwner 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.
patientIdstringoptionalOwner 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.
imageKeysarray of stringsoptionalKeys 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.
pdfKeysarray of stringsoptionalKeys 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).
categoryHintenumoptionalOverrides 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.chatobjectrequiredThe chat the exchange was stored in, including a newly created one.
chatIdstringrequiredChat 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.
titlestringrequiredChat 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.
createdAtstring (date-time)requiredWhen the chat was created (ISO-8601 UTC).
matches `^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$`
updatedAtstring (date-time)requiredWhen the chat last changed, normally the time of the newest message (ISO-8601 UTC).
matches `^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$`
userMessageobjectrequiredThe stored question.
messageIdstringrequiredMessage 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.
timestampstring (date-time)requiredWhen the message was stored (ISO-8601 UTC).
matches `^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$`
roleenumrequiredWho wrote the message:
user — the vet's question.assistant — VetsGPT's answer.contentstringrequiredMessage 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).
attachmentsarray of stringsoptionalAttachment 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.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.assistantMessageobjectrequiredVetsGPT's stored answer.
messageIdstringrequiredMessage 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.
timestampstring (date-time)requiredWhen the message was stored (ISO-8601 UTC).
matches `^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$`
roleenumrequiredWho wrote the message:
user — the vet's question.assistant — VetsGPT's answer.contentstringrequiredMessage 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).
attachmentsarray of stringsoptionalAttachment 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.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.progressEventsarray of stringsrequiredProgress 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.curl -X POST "https://vetnio.com/api/v2/workspaces/furunculotic-loud-chihuahua/vetsgpt/ask" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chatId": "3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53",
"title": "NSAID dosing in a dog with CKD",
"message": "What is the meloxicam dose for a 24 kg dog with stage 2 CKD?",
"retry": true,
"idempotencyKey": "0b7f6a52-93c1-4e2d-8a4f-61d0c9e3b7aa",
"consultationIds": [
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
],
"patientId": "f2a3b4c5-d6e7-4890-fabc-012345678901",
"imageKeys": [
"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"
],
"pdfKeys": [
"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/9c2b7e14-5f3a-4d8b-a1e6-0f7c3d9b2e58"
],
"categoryHint": "clinical"
}'{
"chat": {
"chatId": "rest-chat-4b1f0c9e2d7a4e6b8c3f5a1d9e0b2c7f",
"title": "NSAID dosing in a dog with CKD",
"createdAt": "2026-10-04T09:12:31.000Z",
"updatedAt": "2026-10-04T09:12:58.000Z"
},
"userMessage": {
"messageId": "rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b",
"timestamp": "2026-10-04T09:12:58.000Z",
"role": "assistant",
"content": "Meloxicam is generally avoided in dogs with CKD unless the benefit outweighs the risk...",
"attachments": [
"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"
],
"feedback": "none"
},
"assistantMessage": {
"messageId": "rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b",
"timestamp": "2026-10-04T09:12:58.000Z",
"role": "assistant",
"content": "Meloxicam is generally avoided in dogs with CKD unless the benefit outweighs the risk...",
"attachments": [
"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"
],
"feedback": "none"
},
"progressEvents": [
"analyzing_question",
"searching_sources",
"generating_answer"
]
}POST/workspaces/{workspaceId}/vetsgpt/chats
Creates an empty VetsGPT chat owned by the calling user, optionally with consultation and patient context. Create a chat first when the first message carries file attachments, because upload URLs are issued per chat. Not idempotent: each call creates a new chat.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
titlestringoptionalInitial title. Defaults to New Chat <date>. VetsGPT replaces it with a generated title after the first message on a topic unless you set it later with the update endpoint.
consultationIdsarray of stringsoptionalConsultations to attach as context (up to 50). Each must be readable by the caller, otherwise 404 (the chat is still created).
patientIdstringoptionalPatient to attach as context. Used only while no consultations are attached. Not validated; an unknown id gives no context.
chat_idstringrequiredChat id (UUID). Use it as chatId in the other VetsGPT endpoints.
user_idstringrequiredId of the Vetnio user who owns the chat, i.e. the caller.
workspace_idstringrequiredWorkspace the chat belongs to.
titlestringrequiredChat title. Without a supplied title the server stores New Chat <date> (date in the server's locale format). Either way, a short generated title replaces it in the background after the first message on a topic, unless the title is set with the update endpoint first.
created_atstringrequiredWhen the chat was created (ISO-8601 UTC).
last_updated_atstringrequiredWhen the chat last changed (ISO-8601 UTC).
messagesarray of objectsrequiredMessages in the chat, oldest first. Always empty for a newly created chat.
message_idstringrequiredMessage id, unique within the chat. Use it with the feedback endpoint.
timestampstringrequiredWhen the message was stored (ISO-8601 UTC).
typeenumrequiredWho wrote the message:
user_message — the vet.bot_message — VetsGPT.contentobjectrequiredText and attachments of a stored VetsGPT message.
textstringrequiredMessage text. Assistant answers are Markdown with inline source citations (see the ask endpoint).
attachmentsarray of stringsoptionalFiles attached to a user message. The messages endpoint returns each file inline as a base64 data URI (data:<mime>;name=<url-encoded file name>;base64,<bytes>), which can make responses large; files that can no longer be read are left out. Absent when the message has no attachments.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.isAttachmentAnalysisbooleanoptionalInternal marker for hidden messages that hold VetsGPT's analysis of uploaded files. Such messages are filtered out of the messages endpoint, so REST clients do not normally see this field.
copilotProposalsarray of objectsoptionalEdits to a consultation's clinical note or client communication that VetsGPT proposed while the vet chatted from the consultation page in the web app. Absent for chats that never used the consultation editor. Informational for REST clients; proposals can only be applied in the web app.
proposalIdstringrequiredId of the proposal, unique within the message.
at least 1 characters
toolenumrequiredThe editing tool VetsGPT used:
edit_clinical_note — edits the consultation's clinical note.edit_communication — edits the consultation's client communication.targetenumrequiredWhich document the edit applies to:
clinical_note — the clinical note.communication — the client communication.summarystringrequiredShort description of the change shown to the vet (up to 300 characters).
at least 1 characters · at most 300 characters
operationobjectrequiredThe edit itself, discriminated by kind: patch carries edits (1 to 20 {find, replace} pairs of lines in the document's HTML); replace_all carries html, the complete new document.
object (option 1)
kindenumrequiredPossible values:patch
editsarray of objectsrequiredat least 1 items · at most 20 items
findstringrequiredThe line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />.
at least 1 characters
replacestringrequiredWhat those lines become. Empty removes them.
object (option 2)
kindenumrequiredPossible values:replace_all
htmlstringrequiredat least 1 characters
sourceenumoptionalWhere the content of the edit came from:
consultation — this consultation's data.vetsgpt_knowledge — VetsGPT's own veterinary knowledge, flagged to the vet for review.
Absent on older proposals, which count as consultation.modeenumrequiredHow the vet had VetsGPT apply edits when the proposal was made:
auto — applied immediately ("Write it").manual — waits for the vet to accept ("Ask first").baseHashstringrequiredFingerprint of the document version the edit was written against. Used to detect that the document changed since.
at least 1 characters
statusenumrequiredReview state of the proposal:
pending — waiting for the vet.applied — applied automatically.accepted — accepted by the vet and applied.rejected — declined by the vet.undone — applied, then reverted.stale — could not be applied because the document changed (shown as Outdated).searchable_contentstringoptionalPlain-text log of message text (questions, extracted file text and most answers) that the list endpoint's search matches against. Not intended for display. Absent on a new chat.
sharingobjectrequiredOwner and effective sharing summary; underlying clinical source access is not granted by chat sharing.
permissionenumrequiredThe current actor's effective permission for this chat.
Possible values:ownerviewcontribute
ownerobjectrequiredThe chat's owner identity.
idstringrequiredUser ID of the chat owner; grants do not transfer ownership.
namestringrequirednullableOwner display name, or null when unavailable.
isSharedbooleanrequiredWhether at least one current workspace member has an explicit grant.
recipientCountnumberrequiredNumber of current explicitly granted recipients, excluding the owner.
firstRecipientNamestringrequirednullableFirst recipient display name for a compact sharing summary, or null.
curl -X POST "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Bella - ear itching",
"consultationIds": [
"dfd6e768-51dd-5fcb-a786-c6dffe511d5f"
]
}'{
"chat_id": "449b3a72-336b-4a52-a3e7-9e90595ea090",
"user_id": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"workspace_id": "demo-north-clinic",
"title": "Bella - ear itching",
"created_at": "2026-10-30T13:47:19.262Z",
"last_updated_at": "2026-10-30T13:47:19.262Z",
"messages": [],
"sharing": {
"permission": "owner",
"owner": {
"id": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"name": "Alex Demo"
},
"isShared": false,
"recipientCount": 0,
"firstRecipientName": null
}
}GET/workspaces/{workspaceId}/vetsgpt/chats
Lists owned and explicitly shared VetsGPT chats in this workspace, newest first by conversation activity, with stable chat-id ordering for ties. Not paginated; every chat is returned. Each chat's searchable_content is included only when searchQuery is given and the actor may access that search projection.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
searchQuerystringoptionalOptional case-insensitive substring to match against chat titles and message text. Leading and trailing whitespace is ignored; an empty value lists every chat. % and _ act as wildcards.
[ ]array of objectsrequiredsharingobjectrequiredOwner and effective sharing summary; underlying clinical source access is not granted by chat sharing.
permissionenumrequiredThe current actor's effective permission for this chat.
Possible values:ownerviewcontribute
ownerobjectrequiredThe chat's owner identity.
idstringrequiredUser ID of the chat owner; grants do not transfer ownership.
namestringrequirednullableOwner display name, or null when unavailable.
isSharedbooleanrequiredWhether at least one current workspace member has an explicit grant.
recipientCountnumberrequiredNumber of current explicitly granted recipients, excluding the owner.
firstRecipientNamestringrequirednullableFirst recipient display name for a compact sharing summary, or null.
chat_idstringoptionalChat id. Use it as chatId in the other VetsGPT endpoints.
titlestringoptionalChat title as shown in the VetsGPT sidebar.
created_atstringoptionalWhen the chat was created (ISO-8601 UTC).
last_updated_atstringoptionalWhen the chat last changed (ISO-8601 UTC).
searchable_contentstringoptionalPlain-text log of the chat's message text (questions, extracted file text and most answers) that searchQuery is matched against. Only returned when searchQuery is given. Not intended for display; it grows with the chat and can be large.
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats" \
-H "Authorization: Bearer $VETNIO_API_KEY"[
{
"sharing": {
"permission": "owner",
"owner": {
"id": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"name": "Alex Demo"
},
"isShared": false,
"recipientCount": 0,
"firstRecipientName": null
},
"chat_id": "449b3a72-336b-4a52-a3e7-9e90595ea090",
"title": "Bella - ear itching",
"created_at": "2026-10-30T13:47:19.262Z",
"last_updated_at": "2026-10-30T13:47:19.319Z"
}
]PATCH/workspaces/{workspaceId}/vetsgpt/chats/{chatId}
Renames a chat owned by the caller and turns off automatic title generation for it. View and contribute grants do not permit renaming. Returns 404 when the chat does not exist or the caller is not its owner.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
titlestringrequiredNew title, 1 to 100 characters. A title set here is kept: VetsGPT stops generating titles for this chat.
at least 1 characters · at most 100 characters
successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X PATCH "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Bella - otitis work-up"
}'{
"success": true
}DELETE/workspaces/{workspaceId}/vetsgpt/chats/{chatId}
Deletes a chat owned by the caller. It disappears for its owner and all recipients and can no longer be read or continued; this cannot be undone. View and contribute grants do not permit deletion. Returns 404 when the chat does not exist (including a second delete) or the caller is not its owner.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X DELETE "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"success": true
}GET/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments
Returns the consultations and patient attached to an owned or explicitly shared chat as context. Despite the path, uploaded files are not listed here. Sharing does not grant access to the underlying clinical resources. Returns 404 when the chat does not exist or the caller lacks access.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
consultationsarray of objectsrequiredConsultations attached to the chat as context, in attachment order. Empty when none are attached.
idstringrequiredConsultation id.
namestringrequiredConsultation name. Unknown when the consultation no longer exists or the caller can no longer read it; it is then still listed but not used as context.
patientobjectrequirednullableThe patient attached to the chat as context, or null when none is attached or the patient has since been deleted.
idstringrequiredPatient id.
namestringrequiredPatient name, or Unknown when the record has no name.
speciesstringrequirednullableSpecies as recorded on the patient, or null.
identifierstringrequirednullablePatient identifier (for example a microchip number), or null.
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"consultations": [
{
"id": "dfd6e768-51dd-5fcb-a786-c6dffe511d5f",
"name": "DEMO Milo - annual wellness visit"
}
],
"patient": {
"id": "062579c4-60ce-5d25-a89c-d75d5760378a",
"name": "Milo",
"species": "dog",
"identifier": null
}
}PUT/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/consultations
Owner only: replaces the consultations attached as context for new questions. VetsGPT reads each consultation's name, date, transcript, clinical note, client communication and linked patient, re-checking read access on every message. Existing questions retain their captured context on retry. Returns 404 when the chat does not exist or the caller is not its owner. More than 50 consultations currently returns 500.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
consultationIdsarray of stringsrequiredThe complete new set of consultations (duplicates removed, up to 50). An empty array removes all consultation context. Every id must be a consultation the caller can read, otherwise 404 and nothing changes.
successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X PUT "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/consultations" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"consultationIds": [
"dfd6e768-51dd-5fcb-a786-c6dffe511d5f"
]
}'{
"success": true
}PUT/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/patient
Owner only: attaches one patient to the chat as context, replacing any previous patient. For new questions VetsGPT uses the patient's details, up to five recent clinical notes and up to five analysed patient files, but only while no consultations are attached (attached consultations bring their own patient). Existing questions retain their captured context on retry. Returns 404 when the chat does not exist or the caller is not its owner.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
patientIdstringrequiredPatient to attach. Replaces any patient already attached. Not validated; an unknown id is stored but gives no context.
successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X PUT "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/patient" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"patientId": "062579c4-60ce-5d25-a89c-d75d5760378a"
}'{
"success": true
}DELETE/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/patient
Owner only: detaches the patient from the chat's context for new questions. Attached consultations are not affected, and existing questions retain their captured context on retry. Succeeds when no patient was attached. Returns 404 when the chat does not exist or the caller is not its owner.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X DELETE "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/patient" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"success": true
}POST/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/upload-url
Issues a presigned URL for uploading one file to an existing chat the caller owns or can contribute to. Steps:
PUT the raw bytes to chatAttachmentUploadUrl within 24 hours, with the file's real Content-Type (for example image/jpeg or application/pdf).key in imageKeys or pdfKeys on the ask endpoint for the same chat.VetsGPT can read images, PDFs, plain text, CSV, Word (.docx) and Excel files; other types are skipped without an error. No size limit is enforced on the upload (the web app caps PDFs at 50 MB), and at most 100,000 extracted characters per file are used.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
filenamestringoptionalOriginal file name. Shown to VetsGPT as the file's label and returned in the messages endpoint's data URIs. When omitted, the generated key is used instead.
chatAttachmentUploadUrlstring (uri)requiredPresigned S3 URL, valid for 24 hours. PUT the raw file bytes to it with a Content-Type header matching the file (for example application/pdf or image/jpeg).
keystringrequiredAttachment key (chats/<workspaceId>/<chatId>/attachments/<uuid>). After the upload, pass it in imageKeys or pdfKeys when you call the ask endpoint for the same chat. Keys are only valid in the chat they were issued for.
curl -X POST "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/upload-url" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "ear-cytology.jpg"
}'{
"chatAttachmentUploadUrl": "https://storage.example.com/chats/demo-north-clinic/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/e425aa67-548c-4587-9e56-9befdab96e96?X-Amz-Expires=86400&X-Amz-Signature=…",
"key": "chats/demo-north-clinic/449b3a72-336b-4a52-a3e7-9e90595ea090/attachments/e425aa67-548c-4587-9e56-9befdab96e96"
}GET/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/messages
Returns the stored messages of an owned or explicitly shared chat, oldest first. Hidden internal messages (extracted file text and answers still being generated) are left out. Attachments are returned inline as base64 data URIs, which can make the response large. Returns 404 when the chat does not exist or the caller lacks access.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
[ ]array of objectsrequiredmessage_idstringrequiredMessage id, unique within the chat. Use it with the feedback endpoint.
timestampstringrequiredWhen the message was stored (ISO-8601 UTC).
typeenumrequiredWho wrote the message:
user_message — the vet.bot_message — VetsGPT.contentobjectrequiredText and attachments of a stored VetsGPT message.
textstringrequiredMessage text. Assistant answers are Markdown with inline source citations (see the ask endpoint).
attachmentsarray of stringsoptionalFiles attached to a user message. The messages endpoint returns each file inline as a base64 data URI (data:<mime>;name=<url-encoded file name>;base64,<bytes>), which can make responses large; files that can no longer be read are left out. Absent when the message has no attachments.
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.isAttachmentAnalysisbooleanoptionalInternal marker for hidden messages that hold VetsGPT's analysis of uploaded files. Such messages are filtered out of the messages endpoint, so REST clients do not normally see this field.
copilotProposalsarray of objectsoptionalEdits to a consultation's clinical note or client communication that VetsGPT proposed while the vet chatted from the consultation page in the web app. Absent for chats that never used the consultation editor. Informational for REST clients; proposals can only be applied in the web app.
proposalIdstringrequiredId of the proposal, unique within the message.
at least 1 characters
toolenumrequiredThe editing tool VetsGPT used:
edit_clinical_note — edits the consultation's clinical note.edit_communication — edits the consultation's client communication.targetenumrequiredWhich document the edit applies to:
clinical_note — the clinical note.communication — the client communication.summarystringrequiredShort description of the change shown to the vet (up to 300 characters).
at least 1 characters · at most 300 characters
operationobjectrequiredThe edit itself, discriminated by kind: patch carries edits (1 to 20 {find, replace} pairs of lines in the document's HTML); replace_all carries html, the complete new document.
object (option 1)
kindenumrequiredPossible values:patch
editsarray of objectsrequiredat least 1 items · at most 20 items
findstringrequiredThe line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />.
at least 1 characters
replacestringrequiredWhat those lines become. Empty removes them.
object (option 2)
kindenumrequiredPossible values:replace_all
htmlstringrequiredat least 1 characters
sourceenumoptionalWhere the content of the edit came from:
consultation — this consultation's data.vetsgpt_knowledge — VetsGPT's own veterinary knowledge, flagged to the vet for review.
Absent on older proposals, which count as consultation.modeenumrequiredHow the vet had VetsGPT apply edits when the proposal was made:
auto — applied immediately ("Write it").manual — waits for the vet to accept ("Ask first").baseHashstringrequiredFingerprint of the document version the edit was written against. Used to detect that the document changed since.
at least 1 characters
statusenumrequiredReview state of the proposal:
pending — waiting for the vet.applied — applied automatically.accepted — accepted by the vet and applied.rejected — declined by the vet.undone — applied, then reverted.stale — could not be applied because the document changed (shown as Outdated).curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/vetsgpt/chats/449b3a72-336b-4a52-a3e7-9e90595ea090/messages" \
-H "Authorization: Bearer $VETNIO_API_KEY"[]PUT/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/messages/{messageId}/feedback
Rates a VetsGPT answer as helpful (positive) or unhelpful (negative), or clears the rating (none). Requires ownership or contribute access. Ratings are recorded in Vetnio's product analytics. Returns 404 for an unknown chat or message, or insufficient chat permission.
AcceptsPersonal key
workspaceIdstringrequiredIdentifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.
chatIdstringrequiredIdentifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.
messageIdstringrequiredId of the message to rate, normally an assistant message (assistantMessage.messageId from the ask endpoint or message_id from the messages endpoint).
feedbackenumrequiredThe vet's rating of the message:
positive — rated helpful (thumbs up).negative — rated unhelpful (thumbs down).none — not rated, or the rating was cleared.
Sending the same value again is harmless.successbooleanrequiredAlways true on success; failures are returned as errors.
curl -X PUT "https://vetnio.com/api/v2/workspaces/furunculotic-loud-chihuahua/vetsgpt/chats/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/messages/rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b/feedback" \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"feedback": "positive"
}'{
"success": true
}