{"openapi":"3.1.0","info":{"title":"Vetnio API","description":"REST API for [Vetnio](https://vetnio.com), the AI-powered veterinary documentation platform. Guides, concepts and a complete reference live at [vetnio.com/developers](https://vetnio.com/developers).\n\n## Authentication\n\nSend an API key in the `Authorization` header: `Authorization: Bearer <key>`.\n\n- **Personal keys** (`sk_live_…`), created under Settings → API Keys, act as the user who created them, with all of their permissions, on every endpoint. They do not expire; delete them to revoke.\n- **Organization keys** (`sk_org_…`) and **clinic keys** (`sk_ws_…`), created under Organization → API, are read-only and only work on the organization and usage export endpoints. They are rate limited.\n- A signed-in browser session also works, which is how the interactive explorer calls the API; when a session cookie is present the `Authorization` header is ignored.\n\nThe API is meant for server-to-server use: it does not send CORS headers to other origins, so never call it from a browser with a key.\n\n## Versioning\n\nThis is the current stable **v2** API. A legacy v1 surface exists at `/api/v1` for backward compatibility.\n\n## Common patterns\n\n- Clinic-scoped endpoints take a `workspaceId` path parameter; consultation-scoped endpoints also take `consultationId`.\n- Request and response bodies are JSON. Timestamps are ISO-8601 strings in UTC.\n- `POST`, `PUT` and `PATCH` requests need `Content-Type: application/json` and a JSON body, `{}` if there are no fields.\n- Errors return `{ message, code, data: { code, httpStatus, … }, issues? }`. Unexpected server errors return 500 with the message \"An unexpected error occurred\".\n","version":"1.0.0","contact":{"name":"Vetnio","url":"https://vetnio.com/developers","email":"support@vetnio.com"}},"servers":[{"url":"https://vetnio.com/api/v2"}],"tags":[{"name":"workspaces","description":"A workspace is one veterinary clinic in Vetnio. It scopes every clinical resource; a user can belong to several workspaces with a different role in each."},{"name":"consultations","description":"A consultation is one visit. It is the container for its recordings, transcript, uploaded files, linked patient and generated records."},{"name":"recordings","description":"Upload consultation audio, start transcription and read partial (live) transcripts."},{"name":"transcriptions","description":"Partial and complete transcripts produced from a consultation's recordings."},{"name":"records","description":"Documents attached to a consultation: the clinical note, client communication, referral letter and structured documents. Read, write, generate and inspect their retained versions."},{"name":"templates","description":"Instructions that control how Vetnio writes clinical notes and other free-text documents."},{"name":"json-templates","description":"Structured templates: a typed set of fields that Vetnio fills to produce a form-like document instead of free text."},{"name":"patients","description":"Animal patients. Each patient belongs to one client (owner) and can be linked to consultations."},{"name":"clients","description":"Animal owners. A client owns one or more patients in a workspace."},{"name":"uploaded-files","description":"Files attached to a consultation, such as lab results or referral letters. Vetnio extracts their content so it can be used when generating documents."},{"name":"signed-url","description":"Operations that return a short-lived pre-signed storage URL. Send the file bytes directly to that URL, not to the Vetnio API."},{"name":"vetsgpt","description":"VetsGPT, Vetnio's clinical assistant: chats, messages, consultation and patient context, attachments and feedback."},{"name":"link","description":"Endpoints for clinics that use the Link practice-management system: status, customer and animal lookup, form templates and export."},{"name":"vettigo","description":"Endpoints for clinics that use Vettigo: status, client and patient lookup, and clinical-note export."},{"name":"vetmanager","description":"Endpoints for clinics that use VetManager: status, patient search, creating or recovering the visit for a consultation, and clinical-note export."},{"name":"user","description":"The authenticated user and their registered devices."},{"name":"data-export","description":"Read-only access to your organization's **usage statistics** in Vetnio, for BI tools, dashboards and data warehouses. It returns the same table as **Organization → Export** in the app. It never returns patient records, clinical notes, transcriptions, audio or chat content.\n\n## Quick start\n\n1. An **organization admin** opens **Vetnio → Organization → API** and clicks **Create API key**.\n2. Copy the key right away. It is shown **only once**, so store it like a password.\n3. Check that it works. The response includes your `organizationId`:\n\n```\ncurl https://vetnio.com/api/v2/api-key \\\n  -H \"Authorization: Bearer sk_org_YOUR_KEY\"\n```\n\n4. Fetch usage for the last 30 days, one row per clinic and month:\n\n```\ncurl \"https://vetnio.com/api/v2/organizations/YOUR_ORGANIZATION_ID/data-export/usage?days=30&grain=clinic\" \\\n  -H \"Authorization: Bearer sk_org_YOUR_KEY\"\n```\n\n**Easiest way to build a request:** open **Organization → Export**, choose the period, clinics, level of detail and columns, then click **Use via API**. It shows the exact request for that selection, ready to copy.\n\n## Base URL and authentication\n\n- **Base URL:** `https://vetnio.com/api/v2`\n- **Header on every request:** `Authorization: Bearer <your key>`\n- **Method:** every endpoint is `GET`. Keys are read-only and cannot change anything.\n- **Key types:**\n  - `sk_org_…`: the whole organization, every clinic in it.\n  - `sk_ws_…`: one clinic. It uses the same endpoints and its usage rows only ever cover that clinic. The organization overview still lists the organization's people and organization-level templates.\n\n## Endpoints\n\n| Endpoint | Returns |\n|---|---|\n| `GET /api-key` | The key you are using: its organization, scope, status, limits and request counts for today and the last 30 days |\n| `GET /organizations/{organizationId}` | The organization, its clinics (id, name, city, country), its people (name, email and role per clinic) and the names of its organization-level templates |\n| `GET /organizations/{organizationId}/data-export/usage` | Usage statistics as a table: the same numbers as the in-app usage export |\n\n## Usage parameters\n\nAll optional.\n\n| Parameter | Default | Allowed | Meaning |\n|---|---|---|---|\n| `days` | 30 | 1 to 366 | Rolling window ending today |\n| `startDate` / `endDate` | none | `YYYY-MM-DD`, at most 366 days apart | A fixed range instead of `days`. `endDate` defaults to today and is only used together with `startDate` |\n| `timePeriod` | `monthly` | `daily`, `weekly`, `monthly`, `yearly` | Size of each time bucket |\n| `grain` | `vet` | `vet`, `clinic`, `consultation`, `snapshot` | One row per vet, per clinic, per consultation, or one row for the whole period |\n| `workspaceIds` | every clinic | comma-separated clinic IDs from `GET /organizations/{organizationId}` | Only these clinics |\n| `columns` | every column except note quality | comma-separated column keys | Which columns to return, in the export's column order |\n| `page` / `pageSize` | 1 / 1000 | `pageSize` up to 5000 | Only for `grain=consultation`; every other grain fits in one response |\n\nColumn keys: `workspaceId`, `workspaceName`, `countryCode`, `clinicCreatedAt`, `clinicMembers`, `clinicActiveVets`, `street`, `city`, `stateProvince`, `zipCode`, `phone`, `taxId`, `subscriptionStatus`, `billingType`, `licensedSeats`, `usedSeats`, `unusedSeats`, `overageSeats`, `billingInterval`, `monthlyAmount`, `currency`, `nextPaymentDate`, `nextPaymentAmount`, `lastPaymentDate`, `lastPaymentAmount`, `isPastDue`, `cancelAtPeriodEnd`, `trialExpiresAt`, `userId`, `userName`, `userEmail`, `consultationCount`, `patients`, `recordingHours`, `avgRecordingDurationMinutes`, `consultationsPerVet`, `lastActiveAt`, `avgReadingSeconds`, `avgEditingSeconds`, `acceptanceRate`, `draftOutcome`, `vetsGptConversationsCreated`, `vetsGptMessagesSent`, `callsTotal`, `callsIncoming`, `callsOutgoing`, `callMinutes`, `avgCallSeconds`, `consultationId`, `consultationName`, `pimsConsultationId`, `consultationDate`, `consultationStartTime`, `consultationEndTime`, `consultationRecordingMinutes`, `consultationDeleted`.\n\nThe note-quality columns (`avgReadingSeconds`, `avgEditingSeconds`, `acceptanceRate`, `draftOutcome`) are only included when you list them, because each request with them runs an extra analytics query. A key can make 20 such requests per day.\n\n## Response format\n\n```json\n{\n  \"headers\": [\"Date\", \"Clinic Name\", \"Consultations\"],\n  \"rows\": [[\"2026-09-01\", \"Riverside Animal Clinic\", 412]],\n  \"start\": \"2026-09-01\",\n  \"end\": \"2026-09-30\",\n  \"totalRows\": 1,\n  \"page\": 1,\n  \"totalPages\": 1\n}\n```\n\nFor every grain except `snapshot`, the first column is `Date`: the first day of the bucket (or the first day of the range, for a bucket that starts before it).\n\n- `headers` are the column titles; each entry in `rows` has one value per header, in the same order.\n- `start` and `end` are the first and last day covered.\n- With `grain=consultation`, fetch `page=1`, `page=2`, … until `page` equals `totalPages`. Pages starting past row 50,000 are refused; split the date range into shorter requests instead.\n\n## Nightly syncs\n\nRequest yesterday with `startDate` and `endDate` set to the same day, or re-fetch the current month each night with `timePeriod=monthly`. Figures for past days can still change slightly as notes are finished, so re-fetching a short overlap is safer than only fetching new days.\n\n## Limits\n\n| Limit | Value |\n|---|---|\n| Requests per key | 60 per minute and 10,000 per day (the day resets at 00:00 UTC) |\n| Date range | at most 366 days per request |\n| Note-quality columns | 20 requests per key per day |\n| Request timeout | 10 minutes; a normal request returns in a few seconds |\n| Keys per organization | at most 10 active |\n| Key lifetime | no expiry unless one is chosen when the key is created |\n| What counts | every request, including rejected and rate-limited ones |\n\n## Errors\n\n| Status | Meaning | What to do |\n|---|---|---|\n| `400` | A parameter is invalid; the body says which | Fix the parameter |\n| `401` | Missing, wrong, revoked or expired key, or the admin who created it no longer has admin access | Check the `Authorization` header, or create a new key |\n| `403` | The key cannot use this endpoint, or cannot reach this organization | Use an endpoint listed above with the key's own `organizationId` |\n| `429` | Rate limit reached; the message says how long to wait | Wait, then retry |\n\n## Security\n\n- Keys are **read-only** and work only on the endpoints above. Every other Vetnio endpoint refuses them.\n- A key stops working immediately when it is **revoked**, when it **expires**, or when the admin who created it **loses admin access**.\n- **Replace key** (under Organization → API) issues a new key; the old one keeps working for 24 hours so you can swap it in without downtime.\n- Every overview and usage request is recorded in the audit log, and admins can see each key's last use and daily request counts under **Organization → API**.\n- Never put a key in a browser, a public repository or a shared document."},{"name":"customer-content","description":"Read-only exports of an organization's, clinic's or user's own configuration: templates, settings and transcription terms, including retained versions. Requires a personal key (or session) with admin rights for the scope; organization and clinic keys are not accepted."},{"name":"meta","description":"The OpenAPI document describing this API."}],"paths":{"/workspaces":{"get":{"operationId":"workspaces-listWorkspacesV1","summary":"List workspaces","description":"Returns every workspace (veterinary clinic) the authenticated user is a direct member of, with their role in each. Use it to find the `workspaceId` for workspace-scoped endpoints and to decide which of them the user may call. The list is not paginated and not sorted; sort client-side if needed. Organization admins can also open their organization's clinics without being members, but those clinics are not listed here. Accepts a session or a personal API key; organization and workspace keys get 403.","tags":["workspaces"],"security":[{"Authorization":[]}],"responses":{"200":{"description":"The workspaces the caller belongs to. An empty array means the user has not joined or created a workspace yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"workspaces-createSimple","summary":"Create a workspace","description":"Creates a new workspace (veterinary clinic) from a name and country code, and makes the caller its `superadmin`. Before responding it also records the caller's acceptance of Vetnio's Terms of Service, Privacy Policy and Data Processing Agreement, creates the workspace's default note templates and a billing customer, and may link the clinic to an organization that matches the caller's email domain or lists the clinic on its roster. Failures in those follow-up steps are logged and do not fail the request. The free trial does not start here; it starts with the workspace's first consultation or first VetsGPT conversation. Not idempotent: every successful call creates another workspace. A user may normally create only one workspace (accounts enabled for multi-clinic administration can create up to 200); beyond that the request fails with a generic 500 error. Accepts a session or a personal API key.","tags":["workspaces"],"security":[{"Authorization":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Display name of the clinic, shown in the workspace switcher, on invoices and on PDF letterheads. Not checked for uniqueness or length; an empty string is accepted.","example":"Riverside Animal Clinic"},"countryCode":{"type":"string","description":"Two-letter ISO 3166-1 alpha-2 country code of the clinic, for example `se`, `de` or `us` (matched case-insensitively). It sets regional defaults such as the audio retention policy (12 months for Germany, Austria and Switzerland) and becomes the billing address country. Stored as sent and not validated, so send a real code.","example":"se"}},"required":["name","countryCode"],"title":"Create workspace — request","description":"Workspace creation payload. Only a clinic name and country code are needed; the address and tax ID can be completed later in the app."}}}},"responses":{"200":{"description":"Workspace created. Use the returned `id` as `workspaceId` in subsequent workspace-scoped requests.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceCreated"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/ask":{"post":{"operationId":"chats-ask","summary":"Send a message to VetsGPT","description":"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.\n\nOmit `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.\n\n**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.\n\nDeep 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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatId":{"description":"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.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53","type":"string"},"title":{"description":"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>`.","example":"NSAID dosing in a dog with CKD","type":"string"},"message":{"type":"string","minLength":1,"maxLength":50000,"description":"The vet's question or instruction, as plain text (1 to 50,000 characters).","example":"What is the meloxicam dose for a 24 kg dog with stage 2 CKD?"},"retry":{"description":"Explicitly retry the latest interrupted turn; network replays must omit this.","type":"boolean"},"idempotencyKey":{"type":"string","minLength":8,"maxLength":128,"description":"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.","example":"0b7f6a52-93c1-4e2d-8a4f-61d0c9e3b7aa"},"consultationIds":{"description":"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`.","example":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"type":"array","items":{"type":"string"}},"patientId":{"description":"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.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901","type":"string"},"imageKeys":{"description":"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`.","example":["chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"],"type":"array","items":{"type":"string"}},"pdfKeys":{"description":"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).","example":["chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/9c2b7e14-5f3a-4d8b-a1e6-0f7c3d9b2e58"],"type":"array","items":{"type":"string"}},"categoryHint":{"description":"Overrides VetsGPT's automatic classification of the question:\n- `clinical` — answer as a clinical question, with web and clinic-knowledge search and citations.\n- `administrative` — answer as a practice-administration task (for example drafting a summary or referral) without web search.\nOmit to let VetsGPT classify the message itself.","example":"clinical","type":"string","enum":["clinical","administrative"]}},"required":["message","idempotencyKey"]}}}},"responses":{"200":{"description":"The persisted user message and completed VetsGPT answer.","content":{"application/json":{"schema":{"type":"object","properties":{"chat":{"type":"object","properties":{"chatId":{"type":"string","description":"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`.","example":"rest-chat-4b1f0c9e2d7a4e6b8c3f5a1d9e0b2c7f"},"title":{"type":"string","description":"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.","example":"NSAID dosing in a dog with CKD"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the chat was created (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the chat last changed, normally the time of the newest message (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z"}},"required":["chatId","title","createdAt","updatedAt"],"additionalProperties":false,"title":"VetsGPT chat summary","description":"The chat the exchange was stored in, including a newly created one."},"userMessage":{"description":"The stored question.","$ref":"#/components/schemas/VetsgptMessage"},"assistantMessage":{"description":"VetsGPT's stored answer.","$ref":"#/components/schemas/VetsgptMessage"},"progressEvents":{"type":"array","items":{"type":"string"},"description":"Progress phases VetsGPT went through while generating this answer, in order:\n- `analyzing_question` — preparing a clinical question for search.\n- `searching_sources` — searching the web and the clinic's knowledge material.\n- `generating_answer` — writing the answer.\nA 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.","example":["analyzing_question","searching_sources","generating_answer"]}},"required":["chat","userMessage","assistantMessage","progressEvents"],"additionalProperties":false,"title":"Ask VetsGPT result","description":"The stored question and VetsGPT's completed answer."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats":{"get":{"operationId":"chats-list","summary":"List VetsGPT chats","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"query","name":"searchQuery","schema":{"type":"string","description":"Optional 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.","example":"meloxicam"}}],"responses":{"200":{"description":"A list of VetsGPT chat summaries.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VetsgptChatListItem"}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"chats-create","summary":"Create a VetsGPT chat","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"Initial 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.","example":"Bella - post-op follow-up","type":"string"},"consultationIds":{"description":"Consultations to attach as context (up to 50). Each must be readable by the caller, otherwise `404` (the chat is still created).","example":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"type":"array","items":{"type":"string"}},"patientId":{"description":"Patient to attach as context. Used only while no consultations are attached. Not validated; an unknown id gives no context.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901","type":"string"}}}}}},"responses":{"200":{"description":"The created VetsGPT chat.","content":{"application/json":{"schema":{"type":"object","properties":{"chat_id":{"type":"string","description":"Chat id (UUID). Use it as `chatId` in the other VetsGPT endpoints.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"user_id":{"type":"string","description":"Id of the Vetnio user who owns the chat, i.e. the caller.","example":"6c1d2e3f-4a5b-4c7d-8e9f-0a1b2c3d4e5f"},"workspace_id":{"type":"string","description":"Workspace the chat belongs to.","example":"furunculotic-loud-chihuahua"},"title":{"type":"string","description":"Chat 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.","example":"NSAID dosing in a dog with CKD"},"created_at":{"type":"string","description":"When the chat was created (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z"},"last_updated_at":{"type":"string","description":"When the chat last changed (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z"},"messages":{"type":"array","items":{"type":"object","properties":{"message_id":{"type":"string","description":"Message id, unique within the chat. Use it with the feedback endpoint.","example":"rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b"},"timestamp":{"type":"string","description":"When the message was stored (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z"},"type":{"type":"string","enum":["user_message","bot_message"],"description":"Who wrote the message:\n- `user_message` — the vet.\n- `bot_message` — VetsGPT.","example":"bot_message"},"content":{"type":"object","properties":{"text":{"type":"string","description":"Message text. Assistant answers are Markdown with inline source citations (see the ask endpoint).","example":"What is the meloxicam dose for a 24 kg dog?"},"attachments":{"description":"Files 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.","example":["data:application/pdf;name=bloodwork.pdf;base64,JVBERi0xLjcK..."],"type":"array","items":{"type":"string"}}},"required":["text"],"additionalProperties":false,"title":"VetsGPT message content","description":"Text and attachments of a stored VetsGPT message."},"feedback":{"type":"string","enum":["positive","negative","none"],"description":"The vet's rating of the message:\n- `positive` — rated helpful (thumbs up).\n- `negative` — rated unhelpful (thumbs down).\n- `none` — not rated, or the rating was cleared.","example":"positive"},"isAttachmentAnalysis":{"description":"Internal 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.","example":false,"type":"boolean"},"copilotProposals":{"description":"Edits 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.","type":"array","items":{"type":"object","properties":{"proposalId":{"type":"string","minLength":1,"description":"Id of the proposal, unique within the message.","example":"cp_7f3a9c21"},"tool":{"type":"string","enum":["edit_clinical_note","edit_communication"],"description":"The editing tool VetsGPT used:\n- `edit_clinical_note` — edits the consultation's clinical note.\n- `edit_communication` — edits the consultation's client communication.","example":"edit_clinical_note"},"target":{"type":"string","enum":["clinical_note","communication"],"description":"Which document the edit applies to:\n- `clinical_note` — the clinical note.\n- `communication` — the client communication.","example":"clinical_note"},"summary":{"type":"string","minLength":1,"maxLength":300,"description":"Short description of the change shown to the vet (up to 300 characters).","example":"Add the meloxicam dose to the treatment plan"},"operation":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"patch"},"edits":{"readOnly":true,"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"find":{"type":"string","minLength":1,"description":"The line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />."},"replace":{"type":"string","description":"What those lines become. Empty removes them."}},"required":["find","replace"],"additionalProperties":false}}},"required":["kind","edits"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace_all"},"html":{"type":"string","minLength":1}},"required":["kind","html"],"additionalProperties":false}],"description":"The 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.","type":"object"},"source":{"description":"Where the content of the edit came from:\n- `consultation` — this consultation's data.\n- `vetsgpt_knowledge` — VetsGPT's own veterinary knowledge, flagged to the vet for review.\nAbsent on older proposals, which count as `consultation`.","example":"consultation","type":"string","enum":["consultation","vetsgpt_knowledge"]},"mode":{"type":"string","enum":["auto","manual"],"description":"How the vet had VetsGPT apply edits when the proposal was made:\n- `auto` — applied immediately (\"Write it\").\n- `manual` — waits for the vet to accept (\"Ask first\").","example":"manual"},"baseHash":{"type":"string","minLength":1,"description":"Fingerprint of the document version the edit was written against. Used to detect that the document changed since.","example":"9b1e4c7a"},"status":{"type":"string","enum":["pending","applied","accepted","rejected","undone","stale"],"description":"Review state of the proposal:\n- `pending` — waiting for the vet.\n- `applied` — applied automatically.\n- `accepted` — accepted by the vet and applied.\n- `rejected` — declined by the vet.\n- `undone` — applied, then reverted.\n- `stale` — could not be applied because the document changed (shown as Outdated).","example":"accepted"}},"required":["proposalId","tool","target","summary","operation","mode","baseHash","status"],"additionalProperties":false,"title":"VetsGPT edit proposal","description":"An edit to a consultation's clinical note or client communication that VetsGPT proposed in the web app's consultation panel. Read-only through the REST API."}}},"required":["message_id","timestamp","type","content","feedback"],"additionalProperties":false,"title":"Stored VetsGPT message","description":"One stored message of a VetsGPT chat."},"description":"Messages in the chat, oldest first. Always empty for a newly created chat."},"searchable_content":{"description":"Plain-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.","type":"string"},"sharing":{"type":"object","properties":{"permission":{"type":"string","enum":["owner","view","contribute"],"description":"The current actor's effective permission for this chat."},"owner":{"type":"object","properties":{"id":{"type":"string","description":"User ID of the chat owner; grants do not transfer ownership."},"name":{"description":"Owner display name, or null when unavailable.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"The chat's owner identity."},"isShared":{"type":"boolean","description":"Whether at least one current workspace member has an explicit grant."},"recipientCount":{"type":"number","description":"Number of current explicitly granted recipients, excluding the owner."},"firstRecipientName":{"description":"First recipient display name for a compact sharing summary, or null.","type":["string","null"]}},"required":["permission","owner","isShared","recipientCount","firstRecipientName"],"additionalProperties":false,"description":"Owner and effective sharing summary; underlying clinical source access is not granted by chat sharing."}},"required":["chat_id","user_id","workspace_id","title","created_at","last_updated_at","messages","sharing"],"additionalProperties":false}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/messages":{"get":{"operationId":"chats-getMessages","summary":"Get VetsGPT chat messages","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"responses":{"200":{"description":"The persisted chat messages.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"message_id":{"type":"string","description":"Message id, unique within the chat. Use it with the feedback endpoint.","example":"rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b"},"timestamp":{"type":"string","description":"When the message was stored (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z"},"type":{"type":"string","enum":["user_message","bot_message"],"description":"Who wrote the message:\n- `user_message` — the vet.\n- `bot_message` — VetsGPT.","example":"bot_message"},"content":{"type":"object","properties":{"text":{"type":"string","description":"Message text. Assistant answers are Markdown with inline source citations (see the ask endpoint).","example":"What is the meloxicam dose for a 24 kg dog?"},"attachments":{"description":"Files 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.","example":["data:application/pdf;name=bloodwork.pdf;base64,JVBERi0xLjcK..."],"type":"array","items":{"type":"string"}}},"required":["text"],"additionalProperties":false,"title":"VetsGPT message content","description":"Text and attachments of a stored VetsGPT message."},"feedback":{"type":"string","enum":["positive","negative","none"],"description":"The vet's rating of the message:\n- `positive` — rated helpful (thumbs up).\n- `negative` — rated unhelpful (thumbs down).\n- `none` — not rated, or the rating was cleared.","example":"positive"},"isAttachmentAnalysis":{"description":"Internal 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.","example":false,"type":"boolean"},"copilotProposals":{"description":"Edits 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.","type":"array","items":{"type":"object","properties":{"proposalId":{"type":"string","minLength":1,"description":"Id of the proposal, unique within the message.","example":"cp_7f3a9c21"},"tool":{"type":"string","enum":["edit_clinical_note","edit_communication"],"description":"The editing tool VetsGPT used:\n- `edit_clinical_note` — edits the consultation's clinical note.\n- `edit_communication` — edits the consultation's client communication.","example":"edit_clinical_note"},"target":{"type":"string","enum":["clinical_note","communication"],"description":"Which document the edit applies to:\n- `clinical_note` — the clinical note.\n- `communication` — the client communication.","example":"clinical_note"},"summary":{"type":"string","minLength":1,"maxLength":300,"description":"Short description of the change shown to the vet (up to 300 characters).","example":"Add the meloxicam dose to the treatment plan"},"operation":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"patch"},"edits":{"readOnly":true,"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"find":{"type":"string","minLength":1,"description":"The line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />."},"replace":{"type":"string","description":"What those lines become. Empty removes them."}},"required":["find","replace"],"additionalProperties":false}}},"required":["kind","edits"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace_all"},"html":{"type":"string","minLength":1}},"required":["kind","html"],"additionalProperties":false}],"description":"The 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.","type":"object"},"source":{"description":"Where the content of the edit came from:\n- `consultation` — this consultation's data.\n- `vetsgpt_knowledge` — VetsGPT's own veterinary knowledge, flagged to the vet for review.\nAbsent on older proposals, which count as `consultation`.","example":"consultation","type":"string","enum":["consultation","vetsgpt_knowledge"]},"mode":{"type":"string","enum":["auto","manual"],"description":"How the vet had VetsGPT apply edits when the proposal was made:\n- `auto` — applied immediately (\"Write it\").\n- `manual` — waits for the vet to accept (\"Ask first\").","example":"manual"},"baseHash":{"type":"string","minLength":1,"description":"Fingerprint of the document version the edit was written against. Used to detect that the document changed since.","example":"9b1e4c7a"},"status":{"type":"string","enum":["pending","applied","accepted","rejected","undone","stale"],"description":"Review state of the proposal:\n- `pending` — waiting for the vet.\n- `applied` — applied automatically.\n- `accepted` — accepted by the vet and applied.\n- `rejected` — declined by the vet.\n- `undone` — applied, then reverted.\n- `stale` — could not be applied because the document changed (shown as Outdated).","example":"accepted"}},"required":["proposalId","tool","target","summary","operation","mode","baseHash","status"],"additionalProperties":false,"title":"VetsGPT edit proposal","description":"An edit to a consultation's clinical note or client communication that VetsGPT proposed in the web app's consultation panel. Read-only through the REST API."}}},"required":["message_id","timestamp","type","content","feedback"],"additionalProperties":false,"title":"Stored VetsGPT message","description":"One stored message of a VetsGPT chat."}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments":{"get":{"operationId":"chats-getChatAttachments","summary":"Get VetsGPT chat attachments","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"responses":{"200":{"description":"The chat context attachments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VetsgptChatContext"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}":{"patch":{"operationId":"chats-updateTitle","summary":"Update a VetsGPT chat title","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":100,"description":"New title, 1 to 100 characters. A title set here is kept: VetsGPT stops generating titles for this chat.","example":"Bella - CKD and NSAIDs"}},"required":["title"]}}}},"responses":{"200":{"description":"The title was updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"chats-delete","summary":"Delete a VetsGPT chat","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"responses":{"200":{"description":"The chat was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/messages/{messageId}/feedback":{"put":{"operationId":"chats-updateFeedback","summary":"Update VetsGPT message feedback","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."},{"in":"path","name":"messageId","schema":{"type":"string","description":"Id of the message to rate, normally an assistant message (`assistantMessage.messageId` from the ask endpoint or `message_id` from the messages endpoint).","example":"rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b"},"required":true,"description":"Id of the message to rate, normally an assistant message (`assistantMessage.messageId` from the ask endpoint or `message_id` from the messages endpoint)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feedback":{"type":"string","enum":["positive","negative","none"],"description":"The vet's rating of the message:\n- `positive` — rated helpful (thumbs up).\n- `negative` — rated unhelpful (thumbs down).\n- `none` — not rated, or the rating was cleared.\nSending the same value again is harmless.","example":"positive"}},"required":["feedback"]}}}},"responses":{"200":{"description":"The feedback was updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/upload-url":{"post":{"operationId":"chats-getChatAttachmentUploadUrl","summary":"Get a VetsGPT attachment upload URL","description":"Issues a presigned URL for uploading one file to an existing chat the caller owns or can contribute to. Steps:\n\n1. Call this endpoint for each file.\n2. `PUT` the raw bytes to `chatAttachmentUploadUrl` within 24 hours, with the file's real `Content-Type` (for example `image/jpeg` or `application/pdf`).\n3. Pass the `key` in `imageKeys` or `pdfKeys` on the ask endpoint for the same chat.\n\nVetsGPT 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.","tags":["vetsgpt","signed-url"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"description":"Original 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.","example":"bella_bloodwork_2026-10-01.pdf","type":"string"}}}}}},"responses":{"200":{"description":"A signed upload URL and attachment key.","content":{"application/json":{"schema":{"type":"object","properties":{"chatAttachmentUploadUrl":{"type":"string","format":"uri","description":"Presigned 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`).","example":"https://vetnio-bucket.s3.eu-central-1.amazonaws.com/chats/furunculotic-loud-chihuahua/3f9c2a71-.../attachments/6a1e0f3c-...?X-Amz-Signature=..."},"key":{"type":"string","description":"Attachment 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.","example":"chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"}},"required":["chatAttachmentUploadUrl","key"],"additionalProperties":false,"title":"VetsGPT attachment upload URL","description":"Where to upload a chat attachment and the key that identifies it afterwards."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/patient":{"put":{"operationId":"chats-setPatient","summary":"Set VetsGPT patient context","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patientId":{"type":"string","description":"Patient to attach. Replaces any patient already attached. Not validated; an unknown id is stored but gives no context.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"}},"required":["patientId"]}}}},"responses":{"200":{"description":"The patient context was attached.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"chats-removePatient","summary":"Remove VetsGPT patient context","description":"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.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"responses":{"200":{"description":"The patient context was removed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetsgpt/chats/{chatId}/attachments/consultations":{"put":{"operationId":"chats-attachConsultation","summary":"Set VetsGPT consultation context","description":"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`.","tags":["vetsgpt"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic). The caller must be a member, and VetsGPT must be enabled for them in this workspace."},{"in":"path","name":"chatId","schema":{"type":"string","description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"required":true,"description":"Identifier of a VetsGPT chat owned by or explicitly shared with the caller. Unshared chats behave as if they did not exist."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"consultationIds":{"type":"array","items":{"type":"string"},"description":"The 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.","example":["a1b2c3d4-e5f6-7890-abcd-ef1234567890","b2c3d4e5-f6a7-8901-bcde-f12345678901"]}},"required":["consultationIds"]}}}},"responses":{"200":{"description":"The consultation context was updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` on success; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"VetsGPT success response","description":"Acknowledgement returned by VetsGPT mutations that have no resource body."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}":{"get":{"operationId":"consultations-getV1","summary":"Get consultation details","description":"Returns the status of one consultation: name, uploaded audio duration, transcription state and document-generation flags. This is the endpoint to poll while waiting for work to finish: after `POST .../transcriptions/start`, poll until `transcriptionStatus` is `completed` or `failed`; after requesting a clinical note, poll until `isGeneratingClinicalNote` is `false`.\n\nAny member of the workspace can read any consultation in it, including consultations created by colleagues and archived consultations. Returns `404` if the consultation does not exist in this workspace. Fields such as `externalId`, template IDs and the linked patient are not included here; they are returned by `GET .../consultations`.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"Consultation status fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationDetail"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"consultations-delete","summary":"Archive a consultation","description":"Archives the consultation. Nothing is erased: recordings, transcript, notes and uploaded files are kept, and the consultation stays readable by ID (`GET .../consultations/{consultationId}`, transcript and records). It disappears from `GET .../consultations`, but still appears in the admin export list. Archived consultations cannot be changed: write endpoints, including a second `DELETE`, return `403` with `data.reason` `archived_consultation`. Users can restore archived consultations in the Vetnio web app; permanent erasure is not available through the API. The clinic's audio-retention policy still removes audio on its normal schedule.\n\nAny member of the workspace can archive any consultation in it. Returns `404` if the consultation does not exist in this workspace.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"Consultation archived.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the consultation was archived.","example":true}},"required":["success"],"additionalProperties":false,"title":"Consultation archived","description":"Acknowledgement that the consultation was archived."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"patch":{"operationId":"consultations-rename","summary":"Rename a consultation","description":"Changes the display name of a consultation. Only `name` can be changed through this endpoint. Any member of the workspace can rename any consultation in it. Returns `403` for archived consultations and `404` if the consultation does not exist in this workspace.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New display name. Replaces the current name; free text with no length limit (an empty string is accepted).","example":"Bella - vaccination and dental check"}},"required":["name"]}}}},"responses":{"200":{"description":"Consultation renamed.","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"title":"Empty response","description":"Empty object returned on success."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/data-export":{"get":{"operationId":"consultations-getDataExport","summary":"Export raw consultation data","description":"Returns presigned download URLs for the full audio recording, transcription, clinical note, structured JSON document, owner communication, and referral letter of a consultation. Each field is null when the underlying artifact does not yet exist (for example if the clinical note has not been generated). Creator-only playback settings do not apply to this authorized admin export.\n\nWorkspace admin only (direct workspace admins and organization admins); other members get `403`. Archived or deleted consultations return `403` even though they appear in `GET .../data-export/consultations`. URLs are valid for 1 hour (`expiresAt`); call again for fresh ones. Read-only: nothing is generated or changed.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"Presigned download URLs for the consultation's stored artifacts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationDataExport"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/consultations":{"get":{"operationId":"consultations-listForExport","summary":"List consultations with export URLs","description":"Paginated list of all consultations in the workspace, regardless of creator, including archived consultations and consultations deleted in the Vetnio app (rows do not say which). Each row includes the selected clinical note template ID (`clinicalNoteTemplateId`, or `null` if none is selected) and presigned download URLs for the audio recording, transcription, clinical note, structured JSON document, owner communication, and referral letter (or `null` when the artifact does not exist). Workspace admin only.\n\nCreator-only playback settings do not apply to this authorized admin export.\n\nOptional createdAtFrom (inclusive) and createdAtBefore (exclusive) filter the consultation creation timestamp, not the last edit or recording time. Supply ISO-8601 timestamps with Z or an explicit offset. Filters apply before pagination and to the total count. Results are ordered by createdAt descending, then ID descending. Omit either bound for an open-ended range.\n\nPair with `GET .../data-export` for single-consultation export, or use this endpoint to build a bulk export UI. URLs expire after 1 hour; re-fetch the page if they go stale. Each row checks storage for six artifacts, so larger pages take noticeably longer.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Workspace to list consultations for.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Workspace to list consultations for."},{"in":"query","name":"page","schema":{"default":1,"description":"Page to return, starting at 1. Defaults to 1. Pages past the end return an empty `consultations` array.","example":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"in":"query","name":"pageSize","schema":{"default":10,"description":"Consultations per page, 1 to 50. Defaults to 10. Capped at 50 because each row includes presigned download URLs for six artifacts.","example":10,"type":"integer","minimum":1,"maximum":50}},{"in":"query","name":"searchQuery","schema":{"type":"string","description":"Case-insensitive substring filter matched against the consultation name, the plain text of its clinical note, its `externalId`, and the linked patient's name or identifier. Surrounding whitespace is ignored; omit for no filter.","example":"Bella"}},{"in":"query","name":"createdAtFrom","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on the consultation creation timestamp (not last edit or recording time). ISO-8601 with Z or an explicit timezone offset. Omit for no lower bound.","example":"2026-09-01T00:00:00Z"}},{"in":"query","name":"createdAtBefore","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Exclusive upper bound on the consultation creation timestamp. ISO-8601 with Z or an explicit timezone offset. Must be later than createdAtFrom. Omit for no upper bound.","example":"2026-10-01T00:00:00Z"}}],"responses":{"200":{"description":"Paginated consultation list with presigned export URLs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationExportList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations":{"get":{"operationId":"consultations-getPageWithCount","summary":"Get a page of consultations","description":"Returns a paginated list of the consultations the authenticated user created in this workspace. Colleagues' consultations are never listed, even when the workspace lets members see each other's consultations in the Vetnio app; they can still be read by ID. Archived consultations and consultations deleted in the app are excluded.\n\nEach item carries metadata (name, dates, audio duration, template IDs, generation flags) and `searchableContent`, a plain-text copy of the latest clinical note. Use `GET .../records` for the formatted note.\n\nResults are ordered by creation date, newest first. Consultations linked in a timeline (follow-up visits) are kept together and count as one entry toward `consultationsPerPage` and `count`. Use `searchQuery` to filter by name, clinical note text, external ID or patient name/identifier (case-insensitive substring match). Pagination is offset-based, so items can shift between pages while consultations are being created.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"query","name":"currentPage","schema":{"default":1,"description":"Page to return, starting at 1. Defaults to 1. Must be 1 or greater; lower values cause a server error.","example":1,"type":"number"}},{"in":"query","name":"consultationsPerPage","schema":{"default":10,"description":"Page size, counted in entries (a timeline of linked consultations is one entry). Defaults to 10. No maximum is enforced, but large pages are slow because each row checks for stored notes.","example":10,"type":"number"}},{"in":"query","name":"searchQuery","schema":{"type":"string","description":"Case-insensitive substring filter matched against the consultation name, the plain text of its clinical note, its `externalId`, and the linked patient's name or identifier. Surrounding whitespace is ignored; omit or send an empty value for no filter.","example":"Bella"}}],"responses":{"200":{"description":"Paginated consultation list with total count for the current user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationPage"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"consultations-createV1","summary":"Create a new consultation","description":"Creates a consultation owned by the authenticated user and returns a presigned URL for uploading its first audio recording.\n\nWith `externalId`, the call is an upsert: if an active consultation in the workspace already has that `externalId`, it is returned unchanged (with a fresh upload URL) and nothing is created. Without `externalId` or `clientConsultationId`, every call creates a new consultation, so retrying a request that timed out can create duplicates. With `clientConsultationId`, retries return the consultation the first request created, and an ID that belongs to another consultation returns `409`.\n\nCreating a consultation does not record or transcribe anything. Next steps: `PUT` audio to `recordingUploadUrl`, then call `POST .../transcriptions/start`. The first consultation in a workspace that is waiting to start its free trial starts the trial.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientConsultationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Client-generated UUID that makes creation idempotent. Retrying with the same ID returns the consultation the original request created for the same workspace and user; an ID that belongs to any other consultation returns `409`. With `externalId`, an existing consultation for that `externalId` still takes precedence, and the ID is used when a new consultation is created.","example":"3f2b8c1e-5d4a-4e7b-9c6f-1a2b3c4d5e6f"},"name":{"type":"string","description":"Display name for the consultation, typically the patient's name and the reason for the visit. Free text; not validated (an empty string is accepted).","example":"Bella - vaccination"},"recordingLanguageCode":{"type":"string","pattern":"^(?:[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*)?$","description":"Language spoken in the consultation, as a lowercase ISO 639 code such as `en`, `sv` or `de`, optionally followed by subtags (`pt-BR`). Stored on the consultation and embedded in the returned upload URL's recording ID, which sets the transcription language of that first recording. A value that is not a two- or three-letter code with optional subtags returns `400`; use a supported language code.","example":"en"},"externalId":{"type":"string","description":"Identifier of the matching visit in your practice-management system. If an active (not archived or deleted) consultation in this workspace already has this `externalId`, that consultation is returned unchanged instead of creating a new one, whoever created it; `name` and `recordingLanguageCode` are then not applied. When `externalId` is set, `clinicalNoteTemplateId` is ignored, even if a new consultation is created.","example":"123456"},"clinicalNoteTemplateId":{"type":"string","description":"ID of the clinical note template to use when generating this consultation's note. An unknown ID, or `auto`, is ignored and the consultation is created without a template. If the template is linked to a JSON template, that structured template is bound as well. Ignored when `externalId` is provided.","example":"6a4dd7d0-0fe8-4f73-8e05-8898748da1ce"}},"required":["name","recordingLanguageCode"]}}}},"responses":{"200":{"description":"The created (or matched) consultation with an upload URL for its first recording.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationCreated"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/transcription":{"get":{"operationId":"consultations-getTranscription","summary":"Get consultation transcript","description":"Returns the saved full transcript of a consultation as plain text, or an empty string if none has been saved. By default it returns immediately and does not start transcription: call `POST .../transcriptions/start` and poll `GET .../consultations/{consultationId}` until `transcriptionStatus` is `completed` or `failed` before reading it.\n\nSet `waitForTranscriptions=true` to start transcription and wait for it in one call, using the same completion flow as document generation; this requires write access. Waiting is best effort: stale jobs, permanent failures, exhausted retries or the 10-minute limit can leave a partial transcript, and the response does not say which happened, so check `transcriptionStatus` afterwards. Set your HTTP client timeout above 10 minutes when waiting.\n\nAny member of the workspace can read the transcript, including for archived consultations.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"waitForTranscriptions","schema":{"description":"When `true`, first starts transcription of any untranscribed recordings (retrying failed ones) and waits until they settle, then returns the transcript. Defaults to false, which returns the saved transcript immediately without starting anything. Waiting requires write access to the consultation (`403` for archived consultations) and can hold the request open for up to 10 minutes.","example":false,"anyOf":[{"type":"boolean"},{"type":"string","enum":["true","false"]}]}}],"responses":{"200":{"description":"The consultation's full transcript.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultationTranscript"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/additional-info":{"get":{"operationId":"consultations-getAdditionalInfo","summary":"Get additional info","description":"Returns the free-text additional information attached to the consultation. Vetnio adds this text to the AI prompt, next to the transcript, whenever it generates the clinical note or other documents, so it is the place for facts that were not said aloud (lab values, history, owner messages). Returns `404` when no additional information has been saved. Archived consultations remain readable.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"The saved additional information.","content":{"application/json":{"schema":{"type":"object","properties":{"additionalInfo":{"type":"string","description":"The saved text exactly as stored, up to 10,000 characters.","example":"Blood panel 2026-09-10: ALT 85 U/L (slightly elevated), creatinine normal. Owner reports reduced appetite for two days."}},"required":["additionalInfo"],"additionalProperties":false,"title":"Consultation additional info","description":"Free-text context used alongside the transcript for document generation."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"put":{"operationId":"consultations-updateAdditionalInfo","summary":"Update additional info","description":"Creates or replaces the free-text additional information for a consultation. The text is used the next time a clinical note or other document is generated; saving it does not regenerate existing documents. Idempotent: sending the same text again has no further effect. Returns `403` for archived consultations.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"additionalInfo":{"type":"string","minLength":1,"maxLength":10000,"description":"Text to store, 1 to 10,000 characters, in any language. Replaces the previous value entirely (there is no append). Because empty strings are rejected, saved text cannot be cleared through the API.","example":"Blood panel 2026-09-10: ALT 85 U/L (slightly elevated), creatinine normal. Owner reports reduced appetite for two days."}},"required":["additionalInfo"]}}}},"responses":{"200":{"description":"Additional information saved.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the text was saved.","example":true}},"required":["success"],"additionalProperties":false,"title":"Additional info saved","description":"Acknowledgement that the additional information was stored."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/external-id":{"put":{"operationId":"consultations-updateExternalId","summary":"Link consultation to external system","description":"Sets or replaces the consultation's `externalId`, the link to the matching visit in the clinic's practice-management system. Vetnio's practice-management integrations (such as Provet) use it to find the consultation and to export notes back to that visit, and `POST .../consultations` with the same `externalId` returns this consultation instead of creating a new one. Uniqueness is not enforced: if several active consultations share an external ID, lookups return one of them, so avoid reusing IDs. Idempotent. Returns `403` for archived consultations.","tags":["consultations"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","description":"Identifier of the matching visit or consultation in your practice-management system (for example a Provet consultation ID). Free text; replaces any previous value. Not checked for uniqueness, so several consultations can share one external ID.","example":"123456"}},"required":["externalId"]}}}},"responses":{"200":{"description":"External ID saved.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the external ID was saved.","example":true}},"required":["success"],"additionalProperties":false,"title":"External ID saved","description":"Acknowledgement that the external ID was stored."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/templates":{"get":{"operationId":"templates-getAll","summary":"List templates","description":"Returns the clinic's prompt templates that the caller can see, sorted by name: templates written by clinic users, Vetnio default templates and templates provisioned by the organization or an integration. Use it to let users pick the `templateId` passed to Generate a clinical note.\n\nVisibility follows the clinic's template permissions. Admins see every template. Members see all templates under Full Access and View & Use Only; under Private they see their own, admin-created and managed templates; under Strict Mode only admin-created and managed templates. Templates the user has hidden from their own picker are still listed, with `isHidden` set to `true`. `isPinned` reflects the calling user's starred templates.\n\nOnly metadata is returned. Clinic admins can read a template's body through the configuration export (`GET /workspaces/{workspaceId}/data-export/templates/versions` and `…/templates/version`); Vetnio's built-in templates are not exported. Not paginated; a clinic holds at most about 100 templates. Requires a personal API key.","tags":["templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."}],"responses":{"200":{"description":"The visible templates, sorted by name. Empty when the caller can see none.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"templates-createTemplateData","summary":"Create a template","description":"Creates a prompt template in the clinic, owned by the calling user and stamped with their current clinic role (`creatorRole`). Pass the returned `templateId` to Generate a clinical note to use it.\n\nWrite the body as reusable instructions, not as an example patient record: anything written as fixed text can appear in every generated document. Creating a template does not change any existing record.\n\nThe caller must be a direct member of the clinic (organization admins without a clinic membership cannot create templates). A clinic can hold about 100 templates; beyond that creation fails. The API does not apply the clinic's Strict Mode creation block, but a member's template is then hidden from that member under Strict Mode. Not idempotent: repeating the call creates another template. Requires a personal API key.","tags":["templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"string","description":"The template body: the headings of the document, each followed by instructions in parentheses saying what belongs there, how to format it and what to write when the information is missing. HTML as produced by Vetnio's template editor; plain text is also accepted. Unsafe markup is removed before saving. No length limit is enforced by the API (Vetnio's editor stops at 150,000 characters).","example":"<p><strong>Reason for visit</strong></p><p>(Summarize the reason for the visit in one sentence. If absent, write \"Not recorded\".)</p><p><strong>Examination</strong></p><p>(Include only findings explicitly recorded in this consultation. Preserve measurements and units. If none are recorded, write \"Not recorded\".)</p><p><strong>Plan</strong></p><p>(List only the actions and treatments actually discussed, one bullet per action.)</p>"},"name":{"type":"string","description":"Template Name shown in Vetnio's template lists and pickers. Does not need to be unique. Name it after the purpose or reader, not a patient.","example":"Follow-up - clinical team"},"type":{"description":"The Template Type: which kind of document the template writes. Defaults to `clinical_note` when omitted.\n- `clinical_note` — Clinical Note: the medical record of the visit.\n- `client_communication` — Client Communication: an owner-facing message.\n- `referral` — Referral: a letter to or from another clinician or clinic.","example":"clinical_note","type":"string","enum":["clinical_note","referral","client_communication"]},"jsonTemplateId":{"description":"ID of a JSON template (structured template) to link, from List JSON templates. When set, clinical notes generated on consultations that use this template are produced as structured JSON documents with this template's instructions guiding the field content. Omit or pass `null` for a free-text template. An ID the caller cannot read returns 404.","example":null,"type":["string","null"]}},"required":["template","name"]}}}},"responses":{"200":{"description":"The template was created; its ID is returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/templates/{templateId}":{"put":{"operationId":"templates-updateContent","summary":"Update template content","description":"Replaces the body of a template. The name, type and structured-template link are unchanged and cannot be edited through this API. The previous body is kept in the template's history in Vetnio.\n\nThe change applies to every future generation that uses the template, for every user of the clinic; records generated earlier are not rewritten.\n\nWho may update: the template's creator, clinic admins, and, when the clinic's template permissions are Full Access, members for other members' templates that are not managed. Others get 403, as does any attempt to update a Vetnio default template (duplicate it first). A template the caller cannot see returns 404. A stale `expectedContentVersion` returns 409. Requires a personal API key.","tags":["templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"templateId","schema":{"type":"string","description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"},"required":true,"description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"string","description":"The complete new template body, in the same format as when creating a template (headings with instructions in parentheses; HTML or plain text). It replaces the current body entirely. Unsafe markup is removed before saving.","example":"<p><strong>Reason for visit</strong></p><p>(Summarize the reason for the visit in one sentence.)</p><p><strong>Plan</strong></p><p>(List only the actions actually discussed, one bullet per action. If no plan is recorded, write \"Not recorded\".)</p>"},"expectedContentVersion":{"description":"Optimistic-concurrency guard: the `contentVersion` returned by your previous update of this template, sent unchanged including its double quotes. If the template body has changed since then, the update is rejected with 409 and nothing is saved. Omit it or pass `null` to overwrite unconditionally.","example":"\"9b2cf535f27731c974343645a3985328\"","type":["string","null"]}},"required":["template"]}}}},"responses":{"200":{"description":"The new body was saved; `contentVersion` identifies it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTemplateContentOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"templates-delete","summary":"Delete a template","description":"Deletes a template from the clinic. It disappears from every list and picker and cannot be restored through the API or Vetnio.\n\nRecords already generated with it are not changed. Consultations that had it selected lose the selection, so their next generation runs without a template unless one is passed.\n\nWho may delete: the same users who may update it (the creator, clinic admins, and under Full Access other members for non-managed member templates); others get 403. Vetnio default templates cannot be deleted (403). Deleting an unknown or already deleted template returns 404. Requires a personal API key.","tags":["templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"templateId","schema":{"type":"string","description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"},"required":true,"description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404."}],"responses":{"200":{"description":"The template was deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteTemplateOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/templates/{templateId}/duplicate":{"post":{"operationId":"templates-duplicate","summary":"Duplicate a template","description":"Creates an editable copy of a template the caller can see, with the same body, type and structured-template link. The copy belongs to the caller (`creatorId`, and `creatorRole` set to their current role) and is never a default or managed template, which makes this the way to customize a Vetnio default or organization template.\n\nOnly read access to the source is needed. The copy counts toward the clinic's limit of about 100 templates, and organization admins without a clinic membership cannot duplicate. Under Strict Mode a member's copy is hidden from that member. Not idempotent: each call creates another copy. Requires a personal API key.","tags":["templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"templateId","schema":{"type":"string","description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"},"required":true,"description":"ID of the template (a UUID), as returned by List templates or Create a template. The template must belong to the workspace in the path and be visible to the caller under the clinic's template permissions; otherwise the request returns 404."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"copySuffix":{"type":"string","description":"Text added to the original name to name the copy. Vetnio inserts a space between them, so `(copy)` turns \"Follow-up - clinical team\" into \"Follow-up - clinical team (copy)\". Use your users' language, for example `(kopia)` in Swedish.","example":"(copy)"}},"required":["copySuffix"]}}}},"responses":{"200":{"description":"The copy was created; its ID is returned in `id`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateTemplateOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/json-templates":{"get":{"operationId":"templates-json-getMetadata","summary":"List JSON templates","description":"Returns the ID and name of every JSON template (called structured templates in Vetnio) available in the workspace: the workspace's own, followed by Vetnio's built-in ones. Use the ID with Generate a structured document, or fetch the fields with Get JSON template detail.\n\nEvery workspace member sees every JSON template; there are no per-user visibility rules. The list is not paginated and the order of the workspace's own templates is not guaranteed. Requires a personal API key.","tags":["json-templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."}],"responses":{"200":{"description":"The workspace's JSON templates followed by the built-in ones. Never empty, because the built-in templates are always included.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/JsonTemplateMetadataItem"},"description":"The workspace's own JSON templates (in no guaranteed order) followed by Vetnio's built-in JSON templates, which are available in every workspace."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/json-templates/{jsonTemplateId}":{"get":{"operationId":"templates-json-getJSONTemplateDetail","summary":"Get JSON template detail","description":"Returns a JSON template with its full JSON Schema. `jsonTemplateSchema.properties` lists the fields a generated document will contain, keyed exactly as in the output, so you can map them to your own system or render a structured clinical note.\n\nAvailable to any workspace member for the workspace's own and the built-in JSON templates. An ID from another workspace, or one that does not exist, returns 404. Requires a personal API key.","tags":["json-templates"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"jsonTemplateId","schema":{"type":"string","description":"ID of the JSON template (a UUID), from List JSON templates. Either one of this workspace's JSON templates or a built-in one; anything else returns 404.","example":"2a859133-0e04-4f63-88d2-aa0ee318cd8d"},"required":true,"description":"ID of the JSON template (a UUID), from List JSON templates. Either one of this workspace's JSON templates or a built-in one; anything else returns 404."}],"responses":{"200":{"description":"The template and its schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonTemplateDetail"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/transcriptions/start":{"post":{"operationId":"transcriptions-transcribe","summary":"Start transcription","description":"Starts background transcription of every uploaded recording that has not been transcribed yet, in recording-ID order. Uploading audio does not start transcription by itself; call this after your uploads. The endpoint returns immediately with the number of recordings waiting; the work continues after the response. Poll `GET .../consultations/{consultationId}` until `transcriptionStatus` is `completed` or `failed`, then read `GET .../transcription`.\n\nSafe to call repeatedly: transcribed recordings are skipped, recordings another call is already transcribing are not processed twice, and failed recordings are retried (up to 3 attempts in total). If `transcriptionStatus` is still `processing` after about 10 minutes, call it again; jobs that have been running for more than 5 minutes are picked up again. If nothing is waiting, `recordingsProcessed` is `0` and no work starts.\n\nTranscription uses third-party speech-to-text and AI spelling correction. Any member of the workspace can start it; returns `403` for archived consultations.","tags":["recordings","transcriptions"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"Transcription status with the number of recordings queued for processing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptionStart"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/records":{"get":{"operationId":"records-getRecord","summary":"Get a record","description":"Returns the current content of one of the consultation's records: the clinical note, the client communication or the referral letter. Records have no IDs of their own; a consultation holds at most one record of each type, selected with `recordType`.\n\nThe body is the content itself, not an envelope: an HTML string for free-text records, a JSON object (one key per field) for a clinical note generated from a structured template, or `null` when no record of this type exists.\n\nAny workspace member who can open the consultation can read its records, including on archived consultations. Requires a personal API key; organization and clinic export keys are rejected with 403. An unknown consultation, or one outside the workspace, returns 404.\n\nReading has no side effects. While a record is being generated this returns the previous content (or `null`) until the new version is saved; poll the consultation's `isGeneratingClinicalNote` / `isGeneratingCommunication` flags to know when generation has finished. Earlier saved versions are available from List retained record versions.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"recordType","schema":{"type":"string","enum":["clinical note","communication","referral"],"description":"Which of the consultation's records to read. A consultation holds at most one record of each type, so the type identifies the record. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio). HTML, or a JSON object when it was generated from a structured template.\n- `communication` — the client communication: an owner-facing summary or message about the visit. HTML.\n- `referral` — the referral letter to or from another clinic. HTML.","example":"clinical note"},"required":true,"description":"Which of the consultation's records to read. A consultation holds at most one record of each type, so the type identifies the record. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio). HTML, or a JSON object when it was generated from a structured template.\n- `communication` — the client communication: an owner-facing summary or message about the visit. HTML.\n- `referral` — the referral letter to or from another clinic. HTML."}],"responses":{"200":{"description":"The record content in its stored format (HTML string or JSON object), or `null` if the consultation has no record of this type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRecordOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"records-createRecordV1","summary":"Create a record","description":"Writes or generates the consultation's clinical note or client communication. A consultation holds one record per type, so if a record of this type already exists it is replaced; the replaced content stays available as a retained version.\n\n**With `content`:** the content is sanitized and saved as a manual edit (`changeType: edit` in version history). This behaves exactly like Update a record.\n\n**Without `content`:** Vetnio generates the record from scratch with AI and the request blocks until it is saved, usually well under a minute. Generation uses the consultation's current transcript, additional info, uploaded files, the template selected on the consultation, and the user's and clinic's writing instructions. Unlike Generate a clinical note, this does not wait for recordings that are still being transcribed, so call it only after the consultation's `transcriptionStatus` is `completed`. If there is no transcript or uploaded file to work from, no error is returned: the existing record is kept, or a short \"no information found\" message in the recording language is saved. When the clinical note uses a structured template, the request returns as soon as background generation has started.\n\nRequires a personal API key and write access to the consultation; archived consultations return 403. Not idempotent: every call writes a new version, and every generation calls the AI model again.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recordType":{"type":"string","enum":["clinical note","communication"],"description":"Which of the consultation's records to write. A consultation holds at most one record of each type, so the type identifies the record.\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio).\n- `communication` — the client communication: an owner-facing summary or message about the visit.\nReferral letters can be read with Get a record but not created, replaced or deleted through this API.","example":"clinical note"},"content":{"description":"The record body as HTML (plain text is accepted). When present and not blank, it is saved as a manual edit and no AI runs. When omitted, empty or whitespace-only, Vetnio generates the record with AI instead. Unsafe markup is removed before saving, and clinical notes are normalized to the note editor's format (paragraphs become `<br />` line breaks, tables are flattened to text). At most 50,000 characters.","example":"<strong>History</strong><br />Bella, an 8-year-old Labrador, has vomited three times since yesterday evening.<br /><br /><strong>Plan</strong><br />• Bland diet for 3 days<br />• Recheck if vomiting persists","type":"string"}},"required":["recordType"]}}}},"responses":{"200":{"description":"The record has been saved, or (for a structured-template clinical note) its generation has started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecordOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"put":{"operationId":"records-updateRecordV1","summary":"Update a record","description":"Replaces the consultation's clinical note or client communication with the supplied content, creating the record if it does not exist yet. This is a full replacement: send the whole body. The write is saved as a manual edit (`changeType: edit` in version history) and the previous content stays available as a retained version.\n\nA manual edit does not lock the record: a later AI generation for the same record type creates a new version on top of it (in update mode the edited text is used as the starting point; in from-scratch mode it is replaced). When the edited record was originally generated from a transcript, Vetnio may learn from the difference to adapt the user's personal writing style.\n\nThere is no concurrency check on this endpoint; the last write wins. Content written here is always stored as HTML, so it cannot replace a structured-template clinical note with a JSON document.\n\nRequires a personal API key and write access to the consultation; archived consultations return 403. Idempotent in effect (the same body yields the same content), but each call adds a version.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recordType":{"type":"string","enum":["clinical note","communication"],"description":"Which of the consultation's records to write. A consultation holds at most one record of each type, so the type identifies the record.\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio).\n- `communication` — the client communication: an owner-facing summary or message about the visit.\nReferral letters can be read with Get a record but not created, replaced or deleted through this API.","example":"clinical note"},"content":{"type":"string","description":"The complete new record body as HTML (plain text is accepted). It replaces the current content entirely; there are no partial updates. Unsafe markup (scripts, styles, attributes other than link `href`/`name`/`target`) is removed. Clinical notes are also normalized to the note editor's format: paragraphs become `<br />` line breaks and tables are flattened to text. At most 50,000 characters. An empty string saves an empty version, after which Get a record returns `null`.","example":"<strong>Assessment</strong><br />Lab results consistent with mild pancreatitis.<br /><br /><strong>Plan</strong><br />• Low-fat diet<br />• Recheck cPLI in 2 weeks"}},"required":["recordType","content"]}}}},"responses":{"200":{"description":"The supplied content is now the record's current version.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecordOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"records-deleteRecordV1","summary":"Delete a record","description":"Removes the consultation's current clinical note or client communication. Afterwards Get a record returns `null` and the consultation no longer counts as having that record.\n\nThis is not an erasure. Previously saved versions remain in the record's history and can still be listed and read with the record version endpoints; they are only destroyed when the consultation itself is permanently erased. Deleting the clinical note does not delete a separate document produced by Generate a structured document.\n\nDeleting a record that does not exist succeeds without changing anything, so the call is idempotent. Referral letters cannot be deleted through this API. Requires a personal API key and write access to the consultation; archived consultations return 403.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"recordType","schema":{"type":"string","enum":["clinical note","communication"],"description":"Which of the consultation's records to write. A consultation holds at most one record of each type, so the type identifies the record.\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio).\n- `communication` — the client communication: an owner-facing summary or message about the visit.\nReferral letters can be read with Get a record but not created, replaced or deleted through this API.","example":"clinical note"},"required":true,"description":"Which of the consultation's records to write. A consultation holds at most one record of each type, so the type identifies the record.\n- `clinical note` — the medical record of the visit (the Clinical note tab in Vetnio).\n- `communication` — the client communication: an owner-facing summary or message about the visit.\nReferral letters can be read with Get a record but not created, replaced or deleted through this API."}],"responses":{"200":{"description":"The consultation has no current record of this type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteRecordOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/records/versions":{"get":{"operationId":"records-getRecordVersionHistory","summary":"List retained record versions","description":"Lists the saved versions of the consultation's clinical note, client communication or referral letter, newest first, with timestamps and whether each was AI-generated or saved by a person. Use it with Read a retained record version to compare the AI draft with the clinician's corrections.\n\nEvery generation, manual edit, API write and restore adds a version. Versions survive Delete a record and are only destroyed when the consultation is permanently erased. The list is complete and not paginated.\n\nThis is a history of saved content, not an audit trail: it does not say who made a change or what changed between versions, and keystrokes between saves are not captured. Listing and reading are separate requests, so a save in between can make `currentVersionId` and `isLatest` stale.\n\nRequires a personal API key whose user can read the consultation; organization and clinic export keys are rejected with 403. An unknown consultation returns 404; a consultation that never had this record returns an empty `versions` array. Structured documents from Generate a structured document and transcript history are not included.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"recordType","schema":{"type":"string","enum":["clinical note","communication","referral"],"description":"Which of the consultation's records the history belongs to. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit.\n- `communication` — the client communication sent to the animal owner.\n- `referral` — the referral letter to or from another clinic.","example":"clinical note"},"required":true,"description":"Which of the consultation's records the history belongs to. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit.\n- `communication` — the client communication sent to the animal owner.\n- `referral` — the referral letter to or from another clinic."}],"responses":{"200":{"description":"The record's current version ID and all retained versions, newest first.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"currentVersionId":{"description":"`versionId` of the record's current content. `null` when the record does not exist or has been deleted; older versions can still be listed in that case.","example":"Wq8sY0bq2b9Kp7sQ1nZ0uJ3VxR5mT6cA","type":["string","null"]},"versions":{"type":"array","items":{"$ref":"#/components/schemas/RecordVersionSummary"},"description":"Every retained version of the record, newest first, in one unpaginated list. Empty when the consultation has never had a record of this type. Deletions are not listed as versions."}},"required":["currentVersionId","versions"],"additionalProperties":false},{"type":"null"}],"title":"Record version history","description":"The saved versions of one record. Each save, generation, manual edit or restore adds a version; versions are kept until the consultation is permanently erased."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/records/version":{"get":{"operationId":"records-getRecordVersion","summary":"Read a retained record version","description":"Returns the full saved content and metadata of one version of the consultation's clinical note, client communication or referral letter. The version is looked up only within this consultation and record type.\n\nThe `content` of a given `versionId` never changes; `currentVersionId` and `version.isLatest` describe the record at the time of the request. Reading a version is read-only: it does not restore it.\n\nRequires a personal API key whose user can read the consultation; organization and clinic export keys are rejected with 403. Returns 404 if the consultation or the version does not exist.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"recordType","schema":{"type":"string","enum":["clinical note","communication","referral"],"description":"Which of the consultation's records the history belongs to. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit.\n- `communication` — the client communication sent to the animal owner.\n- `referral` — the referral letter to or from another clinic.","example":"clinical note"},"required":true,"description":"Which of the consultation's records the history belongs to. The values contain a space; URL-encode them in query strings (`clinical%20note`).\n- `clinical note` — the medical record of the visit.\n- `communication` — the client communication sent to the animal owner.\n- `referral` — the referral letter to or from another clinic."},{"in":"query","name":"versionId","schema":{"type":"string","minLength":1,"description":"`versionId` of the version to read, exactly as returned by List retained record versions. URL-encode it: it can contain `+`, `/` and `=`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY+MTRCxf3vjVBH40Nr8X8gdRQBpUMLUo"},"required":true,"description":"`versionId` of the version to read, exactly as returned by List retained record versions. URL-encode it: it can contain `+`, `/` and `=`."}],"responses":{"200":{"description":"The version's content and metadata, with the record's current version ID.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"currentVersionId":{"description":"`versionId` of the record's current content at the time of this request, so you can tell whether the requested version is still current. `null` when the record has been deleted.","example":"Wq8sY0bq2b9Kp7sQ1nZ0uJ3VxR5mT6cA","type":["string","null"]},"version":{"description":"Metadata of the requested version.","$ref":"#/components/schemas/RecordVersionSummary"},"content":{"type":"string","description":"The exact content of this version as saved: an HTML string, or a JSON document serialized as a string for a structured-template clinical note (parse it yourself). It never changes for a given `versionId`.","example":"<strong>History</strong><br />Bella, an 8-year-old Labrador, has had intermittent left hind lameness for 2 weeks."}},"required":["currentVersionId","version","content"],"additionalProperties":false},{"type":"null"}],"title":"Record version","description":"One saved version of a record with its full content."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/clinical-note/generate":{"post":{"operationId":"records-generateClinicalNoteV1","summary":"Generate a clinical note","description":"Writes the consultation's clinical note with AI and saves it as the current version of the record (`changeType: generated` in version history).\n\nFirst transcribes any uploaded recordings that have not been transcribed yet and waits for every recording on the consultation to finish (up to 10 minutes). Generation then uses the full transcript, the consultation's additional info and uploaded files, the selected template, the linked patient's details and earlier visits, the clinic-wide and personal writing instructions, the user's learned writing style, and the recording language. Generation itself usually takes well under a minute.\n\n**Synchronous (default):** the request blocks until the note is saved and returns it in `clinicalNote`. If the consultation's clinical note uses a structured template, the response is `message: \"Structured document generation initiated\"` and the note is generated in the background; poll the consultation until `isGeneratingClinicalNote` is `false`, then read the record. A consultation with no transcript returns 400.\n\n**Callback (`callbackUrl` set):** returns at once; the note or the error (including an empty transcript) is POSTed to the callback URL. Use it to avoid holding a connection open. Both modes share a 10-minute limit for the whole job, transcription wait included; a job cut off by that limit returns a gateway timeout in synchronous mode and sends no callback at all in callback mode.\n\nSide effects: the consultation's selected template is updated when `templateId` is given, the consultation's AI title may be refreshed, and the consultation is marked as submitted. Not idempotent: every call runs the AI model again and adds a version. Requires a personal API key and write access to the consultation; archived consultations return 403.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"description":"ID of the template (from List templates) whose sections and instructions shape the note. The template is also saved as the consultation's selected clinical-note template. When omitted, the template already selected on the consultation is used, or none if it has none. Pass `auto` to generate without a template and clear the selection. An ID that does not belong to this workspace is not rejected: the note is generated without a template and the selection is cleared. The template's type is not checked, so pass a Clinical Note template.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13","type":"string"},"shouldGenerateFromScratch":{"description":"Defaults to `true`: write a new note from the full transcript, replacing the current one. Set `false` to update the existing note instead, keeping its content (including manual edits) and adding what was said in recordings transcribed since the last generation. Vetnio falls back to from-scratch when there is no existing note or when `templateId` names a different template than the consultation's current one.","example":false,"type":"boolean"},"callbackUrl":{"description":"Absolute URL (use HTTPS) that switches the request to callback mode: the response returns immediately with `message: \"Callback URL has been queued\"`, and the outcome is POSTed to this URL as JSON once transcription and generation finish. Each callback has an `X-Vetnio-Callback-Status` header of `success` (body `{ \"clinicalNote\": \"<html>\" }`; for a structured-template note the body is `{}` and is sent as soon as background generation starts, so read the record once `isGeneratingClinicalNote` is `false`) or `error` (body `{ \"error\": { \"code\", \"message\" }, \"workspaceId\", \"consultationId\" }`). One attempt with a 30-second timeout and no retries; callbacks are not signed, so put a secret token in the URL if you need to authenticate them.","example":"https://pms.example.com/webhooks/vetnio/clinical-note?token=9f2c7e","type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Synchronous free-text generation: the saved note in `clinicalNote`. Callback mode or structured-template notes: a status `message`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateClinicalNoteOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/documents":{"post":{"operationId":"records-generateDocumentV1","summary":"Generate a structured document","description":"Extracts the consultation into a JSON object that follows a JSON template's schema, for example to fill the fields of a practice-management system's journal entry.\n\nFirst transcribes any uploaded recordings that have not been transcribed yet and waits for every recording on the consultation to finish (up to 10 minutes). The document is generated from the transcript and the consultation's additional info only: prompt templates, uploaded files, patient history and personal writing style are not used. Values are plain text taken from what was said; fields the conversation did not cover are left empty rather than invented.\n\nThe result is stored as the consultation's latest generated document, separately from the clinical note: it does not change the record returned by Get a record, and it cannot be read back through this API, so keep the response or callback body. Calling again generates and stores a new document.\n\n**Synchronous (default):** blocks until the document is ready and returns it. A consultation with no transcript returns 400.\n\n**Callback (`callbackUrl` set):** returns at once; the document or the error (including an empty transcript) is POSTed to the callback URL. Use it to avoid holding a connection open. Both modes share a 10-minute limit for the whole job, transcription wait included; a job cut off by that limit returns a gateway timeout in synchronous mode and sends no callback at all in callback mode.\n\nAn unknown `jsonTemplateId` returns 404 in both modes, before anything is generated. Requires a personal API key and write access to the consultation; archived consultations return 403. Not idempotent: every call runs the AI model again.","tags":["consultations","records"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jsonTemplateId":{"type":"string","description":"ID of the JSON template (structured template) whose schema the document must follow, from List JSON templates. Must be one of this workspace's JSON templates or a built-in one; otherwise 404.","example":"2a859133-0e04-4f63-88d2-aa0ee318cd8d"},"callbackUrl":{"description":"Absolute URL (use HTTPS) that switches the request to callback mode: the response returns immediately with `message: \"Callback URL has been queued\"`, and the outcome is POSTed to this URL as JSON once transcription and generation finish. Each callback has an `X-Vetnio-Callback-Status` header of `success` (body: the document object) or `error` (body `{ \"error\": { \"code\", \"message\" }, \"workspaceId\", \"consultationId\" }`). One attempt with a 30-second timeout and no retries; callbacks are not signed, so put a secret token in the URL if you need to authenticate them.","example":"https://pms.example.com/webhooks/vetnio/document?token=9f2c7e","type":"string","format":"uri"},"languageCode":{"description":"Language to write the document in, as a recording-language code (mostly ISO 639-1, for example `sv`, `en`, `de`, `no`; a few three-letter codes such as `yue` or `fil`). The transcript can be in another language. When omitted, the consultation's recording language is used; if the consultation has none, the model chooses.","example":"sv","type":"string","enum":["sv","en","af","am","ar","hy","as","ast","az","be","bn","bs","bg","my","yue","ca","ceb","ny","zh","hr","cs","da","nl","et","fil","fi","fr","ff","gl","lg","ka","de","el","gu","ha","he","hi","hu","is","ig","id","ga","it","ja","jv","kea","kn","kk","km","ko","ku","ky","lo","lv","ln","lt","luo","lb","mk","ms","ml","mt","mi","mr","mn","ne","nso","no","oc","or","ps","fa","pl","pt","pa","ro","ru","sr","sn","sd","sk","sl","so","es","sw","tl","ta","tg","te","th","tr","uk","umb","ur","uz","vi","cy","wo","xh","zu"]}},"required":["jsonTemplateId"]}}}},"responses":{"200":{"description":"Synchronous mode: the generated document object. Callback mode: `{ \"message\": \"Callback URL has been queued\" }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDocumentOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/recording-chunks":{"post":{"operationId":"recordings-prepareDurableChunk","summary":"Prepare an immutable recording chunk upload","description":"Registers one chunk of a recording and returns where to upload its audio. Upload the bytes with a single `PUT` to `uploadUrl`, sending the returned `headers`; an upload never replaces bytes already stored for the chunk. Safe to repeat: the same chunk returns a fresh upload URL, or `alreadyUploaded: true` once its exact bytes are stored. The same chunk `id` with different metadata, or stored bytes that do not match it, returns `409`.\n\nAfter every chunk is uploaded, submit them with `POST .../recording-operations`. Requires write access to the consultation's recordings.","tags":["recordings"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Client-generated UUID that permanently identifies this chunk of audio. Store it before the first request and reuse it on retries; reusing it for different audio returns `409`.","example":"9b2f6c1e-3a4d-4f5e-8a7b-1c2d3e4f5a6b"},"sessionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the recording session the chunk belongs to. Within one submission, `sessionId` and `index` together must be unique.","example":"5e1d2c3b-4a5f-4e6d-9c8b-7a6f5e4d3c2b"},"index":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Position of the chunk within its recording session, starting at 0. Any non-negative integer that is unique within the session is accepted.","example":0},"recordedAt":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"When the chunk's audio was recorded, in Unix epoch milliseconds from the recording device. It places the chunk among the consultation's other recordings in the transcript.","example":1759600000000},"languageCode":{"type":"string","pattern":"^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$","description":"Language spoken in the chunk, as a lowercase ISO 639 code optionally followed by subtags, such as `sv` or `pt-BR`. Sets the transcription language.","example":"sv"},"size":{"type":"integer","minimum":1,"maximum":2147483648,"description":"Exact size of the audio in bytes, at most 2 GiB.","example":1048576},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Lowercase hexadecimal SHA-256 digest of the audio bytes. Audio whose stored size or digest does not match is rejected before transcription.","example":"4a1f0c6e3b2d9a8f7e6d5c4b3a2918070f1e2d3c4b5a69788776655443322110"}},"required":["id","sessionId","index","recordedAt","languageCode","size","sha256"],"additionalProperties":false,"description":"The chunk of audio to register before uploading it."}},"required":["chunk"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"alreadyUploaded":{"type":"boolean","description":"`true` when the chunk's exact bytes are already stored, so no upload is needed and `uploadUrl` is `null`.","example":false},"uploadUrl":{"description":"Presigned URL for one `PUT` of the audio bytes, valid for 15 minutes, or `null` when `alreadyUploaded` is `true`.","example":"https://storage.example.com/recordings/...","type":["string","null"]},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"Headers to send with the `PUT`.","example":{"If-None-Match":"*"}}},"required":["alreadyUploaded","uploadUrl","headers"],"additionalProperties":false}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations":{"post":{"operationId":"recordings-submitRecordingOperation","summary":"Durably accept an idempotent recording submission","description":"Queues transcription of uploaded chunks, and optionally clinical-note generation, and immediately returns the operation's receipt. On `/api/v1` the response is `202 Accepted` with a `Location` header for the status endpoint and a `Retry-After` header while the operation is still running; repeating the request for a finished operation returns `200` with its final receipt. On `/api/v2` it is always `200`. The work continues on the server even if the client disconnects. Repeating the request with the same `operationId` and payload returns the same receipt; a different payload with that ID returns `409`. Operations on one consultation run one at a time, in the order they were submitted.\n\nThe generated note is merged into the consultation's current note, so earlier edits are kept. If the note is edited while the operation is generating, the edit is kept, the operation fails with `note_conflict`, and the generated note stays available from the result endpoint. Requires write access to the consultation's recordings.","tags":["recordings"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"submission":{"type":"object","properties":{"protocolVersion":{"type":"number","const":1,"description":"Version of the recording-operation protocol. Must be `1`.","example":1},"operationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Client-generated UUID that identifies this submission. Store it before sending and reuse it after a lost or failed response: the same ID with the same payload returns the existing receipt, and a different payload returns `409`.","example":"0c9d8e7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"chunks":{"maxItems":2000,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Client-generated UUID that permanently identifies this chunk of audio. Store it before the first request and reuse it on retries; reusing it for different audio returns `409`.","example":"9b2f6c1e-3a4d-4f5e-8a7b-1c2d3e4f5a6b"},"sessionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the recording session the chunk belongs to. Within one submission, `sessionId` and `index` together must be unique.","example":"5e1d2c3b-4a5f-4e6d-9c8b-7a6f5e4d3c2b"},"index":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Position of the chunk within its recording session, starting at 0. Any non-negative integer that is unique within the session is accepted.","example":0},"recordedAt":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"When the chunk's audio was recorded, in Unix epoch milliseconds from the recording device. It places the chunk among the consultation's other recordings in the transcript.","example":1759600000000},"languageCode":{"type":"string","pattern":"^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$","description":"Language spoken in the chunk, as a lowercase ISO 639 code optionally followed by subtags, such as `sv` or `pt-BR`. Sets the transcription language.","example":"sv"},"size":{"type":"integer","minimum":1,"maximum":2147483648,"description":"Exact size of the audio in bytes, at most 2 GiB.","example":1048576},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Lowercase hexadecimal SHA-256 digest of the audio bytes. Audio whose stored size or digest does not match is rejected before transcription.","example":"4a1f0c6e3b2d9a8f7e6d5c4b3a2918070f1e2d3c4b5a69788776655443322110"}},"required":["id","sessionId","index","recordedAt","languageCode","size","sha256"],"additionalProperties":false},"description":"Every chunk this operation covers, up to 2000, each registered with `POST .../recording-chunks` and uploaded first. Chunks already transcribed for this consultation are reused instead of being transcribed again. An empty list generates from the consultation's existing transcript."},"generateClinicalNote":{"type":"boolean","description":"Whether to generate the clinical note after transcription. With `false` the chunks are only added to the consultation's transcript.","example":true},"templateId":{"default":null,"description":"ID of the clinical note template to generate with, or `null` to use the consultation's current template.","example":null,"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"null"}]}},"required":["protocolVersion","operationId","chunks","generateClinicalNote"],"additionalProperties":false,"description":"The immutable recording command. Keep it unchanged for every retry of the same `operationId`."}},"required":["submission"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"operationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The submission's `operationId`.","example":"0c9d8e7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"status":{"type":"string","enum":["accepted","processing","retrying","succeeded","failed"],"description":"`accepted` (queued), `processing`, `retrying` (a step failed and is retried automatically), or the final `succeeded` or `failed` (see `error`).","example":"processing"},"stage":{"type":"string","description":"Current step: `uploads`, `transcribing`, `generating`, `publishing`, or `complete` once the operation succeeded.","example":"transcribing"},"error":{"anyOf":[{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable failure code, for example `waiting_for_uploads`, `no_speech`, `note_conflict`, `transcript_changed`, `access_revoked` or `audio_integrity`.","example":"note_conflict"},"message":{"type":"string","description":"Explanation of the failure that can be shown to the user.","example":"The note changed during generation. Your edits were preserved. Generate the note again to include this recording."}},"required":["code","message"],"additionalProperties":false},{"type":"null"}],"description":"The most recent failure, or `null`. While `status` is `retrying` it is the failure being retried; when `status` is `failed` it is final."},"resultAvailable":{"type":"boolean","description":"Whether a generated note can be read from `GET .../recording-operations/{operationId}/result`, including one kept after a `note_conflict` instead of being published.","example":false},"skippedChunks":{"type":"object","propertyNames":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"additionalProperties":{"type":"string","enum":["too_short","unreadable_input","no_speech","transcription_failed"]},"description":"Chunks left out of the transcript, by chunk ID, with the reason: `too_short`, `unreadable_input` or `no_speech` for audio without usable speech, or `transcription_failed` for a chunk that kept failing transcription for about an hour. The other chunks are still used.","example":{}}},"required":["operationId","status","stage","error","resultAvailable","skippedChunks"],"additionalProperties":false}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}":{"get":{"operationId":"recordings-getRecordingOperation","summary":"Get the authoritative recording operation status","description":"Returns the current state of a submitted recording operation. Poll it, a few seconds apart, until `status` is `succeeded` or `failed`. Returns `404` when the consultation has no operation with this ID.","tags":["recordings"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"path","name":"operationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The `operationId` the recording operation was submitted with.","example":"0c9d8e7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"required":true,"description":"The `operationId` the recording operation was submitted with."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"operationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The submission's `operationId`.","example":"0c9d8e7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"status":{"type":"string","enum":["accepted","processing","retrying","succeeded","failed"],"description":"`accepted` (queued), `processing`, `retrying` (a step failed and is retried automatically), or the final `succeeded` or `failed` (see `error`).","example":"processing"},"stage":{"type":"string","description":"Current step: `uploads`, `transcribing`, `generating`, `publishing`, or `complete` once the operation succeeded.","example":"transcribing"},"error":{"anyOf":[{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable failure code, for example `waiting_for_uploads`, `no_speech`, `note_conflict`, `transcript_changed`, `access_revoked` or `audio_integrity`.","example":"note_conflict"},"message":{"type":"string","description":"Explanation of the failure that can be shown to the user.","example":"The note changed during generation. Your edits were preserved. Generate the note again to include this recording."}},"required":["code","message"],"additionalProperties":false},{"type":"null"}],"description":"The most recent failure, or `null`. While `status` is `retrying` it is the failure being retried; when `status` is `failed` it is final."},"resultAvailable":{"type":"boolean","description":"Whether a generated note can be read from `GET .../recording-operations/{operationId}/result`, including one kept after a `note_conflict` instead of being published.","example":false},"skippedChunks":{"type":"object","propertyNames":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"additionalProperties":{"type":"string","enum":["too_short","unreadable_input","no_speech","transcription_failed"]},"description":"Chunks left out of the transcript, by chunk ID, with the reason: `too_short`, `unreadable_input` or `no_speech` for audio without usable speech, or `transcription_failed` for a chunk that kept failing transcription for about an hour. The other chunks are still used.","example":{}}},"required":["operationId","status","stage","error","resultAvailable","skippedChunks"],"additionalProperties":false}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}/result":{"get":{"operationId":"recordings-getRecordingOperationResult","summary":"Retrieve a generated result, including one preserved after an edit conflict","description":"Returns the clinical note an operation generated, including one kept after a `note_conflict` instead of replacing an edited note. Returns `404` until a note has been generated, and for operations that do not generate one.","tags":["recordings"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"path","name":"operationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The `operationId` the recording operation was submitted with.","example":"0c9d8e7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"required":true,"description":"The `operationId` the recording operation was submitted with."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","description":"The generated clinical note: HTML for free-text notes, or a JSON document serialized as a string for structured templates.","example":"<p>Bella presented for annual vaccination...</p>"},"isJsonDocument":{"type":"boolean","description":"`true` when `content` is a JSON document from a structured template.","example":false},"jsonTemplateId":{"description":"ID of the structured template the document follows, for structured notes.","example":"jtpl_123","type":"string"}},"required":["content","isJsonDocument"],"additionalProperties":false}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/recording-upload-url":{"get":{"operationId":"recordings-getRecordingUploadUrlV1","summary":"Get a signed URL to upload a recording","description":"Returns a presigned URL for uploading one audio recording (one segment of the consultation). Upload it with `PUT <recordingUploadUrl>` and the raw audio bytes as the body; the URL is valid for 24 hours.\n\nRequest a new URL for every segment, just before uploading it. The recording ID (`<epoch-ms>-<language>`) is fixed when the URL is issued and recordings are transcribed in recording-ID order. A recording uploaded after a later-issued recording has already been transcribed is never transcribed, so do not fetch URLs ahead of time or upload segments out of order. Fetching a URL changes nothing until something is uploaded.\n\nAfter each upload, Vetnio's audio processor updates the consultation's recording duration and the full-length audio used for exports; uploaded audio counts toward the clinic's recorded usage. Uploading does not start transcription: call `POST .../transcriptions/start` when the segments are uploaded. Returns `403` for archived consultations.","tags":["recordings","signed-url"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."},{"in":"query","name":"recordingLanguageCode","schema":{"type":"string","pattern":"^(?:[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*)?$","description":"Language spoken in this recording, as a lowercase ISO 639 code such as `en`, `sv` or `de`, optionally followed by subtags (`pt-BR`). It becomes part of the recording ID and sets the transcription language for this segment, so segments of one consultation can differ. A value that is not a two- or three-letter code with optional subtags returns `400`; use a supported language code. An empty value falls back to English.","example":"en"},"required":true,"description":"Language spoken in this recording, as a lowercase ISO 639 code such as `en`, `sv` or `de`, optionally followed by subtags (`pt-BR`). It becomes part of the recording ID and sets the transcription language for this segment, so segments of one consultation can differ. A value that is not a two- or three-letter code with optional subtags returns `400`; use a supported language code. An empty value falls back to English."}],"responses":{"200":{"description":"Presigned upload URL for the new recording.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordingUploadUrl"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/partial-transcriptions":{"get":{"operationId":"recordings-listPartialTranscriptions","summary":"List partial transcriptions","description":"Lists the partial transcriptions of a consultation: one per transcribed audio recording plus one per text snippet added with `POST .../partial-transcriptions`. They are not live or streaming results; an audio partial appears only after its recording has been transcribed. Only metadata is returned; the text of individual partials is not available through the API. Read the combined text with `GET .../transcription`. Useful to check which recordings have been transcribed and whether text snippets were added.","tags":["recordings","transcriptions"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"List of partial transcription metadata with count.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartialTranscriptionList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"recordings-createPartialTranscription","summary":"Create partial transcription","description":"Adds text to the consultation's transcript as a new partial transcription. The text is stored as-is, merged into the full transcript immediately (ordered by creation time among the audio recordings), and used by later document generation. The text is not spell-checked or otherwise changed, and adding it does not start audio transcription.\n\nNot idempotent: every call adds another entry, and there is no endpoint to edit or remove a partial transcription, so retry only when you know the first call failed. Returns `403` for archived consultations.","tags":["recordings","transcriptions"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":50000,"description":"Text to add to the transcript verbatim, 1 to 50,000 characters. Typical uses: notes typed during the visit, an owner's SMS or email, or a transcript produced by your own speech-to-text.","example":"Owner reports Bella has been limping on the left hind leg for 3 days."},"languageCode":{"default":"en","description":"Language of the text, as one of the supported lowercase ISO 639 codes. Defaults to `en`. Stored in the generated `recordingId`; the text itself is not translated.","example":"en","type":"string","enum":["sv","en","af","am","ar","hy","as","ast","az","be","bn","bs","bg","my","yue","ca","ceb","ny","zh","hr","cs","da","nl","et","fil","fi","fr","ff","gl","lg","ka","de","el","gu","ha","he","hi","hu","is","ig","id","ga","it","ja","jv","kea","kn","kk","km","ko","ku","ky","lo","lv","ln","lt","luo","lb","mk","ms","ml","mt","mi","mr","mn","ne","nso","no","oc","or","ps","fa","pl","pt","pa","ro","ru","sr","sn","sd","sk","sl","so","es","sw","tl","ta","tg","te","th","tr","uk","umb","ur","uz","vi","cy","wo","xh","zu"]}},"required":["text"]}}}},"responses":{"200":{"description":"Confirmation with the generated recording ID for the new partial transcription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartialTranscriptionCreated"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/process-recordings":{"post":{"operationId":"recordings-processRecordings","summary":"Process recordings","description":"Optional. Runs audio processing (conversion to 16 kHz mono WAV, silence removal and duration measurement) for every untranscribed recording and waits for the results. Transcription performs this step itself, so you do not need to call this before `POST .../transcriptions/start`; calling it first only does the processing earlier and lets you find too-short or unreadable audio before transcribing. Processed results are reused by transcription.\n\nSynchronous: takes from a few seconds to minutes for long audio. Does not transcribe or change the consultation. Requires access to the consultation's audio: when the recording is private to its creator, other users get `403` (`recordingPrivate`). If nothing is untranscribed, both lists are empty.","tags":["recordings"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"Processing result with per-recording details including duration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessRecordingsResult"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/uploaded-files":{"get":{"operationId":"uploadedFiles-list","summary":"List uploaded files for a consultation","description":"Returns every file attached to a consultation, newest first (by `createdAt`). Each file carries its current analysis status and, when extraction failed, the error message. Use this endpoint to render a file list or to poll for the `analyzing` → `analyzed` transition after `finalizeUpload`. Files whose upload was initialized but never finalized are listed with status `uploaded`. Any member of the workspace can list the files.","tags":["uploaded-files"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller."}],"responses":{"200":{"description":"List of files attached to the consultation. An empty array means no files have been uploaded yet.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UploadedFile"}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"uploadedFiles-initUpload","summary":"Initialize a file upload","description":"Reserves a slot for a new file in the consultation and returns a short-lived presigned S3 URL. Three-step flow:\n\n1. Call this endpoint to get `uploadUrl` and `fileName`.\n2. `PUT` the file bytes directly to `uploadUrl`.\n3. Call `finalizeUpload` with the same `fileName` to start content extraction, then poll `GET .../uploaded-files` until the status is `analyzed` or `failed`.\n\nDe-duplication is by SHA-256: a second `initUpload` with the same `sha256` in the same consultation returns `409 CONFLICT`, including when the first upload was never completed (delete that file first to retry). The slot is created immediately with status `uploaded`. If URL generation fails after the slot is created, the slot is removed so the client can safely retry. Returns `403` for archived consultations.","tags":["uploaded-files"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"originalFileName":{"type":"string","minLength":1,"description":"The file name as it was on the uploader's device. Shown to users in the UI. May contain characters that are unsafe for object-storage keys, which is why it is never used as a storage identifier.","example":"xray_bella_2024-06-12.pdf"},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Hexadecimal SHA-256 digest (64 characters) of the exact bytes you will upload, computed client-side. Used only for de-duplication: a consultation cannot hold two files with the same digest, so a second `initUpload` with the same value returns `409 CONFLICT`. Vetnio does not verify that the uploaded bytes match it.","example":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"mimeType":{"type":"string","enum":["application/pdf","image/png","image/jpeg","image/webp","image/gif","text/csv","text/plain","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/vnd.ms-excel"],"description":"MIME type of the file. Restricted to the formats Vetnio can analyze: PDF, images (PNG / JPEG / WebP / GIF), plain text, CSV, Word (.docx), and Excel (.xlsx / .xls). Other values are rejected with `400`. Not checked against the uploaded bytes, so send the real type: it decides how the content is extracted.","example":"application/pdf"},"sizeBytes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Exact size of the file in bytes. `finalizeUpload` compares it with the size of the uploaded object and returns `412` until they match, so it must equal the number of bytes you `PUT`. No maximum is enforced by the API.","example":184320}},"required":["originalFileName","sha256","mimeType","sizeBytes"]}}}},"responses":{"200":{"description":"Upload slot reserved; use `uploadUrl` to send the bytes and `fileName` to finalize.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedFileInitResult"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/uploaded-files/{fileName}/finalize":{"post":{"operationId":"uploadedFiles-finalizeUpload","summary":"Finalize a file upload and trigger analysis","description":"Confirms that the bytes were uploaded and starts background content extraction (status becomes `analyzing`). Only call this after the `PUT` to the presigned URL has completed: the API checks that the stored object exists and has exactly `sizeBytes` bytes, and returns `412 PRECONDITION_FAILED` until it does.\n\nSafe to call multiple times: if the file is already `analyzing` or `analyzed`, the call does nothing and still returns `ok: true`. If the file is `failed`, calling it again retries extraction. Extraction runs after the response: Excel, CSV, plain-text and Word files are converted locally; PDFs go through OCR and images are described by an AI model. Poll `GET .../uploaded-files` for the result.","tags":["uploaded-files"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller."},{"in":"path","name":"fileName","schema":{"type":"string","minLength":1,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that.","example":"8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"},"required":true,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that."}],"responses":{"200":{"description":"Extraction scheduled (or already in progress / completed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/uploaded-files/{fileName}/download-url":{"get":{"operationId":"uploadedFiles-getDownloadUrl","summary":"Get a download URL for an uploaded file","description":"Returns a short-lived presigned URL the client can use to download the file directly from S3, bypassing the Vetnio API. Prefer this over streaming the file through the API — it keeps latency low and avoids large-payload bandwidth on our servers.","tags":["uploaded-files"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller."},{"in":"path","name":"fileName","schema":{"type":"string","minLength":1,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that.","example":"8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"},"required":true,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that."}],"responses":{"200":{"description":"Presigned download URL with display metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedFileDownload"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/uploaded-files/{fileName}":{"delete":{"operationId":"uploadedFiles-delete","summary":"Delete an uploaded file","description":"Removes the file and its extracted analysis text from S3, then deletes the database row. Idempotent — deleting a file that no longer exists still returns `ok: true`. If any S3 object fails to delete, the call returns `500` and the database row is preserved so the delete can be retried without leaking orphaned storage.","tags":["uploaded-files"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Opaque identifier of the Vetnio workspace (veterinary clinic) that owns the resource. Scopes every request — callers can only access files under workspaces they are a member of."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (a single veterinary visit) the file is attached to. The consultation must belong to the same workspace as the authenticated caller."},{"in":"path","name":"fileName","schema":{"type":"string","minLength":1,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that.","example":"8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"},"required":true,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that."}],"responses":{"200":{"description":"File and its analysis were removed (or were already gone).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/patients":{"get":{"operationId":"patientsAndClients-listPatientsV1","summary":"List patients","description":"Returns one page of the workspace's patients, each with its owner's name. Combine `searchQuery` (a case-insensitive substring of the patient name, identifier or owner name) with the optional filters; all supplied conditions must match. Ordered by `sort`, newest first by default. Paginate with `page` and `pageSize` and use `totalCount` to know when to stop. Every workspace member can list all patients.","tags":["patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"query","name":"page","schema":{"default":1,"description":"1-based page number. A page past the end returns an empty `patients` array.","example":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"in":"query","name":"pageSize","schema":{"default":20,"description":"Patients per page, 1 to 100.","example":20,"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"searchQuery","schema":{"type":"string","maxLength":200,"description":"Case-insensitive substring matched against the patient name, the patient identifier (for example a microchip number) and the owner's name. Up to 200 characters, used as typed (not trimmed); `%` and `_` act as wildcards. Species is not searched; use `speciesFilter`.","example":"Bella"}},{"in":"query","name":"speciesFilter","schema":{"type":"string","description":"Species to filter by, case-insensitive. A known species name in any language Vetnio supports (for example `Dog`, `dog` or `Hund`) matches every stored spelling of that species, with or without a ` - <breed>` suffix. Any other value must match the stored species exactly (case-insensitive), optionally followed by ` - <breed>`.","example":"Dog"}},{"in":"query","name":"insuranceFilter","schema":{"type":"string","description":"Insurance company name; must match the stored value exactly, ignoring case.","example":"Agria"}},{"in":"query","name":"genderFilter","schema":{"type":"string","description":"Sex value; must match the stored value exactly, ignoring case (for example `Female Neutered` does not match `Female`).","example":"Female"}},{"in":"query","name":"hasWeightFilter","schema":{"type":"string","enum":["yes","no"],"description":"Filter on whether a weight is recorded:\n- `yes` — only patients with a non-empty weight.\n- `no` — only patients without a weight.\nOmit to include both.","example":"yes"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["date_added","last_visit","name"],"description":"Order of the results (default `date_added`):\n- `date_added` — newest patients first.\n- `last_visit` — patients with the most recent consultation first; patients without consultations last.\n- `name` — alphabetical by name, case-insensitive; patients without a name last.\nTies are broken by newest first.","example":"last_visit"}}],"responses":{"200":{"description":"Paginated patient list with total count for pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"patientsAndClients-createPatientV1","summary":"Create a patient","description":"Creates a patient and, always, a new owner (client) for it: the `client` object fills in the owner's details, and omitting it creates an empty placeholder owner. An existing client cannot be reused through this endpoint. All fields are optional and stored as given. Returns the patient with the new owner embedded.\n\nNot idempotent and not deduplicated: Vetnio does not check for an existing patient with the same name or identifier, so repeating the call creates another patient and owner. Search the patient list by `identifier` first if duplicates matter. An invalid `dateOfBirth` fails with `500` and may leave the new owner behind without a patient.","tags":["patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"The animal's name. Free text; Vetnio does not enforce uniqueness.","example":"Bella","type":"string"},"species":{"description":"Species, free text. The Vetnio web app stores the English species name, followed by ` - <breed>` when a breed is chosen (for example `Dog` or `Dog - Labrador Retriever`); patients synced from a practice-management system may use that system's values.","example":"Dog - Labrador Retriever","type":"string"},"breed":{"description":"Breed, free text.","example":"Labrador Retriever","type":"string"},"dateOfBirth":{"description":"Date of birth as an ISO-8601 calendar date (`YYYY-MM-DD`). Stored as a date, so other formats are rejected by the database.","example":"2018-04-12","type":"string"},"gender":{"description":"Sex and neuter status, free text. The Vetnio web app uses `Male`, `Female`, `Male Neutered` and `Female Neutered`; use the same values so the patient list's gender filter and the UI stay consistent.","example":"Female Neutered","type":"string"},"weight":{"description":"Body weight as free text including the unit, as the web app writes it (for example `24.5 kg`). Not parsed or converted.","example":"24.5 kg","type":"string"},"identifier":{"description":"The animal's identifier, typically a microchip (transponder) number, but it can be a tattoo, registration number or practice-management-system id. Free text, not unique; matched by the patient list search.","example":"752098100012345","type":"string"},"insurance":{"description":"Name of the animal's insurance company, free text.","example":"Agria","type":"string"},"client":{"title":"Client (owner) data","description":"Details for the new owner created with the patient. When omitted, an owner with no details is created.","type":"object","properties":{"name":{"description":"The owner's full name, free text.","example":"Alex Morgan","type":"string"},"email":{"description":"The owner's email address. Stored as given; the format is not validated.","example":"alex.morgan@example.com","type":"string"},"address":{"description":"The owner's street address, free text.","example":"12 Harbour Street, Riverside","type":"string"},"zipCode":{"description":"The owner's postal code, free text.","example":"114 51","type":"string"},"phoneNumbers":{"description":"The owner's phone numbers, stored as given (no normalisation). E.164 format such as `+46701234567` is recommended. Defaults to an empty list.","type":"array","items":{"type":"string","description":"One phone number.","example":"+46701234567"}}}}}}}}},"responses":{"200":{"description":"The newly created patient with its embedded client.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientWithClient"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/patients/{patientId}":{"get":{"operationId":"patientsAndClients-getPatientV1","summary":"Get patient details","description":"Returns one patient with its owner (client) embedded. Returns `404` when no patient with this id exists in the workspace. Consultation history is not included; consultations reference the patient through their `patientId`.","tags":["patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"patientId","schema":{"type":"string","description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"required":true,"description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"responses":{"200":{"description":"Full patient record with embedded client.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientWithClient"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"patch":{"operationId":"patientsAndClients-updatePatientV1","summary":"Update a patient","description":"Updates the fields present in the body and leaves omitted fields unchanged. Fields cannot be set to `null`; send an empty string to blank a text field (not `dateOfBirth`, where an empty or invalid value fails with `500`). The owner cannot be changed here. Repeating the same request leaves the same data, but `updatedAt` is refreshed on every call. Returns `404` when the patient does not exist in the workspace. Patients synced from a practice-management system can be overwritten by the next sync.","tags":["patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"patientId","schema":{"type":"string","description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"required":true,"description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New value for the name. The animal's name. Free text; Vetnio does not enforce uniqueness.","example":"Bella","type":"string"},"species":{"description":"New value for the species. Species, free text. The Vetnio web app stores the English species name, followed by ` - <breed>` when a breed is chosen (for example `Dog` or `Dog - Labrador Retriever`); patients synced from a practice-management system may use that system's values.","example":"Dog - Labrador Retriever","type":"string"},"breed":{"description":"New value for the breed. Breed, free text.","example":"Labrador Retriever","type":"string"},"dateOfBirth":{"description":"New date of birth. Date of birth as an ISO-8601 calendar date (`YYYY-MM-DD`). Stored as a date, so other formats are rejected by the database.","example":"2018-04-12","type":"string"},"gender":{"description":"New value for sex and neuter status. Sex and neuter status, free text. The Vetnio web app uses `Male`, `Female`, `Male Neutered` and `Female Neutered`; use the same values so the patient list's gender filter and the UI stay consistent.","example":"Female Neutered","type":"string"},"weight":{"description":"New weight. Body weight as free text including the unit, as the web app writes it (for example `24.5 kg`). Not parsed or converted.","example":"25.0 kg","type":"string"},"identifier":{"description":"New identifier. The animal's identifier, typically a microchip (transponder) number, but it can be a tattoo, registration number or practice-management-system id. Free text, not unique; matched by the patient list search.","example":"752098100012345","type":"string"},"insurance":{"description":"New insurance company. Name of the animal's insurance company, free text.","example":"Agria","type":"string"}}}}}},"responses":{"200":{"description":"Confirmation that the patient was updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientSuccess"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"patientsAndClients-deletePatientV1","summary":"Delete a patient","description":"Permanently deletes the patient and the files uploaded to its patient record. Consultations linked to the patient are kept, with their recordings, transcripts and notes, but are no longer linked to any patient. The owner (client) is not deleted. Cannot be undone. Requires the workspace `admin` or `superadmin` role (or organization admin access); other members get `403`, even for an unknown id. Returns `404` when the patient does not exist, including when it was already deleted.","tags":["patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"patientId","schema":{"type":"string","description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"required":true,"description":"Patient id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"responses":{"200":{"description":"Empty object confirming the patient was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"title":"Empty response","description":"Empty object returned on successful deletion."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/clients":{"get":{"operationId":"patientsAndClients-listClientsV1","summary":"List clients (owners)","description":"Returns every client (owner) in the workspace in one unpaginated response, in no guaranteed order, including the empty placeholder owners created with patients that had no owner details. Clients do not embed their patients; search the patient list by the owner's name to find them (each patient carries `clientId`).","tags":["clients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."}],"responses":{"200":{"description":"List of all clients in the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientList"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"post":{"operationId":"patientsAndClients-createClientV1","summary":"Create a client (owner)","description":"Creates a client (owner) in the workspace. All fields are optional and stored as given, without format validation. Not idempotent and not deduplicated: repeating the call creates another client. Note that patients cannot currently be attached to an existing client through the API (creating a patient always creates its own owner).","tags":["clients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"The owner's full name, free text.","example":"Alex Morgan","type":"string"},"email":{"description":"The owner's email address. Stored as given; the format is not validated.","example":"alex.morgan@example.com","type":"string"},"address":{"description":"The owner's street address, free text.","example":"12 Harbour Street, Riverside","type":"string"},"zipCode":{"description":"The owner's postal code, free text.","example":"114 51","type":"string"},"phoneNumbers":{"description":"The owner's phone numbers, stored as given (no normalisation). E.164 format such as `+46701234567` is recommended. Defaults to an empty list.","type":"array","items":{"type":"string","description":"One phone number.","example":"+46701234567"}}}}}}},"responses":{"200":{"description":"The newly created client.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/clients/{clientId}":{"get":{"operationId":"patientsAndClients-getClientV1","summary":"Get client (owner) details","description":"Returns one client (owner) with its contact details. Returns `404` when no client with this id exists in the workspace.","tags":["clients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"clientId","schema":{"type":"string","description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"e1f2a3b4-c5d6-4789-efab-901234567890"},"required":true,"description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"responses":{"200":{"description":"Full client record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientOutput"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"patch":{"operationId":"patientsAndClients-updateClientV1","summary":"Update a client (owner)","description":"Updates the fields present in the body and leaves omitted fields unchanged; `phoneNumbers` replaces the whole list. Fields cannot be set to `null`; send an empty string to blank a text field. Send at least one field: an empty body currently fails with `500`. Repeating the same request has no further effect. Returns `404` when the client does not exist in the workspace.","tags":["clients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"clientId","schema":{"type":"string","description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"e1f2a3b4-c5d6-4789-efab-901234567890"},"required":true,"description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name. The owner's full name, free text.","example":"Alex Morgan","type":"string"},"email":{"description":"New email address. The owner's email address. Stored as given; the format is not validated.","example":"alex.morgan@example.net","type":"string"},"address":{"description":"New street address. The owner's street address, free text.","example":"4 Mill Lane, Riverside","type":"string"},"zipCode":{"description":"New postal code. The owner's postal code, free text.","example":"111 43","type":"string"},"phoneNumbers":{"description":"Complete new list of phone numbers; replaces the stored list. Send an empty array to remove all. The owner's phone numbers, stored as given (no normalisation). E.164 format such as `+46701234567` is recommended.","type":"array","items":{"type":"string","description":"One phone number.","example":"+46709876543"}}}}}}},"responses":{"200":{"description":"Confirmation that the client was updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientSuccess"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]},"delete":{"operationId":"patientsAndClients-deleteClientV1","summary":"Delete a client (owner)","description":"Permanently deletes the client (owner) and every patient it owns. Consultations of those patients are kept, with their recordings, transcripts and notes, but lose their patient and owner link. Cannot be undone. Requires the workspace `admin` or `superadmin` role (or organization admin access); other members get `403`, even for an unknown id. Returns `404` when the client does not exist.","tags":["clients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"clientId","schema":{"type":"string","description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`.","example":"e1f2a3b4-c5d6-4789-efab-901234567890"},"required":true,"description":"Client (owner) id (UUID) in this workspace. Unknown ids and ids from other workspaces return `404`."}],"responses":{"200":{"description":"Empty object confirming the client was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"title":"Empty response","description":"Empty object returned on successful deletion."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/patient":{"post":{"operationId":"patientsAndClients-linkPatientToConsultationV1","summary":"Link a patient to a consultation","description":"Sets the consultation's patient. A consultation has at most one patient, so this replaces any patient already linked; the consultation then appears in that patient's history. Only the patient link changes (the owner, title and notes are untouched). Repeating the call with the same patient is harmless. Returns `404` when the consultation or the patient does not exist in the workspace and `403` when the consultation is archived. There is no unlink endpoint in the REST API.","tags":["consultations","patients"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) that owns the patients and clients. The caller must be a member of it; patients and clients are shared by all members of the workspace."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Consultation (UUID) to link the patient to. Must be in the workspace and not archived.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Consultation (UUID) to link the patient to. Must be in the workspace and not archived."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patientId":{"type":"string","description":"Patient (UUID) in the same workspace to link to the consultation.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"}},"required":["patientId"]}}}},"responses":{"200":{"description":"Confirmation that the patient is now linked to the consultation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatientSuccess"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/user/register-mobile-device":{"post":{"operationId":"user-passwordsAndApiKeys-registerMobileDevice","summary":"Register the calling device","description":"Labels the device that owns the API key used to make this request, so it appears under the user's connected devices in the web app and can be revoked individually. The mobile app calls it right after pairing with the key obtained from the QR-code flow. Must be called with an API key in the `Authorization` header (a session gets 400). The key is marked as a mobile-device key, which removes it from the user's programmatic API-key list, so do not call this with a key used for server integrations. Safe to repeat.","tags":["user"],"security":[{"Authorization":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceName":{"description":"Name the device reports for itself, 1-60 characters after trimming. Applied only while the key still has the default name `New device`; a name the user typed in the web app when pairing always wins. Omit to keep the current name.","example":"Alex's iPhone","type":"string","minLength":1,"maxLength":60},"platform":{"description":"Free-text platform label shown next to the device, up to 40 characters, for example `ios` or `android`. Omitting it or sending an empty string clears the stored platform.","example":"ios","type":"string","maxLength":40}},"title":"Register mobile device — request","description":"Self-reported details of the device that owns the calling API key."}}}},"responses":{"200":{"description":"Device registered.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the device details were saved.","example":true}},"required":["success"],"additionalProperties":false,"title":"Register mobile device — result","description":"Acknowledgement that the device details were saved."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/user/me":{"get":{"operationId":"user-meV1","summary":"Get the authenticated user","description":"Returns the ID of the user behind this request: the owner of the personal or mobile-device API key, or the signed-in user for a browser session. Clients use it to correlate their own telemetry with the user's activity. Organization (`sk_org_…`) and workspace (`sk_ws_…`) keys are not accepted and get 403.","tags":["user"],"security":[{"Authorization":[]}],"responses":{"200":{"description":"The authenticated user's ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticatedUser"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vettigo/status":{"get":{"operationId":"vettigo-getStatus","summary":"Vettigo integration status","description":"Returns whether the calling user has a Vettigo account linked to Vetnio. The link is created when the user first opens Vetnio from inside Vettigo, cannot be set up through the REST API, and is the same in every workspace. Use it to decide whether to offer Vettigo features. Never fails: any problem is reported as `connected: false`.","tags":["vettigo"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace."}],"responses":{"200":{"description":"Vettigo connection status.","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean","description":"`true` when the calling user has a Vettigo account linked to Vetnio, which happens the first time they open Vetnio from Vettigo. The other Vettigo endpoints return `401` while this is `false`. Also `false` when the status could not be determined.","example":true},"ehrIntegrationName":{"description":"Name of the connected practice-management system: always `vettigo` when `connected` is `true`, otherwise `null`.","example":"vettigo","type":["string","null"]}},"required":["connected","ehrIntegrationName"],"additionalProperties":false,"title":"Vettigo integration status","description":"Whether the calling user can use the Vettigo endpoints. The link belongs to the user, not to the workspace."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vettigo/clients":{"get":{"operationId":"vettigo-searchClients","summary":"Search Vettigo clients","description":"Searches clients (owners) by name in the Vettigo clinic the caller last launched Vetnio from, using Vettigo's own search. Returns at most 50 clients. Queries shorter than 3 characters (after trimming) return an empty list without contacting Vettigo. Returns `401` when the caller has no linked Vettigo account and `429` when Vettigo's rate limit is hit.","tags":["vettigo"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace."},{"in":"query","name":"query","schema":{"type":"string","description":"Name or part of a name to search for. At least 3 characters after trimming; avoid commas, which Vettigo treats as separators.","example":"Morgan"},"required":true,"description":"Name or part of a name to search for. At least 3 characters after trimming; avoid commas, which Vettigo treats as separators."}],"responses":{"200":{"description":"Matching clients.","content":{"application/json":{"schema":{"type":"object","properties":{"clients":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","description":"Vettigo client id. Pass it as `clientId` to list the client's animals.","example":104552},"name":{"type":"string","description":"Client name from Vettigo, or `#<id>` when Vettigo has none.","example":"Alex Morgan"},"clientNumber":{"description":"The clinic's customer number for this client in Vettigo, or `null`. The search result has no contact details, so this is the only way to tell clients with the same name apart.","example":2381,"type":["number","null"]}},"required":["id","name","clientNumber"],"additionalProperties":false,"title":"Vettigo client","description":"An animal owner in the caller's Vettigo clinic."},"description":"Matching clients, at most 50, in Vettigo's order. Empty when the query is shorter than 3 characters."}},"required":["clients"],"additionalProperties":false,"title":"Vettigo client search results","description":"Clients returned by Vettigo's name search."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vettigo/clients/{clientId}/patients":{"get":{"operationId":"vettigo-listClientPatients","summary":"List a Vettigo client's patients","description":"Lists every animal belonging to a client in the caller's Vettigo clinic, including deceased animals. Read-only: nothing is created in Vetnio. Returns `401` when the caller has no linked Vettigo account.","tags":["vettigo"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace."},{"in":"path","name":"clientId","schema":{"type":"number","description":"Vettigo client id, as returned in `clients[].id` by the client search.","example":104552},"required":true,"description":"Vettigo client id, as returned in `clients[].id` by the client search."}],"responses":{"200":{"description":"The client's patients.","content":{"application/json":{"schema":{"type":"object","properties":{"patients":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","description":"Vettigo animal id.","example":482913},"name":{"type":"string","description":"Animal name from Vettigo, or `#<id>` when Vettigo has none.","example":"Bella"},"breed":{"description":"Vettigo's race label for the animal, passed through as text. Depending on the clinic's data it can hold a species rather than a breed. `null` when not set.","example":"Labrador retriever","type":["string","null"]},"regNumber":{"description":"The animal's registration number in Vettigo (free text, up to 50 characters), or `null`. This is not the microchip number.","type":["string","null"]}},"required":["id","name","breed","regNumber"],"additionalProperties":false,"title":"Vettigo animal","description":"An animal belonging to a Vettigo client."},"description":"All of the client's animals in Vettigo, including deceased ones. Not paginated."}},"required":["patients"],"additionalProperties":false,"title":"Vettigo client animals","description":"The animals of one Vettigo client."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vettigo/export":{"post":{"operationId":"vettigo-exportClinicalNote","summary":"Export clinical note to Vettigo","description":"Adds the supplied clinical note as a new, dated note in a Vettigo animal's medical record, authored by the caller's Vettigo user and department. The animal is taken from the consultation: a consultation started from Vettigo for an animal, else the Vettigo animal synced to the consultation's patient, else the animal of the Vettigo appointment the consultation was started from.\n\nThe note text is taken from the request, not from the consultation's stored note. Not idempotent: every call adds another note.\n\nErrors: `400` when the consultation is not linked to Vettigo, the note is empty or the request is invalid (all reported as `Invalid Vettigo request`); `401` when the caller has no linked Vettigo account or Vettigo rejects Vetnio's credentials; `404` when the consultation does not exist; `429` on Vettigo rate limiting; `500` for other Vettigo failures.","tags":["vettigo"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. The Vettigo clinic used is the one the caller last launched Vetnio from, not something configured on the workspace."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Vetnio consultation (UUID) whose Vettigo animal or appointment receives the note.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Vetnio consultation (UUID) whose Vettigo animal or appointment receives the note."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clinicalNote":{"type":"string","description":"The note to write. Either HTML or plain text, or a JSON object serialised as a string (a structured note), which is written as one `Field name:` block per key with the key turned into a readable label. HTML is converted to plain text and characters Vettigo cannot store are replaced. Must not be empty after conversion.","example":"<p><strong>Anamnesis</strong><br>Limping on the left hind leg for 2 weeks.</p><p><strong>Plan</strong><br>Meloxicam 0.1 mg/kg PO SID for 5 days.</p>"}},"required":["clinicalNote"]}}}},"responses":{"200":{"description":"Export result, including the Vettigo animalID when resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VettigoExportResult"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetmanager/status":{"get":{"operationId":"vetmanagerApi-getStatus","summary":"VetManager integration status","description":"Returns whether the calling user has a VetManager account linked to Vetnio. The link is created when the user opens Vetnio from a VetManager visit and cannot be set up through the REST API. Use it to decide whether to offer VetManager export. Never fails: any problem is reported as `connected: false`.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. Patient and visit endpoints also require the workspace to be linked to the caller's VetManager practice.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. Patient and visit endpoints also require the workspace to be linked to the caller's VetManager practice."}],"responses":{"200":{"description":"VetManager connection status.","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean","description":"`true` when the calling user has a VetManager account linked to Vetnio, created the first time they open Vetnio from a VetManager visit. Also `false` when the status could not be determined.","example":true}},"required":["connected"],"additionalProperties":false,"title":"VetManager integration status","description":"Whether the calling user can use the VetManager endpoints."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/vetmanager/patients":{"get":{"operationId":"vetmanagerApi-searchPatients","summary":"Search VetManager patients","description":"Searches the caller's VetManager practice by animal name and owner surname and returns animal and owner pairs. Read-only: nothing is created in Vetnio or VetManager.\n\nErrors: `400` for a query shorter than 3 characters; `401` when the caller has no linked VetManager account or must sign in again; `403` when the practice is not linked to this workspace or VetManager has not enabled search for it.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. Patient and visit endpoints also require the workspace to be linked to the caller's VetManager practice.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the Vetnio workspace (clinic). The caller must be a member. Patient and visit endpoints also require the workspace to be linked to the caller's VetManager practice."},{"in":"query","name":"query","schema":{"type":"string","minLength":3,"maxLength":200,"description":"Animal name or owner surname to search for in VetManager. 3 to 200 characters after trimming.","example":"Bella"},"required":true,"description":"Animal name or owner surname to search for in VetManager. 3 to 200 characters after trimming."}],"responses":{"200":{"description":"Matching animals.","content":{"application/json":{"schema":{"type":"object","properties":{"patients":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"animalName":{"description":"Animal name, or `null` when VetManager has none.","example":"Bella","type":["string","null"]},"animalKind":{"description":"Animal kind as VetManager names it (Swedish).","example":"Häst","type":["string","null"]},"ownerName":{"description":"Owner name. `null` when the match came only from the animal search, which returns no owner names.","example":"Anna Lindqvist","type":["string","null"]},"customerNumber":{"description":"The practice's customer number for the owner, when known.","example":"1042","type":["string","null"]},"patientId":{"description":"Vetnio patient already created from this animal in the workspace, or `null`.","example":null,"type":["string","null"]}},"required":["contactId","animalId","animalName","animalKind","ownerName","customerNumber","patientId"],"additionalProperties":false,"title":"VetManager patient match","description":"One animal and owner pair from VetManager."},"description":"At most 20 matches, animal-name matches first."}},"required":["patients"],"additionalProperties":false,"title":"VetManager patient matches","description":"Animals matching the query by animal name or owner surname."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/patient":{"put":{"operationId":"vetmanagerApi-linkPatient","summary":"Link a VetManager animal to a consultation","description":"Makes the VetManager animal from a patient search match a Vetnio patient (with its owner), reusing the patient when the animal was added before, and sets it as the consultation's patient. Replaces any earlier patient. The visit context then returns it as `patientChoice`, so export starts with that animal. Nothing is created in VetManager.\n\nErrors: `401` when the caller has no linked VetManager account or must sign in again; `403` when the practice is not linked to this workspace or the caller may not use the patient; `409` when the patient changed while it was being added.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"animalName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"`animalName` from the search match.","example":"Bella"},"animalKind":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"description":"`animalKind` from the search match.","example":"Häst"},"ownerName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"`ownerName` from the search match.","example":"Anna Lindqvist"},"customerNumber":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"description":"`customerNumber` from the search match.","example":"1042"}},"required":["contactId","animalId","animalName","animalKind","ownerName","customerNumber"],"title":"VetManager patient selection","description":"A match from the patient search, as returned (its `patientId` may be left out)."}},"required":["match"]}}}},"responses":{"200":{"description":"The linked patient.","content":{"application/json":{"schema":{"type":"object","properties":{"patientId":{"type":"string","description":"The Vetnio patient now linked to the consultation.","example":"c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f"},"name":{"description":"Patient name.","example":"Bella","type":["string","null"]},"species":{"description":"Patient species, when VetManager's animal kind could be mapped or kept.","example":"horse","type":["string","null"]}},"required":["patientId","name","species"],"additionalProperties":false,"title":"VetManager linked patient","description":"The Vetnio patient made from the VetManager animal."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/visit-context":{"get":{"operationId":"vetmanagerApi-getVisitContext","summary":"VetManager visit context for a consultation","description":"Returns what the vet needs before exporting: whether the consultation is already linked to a VetManager visit, an unfinished visit creation to resume, earlier visits the animal can be added to, and the VetManager animal of the consultation's patient. Errors: `401` when the caller must sign in to VetManager again; `403` when the practice is not linked to this workspace; `404` when the consultation does not exist.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"responses":{"200":{"description":"The visit context.","content":{"application/json":{"schema":{"type":"object","properties":{"identityKey":{"type":"string","minLength":1,"description":"Opaque key from the visit context. A request is rejected with `409` when the signed-in VetManager account or practice changed since it was issued.","example":"3f1e9c0b7a"},"practice":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"name":{"type":"string","description":"Practice name.","example":"Demogården"}},"required":["id","name"],"additionalProperties":false,"description":"The VetManager practice of the signed-in account."},"linked":{"type":"boolean","description":"`true` when the consultation is already linked to a visit; export directly.","example":false},"linkedVisit":{"anyOf":[{"type":"object","properties":{"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"assignmentId":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"VetManager visit (assignment) id; `null` for a recovered visit, which cannot take more animals.","example":3100001},"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"clientBlocked":{"type":"boolean","description":"`true` when VetManager flags the owner as blocked; show a warning.","example":false}},"required":["resonId","assignmentId","practiceId","contactId","animalId","clientBlocked"],"additionalProperties":false},{"type":"null"}],"description":"The linked visit when it was created through Vetnio, else `null`."},"returnUrl":{"description":"Link back to the linked visit in VetManager, when known.","example":null,"type":["string","null"]},"pending":{"anyOf":[{"type":"object","properties":{"key":{"type":"string","description":"Key of the unfinished creation; pass it as `pendingKey` to recovery.","example":"vetnio-visit-6c1f"},"selection":{"type":"object","properties":{"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"assignmentId":{"description":"Add the animal to this earlier visit (assignment) created through Vetnio for the same owner, without another basic fee. Omit to create a new visit, which charges the practice's basic fee.","example":3100001,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"name":{"default":"","description":"Optional visit reason shown in VetManager.","example":"Hälta","type":"string","maxLength":254}},"required":["contactId","animalId","name"],"additionalProperties":false,"title":"VetManager visit selection","description":"The owner and animal the visit is for."},"canRetry":{"type":"boolean","description":"`true`: resend this selection to the create-visit endpoint to finish safely. `false`: the retry window passed or another vet started it; use recovery instead.","example":true}},"required":["key","selection","canRetry"],"additionalProperties":false},{"type":"null"}],"description":"An earlier visit creation that did not finish, or `null`."},"visits":{"type":"array","items":{"type":"object","properties":{"assignmentId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Pass as `selection.assignmentId`.","example":3100001},"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"name":{"description":"Name of the Vetnio consultation that created it.","example":"Bella – Hälta","type":["string","null"]}},"required":["assignmentId","contactId","name"],"additionalProperties":false,"description":"A visit this vet created through Vetnio in this workspace."},"description":"Earlier visits another animal of the same owner can be added to. Filter by `contactId`."},"patientChoice":{"anyOf":[{"type":"object","properties":{"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"animalName":{"description":"Animal name.","example":"Bella","type":["string","null"]},"ownerName":{"description":"Owner name as it was when the animal was picked.","example":"Anna Lindqvist","type":["string","null"]}},"required":["contactId","animalId","animalName","ownerName"],"additionalProperties":false},{"type":"null"}],"description":"Owner and animal of the consultation's patient when it was picked from VetManager; preselect it."}},"required":["identityKey","practice","linked","linkedVisit","returnUrl","pending","visits","patientChoice"],"additionalProperties":false,"title":"VetManager visit context","description":"Everything needed to choose or create the VetManager visit for a consultation."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/visit":{"post":{"operationId":"vetmanagerApi-createVisit","summary":"Create the VetManager visit for a consultation","description":"Creates a visit for the selected owner and animal in VetManager (or adds the animal to an earlier visit) and links the consultation to it. It does not export the note: call the export endpoint next. A new visit charges the practice's basic fee. Safe to retry: when the visit context reports a pending creation with `canRetry`, resend the same selection to finish it without creating a duplicate.\n\nErrors: `400` for an empty note or a selection VetManager rejects (for example an animal the owner does not own); `401` when the caller must sign in to VetManager again; `403` when the practice is not linked or not allowed to create visits; `409` when the account changed, the consultation is already linked, or another creation is in progress.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"identityKey":{"type":"string","minLength":1,"description":"Opaque key from the visit context. A request is rejected with `409` when the signed-in VetManager account or practice changed since it was issued.","example":"3f1e9c0b7a"},"clinicalNote":{"type":"string","description":"The note to write: HTML, plain text, or a structured note serialised as a JSON object. It is converted to plain text and must not be empty.","example":"<p><strong>Anamnes</strong><br>Hälta vänster bak sedan två veckor.</p>"},"selection":{"type":"object","properties":{"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"assignmentId":{"description":"Add the animal to this earlier visit (assignment) created through Vetnio for the same owner, without another basic fee. Omit to create a new visit, which charges the practice's basic fee.","example":3100001,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"name":{"default":"","description":"Optional visit reason shown in VetManager.","example":"Hälta","type":"string","maxLength":254}},"required":["contactId","animalId"],"title":"VetManager visit selection","description":"The owner and animal the visit is for."}},"required":["practiceId","identityKey","clinicalNote","selection"]}}}},"responses":{"200":{"description":"The linked visit.","content":{"application/json":{"schema":{"type":"object","properties":{"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"assignmentId":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"VetManager visit (assignment) id; `null` for a recovered visit, which cannot take more animals.","example":3100001},"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"clientBlocked":{"type":"boolean","description":"`true` when VetManager flags the owner as blocked; show a warning.","example":false},"returnUrl":{"description":"Link to the visit in VetManager, when known.","example":"https://vetmanager.se/vet_assignments/3100001/edit","type":["string","null"]}},"required":["resonId","assignmentId","practiceId","contactId","animalId","clientBlocked","returnUrl"],"additionalProperties":false,"title":"VetManager visit","description":"The VetManager visit the consultation is now linked to."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/visit/recovery-preview":{"post":{"operationId":"vetmanagerApi-previewRecovery","summary":"Preview recovering an existing VetManager visit","description":"For a pending creation that can no longer be retried: checks that the VetManager visit with the given id belongs to the same owner, animal, account and practice, and returns it for confirmation. Changes nothing. The vet must have opened that visit from VetManager once so Vetnio holds its access.\n\nErrors: `400` when the visit's owner or animal differ; `401` when the visit has not been opened from VetManager; `403` for another account or practice; `409` when the pending creation changed or the visit is locked.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"identityKey":{"type":"string","minLength":1,"description":"Opaque key from the visit context. A request is rejected with `409` when the signed-in VetManager account or practice changed since it was issued.","example":"3f1e9c0b7a"},"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"pendingKey":{"type":"string","minLength":1,"description":"`pending.key` from the visit context.","example":"vetnio-visit-6c1f"}},"required":["practiceId","identityKey","resonId","pendingKey"]}}}},"responses":{"200":{"description":"The visit that would be linked.","content":{"application/json":{"schema":{"type":"object","properties":{"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"name":{"type":"string","description":"Visit reason name in VetManager.","example":"Hälta"},"date":{"description":"Visit date (ISO 8601), when VetManager has one.","example":"2026-10-26T09:30:00+01:00","type":["string","null"]},"animalName":{"description":"Animal on the visit.","example":"Bella","type":["string","null"]},"clientName":{"description":"Owner on the visit.","example":"Anna Lindqvist","type":["string","null"]}},"required":["resonId","name","date","animalName","clientName"],"additionalProperties":false,"title":"VetManager recovery preview","description":"The existing visit recovery would link, for the vet to confirm."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/visit/recovery":{"post":{"operationId":"vetmanagerApi-recoverVisit","summary":"Recover an existing VetManager visit","description":"Links the consultation to the existing VetManager visit checked by the recovery preview, without creating anything in VetManager. Call the export endpoint next. Same errors as the preview, plus `400` for an empty note.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"identityKey":{"type":"string","minLength":1,"description":"Opaque key from the visit context. A request is rejected with `409` when the signed-in VetManager account or practice changed since it was issued.","example":"3f1e9c0b7a"},"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"pendingKey":{"type":"string","minLength":1,"description":"`pending.key` from the visit context.","example":"vetnio-visit-6c1f"},"clinicalNote":{"type":"string","description":"The note to write: HTML, plain text, or a structured note serialised as a JSON object. It is converted to plain text and must not be empty.","example":"<p><strong>Anamnes</strong><br>Hälta vänster bak sedan två veckor.</p>"}},"required":["practiceId","identityKey","resonId","pendingKey","clinicalNote"]}}}},"responses":{"200":{"description":"The linked visit.","content":{"application/json":{"schema":{"type":"object","properties":{"resonId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager visit reason (\"reson\") id: the record the note is written to.","example":2535050},"assignmentId":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"VetManager visit (assignment) id; `null` for a recovered visit, which cannot take more animals.","example":3100001},"practiceId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager practice id, as returned in `practice.id` by the visit context.","example":4242},"contactId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager client (owner) id.","example":5101},"animalId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"VetManager animal id.","example":8811},"clientBlocked":{"type":"boolean","description":"`true` when VetManager flags the owner as blocked; show a warning.","example":false},"returnUrl":{"description":"Link to the visit in VetManager, when known.","example":"https://vetmanager.se/vet_assignments/3100001/edit","type":["string","null"]}},"required":["resonId","assignmentId","practiceId","contactId","animalId","clientBlocked","returnUrl"],"additionalProperties":false,"title":"VetManager visit","description":"The VetManager visit the consultation is now linked to."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/vetmanager/export":{"post":{"operationId":"vetmanagerApi-exportClinicalNote","summary":"Export clinical note to VetManager","description":"Adds the supplied note to the consultation's VetManager visit as a new AI note (\"AI-anteckning\"). The consultation must be linked to a visit, either by opening Vetnio from that visit or through the create-visit endpoint. Exporting the same text again replays the first result; edited text adds another note.\n\nErrors: `400` when the consultation is not linked or the note is empty; `401` when the caller must sign in to VetManager again; `403` when the visit's access belongs to another visit; `404` when the visit no longer exists; `409` when the visit is locked.","tags":["vetmanager"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the consultation (UUID), as returned when it was created or by `GET /workspaces/{workspaceId}/consultations`. It must belong to the clinic in `workspaceId`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clinicalNote":{"type":"string","description":"The note to write: HTML, plain text, or a structured note serialised as a JSON object. It is converted to plain text and must not be empty.","example":"<p><strong>Anamnes</strong><br>Hälta vänster bak sedan två veckor.</p>"}},"required":["clinicalNote"]}}}},"responses":{"200":{"description":"The created note.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","const":"ok","description":"Always `ok` on success.","example":"ok"},"vetmanagerEventId":{"description":"Id of the AI note created in VetManager, or `null` when VetManager did not return one.","example":990001,"type":["number","null"]}},"required":["status","vetmanagerEventId"],"additionalProperties":false,"title":"VetManager export result","description":"The note was added to the visit as a new AI note."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/status":{"get":{"operationId":"link-getStatus","summary":"Link integration status","description":"Returns whether the calling user has connected Vetnio to a Link tenant in this workspace, with the tenant subdomain and default location when they have. Link credentials are saved per user and workspace in Vetnio's integration settings; they cannot be created through the REST API. Call this first to decide whether to show Link features. Never calls Link itself, so it does not prove the stored API key still works.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."}],"responses":{"200":{"description":"Configuration status payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkStatus"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/templates":{"get":{"operationId":"link-listTemplates","summary":"List Link form templates","description":"Lists journal form templates from the caller's Link tenant. By default every public (`status=public`) animal, herd, and combined animal-and-herd journal template is returned; Vetnio follows Link's pagination and returns all pages in one unpaginated array. Use it to let the vet pick the Link template a consultation's note should be written for. Returns `412 PRECONDITION_FAILED` when the caller has no Link credentials in this workspace and `401 UNAUTHORIZED` when Link rejects the stored API key.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"query","name":"kind","schema":{"type":"string","description":"Link template kind filter, passed to Link unchanged. Accepts a single kind or a comma-separated list (`animal_journal`, `animal_certificate`, `herd_journal`, `animal_and_herd_journal`, `quotation`). Defaults to `animal_journal,herd_journal,animal_and_herd_journal`.","example":"animal_journal"}},{"in":"query","name":"status","schema":{"type":"string","description":"Link template status filter, passed to Link unchanged: `public` (published) or `edit` (draft). Defaults to `public`.","example":"public"}}],"responses":{"200":{"description":"Array of Link template summaries.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LinkTemplateSummary"}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/templates/{templateId}":{"get":{"operationId":"link-getTemplate","summary":"Get Link template detail","description":"Fetches one Link form template and returns the fields Vetnio can write into (`textarea`, `select`, `multiCheckbox`, `internalSample`), in template order. Read-only; nothing is stored in Vetnio. Returns `404 NOT_FOUND` when Link has no template with this id.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"templateId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link journal form template id, as returned in `id` by the template list endpoint.","example":3423},"required":true,"description":"Link journal form template id, as returned in `id` by the template list endpoint."}],"responses":{"200":{"description":"Template detail with field metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Link form template id.","example":3423},"name":{"type":"string","description":"Template name as shown in Link.","example":"Allmän undersökning hund"},"description":{"description":"Template description from Link, or `null`.","example":null,"type":["string","null"]},"fieldMetadata":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"Field label. For a free-text field placed directly under a heading without its own label, the heading text is used. Becomes the field name in the generated Vetnio JSON template.","example":"Anamnes"},"type":{"type":"string","enum":["textarea","select","multiCheckbox","internalSample"],"description":"How Vetnio writes the field:\n- `textarea` — free text (Link `textarea` and `input` fields).\n- `select` — exactly one value from `options`.\n- `multiCheckbox` — any number of values from `options`.\n- `internalSample` — a lab or measurement result row (Link `internal_sample` and `milksample*` fields). For `internal_sample`, only the first number in the value is sent (for example `24.5 kg` is written as `24.5`).","example":"textarea"},"apiFieldId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Id of the field in the Link template.","example":98765},"options":{"description":"Allowed values. Present for `select` and `multiCheckbox` fields, absent otherwise.","type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"Option value Link stores when the option is chosen. Exported structured notes use this value.","example":"normal"},"label":{"type":"string","description":"Option text shown to the vet in Link.","example":"Normal"}},"required":["value","label"],"additionalProperties":false,"title":"Link template field option","description":"One choice of a `select` or `multiCheckbox` Link template field."}}},"required":["title","type","apiFieldId"],"additionalProperties":false,"title":"Link template field","description":"A field of a Link template that Vetnio can write. Headings, labels and other non-writable rows, and fields without a title, are left out."},"description":"Writable fields in the order they appear in the Link template. An empty array means Vetnio cannot export to this template."}},"required":["id","name","description","fieldMetadata"],"additionalProperties":false,"title":"Link template detail","description":"A Link form template with the writable fields Vetnio derives from it. The same field list drives the JSON template created by the resolve endpoint."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/customers":{"get":{"operationId":"link-searchCustomers","summary":"Search Link customers","description":"Searches active (not removed) customers in the caller's Link tenant. Use exactly one search mode per request, otherwise the request fails with `400 BAD_REQUEST`:\n\n- `name` — Link's own partial match on first or last name.\n- `identifier` — exact match on the customer identifier (for example a Swedish personal identity number). Vetnio also tries the common spellings with and without century digits and hyphen, and merges the results.\n- `firstName` and/or `lastName` — at least one with two or more characters. Vetnio queries Link with the longer term and keeps only customers whose first and last names contain the supplied values (case-insensitive).\n\nResults are paginated with `page` (default 1) and `perPage` (1–100, default 100). `total` and `sourceTotal` count upstream Link rows, not filtered matches: the final field-aware match count is known only after all source pages are scanned, so keep requesting pages while `hasNextPage` is `true` to see every match.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"query","name":"name","schema":{"type":"string","minLength":1,"description":"Legacy search: partial, case-insensitive match on the customer's first or last name, performed by Link. Use exactly one search mode: `name`, `identifier`, or `firstName`/`lastName`.","example":"Morgan"}},{"in":"query","name":"identifier","schema":{"type":"string","minLength":1,"description":"Exact customer identifier, typically a Swedish personal identity number. Vetnio also tries the common spellings (with or without century digits and hyphen) and merges the results.","example":"19850101-1234"}},{"in":"query","name":"firstName","schema":{"type":"string","minLength":1,"description":"Case-insensitive substring of the customer's first name. Combine with `lastName`; at least one of the two must have two or more characters.","example":"Alex"}},{"in":"query","name":"lastName","schema":{"type":"string","minLength":1,"description":"Case-insensitive substring of the customer's last name.","example":"Morgan"}},{"in":"query","name":"page","schema":{"default":1,"description":"1-based page of Link results.","example":1,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"in":"query","name":"perPage","schema":{"default":100,"description":"Results per page, from 1 to 100.","example":100,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated customer search results.","content":{"application/json":{"schema":{"type":"object","properties":{"customers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Link customer id. Pass it as `customerId` to the animal and export endpoints.","example":54967922},"name":{"description":"Full display name from Link, or `null`.","example":"Alex Morgan","type":["string","null"]},"firstName":{"description":"First name from Link, or `null` (for example for companies).","example":"Alex","type":["string","null"]},"lastName":{"description":"Last name from Link, or `null`.","example":"Morgan","type":["string","null"]},"identifier":{"description":"Customer identifier in Link, typically a Swedish personal identity number or organisation number. `null` when not recorded.","example":"198501011234","type":["string","null"]},"primaryEmail":{"description":"The customer's email address marked primary in Link, or `null`.","example":"alex.morgan@example.com","type":["string","null"]},"primaryPhone":{"description":"The customer's phone number marked primary in Link, or `null`.","example":"0701234567","type":["string","null"]}},"required":["id","name","firstName","lastName","identifier","primaryEmail","primaryPhone"],"additionalProperties":false,"title":"Link customer","description":"An active (not removed) animal owner in the clinic's Link tenant."},"description":"Matching customers from this page of Link results. In `firstName`/`lastName` mode the page is filtered after it is fetched, so it can hold fewer than `perPage` rows (or none) while `hasNextPage` is still `true`."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Same value as `sourceTotal`, kept for older clients. It is not the number of matches after Vetnio's own filtering.","example":3},"sourceTotal":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of customers Link reported for the upstream query. In `identifier` mode it is the sum over all identifier spellings searched.","example":3},"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The page that was returned (1-based).","example":1},"perPage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Page size used for the upstream Link query.","example":100},"scannedCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"How many upstream Link rows have been covered up to and including this page.","example":3},"hasNextPage":{"type":"boolean","description":"`true` when Link has more rows for this query. Request `page + 1` to continue; a filtered page can be empty while this is `true`.","example":false}},"required":["customers","total","sourceTotal","page","perPage","scannedCount","hasNextPage"],"additionalProperties":false,"title":"Link customer search results","description":"One page of Link customer search results."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/customers/{customerId}/animals":{"get":{"operationId":"link-listAnimalsForCustomer","summary":"List animals for a Link customer","description":"Lists active animals (not deceased, removed or marked duplicate) owned by the given Link customer, most recently updated first. Only the first 100 animals are returned and there is no pagination metadata; prefer the paginated `/animals/page` variant, which also supports a name filter.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"customerId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint.","example":54967922},"required":true,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint."}],"responses":{"200":{"description":"Array of animals.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LinkAnimal"}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/customers/{customerId}/animals/page":{"get":{"operationId":"link-listAnimalsForCustomerPage","summary":"List a page of animals for a Link customer","description":"Lists one page of active animals (not deceased, removed or marked duplicate) owned by the given Link customer, optionally filtered by a partial animal name. Vetnio checks Link's paging metadata and fails with `500` rather than return an inconsistent page.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"customerId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint.","example":54967922},"required":true,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint."},{"in":"query","name":"name","schema":{"type":"string","minLength":1,"description":"Optional partial, case-insensitive match on the animal name, applied by Link. Leading and trailing whitespace is ignored.","example":"Bel"}},{"in":"query","name":"page","schema":{"default":1,"description":"1-based page number.","example":1,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"in":"query","name":"perPage","schema":{"default":100,"description":"Animals per page, 1 to 100.","example":100,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated animal results.","content":{"application/json":{"schema":{"type":"object","properties":{"animals":{"type":"array","items":{"$ref":"#/components/schemas/LinkAnimal"},"description":"Animals on this page, in Link's order (most recently updated first)."},"total":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Total number of matching animals across all pages.","example":2},"page":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The page that was returned (1-based).","example":1},"perPage":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Page size used.","example":100},"hasNextPage":{"type":"boolean","description":"`true` when more animals exist after this page.","example":false}},"required":["animals","total","page","perPage","hasNextPage"],"additionalProperties":false,"title":"Link animal page","description":"One page of a Link customer's active animals."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/link/compatible-entries":{"get":{"operationId":"link-listCompatibleEntries","summary":"List compatible Link entries","description":"Returns up to three existing journal entries in the selected animal's Link journal that this consultation's structured note could be written into instead of creating a new entry: newest first, not locked, deleted or cancelled, and created from the consultation's Link template or one with an identical ordered list of writable fields. Pass a candidate's `id` as `targetEntryId` to the export endpoint. The consultation must use a Link JSON template (see the resolve endpoint), otherwise `400 BAD_REQUEST`; `404 NOT_FOUND` when the animal does not belong to the customer or the Link template can no longer be found in the tenant.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","minLength":1,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link."},{"in":"query","name":"customerId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint.","example":54967922},"required":true,"description":"Link customer (animal owner) id, as returned in `customers[].id` by the customer search endpoint."},{"in":"query","name":"animalId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link animal id, as returned in `id` by the animal list endpoints. The animal must be owned by `customerId`.","example":1234567},"required":true,"description":"Link animal id, as returned in `id` by the animal list endpoints. The animal must be owned by `customerId`."}],"responses":{"200":{"description":"Compatible Link entry candidates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Link journal entry id. Pass it as `targetEntryId` to the export endpoint to write into this entry.","example":8812345},"title":{"type":"string","description":"Entry title as shown in Link.","example":"Allmän undersökning hund"},"createdAt":{"type":"string","description":"When the entry was created in Link, passed through as Link returns it (ISO-8601, may carry a local UTC offset).","example":"2026-10-01T09:30:00.000+02:00"},"visitReason":{"description":"Visit reason(s) of the Link appointment the entry belongs to, comma-separated, falling back to the appointment description. `null` when the entry has no appointment or it could not be loaded.","example":"Vaccination","type":["string","null"]}},"required":["id","title","createdAt","visitReason"],"additionalProperties":false,"title":"Compatible Link entry","description":"An existing Link journal entry that can receive this consultation's note: not locked, deleted or cancelled, and created from the same template or one with an identical ordered list of writable fields."}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/link/entry-url":{"get":{"operationId":"link-getEntryUrl","summary":"Get Link entry URL","description":"Returns the Link web URL of the journal entry this consultation was last exported to. Returns `404 NOT_FOUND` when the consultation has never been exported to Link (or the animal can no longer be found among the customer's active animals), and `400 BAD_REQUEST` when the entry has no customer.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","minLength":1,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link."}],"responses":{"200":{"description":"Canonical Link entry URL.","content":{"application/json":{"schema":{"type":"object","properties":{"entryUrl":{"type":"string","description":"Deep link that opens the journal entry in Link's web app (format `https://<subdomain>.linkjournal.se/customers/<customerId>/animals/<animalId>?only_entry=<entryId>`).","example":"https://riverside.linkjournal.se/customers/54967922/animals/1234567?only_entry=8812345"}},"required":["entryUrl"],"additionalProperties":false,"title":"Link entry URL","description":"Where to open the consultation's Link journal entry."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/link/templates/{linkTemplateId}/resolve":{"post":{"operationId":"link-resolveJsonTemplateForLinkTemplate","summary":"Resolve Link template to JSON template id","description":"Maps a Link form template to a Vetnio JSON template so the clinical note is generated with one value per Link field. Vetnio reads the template's writable fields, derives a signature from their ordered titles, and returns the workspace's JSON template with that signature, creating it on first use (creation runs an AI step that writes per-field instructions, so the first call is slower). When `consultationId` is given, the JSON template is also set as that consultation's clinical-note template. Idempotent: repeated calls return the same id with `created: false`. Returns `400 BAD_REQUEST` when the template has no writable fields.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"linkTemplateId","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Link journal form template id, as returned in `id` by the template list endpoint.","example":3423},"required":true,"description":"Link journal form template id, as returned in `id` by the template list endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"consultationId":{"description":"Optional consultation to bind the resolved JSON template to as its clinical-note template. Only the template is set; no note is generated.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","type":"string","minLength":1}}}}}},"responses":{"200":{"description":"Resolved jsonTemplateId, a `created` flag, and the deterministic ordered keys.","content":{"application/json":{"schema":{"type":"object","properties":{"jsonTemplateId":{"type":"string","description":"Id of the Vetnio JSON template that mirrors the Link template's writable fields. Use it as the consultation's clinical-note JSON template so the generated note has one value per Link field.","example":"0f6c2d7e-3b1a-4c55-9f0e-2a8b7c6d5e4f"},"created":{"type":"boolean","description":"`true` when this call created the JSON template; `false` when a matching one already existed in the workspace.","example":false},"keys":{"type":"array","items":{"type":"string"},"description":"Keys of the JSON template, one per Link field and in the same order as the template detail's `fieldMetadata`. Derived from the field titles (lower-cased, `å`→`a`, `ä`→`ae`, `ö`→`oe`, other characters removed; duplicates get a hash suffix). The structured clinical note uses these keys.","example":["anamnes","status","bedoemning"]}},"required":["jsonTemplateId","created","keys"],"additionalProperties":false,"title":"Resolved Link JSON template","description":"The Vetnio JSON template matching a Link template, created on first use."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/consultations/{consultationId}/link/export":{"post":{"operationId":"link-exportConsultation","summary":"Export consultation to Link","description":"Writes the consultation's structured clinical note (generated with a Link JSON template, see the resolve endpoint) into a Link journal entry.\n\n- **First export**: pass `customerId` and `animalId`. A new entry is created with the Link template, at `locationId` or the integration's default location. Response `mode: created`.\n- **Later exports**: the entry recorded on the consultation is updated in place and `customerId`/`animalId` are ignored. Response `mode: updated`.\n- **Existing entry**: pass `targetEntryId` (from the compatible-entries endpoint) plus `customerId` and `animalId` to write into an entry created in Link.\n- **Reassign**: `reassign: true` with a new `customerId`/`animalId` creates a fresh entry; the old entry is left untouched in Link.\n\nWhen updating, text fields are append-only: only lines added since Vetnio's last successful export to that entry are appended after a blank line, so text the vet wrote in Link is kept and retries do not duplicate text. Select, checkbox and result fields are overwritten; fields missing from the note are not touched. Locked, deleted or cancelled entries cannot be updated (`400`). If Link rejects any field during an update, the request fails with `500`; fields Link accepted may already be saved, but Vetnio does not record the export, so a retry does not duplicate text. When creating, rejected fields are only reported in `fieldWrites.create.errors`.","tags":["link"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the clinic (workspace), as returned by `GET /workspaces`. The key's user must be a member of the clinic, or an admin of the organization it belongs to."},{"in":"path","name":"consultationId","schema":{"type":"string","minLength":1,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Identifier of the Vetnio consultation (UUID) whose structured clinical note is exported to, or matched against, Link."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"description":"Link customer who owns the animal. Required on the first export, with `reassign: true`, and with `targetEntryId`; ignored when the consultation's existing entry is updated in place.","example":54967922,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"animalId":{"description":"Link animal whose journal receives the entry. Required in the same cases as `customerId`, and must belong to that customer.","example":1234567,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"locationId":{"description":"Link location (clinic site) for a newly created entry. Defaults to the integration's `defaultLocationId`; the request fails with `400` when neither is set. Ignored for updates.","example":346,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"reassign":{"description":"Set to `true` to create a new entry for `customerId`/`animalId` even though the consultation was already exported. The previous entry is left as it is in Link and the consultation is re-pointed to the new one. Defaults to `false`.","example":false,"type":"boolean"},"targetEntryId":{"description":"Id of an existing Link entry to write into instead of creating one, typically from the compatible-entries endpoint. Takes precedence over the entry already recorded on the consultation. The entry must belong to `customerId` and `animalId`, be editable, and use a compatible template.","example":8812345,"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"Link entry id, journal id, deep-link URL, mode, and per-field write results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkExportResult"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/organizations/{organizationId}":{"get":{"operationId":"dataExport-organization-overview","summary":"Get an organization with its clinics, people and templates","description":"Returns the organization, its clinics, its people (organization members and clinic staff, one row per person) and the names of its organization-level templates. Use it to look up clinic IDs for the usage export's `workspaceIds` and to map user IDs in usage rows to people. With a workspace key, `workspaces` and clinic staff are limited to that clinic, but organization members and organization templates are still listed. Read-only; every call is recorded in the audit log. Requires organization admin rights: an organization or workspace API key, or a personal key or session of an organization admin.","tags":["data-export"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization (a UUID). With an organization or workspace key, use the `organizationId` returned by `GET /api-key`; any other organization returns 403.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization (a UUID). With an organization or workspace key, use the `organizationId` returned by `GET /api-key`; any other organization returns 403."}],"responses":{"200":{"description":"The organization overview.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationExportOverview"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal","organization","workspace"]}},"/organizations/{organizationId}/data-export/usage":{"get":{"operationId":"dataExport-organization-usage","summary":"Export usage statistics","description":"Returns the same table as Organization → Export in the app, as JSON: `headers` plus one array of cells per row. Choose the period (`days`, or `startDate`/`endDate`), the row level (`grain`), the time bucket (`timePeriod`), clinics (`workspaceIds`) and `columns`. Only `grain=consultation` is paginated. A workspace key only ever gets its own clinic's rows. Read-only; every call is recorded in the audit log. Requests that include note-quality columns run an extra analytics query and are limited per key per day. Requires organization admin rights, like the overview endpoint.","tags":["data-export"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization (a UUID). With an organization or workspace key, use the `organizationId` returned by `GET /api-key`; any other organization returns 403.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization (a UUID). With an organization or workspace key, use the `organizationId` returned by `GET /api-key`; any other organization returns 403."},{"in":"query","name":"workspaceIds","schema":{"type":"string","description":"Comma-separated workspace (clinic) IDs to include, for example `furunculotic-loud-chihuahua,brave-quick-heron`. Every ID must belong to the organization (or, for a workspace key, be the key's own clinic), otherwise the request fails with 400. Default: every clinic attached to the organization, including locked clinics.","example":"furunculotic-loud-chihuahua"}},{"in":"query","name":"columns","schema":{"type":"string","description":"Comma-separated column keys, for example `workspaceName,consultationCount,recordingHours`. Columns are always returned in the export's fixed order, not the order listed. Columns that do not apply to the chosen `grain` are dropped silently: vet columns need `grain=vet` or `consultation`, consultation columns need `grain=consultation`, and at `grain=consultation` the aggregate columns are not available. An unknown key fails with 400 and the message lists every valid key. Default: every column except the note-quality ones (`avgReadingSeconds`, `avgEditingSeconds`, `acceptanceRate`, `draftOutcome`), which are only included when listed and are limited to 20 requests per key per day. The Export dialog's “Use via API” button builds this value for you.","example":"workspaceName,consultationCount,recordingHours"}},{"in":"query","name":"startDate","schema":{"description":"First day of a fixed date range, `YYYY-MM-DD` (UTC). When set, `days` is ignored. The range may span at most 366 days; longer ranges fail with 400.","example":"2026-09-01","type":"string"}},{"in":"query","name":"endDate","schema":{"description":"Last day of the fixed date range, inclusive, `YYYY-MM-DD` (UTC). Only used together with `startDate`; without `startDate` it is ignored. Default: up to the current moment.","example":"2026-09-30","type":"string"}},{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":366,"description":"Length of a rolling window ending now, in days (1-366, default 30). Today counts as the first day, so `days=7` covers today and the 6 days before it, starting at midnight UTC. Ignored when `startDate` is set.","example":30}},{"in":"query","name":"timePeriod","schema":{"default":"monthly","description":"Size of the time bucket each row covers when `grain` is `vet` or `clinic`; ignored for `snapshot` and `consultation`. Buckets are UTC. The first column (`Date`) holds the bucket's first day as `YYYY-MM-DD`, clamped to the start of the range:\n- `daily` — one bucket per calendar day.\n- `weekly` — one bucket per week, starting Monday.\n- `monthly` — one bucket per calendar month.\n- `yearly` — one bucket per calendar year.","example":"monthly","type":"string","enum":["daily","weekly","monthly","yearly"]}},{"in":"query","name":"grain","schema":{"default":"vet","description":"What one row represents:\n- `vet` — one vet in one clinic for one time bucket; only vets with activity get rows, and a vet working in two clinics gets a row for each.\n- `clinic` — one clinic for one time bucket; every clinic in scope gets a row (zero-filled) for each bucket with any activity.\n- `snapshot` — one row per clinic for the whole period, without a `Date` column.\n- `consultation` — one row per consultation, oldest first, including deleted ones (flagged in the `Deleted` column). The only paginated grain.","example":"clinic","type":"string","enum":["clinic","vet","snapshot","consultation"]}},{"in":"query","name":"page","schema":{"default":1,"description":"Page number, starting at 1. Only `grain=consultation` spans several pages; other grains always return everything on page 1. Pages that start beyond row 50,000 are rejected with 400: split the date range instead.","example":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"in":"query","name":"pageSize","schema":{"default":1000,"description":"Rows per page for `grain=consultation`, 1-5000. Ignored for the other grains.","example":1000,"type":"integer","minimum":1,"maximum":5000}}],"responses":{"200":{"description":"One page of the usage table.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUsageExport"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal","organization","workspace"]}},"/users/me/data-export/content":{"get":{"operationId":"customerContent-userConfiguration","summary":"Export your settings and transcription terms","description":"Exports the current stored settings and the current transcription term list of exactly this scope as versioned JSON (`schemaVersion` 1), with an `inventory` that lists what is included, what is excluded and how to interpret it. Credentials, billing identifiers and other scopes' private settings are never included. Values are read at request time, so this is neither a change history nor an atomic snapshot. Read-only. Covers the caller's personal preferences, custom AI instructions and personal term list. Returns only the caller's own settings; no user ID can be passed. Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserContentExport"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/content":{"get":{"operationId":"customerContent-workspaceConfiguration","summary":"Export a workspace's settings and transcription terms","description":"Exports the current stored settings and the current transcription term list of exactly this scope as versioned JSON (`schemaVersion` 1), with an `inventory` that lists what is included, what is excluded and how to interpret it. Credentials, billing identifiers and other scopes' private settings are never included. Values are read at request time, so this is neither a change history nor an atomic snapshot. Read-only. Covers the clinic's identity and address, shared settings, PIMS department mappings, workspace term list and, when configured, the letterhead image as a base64 PNG. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceContentExport"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/organizations/{organizationId}/data-export/content":{"get":{"operationId":"customerContent-organizationConfiguration","summary":"Export an organization's settings and transcription terms","description":"Exports the current stored settings and the current transcription term list of exactly this scope as versioned JSON (`schemaVersion` 1), with an `inventory` that lists what is included, what is excluded and how to interpret it. Credentials, billing identifiers and other scopes' private settings are never included. Values are read at request time, so this is neither a change history nor an atomic snapshot. Read-only. Covers the organization's identity, address, custom domains, billing presentation preferences, audio-retention policy and organization term list. Requires admin rights in the organization. Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization to export (a UUID). The caller must be an admin of it.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization to export (a UUID). The caller must be an admin of it."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationContentExport"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/templates":{"get":{"operationId":"customerContent-workspaceTemplates","summary":"Export a workspace's note templates","description":"Lists customer-owned templates for export, one page at a time, with metadata and a short-lived download link for each stored body. Pages are ordered by ascending template ID: pass `nextCursor` back as `cursor` until it is `null`. Download links expire after one hour (`expiresAt`); request the page again for fresh links. Vetnio's read-only default catalog templates are excluded; workspace-owned copies, including managed ones, are included. Read-only. Covers clinical-note, client-communication and referral templates, including hidden ones, with their imported instructions where present. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":512,"description":"Pagination cursor: the `nextCursor` value from the previous page. Omit for the first page, and keep the same owner and template category while paging. Items with an ID greater than the cursor are returned.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"}},{"in":"query","name":"limit","schema":{"default":20,"description":"Maximum number of templates per page, 1-50.","example":20,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceTemplateExportPage"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/templates/versions":{"get":{"operationId":"customerContent-workspaceTemplateVersions","summary":"List retained versions of a workspace note template","description":"Lists the retained stored versions of one template's body (`part=content`, the default) or of its imported instructions (`part=instructions`, document and meeting templates only), newest first, up to 50 per page. Pass `nextCursor` back as `cursor` until it is `null`. The template must belong to this scope, otherwise 404. Deleted templates and Vetnio's default catalog templates are not available. `currentVersionId` can change while you page if someone edits the template. For `part=content`, versions carry audit metadata about the edit that saved them when it is available. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque pagination cursor: the `nextCursor` value from the previous page of this template's versions. Omit for the first page. URL-encode it."}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionHistory"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/templates/version":{"get":{"operationId":"customerContent-workspaceTemplateVersion","summary":"Get a retained version of a workspace note template","description":"Returns the exact saved body of one retained template version as UTF-8 text, after checking that the template belongs to this scope. Take `versionId` from the versions list and URL-encode it. Read-only: it does not restore or modify the template. Returns 404 when the template, or that version of it, is not available. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"versionId","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"},"required":true,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionSnapshot"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/json-templates":{"get":{"operationId":"customerContent-workspaceJsonTemplates","summary":"Export a workspace's structured (JSON) templates","description":"Lists customer-owned templates for export, one page at a time, with metadata and a short-lived download link for each stored body. Pages are ordered by ascending template ID: pass `nextCursor` back as `cursor` until it is `null`. Download links expire after one hour (`expiresAt`); request the page again for fresh links. Vetnio's read-only default catalog templates are excluded; workspace-owned copies, including managed ones, are included. Read-only. Covers the workspace's own JSON output schemas, downloadable in their original JSON form. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":512,"description":"Pagination cursor: the `nextCursor` value from the previous page. Omit for the first page, and keep the same owner and template category while paging. Items with an ID greater than the cursor are returned.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"}},{"in":"query","name":"limit","schema":{"default":20,"description":"Maximum number of templates per page, 1-50.","example":20,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"nextCursor":{"description":"Pass this value as `cursor` to fetch the next page. `null` when this is the last page.","example":null,"type":["string","null"]},"expiresInSeconds":{"type":"number","description":"Lifetime of every `contentUrl` on this page, in seconds.","example":3600},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the `contentUrl` links on this page stop working (ISO-8601 UTC). Download before then. Expiry does not affect the stored content.","example":"2026-09-28T09:15:00.000Z"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"JSON template ID. Note templates refer to it through `jsonTemplateId`.","example":"9c2e4f81-6a3b-4d5e-8f70-1b2c3d4e5f60"},"workspaceId":{"type":"string","description":"ID of the workspace (clinic) that owns the template.","example":"furunculotic-loud-chihuahua"},"name":{"description":"Schema name shown in the app, or null if it was never named.","example":"Vaccination record","type":["string","null"]},"creatorId":{"type":"string","description":"User ID (UUID) of the person who created the template.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the template was created (ISO-8601 UTC).","example":"2026-03-14T10:02:11.000Z"},"artifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Download of the schema in its original JSON form, or null when no stored body exists."}},"required":["id","workspaceId","name","creatorId","createdAt","artifact"],"additionalProperties":false,"title":"Exported JSON template","description":"One structured-output (JSON schema) template owned by the workspace."},"description":"JSON templates on this page, ordered by ascending ID."}},"required":["nextCursor","expiresInSeconds","expiresAt","items"],"additionalProperties":false,"title":"Workspace JSON template export page","description":"One page of the workspace's structured (JSON) templates with download links."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/json-templates/versions":{"get":{"operationId":"customerContent-workspaceJsonTemplateVersions","summary":"List retained versions of a workspace JSON template","description":"Lists the retained stored versions of one template's body (`part=content`, the default) or of its imported instructions (`part=instructions`, document and meeting templates only), newest first, up to 50 per page. Pass `nextCursor` back as `cursor` until it is `null`. The template must belong to this scope, otherwise 404. Deleted templates and Vetnio's default catalog templates are not available. `currentVersionId` can change while you page if someone edits the template. JSON templates have no instructions part: `part=instructions` returns 400. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque pagination cursor: the `nextCursor` value from the previous page of this template's versions. Omit for the first page. URL-encode it."}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionHistory"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/json-templates/version":{"get":{"operationId":"customerContent-workspaceJsonTemplateVersion","summary":"Get a retained version of a workspace JSON template","description":"Returns the exact saved body of one retained template version as UTF-8 text, after checking that the template belongs to this scope. Take `versionId` from the versions list and URL-encode it. Read-only: it does not restore or modify the template. Returns 404 when the template, or that version of it, is not available. JSON templates have no instructions part: `part=instructions` returns 400. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"versionId","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"},"required":true,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionSnapshot"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/meeting-templates":{"get":{"operationId":"customerContent-workspaceMeetingTemplates","summary":"Export a workspace's meeting templates","description":"Lists customer-owned templates for export, one page at a time, with metadata and a short-lived download link for each stored body. Pages are ordered by ascending template ID: pass `nextCursor` back as `cursor` until it is `null`. Download links expire after one hour (`expiresAt`); request the page again for fresh links. Vetnio's read-only default catalog templates are excluded; workspace-owned copies, including managed ones, are included. Read-only. Covers the workspace's meeting and HR templates, with their imported instructions where present. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":512,"description":"Pagination cursor: the `nextCursor` value from the previous page. Omit for the first page, and keep the same owner and template category while paging. Items with an ID greater than the cursor are returned.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"}},{"in":"query","name":"limit","schema":{"default":20,"description":"Maximum number of templates per page, 1-50.","example":20,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"nextCursor":{"description":"Pass this value as `cursor` to fetch the next page. `null` when this is the last page.","example":null,"type":["string","null"]},"expiresInSeconds":{"type":"number","description":"Lifetime of every `contentUrl` on this page, in seconds.","example":3600},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the `contentUrl` links on this page stop working (ISO-8601 UTC). Download before then. Expiry does not affect the stored content.","example":"2026-09-28T09:15:00.000Z"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Meeting template ID.","example":"7d1f0a2b-3c4d-4e5f-9a8b-7c6d5e4f3a2b"},"workspaceId":{"type":"string","description":"ID of the workspace (clinic) that owns the template.","example":"furunculotic-loud-chihuahua"},"name":{"type":"string","description":"Template name shown in the app.","example":"Weekly staff meeting"},"creatorId":{"type":"string","description":"User ID (UUID) of the person who created the template.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the template was created (ISO-8601 UTC).","example":"2026-03-14T10:02:11.000Z"},"artifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Download of the template body, or null when no stored body exists."},"instructionsArtifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Download of the imported template's separate instructions object, or null when there is none."}},"required":["id","workspaceId","name","creatorId","createdAt","artifact","instructionsArtifact"],"additionalProperties":false,"title":"Exported meeting template","description":"One meeting or HR template owned by the workspace."},"description":"Meeting templates on this page, ordered by ascending ID."}},"required":["nextCursor","expiresInSeconds","expiresAt","items"],"additionalProperties":false,"title":"Workspace meeting template export page","description":"One page of the workspace's meeting templates with download links."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/meeting-templates/versions":{"get":{"operationId":"customerContent-workspaceMeetingTemplateVersions","summary":"List retained versions of a workspace meeting template","description":"Lists the retained stored versions of one template's body (`part=content`, the default) or of its imported instructions (`part=instructions`, document and meeting templates only), newest first, up to 50 per page. Pass `nextCursor` back as `cursor` until it is `null`. The template must belong to this scope, otherwise 404. Deleted templates and Vetnio's default catalog templates are not available. `currentVersionId` can change while you page if someone edits the template. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque pagination cursor: the `nextCursor` value from the previous page of this template's versions. Omit for the first page. URL-encode it."}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionHistory"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/workspaces/{workspaceId}/data-export/meeting-templates/version":{"get":{"operationId":"customerContent-workspaceMeetingTemplateVersion","summary":"Get a retained version of a workspace meeting template","description":"Returns the exact saved body of one retained template version as UTF-8 text, after checking that the template belongs to this scope. Take `versionId` from the versions list and URL-encode it. Read-only: it does not restore or modify the template. Returns 404 when the template, or that version of it, is not available. Requires admin rights in the workspace (workspace admin or superadmin, or an admin of an organization the clinic belongs to). Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"workspaceId","schema":{"type":"string","description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization.","example":"furunculotic-loud-chihuahua"},"required":true,"description":"Identifier of the workspace (clinic) to export. The caller must be an admin of it, directly or as an admin of its organization."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"versionId","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"},"required":true,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionSnapshot"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/organizations/{organizationId}/data-export/templates":{"get":{"operationId":"customerContent-organizationTemplates","summary":"Export an organization's template blueprints","description":"Lists customer-owned templates for export, one page at a time, with metadata and a short-lived download link for each stored body. Pages are ordered by ascending template ID: pass `nextCursor` back as `cursor` until it is `null`. Download links expire after one hour (`expiresAt`); request the page again for fresh links. Vetnio's read-only default catalog templates are excluded; workspace-owned copies, including managed ones, are included. Read-only. Covers the organization-level template blueprints that can be shared to its clinics. Requires admin rights in the organization. Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization to export (a UUID). The caller must be an admin of it.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization to export (a UUID). The caller must be an admin of it."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":512,"description":"Pagination cursor: the `nextCursor` value from the previous page. Omit for the first page, and keep the same owner and template category while paging. Items with an ID greater than the cursor are returned.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"}},{"in":"query","name":"limit","schema":{"default":20,"description":"Maximum number of templates per page, 1-50.","example":20,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"nextCursor":{"description":"Pass this value as `cursor` to fetch the next page. `null` when this is the last page.","example":null,"type":["string","null"]},"expiresInSeconds":{"type":"number","description":"Lifetime of every `contentUrl` on this page, in seconds.","example":3600},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the `contentUrl` links on this page stop working (ISO-8601 UTC). Download before then. Expiry does not affect the stored content.","example":"2026-09-28T09:15:00.000Z"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Organization template ID.","example":"2a9b8c7d-6e5f-4a3b-9c1d-0e2f4a6b8c0d"},"organizationId":{"type":"string","description":"ID of the organization that owns the template (UUID).","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"name":{"type":"string","description":"Template name shown in the app.","example":"Group clinical note"},"type":{"type":"string","enum":["clinical_note","referral","client_communication"],"description":"What the template produces:\n- `clinical_note` — the clinical note (medical record entry) for a consultation.\n- `referral` — a referral letter to another clinic or specialist.\n- `client_communication` — a message to the pet owner.","example":"clinical_note"},"createdBy":{"type":"string","description":"User ID (UUID) of the organization admin who created the template.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the template was created (ISO-8601 UTC).","example":"2026-03-14T10:02:11.000Z"},"artifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Download of the blueprint body, or null when no stored body exists."}},"required":["id","organizationId","name","type","createdBy","createdAt","artifact"],"additionalProperties":false,"title":"Exported organization template","description":"One organization-level template blueprint that can be shared to the organization's clinics."},"description":"Organization templates on this page, ordered by ascending ID."}},"required":["nextCursor","expiresInSeconds","expiresAt","items"],"additionalProperties":false,"title":"Organization template export page","description":"One page of the organization's template blueprints with download links."}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/organizations/{organizationId}/data-export/templates/versions":{"get":{"operationId":"customerContent-organizationTemplateVersions","summary":"List retained versions of an organization template","description":"Lists the retained stored versions of one template's body (`part=content`, the default) or of its imported instructions (`part=instructions`, document and meeting templates only), newest first, up to 50 per page. Pass `nextCursor` back as `cursor` until it is `null`. The template must belong to this scope, otherwise 404. Deleted templates and Vetnio's default catalog templates are not available. `currentVersionId` can change while you page if someone edits the template. Organization templates have no instructions part: `part=instructions` returns 400. Requires admin rights in the organization. Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization to export (a UUID). The caller must be an admin of it.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization to export (a UUID). The caller must be an admin of it."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque pagination cursor: the `nextCursor` value from the previous page of this template's versions. Omit for the first page. URL-encode it."}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionHistory"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/organizations/{organizationId}/data-export/templates/version":{"get":{"operationId":"customerContent-organizationTemplateVersion","summary":"Get a retained version of an organization template","description":"Returns the exact saved body of one retained template version as UTF-8 text, after checking that the template belongs to this scope. Take `versionId` from the versions list and URL-encode it. Read-only: it does not restore or modify the template. Returns 404 when the template, or that version of it, is not available. Organization templates have no instructions part: `part=instructions` returns 400. Requires admin rights in the organization. Accepts a browser session or a personal API key; organization and workspace API keys (`sk_org_…`, `sk_ws_…`) get 403.","tags":["data-export","customer-content"],"security":[{"Authorization":[]}],"parameters":[{"in":"path","name":"organizationId","schema":{"type":"string","description":"Identifier of the organization to export (a UUID). The caller must be an admin of it.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"required":true,"description":"Identifier of the organization to export (a UUID). The caller must be an admin of it."},{"in":"query","name":"part","schema":{"default":"content","description":"Which stored object of the template to read:\n- `content` — the template body itself.\n- `instructions` — the separate instructions object of an imported template (original wording and per-section instructions). Only workspace note and meeting templates have one; other kinds return 400.","example":"content","type":"string","enum":["content","instructions"]}},{"in":"query","name":"templateId","schema":{"type":"string","minLength":1,"maxLength":512,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"required":true,"description":"ID of the template, as returned in `items[].id` by the matching template export. It must belong to the workspace or organization in the path, otherwise 404."},{"in":"query","name":"versionId","schema":{"type":"string","minLength":1,"maxLength":2048,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"},"required":true,"description":"Opaque version ID from the versions list (`versions[].versionId`) or from `artifact.currentVersionId`. URL-encode it; it can contain characters such as `+`, `/` and `=`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVersionSnapshot"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal"]}},"/api-key":{"get":{"operationId":"apiKeys-me","summary":"Check the API key you are using","description":"Returns the calling key's organization, scope, status, limits and request counts for today and the last 30 days. Use it as a first call to confirm a key works and to look up the `organizationId` for the other data-export paths. Only organization (`sk_org_…`) and workspace (`sk_ws_…`) keys are accepted: a personal API key or a browser session gets 400 `BAD_REQUEST`. The call itself counts toward the key's rate limits.","tags":["data-export"],"security":[{"Authorization":[]}],"parameters":[],"responses":{"200":{"description":"The API key used for this request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["organization","workspace"]}},"/openapi.json":{"get":{"operationId":"meta-openapi","summary":"Get the OpenAPI document","description":"Get the OpenAPI document for the Vetnio API.","tags":["meta"],"security":[{"Authorization":[]}],"parameters":[{"in":"query","name":"apiVersion","schema":{"default":"v2","description":"Which API surface to describe: `v2` (current) or `v1` (legacy, same endpoints under `/api/v1`).","example":"v2","type":"string","enum":["v2","v1"]}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.BAD_REQUEST"}}}},"401":{"description":"Authorization not provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.UNAUTHORIZED"}}}},"403":{"description":"Insufficient access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.FORBIDDEN"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.NOT_FOUND"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/error.INTERNAL_SERVER_ERROR"}}}}},"x-vetnio-api-key-types":["personal","organization","workspace"]}}},"components":{"schemas":{"ConsultationListItem":{"type":"object","properties":{"id":{"type":"string","description":"Consultation ID (UUID).","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"workspaceId":{"type":"string","description":"ID of the workspace (clinic) that owns the consultation.","example":"furunculotic-loud-chihuahua"},"creatorId":{"type":"string","description":"User ID of the person who created the consultation. Always the caller for this endpoint.","example":"b8c9d0e1-f2a3-4456-bcde-678901234567"},"name":{"type":"string","description":"Display name of the consultation; may be an empty string.","example":"Bella - annual checkup"},"aiTitle":{"description":"Separate AI-generated title describing the consultation, refreshed after clinical-note saves when automatic naming is enabled. May be `null` when no title is generated or when the workspace uses generated titles as consultation names instead.","example":"Annual vaccination and dental check","type":["string","null"]},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp. The list is sorted by this value, newest first.","example":"2026-09-14T08:30:00.000Z","type":"string"},"recordingLanguageCode":{"description":"Language code chosen when the consultation was created (for example `sv`, `en`, `de`). Each uploaded recording carries its own language code, which is what transcription uses.","example":"en","type":["string","null"]},"recordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed. Same value as `uploadedRecordingDurationInMilliseconds`.","example":754000},"uploadedRecordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed.","example":754000},"isGeneratingClinicalNote":{"type":"boolean","description":"`true` while Vetnio is generating the clinical note for this consultation; set back to `false` when generation ends. Poll it to detect when a requested note is ready.","example":false},"isGeneratingCommunication":{"type":"boolean","description":"`true` while Vetnio is generating the owner communication (the client-facing summary) for this consultation; set back to `false` when generation ends.","example":false},"hasClinicalNote":{"type":"boolean","description":"`true` when a clinical note has been saved for the consultation (generated or written manually).","example":true},"hasCommunication":{"type":"boolean","description":"`true` when an owner communication has been saved for the consultation.","example":false},"discussionStatus":{"description":"Legacy field kept for backward compatibility. Current consultations always report `missing`; do not rely on it.","example":"missing","type":["string","null"]},"rating":{"description":"Legacy feedback field that current Vetnio clients no longer set; normally `null`.\n- `like` — the user rated the consultation output positively.\n- `dislike` — the user rated it negatively.","example":null,"anyOf":[{"type":"string","enum":["like","dislike"]},{"type":"null"}]},"ratingReason":{"description":"Legacy free-text reason for `rating`; normally `null`.","example":null,"type":["string","null"]},"clinicalNoteTemplateId":{"description":"ID of the template used to generate the clinical note, or `null` when none is selected.","example":"6a4dd7d0-0fe8-4f73-8e05-8898748da1ce","type":["string","null"]},"communicationTemplateId":{"description":"ID of the template used to generate the owner communication, or `null` when none is selected.","example":null,"type":["string","null"]},"referralTemplateId":{"description":"ID of the template used to generate a referral letter, or `null` when none is selected.","example":null,"type":["string","null"]},"clinicalNoteJsonTemplateId":{"description":"ID of the JSON (structured document) template bound to the clinical note, or `null`.","example":null,"type":["string","null"]},"isGeneratingReferral":{"description":"`true` while a referral letter is being generated for this consultation.","example":false,"type":"boolean"},"lastTranscribedRecordingId":{"description":"Recording ID (`<epoch-ms>-<language>`) of the latest recording included in the transcript, or `null` if nothing has been transcribed. Recordings whose ID sorts at or before this value are treated as already transcribed.","example":"1726302600000-en","type":["string","null"]},"lastSubmittedRecordingId":{"description":"Value of `lastTranscribedRecordingId` when the user last submitted the consultation for note generation in the Vetnio app. A different `lastTranscribedRecordingId` means audio was added since; `null` if never submitted.","example":"1726302600000-en","type":["string","null"]},"uploadedRecordingDurationInMillisecondsExcludingSilence":{"description":"Same as `recordingDurationInMilliseconds`, but with silent stretches (quieter than -40 dB) removed. `0` until the first upload has been processed.","example":612400,"type":"number"},"clientId":{"description":"ID of the client (pet owner) linked directly to the consultation by some practice-management integrations; usually `null`. Prefer `patientId` and the patient's owner.","example":null,"type":["string","null"]},"patientId":{"description":"ID of the patient linked to the consultation, or `null` if no patient is linked.","example":"c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f","type":["string","null"]},"isDeleted":{"description":"Whether the consultation is archived. Always `false` here because archived consultations are excluded from this list.","example":false,"type":"boolean"},"isHidden":{"description":"Whether the consultation was deleted (moved out of view) in the Vetnio app. Always `false` here because such consultations are excluded.","example":false,"type":"boolean"},"recordingDurationInMillisecondsExcludingSilence":{"description":"Same as `recordingDurationInMilliseconds`, but with silent stretches (quieter than -40 dB) removed. `0` until the first upload has been processed. Same value as `uploadedRecordingDurationInMillisecondsExcludingSilence`.","example":612400,"type":"number"},"searchableContent":{"description":"Plain-text copy of the latest saved clinical note (HTML tags removed, whitespace collapsed, at most 100,000 characters), kept for search. `null` until a clinical note is saved. Use `GET .../records` for the formatted note.","example":"Bella, 6-year-old Labrador, presented for annual vaccination. Weight 31 kg. Mild tartar on upper premolars.","type":["string","null"]},"externalId":{"description":"Identifier of the matching visit or consultation in the clinic's practice-management system, or `null` if the consultation is not linked to one. Free text; not unique.","example":"123456","type":["string","null"]}},"required":["id","workspaceId","creatorId","name","createdAt","recordingDurationInMilliseconds","uploadedRecordingDurationInMilliseconds","isGeneratingClinicalNote","isGeneratingCommunication","hasClinicalNote","hasCommunication"],"title":"Consultation list item","description":"A consultation as returned by the paginated list, with template IDs, audio duration, generation flags and a plain-text copy of the clinical note."},"ConsultationExportItem":{"type":"object","properties":{"structuredDocument":{"description":"Presigned GET URL for the separately stored structured JSON document, or null if none exists. The payload matches the JSON template used to generate it; it is not the rendered clinical note.","type":["string","null"]},"communication":{"description":"Presigned GET URL for the owner communication in its stored format, or null if none exists.","type":["string","null"]},"referral":{"description":"Presigned GET URL for the referral letter in its stored format, or null if none exists.","type":["string","null"]},"id":{"type":"string","description":"Consultation ID (UUID).","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Display name of the consultation; may be an empty string.","example":"Bella - annual checkup"},"creatorId":{"type":"string","description":"User ID of the person who created the consultation.","example":"b8c9d0e1-f2a3-4456-bcde-678901234567"},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp. The `createdAtFrom`/`createdAtBefore` filters and the sort order use this value.","example":"2026-09-14T08:30:00.000Z","type":"string"},"externalId":{"description":"Identifier of the matching visit in the clinic's practice-management system, or `null` if the consultation is not linked to one.","example":"123456","type":["string","null"]},"clinicalNoteTemplateId":{"description":"ID of the clinical note template selected for the consultation, or `null` if none is selected.","example":"6a4dd7d0-0fe8-4f73-8e05-8898748da1ce","type":["string","null"]},"audioRecording":{"description":"Presigned GET URL for the full consultation audio (all uploaded recordings joined into one 16 kHz mono WAV file), or `null` if no audio exists or it was removed by the clinic's audio-retention policy. Creator-only playback settings do not apply to authorized admin exports.","type":["string","null"]},"transcription":{"description":"Presigned GET URL for the full transcript as a UTF-8 plain-text file, or `null` if nothing has been transcribed yet.","type":["string","null"]},"clinicalNote":{"description":"Presigned GET URL for the stored clinical note (HTML, or JSON for structured notes), or `null` if no note has been saved yet.","type":["string","null"]}},"required":["structuredDocument","communication","referral","id","name","creatorId","createdAt","externalId","clinicalNoteTemplateId","audioRecording","transcription","clinicalNote"],"title":"Consultation export item","description":"One consultation in the export list with its metadata and presigned download URLs. Archived and deleted consultations are included and are not flagged."},"TemplateListItem":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template (a UUID). Pass it as `templateId` when generating a record or managing the template.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"},"name":{"type":"string","description":"Template Name shown in Vetnio's template lists and pickers. Not unique within a clinic. An empty string when the template has no name.","example":"Follow-up - clinical team"},"type":{"anyOf":[{"type":"string","enum":["clinical_note","referral","client_communication"],"description":"The Template Type: which kind of document the template writes. It decides where Vetnio offers the template and which instructions its AI template assistant follows.\n- `clinical_note` — Clinical Note: the medical record of the visit, for the clinical team (record type `clinical note`).\n- `client_communication` — Client Communication: an owner-facing message about the visit (record type `communication`).\n- `referral` — Referral: a letter to or from another clinician or clinic (record type `referral`).","example":"clinical_note"},{"type":"null"}],"description":"The Template Type: which kind of document the template writes (`clinical_note`, `client_communication` or `referral`). Always set in practice; templates created without a type are `clinical_note`.","example":"clinical_note"},"creatorId":{"type":"string","description":"User ID (a UUID) of the person who created the template, or who duplicated it from another template. For templates Vetnio added to the clinic, the user who triggered that provisioning.","example":"5b1e9d3c-27a4-4f0e-8c6d-2e9f71a4b852"},"creatorRole":{"type":"string","enum":["member","admin","superadmin"],"description":"The creator's role in the clinic when the template was created; it is not updated if their role changes later. Members' access to a template depends on it under the clinic's template permissions.\n- `member` — created by a regular clinic member.\n- `admin` — created by a clinic admin, or provisioned by Vetnio.\n- `superadmin` — created by a clinic super-admin.","example":"admin"},"createdAt":{"description":"When the template was created, as an ISO-8601 UTC timestamp.","example":"2026-09-14T08:30:00.000Z","type":"string"},"jsonTemplateId":{"description":"ID of the JSON template (structured template) linked to this template, or `null`. When set, clinical notes generated on consultations that use this template are produced as structured JSON documents following that JSON template, with this template's instructions guiding the field content.","example":null,"type":["string","null"]},"isDefault":{"type":"boolean","description":"`true` for a Vetnio default template, added to the clinic from Vetnio's default template library. Default templates are read-only: updating or deleting one returns 403. Duplicate it to get an editable copy.","example":false},"isHidden":{"type":"boolean","description":"`true` when the calling user has hidden this template from their own picker.","example":false},"isPinned":{"type":"boolean","description":"`true` when the calling user has starred this template.","example":false},"isManaged":{"type":"boolean","description":"`true` when Vetnio or the clinic's organization provisioned the template (Vetnio defaults, organization templates, practice-management-system integrations) rather than a clinic user writing it. Managed templates stay visible to members under every template-permission mode, and members cannot edit them unless they created them.","example":false}},"required":["id","name","type","creatorId","creatorRole","createdAt","jsonTemplateId","isDefault","isHidden","isPinned","isManaged"],"title":"Template","description":"A prompt template: reusable writing instructions (headings plus guidance on what belongs under each) that Vetnio follows when it generates a clinical note, client communication or referral letter. The template body is not included."},"Client":{"type":"object","properties":{"id":{"type":"string","description":"Client id (UUID), generated by Vetnio.","example":"e1f2a3b4-c5d6-4789-efab-901234567890"},"name":{"description":"The owner's full name, free text. `null` when not recorded, for example for the placeholder owner created with a patient that had no owner details.","example":"Alex Morgan","type":["string","null"]},"address":{"description":"The owner's street address, free text. `null` when not recorded.","example":"12 Harbour Street, Riverside","type":["string","null"]},"zipCode":{"description":"The owner's postal code, free text. `null` when not recorded.","example":"114 51","type":["string","null"]},"phoneNumbers":{"type":"array","items":{"type":"string","description":"One phone number, as stored.","example":"+46701234567"},"description":"The owner's phone numbers, stored as given (no normalisation). E.164 format such as `+46701234567` is recommended. Empty array when none are recorded."},"email":{"description":"The owner's email address. Stored as given; the format is not validated. `null` when not recorded.","example":"alex.morgan@example.com","type":["string","null"]}},"required":["id","name","address","zipCode","phoneNumbers","email"],"title":"Client (pet owner)","description":"An animal owner registered in the workspace. A client can own any number of patients. Clients are shared by every member of the workspace and are also created automatically when patients are synced from a connected practice-management system."},"WorkspaceListItem":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the workspace (veterinary clinic), generated by Vetnio as three lowercase words joined by hyphens. Pass it as the `workspaceId` path parameter of every workspace-scoped endpoint.","example":"furunculotic-loud-chihuahua"},"name":{"type":"string","description":"Display name of the clinic, as set by its admins. An empty string if no name was ever set.","example":"Riverside Animal Clinic"},"role":{"type":"string","enum":["member","admin","superadmin"],"description":"The authenticated user's own membership role in this workspace. Roles are cumulative and decide which endpoints the user may call:\n- `member` — clinician access: consultations, recordings, notes, patients and VetsGPT.\n- `admin` — everything a member can do, plus member management, billing, workspace settings and the workspace data-export endpoints.\n- `superadmin` — everything an admin can do, plus deleting the workspace and changing other superadmins' roles. The creator of a workspace starts as its superadmin, and a workspace always keeps at least one.","example":"admin"},"phoneCallIntegrationEnabled":{"description":"Whether the clinic receives phone calls into Vetnio through a telephony integration. Use it to show phone-call features only for clinics that have them. Always present in practice.","example":false,"type":"boolean"},"revenueRecoveryEnabled":{"description":"Whether revenue recovery (suggestions for billable items missed in a consultation) is enabled for the clinic. Use it to show those features only where they are switched on. Always present in practice.","example":false,"type":"boolean"}},"required":["id","name","role"],"title":"Workspace list item","description":"A workspace the authenticated user belongs to, with the user's role in it."},"TranscriptionTermList":{"type":"object","properties":{"terms":{"type":"array","items":{"type":"string","description":"One term, in its stored spelling.","example":"Librela"},"description":"Terms in their stored spelling and order. Up to 200 terms, each at most 50 characters and four words. Empty when no list is saved.","example":["Librela","Apoquel","Bravecto"]},"version":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Edit-concurrency revision of the list: 1 or higher for a saved list, 0 when none is saved. It increases with each save; earlier contents are not retained.","example":3},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the list was last saved (ISO 8601, UTC). `null` when no list is saved.","example":"2026-09-28T08:15:00.000Z"},"updatedBy":{"description":"ID of the user who last saved the list (a UUID). `null` when no list is saved or that user's account has been deleted.","example":"7d1f0c3e-2a4b-4e8f-9c61-5b2a8d4e7f10","type":["string","null"]}},"required":["terms","version","updatedAt","updatedBy"],"title":"Transcription term list","description":"The scope's current custom transcription vocabulary: names, abbreviations and specialist terms used as spelling and recognition hints. When no list has been saved, `terms` is empty, `version` is 0 and `updatedAt` and `updatedBy` are `null`."},"error.BAD_REQUEST":{"type":"object","properties":{"message":{"type":"string","description":"The error message","example":"Invalid input data"},"code":{"type":"string","description":"The error code","example":"BAD_REQUEST"},"issues":{"description":"An array of issues that were responsible for the error","example":[],"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}},"data":{"type":"object","description":"Machine-readable details, present on every error response.","properties":{"code":{"type":"string","description":"Same value as the top-level `code`.","example":"NOT_FOUND"},"httpStatus":{"type":"integer","description":"The HTTP status of the response.","example":404},"path":{"type":"string","description":"Internal procedure name, useful when contacting support. Do not branch on it."},"zodError":{"type":["object","null"],"description":"Field-level validation problems for a `400`, as `{ formErrors, fieldErrors }`; otherwise `null`."},"reason":{"type":"string","description":"A stable token for some refusals, such as `archived_consultation`. Absent for most errors.","example":"archived_consultation"}}}},"required":["message","code"],"additionalProperties":true,"title":"Invalid input data error (400)","description":"The error information","example":{"code":"BAD_REQUEST","message":"Invalid input data","issues":[]}},"error.UNAUTHORIZED":{"type":"object","properties":{"message":{"type":"string","description":"The error message","example":"Authorization not provided"},"code":{"type":"string","description":"The error code","example":"UNAUTHORIZED"},"issues":{"description":"An array of issues that were responsible for the error","example":[],"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}},"data":{"type":"object","description":"Machine-readable details, present on every error response.","properties":{"code":{"type":"string","description":"Same value as the top-level `code`.","example":"NOT_FOUND"},"httpStatus":{"type":"integer","description":"The HTTP status of the response.","example":404},"path":{"type":"string","description":"Internal procedure name, useful when contacting support. Do not branch on it."},"zodError":{"type":["object","null"],"description":"Field-level validation problems for a `400`, as `{ formErrors, fieldErrors }`; otherwise `null`."},"reason":{"type":"string","description":"A stable token for some refusals, such as `archived_consultation`. Absent for most errors.","example":"archived_consultation"}}}},"required":["message","code"],"additionalProperties":true,"title":"Authorization not provided error (401)","description":"The error information","example":{"code":"UNAUTHORIZED","message":"Authorization not provided","issues":[]}},"error.FORBIDDEN":{"type":"object","properties":{"message":{"type":"string","description":"The error message","example":"Insufficient access"},"code":{"type":"string","description":"The error code","example":"FORBIDDEN"},"issues":{"description":"An array of issues that were responsible for the error","example":[],"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}},"data":{"type":"object","description":"Machine-readable details, present on every error response.","properties":{"code":{"type":"string","description":"Same value as the top-level `code`.","example":"NOT_FOUND"},"httpStatus":{"type":"integer","description":"The HTTP status of the response.","example":404},"path":{"type":"string","description":"Internal procedure name, useful when contacting support. Do not branch on it."},"zodError":{"type":["object","null"],"description":"Field-level validation problems for a `400`, as `{ formErrors, fieldErrors }`; otherwise `null`."},"reason":{"type":"string","description":"A stable token for some refusals, such as `archived_consultation`. Absent for most errors.","example":"archived_consultation"}}}},"required":["message","code"],"additionalProperties":true,"title":"Insufficient access error (403)","description":"The error information","example":{"code":"FORBIDDEN","message":"Insufficient access","issues":[]}},"error.NOT_FOUND":{"type":"object","properties":{"message":{"type":"string","description":"The error message","example":"Not found"},"code":{"type":"string","description":"The error code","example":"NOT_FOUND"},"issues":{"description":"An array of issues that were responsible for the error","example":[],"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}},"data":{"type":"object","description":"Machine-readable details, present on every error response.","properties":{"code":{"type":"string","description":"Same value as the top-level `code`.","example":"NOT_FOUND"},"httpStatus":{"type":"integer","description":"The HTTP status of the response.","example":404},"path":{"type":"string","description":"Internal procedure name, useful when contacting support. Do not branch on it."},"zodError":{"type":["object","null"],"description":"Field-level validation problems for a `400`, as `{ formErrors, fieldErrors }`; otherwise `null`."},"reason":{"type":"string","description":"A stable token for some refusals, such as `archived_consultation`. Absent for most errors.","example":"archived_consultation"}}}},"required":["message","code"],"additionalProperties":true,"title":"Not found error (404)","description":"The error information","example":{"code":"NOT_FOUND","message":"Not found","issues":[]}},"error.INTERNAL_SERVER_ERROR":{"type":"object","properties":{"message":{"type":"string","description":"The error message","example":"Internal server error"},"code":{"type":"string","description":"The error code","example":"INTERNAL_SERVER_ERROR"},"issues":{"description":"An array of issues that were responsible for the error","example":[],"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}},"data":{"type":"object","description":"Machine-readable details, present on every error response.","properties":{"code":{"type":"string","description":"Same value as the top-level `code`.","example":"NOT_FOUND"},"httpStatus":{"type":"integer","description":"The HTTP status of the response.","example":404},"path":{"type":"string","description":"Internal procedure name, useful when contacting support. Do not branch on it."},"zodError":{"type":["object","null"],"description":"Field-level validation problems for a `400`, as `{ formErrors, fieldErrors }`; otherwise `null`."},"reason":{"type":"string","description":"A stable token for some refusals, such as `archived_consultation`. Absent for most errors.","example":"archived_consultation"}}}},"required":["message","code"],"additionalProperties":true,"title":"Internal server error error (500)","description":"The error information","example":{"code":"INTERNAL_SERVER_ERROR","message":"Internal server error","issues":[]}},"UploadedFile":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that.","example":"8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"},"originalFileName":{"type":"string","minLength":1,"description":"The file name as it was on the uploader's device. Shown to users in the UI. May contain characters that are unsafe for object-storage keys, which is why it is never used as a storage identifier.","example":"xray_bella_2024-06-12.pdf"},"mimeType":{"type":"string","description":"MIME type as recorded at upload time.","example":"application/pdf"},"sizeBytes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"Exact size of the file in bytes. `finalizeUpload` compares it with the size of the uploaded object and returns `412` until they match, so it must equal the number of bytes you `PUT`. No maximum is enforced by the API.","example":184320},"status":{"type":"string","enum":["uploaded","analyzing","analyzed","failed"],"description":"Lifecycle state of the file:\n- `uploaded` — the upload slot was reserved by `initUpload`; the bytes may not have been sent yet and no extraction has started. Call `finalizeUpload` after the `PUT`.\n- `analyzing` — extraction is running in the background (usually seconds; longer for large PDFs).\n- `analyzed` — extraction succeeded; the extracted text is available to document generation and chat features.\n- `failed` — extraction errored; inspect `errorMessage`. Calling `finalizeUpload` again retries the extraction.","example":"analyzed"},"createdAt":{"description":"When the upload was initialized, as an ISO-8601 UTC timestamp. Does not reflect when the bytes arrived or when analysis completed.","example":"2026-09-14T08:42:10.000Z","type":"string"},"errorMessage":{"description":"Human-readable error from the content extractor. Populated only when `status` is `failed`, otherwise `null`.","type":["string","null"]}},"required":["fileName","originalFileName","mimeType","sizeBytes","status","createdAt","errorMessage"],"additionalProperties":false,"title":"Uploaded file","description":"A file attached to a consultation — typically lab results, imaging, or prior medical history provided by the vet or pet owner. Vetnio extracts the content in the background so it can be referenced by the AI scribe and chat features."},"UploadedFileInitResult":{"type":"object","properties":{"uploadUrl":{"type":"string","format":"uri","description":"Presigned S3 URL valid for 1 hour. `PUT` the raw file bytes (no multipart form) to this URL before it expires. If it lapses, delete this file and call `initUpload` again; a second `initUpload` with the same `sha256` returns `409` while this slot exists.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/consultationInformation/furunculotic-loud-chihuahua/uploadedFiles/a1b2c3d4-e5f6-7890-abcd-ef1234567890/8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a?X-Amz-Expires=3600&X-Amz-Signature=..."},"s3Key":{"type":"string","description":"Internal S3 object key where the file will live. Exposed for debugging only — clients should not depend on its format or attempt to access S3 directly with it.","example":"consultationInformation/furunculotic-loud-chihuahua/uploadedFiles/a1b2c3d4-e5f6-7890-abcd-ef1234567890/8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"},"fileName":{"type":"string","minLength":1,"description":"Stable internal identifier for the file — a server-generated UUID returned by `initUpload`. Used in every subsequent endpoint (finalize, download, delete). Not intended for display; use `originalFileName` for that.","example":"8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a"}},"required":["uploadUrl","s3Key","fileName"],"additionalProperties":false,"title":"Uploaded file init result","description":"Carries the presigned URL the client must `PUT` to, plus the `fileName` identifier to use when calling `finalizeUpload`."},"UploadedFileDownload":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Presigned S3 URL valid for 1 hour that lets the client `GET` the original file bytes. Call this endpoint again to obtain a fresh URL if it expires.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/consultationInformation/furunculotic-loud-chihuahua/uploadedFiles/a1b2c3d4-e5f6-7890-abcd-ef1234567890/8f1c4a60-7e3b-4b6f-9a9d-6d9f3c8b2e4a?X-Amz-Expires=3600&X-Amz-Signature=..."},"originalFileName":{"type":"string","minLength":1,"description":"The file name as it was on the uploader's device. Shown to users in the UI. May contain characters that are unsafe for object-storage keys, which is why it is never used as a storage identifier.","example":"xray_bella_2024-06-12.pdf"},"mimeType":{"type":"string","description":"MIME type as recorded at upload time — use this for the `Content-Type` response header when serving the download to the end user.","example":"application/pdf"}},"required":["url","originalFileName","mimeType"],"additionalProperties":false,"title":"Uploaded file download","description":"Presigned download URL plus the display metadata a browser needs to save the file under its original name and render it with the correct content type."},"OkResponse":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always `true` on success.","example":true}},"required":["ok"],"additionalProperties":false,"title":"Ok response","description":"Generic success envelope returned by mutations that do not produce a resource body."},"ConsultationDetail":{"type":"object","properties":{"id":{"type":"string","description":"Consultation ID (UUID), generated by Vetnio when the consultation is created.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Display name of the consultation. Free text set at creation or via `PATCH .../consultations/{consultationId}`; may be an empty string.","example":"Bella - annual checkup"},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp.","example":"2026-09-14T08:30:00.000Z","type":"string"},"recordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed.","example":754000},"recordingDurationInMillisecondsExcludingSilence":{"description":"Same as `recordingDurationInMilliseconds`, but with silent stretches (quieter than -40 dB) removed. `0` until the first upload has been processed.","example":612400,"type":["number","null"]},"isGeneratingClinicalNote":{"type":"boolean","description":"`true` while Vetnio is generating the clinical note for this consultation; set back to `false` when generation ends. Poll it to detect when a requested note is ready.","example":false},"isGeneratingCommunication":{"type":"boolean","description":"`true` while Vetnio is generating the owner communication (the client-facing summary) for this consultation; set back to `false` when generation ends.","example":false},"isReadyForGeneration":{"type":"boolean","description":"`true` when document generation can start: no uploaded recording is still waiting for transcription, and the consultation has transcript text, a text partial transcription or an analyzed uploaded file. Recordings that failed permanently do not block readiness. Always `false` for archived consultations.","example":true},"clinicalNoteJsonTemplateId":{"description":"ID of the JSON (structured document) template bound to this consultation's clinical note, or `null` if none is bound. Set automatically when the selected clinical note template is linked to a JSON template; fetch that template's schema to render a structured note.","example":null,"type":["string","null"]},"linkEntryId":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"ID of the journal entry this consultation was exported to in the Link practice-management system, or `null` if it has not been exported to Link. Only used by clinics with the Link integration.","example":null},"linkJournalId":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"ID of the Link journal (the animal's journal) that holds `linkEntryId`, or `null`. Combine with `linkEntryId` to build a deep link into Link.","example":null},"transcriptionStatus":{"type":"string","enum":["idle","processing","completed","failed"],"description":"Overall state of audio transcription for the consultation. Poll this after `POST .../transcriptions/start`; stop polling on `completed` or `failed`.\n- `idle` — no audio recording has been uploaded yet (text added as a partial transcription does not change this).\n- `processing` — at least one uploaded recording is not transcribed yet. This includes recordings uploaded before transcription was started: the status does not advance until `POST .../transcriptions/start` (or a transcript wait) runs.\n- `completed` — every uploaded recording has been transcribed (recordings shorter than one second count as transcribed with no text).\n- `failed` — nothing is pending, but at least one recording failed permanently; see `transcriptionFailureReason`. Text from the other recordings is still in the transcript.","example":"completed"},"transcriptionFailureReason":{"anyOf":[{"type":"string","enum":["unreadable_recording","processing_failed","transcription_failed"]},{"type":"null"}],"description":"Why a recording failed permanently, when `transcriptionStatus` is `failed`; otherwise `null`.\n- `unreadable_recording` — the uploaded file is empty or is not decodable audio.\n- `processing_failed` — audio processing kept failing and the retries are used up.\n- `transcription_failed` — the speech-to-text providers rejected the audio.","example":null}},"required":["id","name","createdAt","recordingDurationInMilliseconds","recordingDurationInMillisecondsExcludingSilence","isGeneratingClinicalNote","isGeneratingCommunication","isReadyForGeneration","clinicalNoteJsonTemplateId","linkEntryId","linkJournalId","transcriptionStatus","transcriptionFailureReason"],"additionalProperties":false,"title":"Consultation detail","description":"Status view of a single consultation: name, audio duration, transcription state and document-generation flags."},"ConsultationPage":{"type":"object","properties":{"consultations":{"type":"array","items":{"$ref":"#/components/schemas/ConsultationListItemOutput"},"description":"Consultations on the requested page. Consultations that belong to the same timeline (a series of follow-up visits) are returned together and count as one entry toward the page size, so a page can hold more items than `consultationsPerPage`."},"count":{"type":"number","description":"Number of matching entries across all pages, where a timeline of linked consultations counts once.","example":42},"itemsPerPage":{"type":"number","description":"Echo of the requested `consultationsPerPage`.","example":10},"totalPages":{"type":"number","description":"Number of pages, `ceil(count / itemsPerPage)`; `0` when nothing matches.","example":5}},"required":["consultations","count","itemsPerPage","totalPages"],"additionalProperties":false,"title":"Consultation page","description":"One page of the caller's own consultations in the workspace, newest first, with totals for pagination."},"ConsultationCreated":{"type":"object","properties":{"consultationId":{"type":"string","description":"ID of the consultation that was created, or of the existing consultation returned because its `externalId` matched.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"recordingUploadUrl":{"type":"string","format":"uri","description":"Presigned URL for uploading the first audio recording with `PUT` (raw bytes as the body), valid for 24 hours. It behaves exactly like a URL from `GET .../recording-upload-url`: its recording ID is fixed now, so upload promptly and fetch a new URL for each further segment.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/recordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302600000-en?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=86400&X-Amz-Signature=..."},"consultation":{"type":"object","properties":{"id":{"type":"string","description":"Consultation ID (UUID); same as `consultationId`.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Display name. When an existing consultation was returned, this is its stored name, not the name in the request.","example":"Bella - vaccination"},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp.","example":"2026-09-14T08:30:00.000Z","type":"string"},"recordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed. `0` for a new consultation.","example":0},"uploadedRecordingDurationInMilliseconds":{"type":"number","description":"Same value as `recordingDurationInMilliseconds`.","example":0},"isGeneratingClinicalNote":{"type":"boolean","description":"`true` while Vetnio is generating the clinical note for this consultation; set back to `false` when generation ends. Poll it to detect when a requested note is ready.","example":false},"isGeneratingCommunication":{"type":"boolean","description":"`true` while Vetnio is generating the owner communication (the client-facing summary) for this consultation; set back to `false` when generation ends.","example":false},"externalId":{"description":"Identifier of the matching visit or consultation in the clinic's practice-management system, or `null` if the consultation is not linked to one. Free text; not unique.","example":"123456","type":["string","null"]}},"required":["id","name","createdAt","recordingDurationInMilliseconds","uploadedRecordingDurationInMilliseconds","isGeneratingClinicalNote","isGeneratingCommunication","externalId"],"additionalProperties":false,"title":"Created consultation summary","description":"Summary of the created (or matched) consultation. Fetch `GET .../consultations/{consultationId}` for status fields."}},"required":["consultationId","recordingUploadUrl","consultation"],"additionalProperties":false,"title":"Consultation created","description":"The new (or matched) consultation plus a presigned URL for uploading its first recording."},"ConsultationTranscript":{"type":"object","properties":{"transcription":{"type":"string","description":"Full transcript as plain text, or an empty string if nothing has been transcribed yet. Built from the consultation's partial transcriptions in recording order, joined with a single space; text partial transcriptions are included verbatim. Within a recording, a change of speaker starts a new paragraph (blank line), but speakers are not labelled. Medical terms that the spelling check is very confident about are annotated inline as `term (Suggestion?)`.","example":"So this is Bella, she's here for her annual vaccines.\n\nGreat. Any problems since last time?\n\nShe's still on Rimadil (Rimadyl?) for her hip, otherwise fine."}},"required":["transcription"],"additionalProperties":false,"title":"Consultation transcript","description":"The consultation's saved full transcript."},"ConsultationDataExport":{"type":"object","properties":{"structuredDocument":{"description":"Presigned GET URL for the separately stored structured JSON document, or null if none exists. The payload matches the JSON template used to generate it; it is not the rendered clinical note.","type":["string","null"]},"communication":{"description":"Presigned GET URL for the owner communication in its stored format, or null if none exists.","type":["string","null"]},"referral":{"description":"Presigned GET URL for the referral letter in its stored format, or null if none exists.","type":["string","null"]},"consultationId":{"type":"string","description":"The consultation these artifacts belong to.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"workspaceId":{"type":"string","description":"The workspace that owns the consultation.","example":"furunculotic-loud-chihuahua"},"externalId":{"description":"External ID from an integrated system, or `null` if the consultation is not linked to one.","example":"123456","type":["string","null"]},"expiresInSeconds":{"type":"number","description":"How long each presigned download URL remains valid, in seconds.","example":3600},"expiresAt":{"type":"string","description":"ISO-8601 timestamp at which the download URLs expire. Provided for convenience so clients can display a countdown without computing it themselves.","example":"2026-04-16T13:00:00.000Z"},"audioRecording":{"description":"Presigned GET URL for the full consultation audio: every uploaded recording joined into one 16 kHz mono WAV file, silence included. `null` if no audio exists (for example a text-only consultation, or audio removed by the clinic's audio-retention policy). Creator-only playback settings do not apply to authorized admin exports.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/fullRecordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890?X-Amz-Expires=3600&X-Amz-Signature=...","type":["string","null"]},"transcription":{"description":"Presigned GET URL for the full transcript as a UTF-8 plain-text file (the same text as `GET .../transcription`), or `null` if nothing has been transcribed yet.","type":["string","null"]},"clinicalNote":{"description":"Presigned GET URL for the stored clinical note (HTML, or JSON for structured notes), or `null` if no note has been saved yet.","type":["string","null"]}},"required":["structuredDocument","communication","referral","consultationId","workspaceId","externalId","expiresInSeconds","expiresAt","audioRecording","transcription","clinicalNote"],"additionalProperties":false,"title":"Consultation data export","description":"Presigned download URLs for a consultation's retained artifacts: audio recording, transcription, clinical note, structured JSON document, owner communication, and referral letter. Each URL is time-limited; fields are `null` when the corresponding artifact does not exist."},"ConsultationExportList":{"type":"object","properties":{"consultations":{"type":"array","items":{"$ref":"#/components/schemas/ConsultationExportItemOutput"},"description":"Consultations on the current page, each with presigned download URLs for its artifacts."},"count":{"type":"number","description":"Total consultations matching the filters across all pages, including archived and deleted ones.","example":142},"page":{"type":"number","description":"Current page number (1-indexed).","example":1},"pageSize":{"type":"number","description":"Consultations per page.","example":10},"totalPages":{"type":"number","description":"Total pages given the current page size.","example":15},"expiresInSeconds":{"type":"number","description":"How long each presigned URL remains valid, in seconds.","example":3600},"expiresAt":{"type":"string","description":"ISO-8601 timestamp at which the presigned URLs in this response expire.","example":"2026-04-16T14:00:00.000Z"}},"required":["consultations","count","page","pageSize","totalPages","expiresInSeconds","expiresAt"],"additionalProperties":false,"title":"Consultation export list","description":"Paginated list of consultations with presigned download URLs for audio, transcription, clinical note, structured JSON document, owner communication, and referral letter. Workspace admin only."},"RecordVersionSummary":{"type":"object","properties":{"versionId":{"type":"string","description":"Opaque identifier of one saved version, assigned by Vetnio's storage. Treat it as an unparsed string: it can contain characters such as `+`, `/` and `=`, so URL-encode it when passing it back as a query parameter.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY+MTRCxf3vjVBH40Nr8X8gdRQBpUMLUo"},"lastModified":{"anyOf":[{"description":"When this version was saved, as an ISO-8601 UTC timestamp.","type":"string","format":"date-time"},{"type":"null"}],"description":"When this version was saved, as an ISO-8601 UTC timestamp. `null` only if storage did not report a time.","example":"2026-10-01T11:55:00.000Z"},"isLatest":{"type":"boolean","description":"`true` for the version that is the record's current content. All versions are `false` after the record has been deleted, because the deletion itself is the latest change.","example":false},"changeType":{"type":"string","enum":["generated","edit"],"description":"How this version was saved:\n- `generated` — written by Vetnio's AI generation. Also reported when the version's metadata cannot be read, so it is not proof of AI origin.\n- `edit` — saved by a person: an edit in Vetnio, a write through Create or Update a record, or a restore of an earlier version.\nThis says nothing about clinical approval or correctness.","example":"generated"},"size":{"description":"Stored size of this version in bytes, or `null` if unavailable. For clinical notes it includes a small amount of internal padding, so it can be larger than the byte length of `content`.","example":1843,"type":["number","null"]},"contentType":{"description":"Media type of the saved content: `text/html` for free-text records, `application/json` for a clinical note generated from a structured template. `null` if unavailable.","example":"text/html","type":["string","null"]}},"required":["versionId","lastModified","isLatest","changeType","size","contentType"],"additionalProperties":false,"title":"Record version summary","description":"Metadata for one saved version of a record. Fetch its content with Read a retained record version."},"VetsgptChatListItem":{"type":"object","properties":{"sharing":{"type":"object","properties":{"permission":{"type":"string","enum":["owner","view","contribute"],"description":"The current actor's effective permission for this chat."},"owner":{"type":"object","properties":{"id":{"type":"string","description":"User ID of the chat owner; grants do not transfer ownership."},"name":{"description":"Owner display name, or null when unavailable.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"The chat's owner identity."},"isShared":{"type":"boolean","description":"Whether at least one current workspace member has an explicit grant."},"recipientCount":{"type":"number","description":"Number of current explicitly granted recipients, excluding the owner."},"firstRecipientName":{"description":"First recipient display name for a compact sharing summary, or null.","type":["string","null"]}},"required":["permission","owner","isShared","recipientCount","firstRecipientName"],"additionalProperties":false,"description":"Owner and effective sharing summary; underlying clinical source access is not granted by chat sharing."},"chat_id":{"description":"Chat id. Use it as `chatId` in the other VetsGPT endpoints.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53","type":"string"},"title":{"description":"Chat title as shown in the VetsGPT sidebar.","example":"NSAID dosing in a dog with CKD","type":"string"},"created_at":{"description":"When the chat was created (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z","type":"string"},"last_updated_at":{"description":"When the chat last changed (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z","type":"string"},"searchable_content":{"description":"Plain-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.","type":"string"}},"required":["sharing"],"additionalProperties":false,"title":"VetsGPT chat list item","description":"Summary of one of the caller's VetsGPT chats. Messages are not included; fetch them with the messages endpoint."},"VetsgptChatContext":{"type":"object","properties":{"consultations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Consultation id.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Consultation 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.","example":"Bella - vaccination"}},"required":["id","name"],"additionalProperties":false,"title":"VetsGPT consultation context","description":"A consultation attached to the chat as context."},"description":"Consultations attached to the chat as context, in attachment order. Empty when none are attached."},"patient":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Patient id.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"name":{"type":"string","description":"Patient name, or `Unknown` when the record has no name.","example":"Bella"},"species":{"description":"Species as recorded on the patient, or `null`.","example":"Dog","type":["string","null"]},"identifier":{"description":"Patient identifier (for example a microchip number), or `null`.","example":"752098100012345","type":["string","null"]}},"required":["id","name","species","identifier"],"additionalProperties":false},{"type":"null"}],"title":"VetsGPT patient context","description":"The patient attached to the chat as context, or `null` when none is attached or the patient has since been deleted."}},"required":["consultations","patient"],"additionalProperties":false,"title":"VetsGPT chat context","description":"The consultation and patient context attached to a VetsGPT chat. VetsGPT uses it when answering later messages in the chat."},"VetsgptMessage":{"type":"object","properties":{"messageId":{"type":"string","description":"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.","example":"rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b"},"timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the message was stored (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z"},"role":{"type":"string","enum":["user","assistant"],"description":"Who wrote the message:\n- `user` — the vet's question.\n- `assistant` — VetsGPT's answer.","example":"assistant"},"content":{"type":"string","description":"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)`.","example":"Meloxicam is generally avoided in dogs with CKD unless the benefit outweighs the risk..."},"attachments":{"description":"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.","example":["chats/furunculotic-loud-chihuahua/3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53/attachments/6a1e0f3c-2b9d-4c7e-8f5a-1d3b9e7c2a40"],"type":"array","items":{"type":"string"}},"feedback":{"type":"string","enum":["positive","negative","none"],"description":"The vet's rating of the message:\n- `positive` — rated helpful (thumbs up).\n- `negative` — rated unhelpful (thumbs down).\n- `none` — not rated, or the rating was cleared.","example":"none"}},"required":["messageId","timestamp","role","content","feedback"],"additionalProperties":false,"title":"VetsGPT message","description":"One message in a VetsGPT chat, as returned by the ask endpoint."},"LinkStatus":{"oneOf":[{"type":"object","properties":{"configured":{"type":"boolean","const":false,"description":"`false`: the calling user has not saved Link credentials in this workspace. Every other Link endpoint returns `412 PRECONDITION_FAILED` until they do.","example":false}},"required":["configured"],"additionalProperties":false,"title":"Link status (not configured)","description":"No Link integration is stored for the calling user in this workspace."},{"type":"object","properties":{"configured":{"type":"boolean","const":true,"description":"`true`: the calling user has saved Link credentials in this workspace and the other Link endpoints can be used.","example":true},"subdomain":{"type":"string","description":"The clinic's Link tenant subdomain, i.e. the `<subdomain>` in `https://<subdomain>.linkjournal.se`.","example":"riverside"},"defaultLocationId":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Link location (clinic site) used for new journal entries when the export request has no `locationId`. `null` when none was chosen and the tenant has more than one active location; exports must then pass `locationId`.","example":346},"updatedAt":{"type":"string","description":"When the Link credentials were last saved (ISO-8601 UTC).","example":"2026-09-30T08:15:00.000Z"}},"required":["configured","subdomain","defaultLocationId","updatedAt"],"additionalProperties":false,"title":"Link status (configured)","description":"A Link integration is stored for the calling user in this workspace."}],"title":"Link integration status","description":"Whether the calling user has connected Vetnio to a Link tenant in this workspace. Link credentials are stored per user and workspace, so two vets in the same clinic can see different results. Discriminated by `configured`.","type":"object"},"LinkTemplateSummary":{"type":"object","properties":{"id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Link form template id. Pass it to the template detail and resolve endpoints.","example":3423},"name":{"type":"string","description":"Template name as shown in Link.","example":"Allmän undersökning hund"},"description":{"description":"Template description from Link, or `null` when it has none.","example":null,"type":["string","null"]},"kind":{"type":"string","description":"Link template kind, passed through from Link. Values documented by Link: `animal_journal`, `animal_certificate`, `herd_journal`, `animal_and_herd_journal`, `quotation`.","example":"animal_journal"},"status":{"type":"string","description":"Link template status, passed through from Link. Values documented by Link: `public` (published, usable for new entries) and `edit` (draft).","example":"public"}},"required":["id","name","description","kind","status"],"additionalProperties":false,"title":"Link template summary","description":"A journal form template defined in the clinic's Link tenant. A template defines the fields of a Link journal entry; Vetnio fills those fields from a structured clinical note."},"LinkAnimal":{"type":"object","properties":{"id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Link animal id. Pass it as `animalId` to the compatible-entries and export endpoints.","example":1234567},"name":{"type":"string","description":"Animal name from Link.","example":"Bella"},"kindName":{"description":"Species name from Link (Link calls it kind), or `null`.","example":"Hund","type":["string","null"]},"breedName":{"description":"Breed name from Link, or `null`.","example":"Labrador retriever","type":["string","null"]},"genderName":{"description":"Sex name from Link, or `null`.","example":"Tik","type":["string","null"]},"birthdate":{"description":"Date of birth (YYYY-MM-DD) from Link, or `null`.","example":"2020-03-15","type":["string","null"]},"deceased":{"type":"boolean","description":"Whether Link marks the animal as deceased. Only active animals are requested from Link, so this is normally `false`.","example":false}},"required":["id","name","kindName","breedName","genderName","birthdate","deceased"],"additionalProperties":false,"title":"Link animal","description":"An active animal owned by a Link customer."},"LinkExportResult":{"type":"object","properties":{"linkEntryId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Id of the Link journal entry that was created or updated. Stored on the consultation so later exports update the same entry.","example":8812345},"linkJournalId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Id of the animal's Link journal (medical record) that holds the entry.","example":2167548},"entryUrl":{"type":"string","description":"Deep link that opens the entry in Link's web app.","example":"https://riverside.linkjournal.se/customers/54967922/animals/1234567?only_entry=8812345"},"mode":{"type":"string","enum":["created","updated"],"description":"What the export did:\n- `created` — a new journal entry was created (first export, or `reassign: true`).\n- `updated` — an existing entry was updated in place (the consultation's previously exported entry, or `targetEntryId`).","example":"created"},"fieldWrites":{"type":"object","properties":{"create":{"type":"object","properties":{"applied":{"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Ids of the fields Link reports as written.","example":[98765,98766]},"skipped":{"type":"array","items":{"type":"object","properties":{"key":{"description":"The field the result refers to, as Link reports it: the template field id when an entry is created, the entry field id when one is updated.","example":"98765","type":["string","number"]},"reason":{"type":"string","description":"Link's explanation of why the field was not written, passed through unchanged."}},"required":["key","reason"],"additionalProperties":false,"title":"Skipped Link field","description":"A field Link ignored without treating it as an error."},"description":"Fields Link did not write and did not reject."},"errors":{"type":"array","items":{"type":"object","properties":{"key":{"description":"The field the result refers to, as Link reports it: the template field id when an entry is created, the entry field id when one is updated.","example":"98765","type":["string","number"]},"messages":{"type":"array","items":{"type":"string"},"description":"Validation messages from Link, passed through unchanged."}},"required":["key","messages"],"additionalProperties":false,"title":"Rejected Link field","description":"A field Link rejected."},"description":"Fields Link rejected. When an entry is created, rejected fields are reported here and the export still succeeds; when an existing entry is updated, any rejection fails the request instead."}},"required":["applied","skipped","errors"],"additionalProperties":false,"title":"Link field write results","description":"Results of the main write. Despite the name, this also holds the results of an in-place update (`mode: updated`); it is empty when an update had nothing new to write."},"internalSamples":{"description":"Results of the follow-up write that fills lab/measurement result rows on a newly created entry. Absent when there were none, and always absent for `mode: updated` (those values are part of `create`).","type":"object","properties":{"applied":{"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Ids of the fields Link reports as written.","example":[98765,98766]},"skipped":{"type":"array","items":{"type":"object","properties":{"key":{"description":"The field the result refers to, as Link reports it: the template field id when an entry is created, the entry field id when one is updated.","example":"98765","type":["string","number"]},"reason":{"type":"string","description":"Link's explanation of why the field was not written, passed through unchanged."}},"required":["key","reason"],"additionalProperties":false,"title":"Skipped Link field","description":"A field Link ignored without treating it as an error."},"description":"Fields Link did not write and did not reject."},"errors":{"type":"array","items":{"type":"object","properties":{"key":{"description":"The field the result refers to, as Link reports it: the template field id when an entry is created, the entry field id when one is updated.","example":"98765","type":["string","number"]},"messages":{"type":"array","items":{"type":"string"},"description":"Validation messages from Link, passed through unchanged."}},"required":["key","messages"],"additionalProperties":false,"title":"Rejected Link field","description":"A field Link rejected."},"description":"Fields Link rejected. When an entry is created, rejected fields are reported here and the export still succeeds; when an existing entry is updated, any rejection fails the request instead."}},"required":["applied","skipped","errors"],"additionalProperties":false,"title":"Link field write results"}},"required":["create"],"additionalProperties":false,"title":"Link export field writes","description":"Per-field results Link reported for the export."}},"required":["linkEntryId","linkJournalId","entryUrl","mode","fieldWrites"],"additionalProperties":false,"title":"Link export result","description":"Outcome of exporting a consultation's structured clinical note to a Link journal entry."},"VettigoExportResult":{"type":"object","properties":{"status":{"type":"string","const":"ok","description":"Always `ok`; failures are returned as errors.","example":"ok"},"httpStatus":{"type":"number","description":"Always `200`. Kept for older clients.","example":200},"animalID":{"description":"Vettigo animal id whose medical record received the note. `null` when the animal was resolved through the consultation's Vettigo appointment instead.","example":482913,"type":["number","null"]}},"required":["status","httpStatus","animalID"],"additionalProperties":false,"title":"Vettigo export result","description":"Confirmation that the clinical note was added to the animal's Vettigo medical record."},"GetRecordOutput":{"anyOf":[{"anyOf":[{"type":"string"},{}]},{"type":"null"}],"title":"Record content","description":"The current content of the record, in the format it was saved in. An HTML string for free-text records (every client communication and referral letter, and clinical notes written without a structured template). A JSON object with one key per template field for a clinical note generated from a structured template. `null` when the consultation has no record of this type, because none has been generated or written yet or because it was deleted.","example":"<strong>History</strong><br />Bella, an 8-year-old Labrador, has had intermittent left hind lameness for 2 weeks.<br /><br /><strong>Plan</strong><br />• Carprofen 2 mg/kg PO q12h for 7 days<br />• Recheck in 14 days"},"CreateRecordOutput":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the request succeeds; failures are returned as an HTTP error status instead. When the clinical note is generated from a structured template, `true` means generation has started, not that the note is ready.","example":true}},"required":["success"],"additionalProperties":false,"title":"Create record result","description":"Acknowledgement that the record was written, or that AI generation of it has run."},"UpdateRecordOutput":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the request succeeds; failures are returned as an HTTP error status instead.","example":true}},"required":["success"],"additionalProperties":false,"title":"Update record result","description":"Acknowledgement that the supplied content is now the current version of the record."},"DeleteRecordOutput":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the request succeeds, including when the consultation had no record of this type to delete.","example":true}},"required":["success"],"additionalProperties":false,"title":"Delete record result","description":"Acknowledgement that the consultation no longer has a current record of this type."},"GenerateClinicalNoteOutput":{"type":"object","properties":{"message":{"description":"Present instead of `clinicalNote` when the note is not returned in this response:\n- `Callback URL has been queued` — you passed `callbackUrl`; the outcome will be POSTed to it.\n- `Structured document generation initiated` — the consultation's clinical note uses a structured template and is being generated in the background. Poll `GET /workspaces/{workspaceId}/consultations/{consultationId}` until `isGeneratingClinicalNote` is `false`, then read the record.","example":"Callback URL has been queued","type":"string"},"clinicalNote":{"description":"The generated clinical note as HTML, returned in synchronous mode for free-text notes. Generated notes use `<strong>` section headings, `<br />` line breaks and `•` bullet characters rather than heading, paragraph or list elements. The note has already been saved as the consultation's clinical note.","example":"<strong>History</strong><br />Bella, an 8-year-old Labrador, has had intermittent left hind lameness for 2 weeks.<br /><br /><strong>Examination</strong><br />• T 38.6 °C<br />• Mild pain on extension of the left stifle<br /><br /><strong>Plan</strong><br />• Carprofen 2 mg/kg PO q12h for 7 days<br />• Recheck in 14 days","type":"string"}},"additionalProperties":false,"title":"Generate clinical note result","description":"Exactly one of `clinicalNote` (synchronous free-text generation) or `message` (callback mode, or a structured-template note still generating) is present."},"GenerateDocumentOutput":{"title":"Generated structured document","description":"In synchronous mode, the generated document: a JSON object whose keys and value types follow the JSON template's schema. Fields the conversation did not cover are left empty rather than invented. In callback mode, the object `{ \"message\": \"Callback URL has been queued\" }` instead.","example":{"anamnesis":"Intermittent left hind lameness for 2 weeks; worse after exercise.","examination":"T 38.6 °C. Mild pain on extension of the left stifle.","treatment":"Carprofen 2 mg/kg PO q12h for 7 days. Recheck in 14 days."}},"TemplateList":{"type":"array","items":{"$ref":"#/components/schemas/TemplateListItemOutput"},"title":"Template list","description":"The templates the caller can see in the clinic, sorted by name (case-insensitive)."},"CreateTemplateOutput":{"type":"object","properties":{"templateId":{"type":"string","description":"ID (a UUID) of the new template.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"}},"required":["templateId"],"additionalProperties":false,"title":"Create template result","description":"The ID of the template that was created."},"UpdateTemplateContentOutput":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the request succeeds; failures are returned as an HTTP error status instead.","example":true},"contentVersion":{"description":"Opaque version tag of the content you just saved, including its surrounding double quotes. Send it unchanged as `expectedContentVersion` on your next update so that the update fails with 409 if someone else changed the template in between. `null` if storage did not return one.","example":"\"9b2cf535f27731c974343645a3985328\"","type":["string","null"]}},"required":["success"],"additionalProperties":false,"title":"Update template content result","description":"Confirms the new template body was saved and returns its version tag."},"DeleteTemplateOutput":{"type":"object","properties":{},"additionalProperties":false,"title":"Delete template result","description":"An empty object, returned when the template has been deleted."},"DuplicateTemplateOutput":{"type":"object","properties":{"id":{"type":"string","description":"ID (a UUID) of the new copy. Note that this field is `id`, while Create a template returns `templateId`.","example":"8c2d4f6a-1b3e-4a5c-9d7f-0e2b4c6d8f1a"}},"required":["id"],"additionalProperties":false,"title":"Duplicate template result","description":"The ID of the copy that was created."},"PatientWithClient":{"type":"object","properties":{"id":{"type":"string","description":"Patient id (UUID), generated by Vetnio.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"name":{"description":"The animal's name. Free text; Vetnio does not enforce uniqueness. `null` when not recorded.","example":"Bella","type":["string","null"]},"species":{"description":"Species, free text. The Vetnio web app stores the English species name, followed by ` - <breed>` when a breed is chosen (for example `Dog` or `Dog - Labrador Retriever`); patients synced from a practice-management system may use that system's values. `null` when not recorded.","example":"Dog - Labrador Retriever","type":["string","null"]},"breed":{"description":"Breed, free text. `null` when not recorded.","example":"Labrador Retriever","type":["string","null"]},"dateOfBirth":{"description":"Date of birth (`YYYY-MM-DD`), or `null` when not recorded.","example":"2018-04-12","type":["string","null"]},"gender":{"description":"Sex and neuter status, free text. The Vetnio web app uses `Male`, `Female`, `Male Neutered` and `Female Neutered`; use the same values so the patient list's gender filter and the UI stay consistent. `null` when not recorded.","example":"Female Neutered","type":["string","null"]},"weight":{"description":"Body weight as free text including the unit, as the web app writes it (for example `24.5 kg`). Not parsed or converted. `null` when not recorded.","example":"24.5 kg","type":["string","null"]},"identifier":{"description":"The animal's identifier, typically a microchip (transponder) number, but it can be a tattoo, registration number or practice-management-system id. Free text, not unique; matched by the patient list search. `null` when not recorded.","example":"752098100012345","type":["string","null"]},"insurance":{"description":"Name of the animal's insurance company, free text. `null` when the animal is uninsured or it is not recorded.","example":"Agria","type":["string","null"]},"clientId":{"description":"Id of the owner (client). Patients created through the API always have one (an empty placeholder owner when no owner details were given); `null` only for patients created without an owner by other flows.","example":"e1f2a3b4-c5d6-4789-efab-901234567890","type":["string","null"]},"createdAt":{"description":"When the patient was created (ISO-8601). May be `null` for very old records.","example":"2026-09-12T08:41:07.000Z","type":["string","null"]},"updatedAt":{"description":"When the patient was last changed (ISO-8601). Set on every update, even one that changes nothing, and by practice-management-system syncs.","example":"2026-10-01T14:03:22.000Z","type":["string","null"]},"client":{"anyOf":[{"$ref":"#/components/schemas/ClientOutput"},{"type":"null"}],"description":"The patient's owner, embedded. `null` when `clientId` is `null`."}},"required":["id","name","species","breed","dateOfBirth","gender","weight","identifier","insurance","clientId","createdAt","updatedAt","client"],"additionalProperties":false,"title":"Patient with client","description":"A patient with its owner (client) embedded. Returned by the endpoints that read or create a single patient."},"PatientList":{"type":"object","properties":{"patients":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Patient id (UUID).","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"name":{"description":"The animal's name, or `null`.","example":"Bella","type":["string","null"]},"species":{"description":"Species as stored (see `Patient.species`), or `null`.","example":"Dog - Labrador Retriever","type":["string","null"]},"breed":{"description":"Breed, or `null`.","example":"Labrador Retriever","type":["string","null"]},"dateOfBirth":{"description":"Date of birth (`YYYY-MM-DD`), or `null`.","example":"2018-04-12","type":["string","null"]},"gender":{"description":"Sex and neuter status as stored, or `null`.","example":"Female Neutered","type":["string","null"]},"weight":{"description":"Body weight as stored, including the unit, or `null`.","example":"24.5 kg","type":["string","null"]},"identifier":{"description":"Identifier such as a microchip number, or `null`.","example":"752098100012345","type":["string","null"]},"insurance":{"description":"Insurance company name, or `null`.","example":"Agria","type":["string","null"]},"clientId":{"description":"Id of the owner (client), or `null`.","example":"e1f2a3b4-c5d6-4789-efab-901234567890","type":["string","null"]},"clientName":{"description":"The owner's name, included so a list can be shown without fetching each client. `null` when there is no owner or the owner has no name.","example":"Alex Morgan","type":["string","null"]},"createdAt":{"description":"When the patient was created (ISO-8601), or `null` for very old records.","example":"2026-09-12T08:41:07.000Z","type":["string","null"]},"updatedAt":{"description":"When the patient was last changed (ISO-8601).","example":"2026-10-01T14:03:22.000Z","type":["string","null"]}},"required":["id","name","species","breed","dateOfBirth","gender","weight","identifier","insurance","clientId","clientName","createdAt","updatedAt"],"additionalProperties":false,"title":"Patient list item","description":"A patient as returned by the patient list, with the owner's name included."},"description":"The patients on the requested page, in the requested order. Empty when the page is past the end."},"totalCount":{"type":"number","description":"Number of patients matching the search and filters across all pages. The number of pages is `ceil(totalCount / pageSize)`.","example":142}},"required":["patients","totalCount"],"additionalProperties":false,"title":"Patient list","description":"One page of patients plus the total number of matches."},"ClientList":{"type":"object","properties":{"clients":{"type":"array","items":{"$ref":"#/components/schemas/ClientOutput"},"description":"Every client in the workspace, including empty placeholder owners, in no guaranteed order."}},"required":["clients"],"additionalProperties":false,"title":"Client list","description":"All clients (owners) in a workspace, unpaginated."},"PatientSuccess":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true`; failures are returned as errors.","example":true}},"required":["success"],"additionalProperties":false,"title":"Success response","description":"Acknowledgement returned by patient and client mutations that have no resource body."},"TranscriptionStart":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable outcome: `Transcription process started` when work was started, or `No untranscribed recordings found` when there was nothing to do. Use `recordingsProcessed` rather than parsing this text.","example":"Transcription process started"},"recordingsProcessed":{"type":"number","description":"Number of recordings waiting for transcription when the call was made. `0` means nothing was started. Recordings that an earlier call is already transcribing are counted but not transcribed twice; recordings that failed permanently are not counted.","example":3}},"required":["message","recordingsProcessed"],"additionalProperties":false,"title":"Transcription start result","description":"Response returned after triggering background transcription for a consultation's recordings."},"PartialTranscriptionList":{"type":"object","properties":{"count":{"type":"number","description":"Number of partial transcriptions for this consultation.","example":3},"partialTranscriptions":{"type":"array","items":{"type":"object","properties":{"recordingId":{"type":"string","description":"ID of the recording this partial transcription belongs to. Audio recordings use `<epoch-ms>-<language>` (the ID fixed when the upload URL was issued); text partials use `<epoch-ms>-<uuid>-text-<language>`. IDs sort chronologically.","example":"1726302600000-en"},"key":{"type":"string","description":"Internal storage key of the partial transcription. Informational only: it cannot be used to download the text through the API.","example":"transcriptions/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302600000-en"},"isTextBased":{"type":"boolean","description":"`true` for text added with `POST .../partial-transcriptions`, `false` for the transcription of an uploaded audio recording. Derived from `-text-` in `recordingId`.","example":false}},"required":["recordingId","key","isTextBased"],"additionalProperties":false,"title":"Partial transcription item","description":"Metadata for a single partial transcription belonging to a consultation."},"description":"Partial transcriptions sorted by `recordingId`, which is chronological order and the order in which they are joined into the full transcript. Recordings shorter than one second appear here with empty text."}},"required":["count","partialTranscriptions"],"additionalProperties":false,"title":"Partial transcription list","description":"All partial transcriptions of a consultation. Each uploaded audio recording produces one partial transcription when it is transcribed, and each text snippet added through the API is another; together they form the full transcript."},"PartialTranscriptionCreated":{"type":"object","properties":{"success":{"type":"boolean","description":"Always `true` when the partial transcription was created successfully.","example":true},"recordingId":{"type":"string","description":"Generated ID of the new text partial transcription, in the form `<epoch-ms>-<uuid>-text-<language>`.","example":"1726302712345-3f2b8c1e-9d4a-4e6b-8f0c-2a7d5e9b1c64-text-en"},"message":{"type":"string","description":"Human-readable confirmation message. It says so when the text is stored but not yet in the consultation transcript because the consultation is being moved or erased.","example":"Partial transcription created successfully. It will be included in document generation."}},"required":["success","recordingId","message"],"additionalProperties":false,"title":"Partial transcription created","description":"Confirmation returned after creating a text-only partial transcription. The text is normally added to the full transcript straight away and used by later document generation; `message` says so when the consultation is being moved or erased and the transcript has not been updated yet."},"ProcessRecordingsResult":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable status message; always the same text on success.","example":"Recordings processed successfully"},"recordingsProcessed":{"type":"number","description":"Number of entries in `processedRecordings`. Recordings whose processing failed outright appear in neither list.","example":2},"processedRecordings":{"type":"array","items":{"type":"object","properties":{"recordingKey":{"type":"string","description":"Internal storage key of the original recording; its last segment is the recording ID (`<epoch-ms>-<language>`).","example":"recordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302600000-en"},"processedRecordingUrl":{"type":"string","description":"Presigned GET URL, valid for 24 hours, for the processed audio: 16 kHz mono WAV with leading, trailing and long silences removed. This is the audio that is sent for transcription.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/processedRecordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302600000-en?X-Amz-Expires=86400&X-Amz-Signature=..."},"recordingLanguageCode":{"type":"string","description":"Language code taken from the recording ID suffix (for example `en`); this is the language used to transcribe the recording.","example":"en"},"durationInMilliseconds":{"type":"number","description":"Duration of the processed audio, after silence removal, in milliseconds.","example":45200}},"required":["recordingKey","processedRecordingUrl","recordingLanguageCode","durationInMilliseconds"],"additionalProperties":false,"title":"Processed recording","description":"Details of a single recording after audio format conversion and duration measurement."},"description":"Recordings that were processed successfully and can be transcribed."},"skippedRecordings":{"type":"array","items":{"type":"object","properties":{"recordingKey":{"type":"string","description":"Internal storage key of the original recording; its last segment is the recording ID.","example":"recordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302700000-en"},"recordingLanguageCode":{"type":"string","description":"Language code taken from the recording ID suffix.","example":"en"},"durationInMilliseconds":{"type":"number","description":"Duration after silence removal, in milliseconds; `0` for unreadable input.","example":140},"skippedReason":{"type":"string","enum":["too_short","unreadable_input"],"description":"Why the recording will not produce transcript text:\n- `too_short` — less than one second of audio remains after silence removal; transcription records it as empty text.\n- `unreadable_input` — the file is empty or not decodable audio; transcription marks it as a permanent failure (`unreadable_recording`).","example":"too_short"}},"required":["recordingKey","recordingLanguageCode","durationInMilliseconds","skippedReason"],"additionalProperties":false,"title":"Skipped recording","description":"Recording that was processed but intentionally skipped because it cannot produce useful transcription content."},"description":"Recordings that were processed but will not yield transcript text, because they are too short or unreadable."}},"required":["message","recordingsProcessed","processedRecordings","skippedRecordings"],"additionalProperties":false,"title":"Process recordings result","description":"Result of audio processing for a consultation's untranscribed recordings, with duration and a download URL for each processed recording."},"RecordingUploadUrl":{"type":"object","properties":{"recordingUploadUrl":{"type":"string","format":"uri","description":"Presigned URL for uploading one audio recording with a single `PUT` request whose body is the raw file bytes (no multipart form, no extra headers required). Valid for 24 hours. Any audio format FFmpeg can decode is accepted, for example WebM/Opus, MP4/AAC, M4A, MP3 or WAV. The recording ID (`<epoch-ms>-<language>`) is fixed when the URL is issued, and recordings are transcribed in recording-ID order.","example":"https://example-bucket.s3.eu-central-1.amazonaws.com/recordings/furunculotic-loud-chihuahua/a1b2c3d4-e5f6-7890-abcd-ef1234567890/1726302600000-en?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=86400&X-Amz-Signature=..."}},"required":["recordingUploadUrl"],"additionalProperties":false,"title":"Recording upload URL","description":"Presigned upload URL for adding a new audio recording to a consultation."},"WorkspaceList":{"type":"object","properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceListItemOutput"},"description":"Workspaces where the user is a direct member, in no guaranteed order. Clinics the user can only reach as an organization admin, locked clinics, clinics being deleted or merged, and clinics blocked by an IP allowlist for the caller's address are not included."}},"required":["workspaces"],"additionalProperties":false,"title":"Workspace list","description":"The veterinary clinic workspaces the authenticated user is a member of, with the user's role in each."},"AuthenticatedUser":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the authenticated Vetnio user (a UUID). It is the same ID that appears as `userId`, `creatorId` or `Vet ID` in other responses.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"}},"required":["id"],"additionalProperties":false,"title":"Authenticated user","description":"Identity of the user that owns the calling API key or session."},"ApiKey":{"type":"object","properties":{"name":{"type":"string","description":"Label an organization admin gave the key when creating it under Organization → API. A rotated key keeps the name of the key it replaced.","example":"Data warehouse sync"},"organizationId":{"type":"string","description":"Identifier of the organization the key belongs to. Use it as `{organizationId}` in the `/organizations/{organizationId}/…` paths; any other organization ID returns 403.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"scope":{"type":"object","properties":{"type":{"type":"string","enum":["organization","workspace"],"description":"What the key can reach:\n- `organization` — every clinic in the organization. Keys start with `sk_org_`.\n- `workspace` — a single clinic (workspace). Keys start with `sk_ws_` and only ever see that clinic's data.","example":"organization"},"id":{"type":"string","description":"The organization ID when `type` is `organization`, or the workspace (clinic) ID when `type` is `workspace`.","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"}},"required":["type","id"],"additionalProperties":false,"title":"API key scope","description":"The organization or single clinic the key is limited to."},"status":{"type":"string","enum":["active","expiring","expired","revoked"],"description":"Lifecycle state of the key:\n- `active` — valid and has no expiry date.\n- `expiring` — valid until `expiresAt`. A key replaced through rotation is `expiring` during its grace period.\n- `expired` — `expiresAt` has passed; the key no longer authenticates.\n- `revoked` — an admin revoked the key; it no longer authenticates.\nBecause expired and revoked keys are rejected with 401 before this endpoint runs, a successful response is always `active` or `expiring`.","example":"active"},"createdAt":{"description":"When the key was created, as an ISO-8601 UTC timestamp.","example":"2026-09-01T08:15:00.000Z","type":"string"},"expiresAt":{"description":"When the key stops working (ISO-8601 UTC), or `null` if it never expires. Rotating a key moves the old key's expiry to at most 24 hours after the rotation.","example":null,"type":["string","null"]},"lastUsedAt":{"description":"Approximate time of the key's most recent authenticated request (ISO-8601 UTC), or `null` if it has not been recorded yet. Refreshed at most once every 5 minutes, so it may lag and may not include the current request.","example":"2026-09-28T06:00:12.000Z","type":["string","null"]},"limits":{"type":"object","properties":{"requestsPerMinute":{"type":"number","description":"Maximum requests per fixed UTC minute. The next request returns 429 `TOO_MANY_REQUESTS` with the number of seconds to wait in `message`.","example":60},"requestsPerDay":{"type":"number","description":"Maximum requests per UTC day; the counter resets at 00:00 UTC. Exceeding it returns 429 until the reset.","example":10000}},"required":["requestsPerMinute","requestsPerDay"],"additionalProperties":false,"title":"API key limits","description":"Rate limits that apply to every organization and workspace key."},"usage":{"type":"object","properties":{"requestsToday":{"type":"number","description":"Requests counted for this key since 00:00 UTC today, including the current one. Every request to an endpoint the key may call is counted, even if it then fails validation or is rate limited.","example":42},"requestsLast30Days":{"type":"number","description":"Requests counted for this key over the last 30 UTC days, today included.","example":1250},"daily":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"UTC calendar day, formatted `YYYY-MM-DD`.","example":"2026-09-28"},"requests":{"type":"number","description":"Requests counted for this key on that day.","example":37}},"required":["day","requests"],"additionalProperties":false,"title":"API key daily usage","description":"Request count for one UTC day."},"description":"One entry per UTC day in the last 30 days on which the key made at least one request, oldest first. Days without requests are omitted rather than returned as zero."}},"required":["requestsToday","requestsLast30Days","daily"],"additionalProperties":false,"title":"API key usage","description":"Request counts recorded by the key's rate limiter."}},"required":["name","organizationId","scope","status","createdAt","expiresAt","lastUsedAt","limits","usage"],"additionalProperties":false,"title":"API key","description":"The organization or workspace API key that authenticated this request, with its scope, lifecycle and usage. The secret key value is never returned."},"OrganizationExportOverview":{"type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"string","description":"Organization ID (UUID).","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"name":{"type":"string","description":"Organization display name.","example":"Riverside Veterinary Group"}},"required":["id","name"],"additionalProperties":false,"title":"Exported organization","description":"The organization being exported."},"workspaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Workspace (clinic) ID. Use it in the usage export's `workspaceIds` filter.","example":"furunculotic-loud-chihuahua"},"name":{"type":"string","description":"Clinic name, or the clinic ID when no name has been set.","example":"Riverside Animal Clinic"},"city":{"description":"City of the clinic's address, or null if not set.","example":"Uppsala","type":["string","null"]},"countryCode":{"description":"Two-letter country code of the clinic as stored (case as entered), or null if not set.","example":"se","type":["string","null"]},"createdAt":{"description":"When the clinic was created in Vetnio (ISO-8601 UTC).","example":"2025-11-03T09:12:44.000Z","type":"string"}},"required":["id","name","city","countryCode","createdAt"],"additionalProperties":false,"title":"Exported clinic","description":"A clinic (workspace) in the organization."},"description":"Clinics in scope, sorted by name. Clinics that are locked or being deleted or merged are left out here, although the usage export still reports them. A workspace key sees only its own clinic."},"members":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (UUID). Matches the `Vet ID` column of the usage export.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"name":{"description":"The person's display name, or null if they have not set one.","example":"Dr. Sam Lee","type":["string","null"]},"email":{"type":"string","description":"The person's login email address.","example":"sam.lee@riverside-vets.example"},"organizationRole":{"anyOf":[{"type":"string","enum":["member","admin","superadmin"]},{"type":"null"}],"description":"Role in the organization, or `null` for clinic-only staff:\n- `member` — belongs to the organization without admin rights.\n- `admin` — organization administrator.\n- `superadmin` — organization administrator with the highest role.\nBoth `admin` and `superadmin` have organization admin rights in the API.","example":null},"workspaces":{"type":"array","items":{"type":"object","properties":{"workspaceId":{"type":"string","description":"ID of a clinic in scope that the person belongs to directly.","example":"furunculotic-loud-chihuahua"},"role":{"type":"string","enum":["member","admin","superadmin"],"description":"The person's role in this clinic:\n- `member` — clinician.\n- `admin` — clinic administrator.\n- `superadmin` — clinic administrator who can also delete the clinic and manage other superadmins.","example":"member"}},"required":["workspaceId","role"],"additionalProperties":false,"title":"Clinic membership","description":"The person's membership in one clinic."},"description":"The person's direct memberships in the clinics in scope. Empty for organization members who do not belong to any of those clinics."}},"required":["userId","name","email","organizationRole","workspaces"],"additionalProperties":false,"title":"Organization person","description":"One person in the organization or its clinics."},"description":"Organization members and staff of the clinics in scope, merged to one row per person and sorted by email. Organization members are always included, even for a workspace key."},"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Organization template ID (UUID).","example":"2a9b8c7d-6e5f-4a3b-9c1d-0e2f4a6b8c0d"},"name":{"type":"string","description":"Template name.","example":"Group clinical note"},"type":{"type":"string","enum":["clinical_note","referral","client_communication"],"description":"What the template produces:\n- `clinical_note` — the clinical note (medical record entry) for a consultation.\n- `referral` — a referral letter to another clinic or specialist.\n- `client_communication` — a message to the pet owner.","example":"clinical_note"},"createdBy":{"type":"string","description":"User ID (UUID) of the organization admin who created the template.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"createdAt":{"description":"When the template was created (ISO-8601 UTC).","example":"2026-02-10T13:00:00.000Z","type":"string"}},"required":["id","name","type","createdBy","createdAt"],"additionalProperties":false,"title":"Organization template summary","description":"Name and metadata of one organization-level template."},"description":"Organization-level templates shared to its clinics, oldest first. Names and metadata only; download bodies with `GET /organizations/{organizationId}/data-export/templates`."}},"required":["organization","workspaces","members","templates"],"additionalProperties":false,"title":"Organization export overview","description":"The organization with its clinics, people and organization-level templates."},"OrganizationUsageExport":{"type":"object","properties":{"headers":{"type":"array","items":{"type":"string"},"description":"Column titles in display form (for example `Clinic Name`, `Consultations`), in the order of each row's cells. For `grain=vet` and `grain=clinic` the first column is `Date`.","example":["Date","Clinic ID","Clinic Name","Consultations"]},"rows":{"type":"array","items":{"type":"array","items":{"type":["string","number","null"]}},"description":"Table rows, one cell per header. Cells are strings, numbers or `null` (not applicable or unknown). Dates are `YYYY-MM-DD` strings (the next and last payment dates are full ISO-8601 timestamps), consultation start and end times are `HH:mm` in the clinic's local time, flags are `Yes` or `No`, amounts are rounded to 2 decimals and `Draft Kept (%)` is a percentage from 0 to 100.","example":[["2026-09-01","furunculotic-loud-chihuahua","Riverside Animal Clinic",412]]},"start":{"type":"string","description":"First day covered, `YYYY-MM-DD` (UTC).","example":"2026-09-01"},"end":{"type":"string","description":"Last day covered, `YYYY-MM-DD` (UTC).","example":"2026-09-30"},"totalRows":{"type":"number","description":"Number of rows across all pages. For grains other than `consultation` it equals the number of rows returned.","example":24},"page":{"type":"number","description":"The page returned. Always 1 unless `grain=consultation`.","example":1},"totalPages":{"type":"number","description":"Only the consultation grain spans several pages; the others always return 1.","example":1}},"required":["headers","rows","start","end","totalRows","page","totalPages"],"additionalProperties":false,"title":"Organization usage export","description":"One page of the usage table: the same table as the in-app usage CSV export, as JSON."},"UserContentExport":{"type":"object","properties":{"schemaVersion":{"type":"number","const":1,"description":"Version of the export format. Currently always `1`.","example":1},"exportedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When this export was produced (ISO 8601, UTC). Values are read separately, so this is not the time of an atomic snapshot.","example":"2026-09-28T08:15:00.000Z"},"scopeId":{"type":"string","description":"ID of the exported user, workspace or organization. Equal to `configuration.id`.","example":"furunculotic-loud-chihuahua"},"termList":{"$ref":"#/components/schemas/TranscriptionTermListOutput"},"inventory":{"type":"object","properties":{"included":{"type":"array","items":{"type":"string","description":"One included category."},"description":"Categories of content included in this response.","example":["Workspace identity, address and allowlisted settings","Current workspace transcription term list"]},"excluded":{"type":"array","items":{"type":"string","description":"One excluded category."},"description":"Categories deliberately left out of this response, such as credentials, billing identifiers and other owners' settings.","example":["Credentials, API keys, OAuth/session/password material and provider connection secrets"]},"limitations":{"type":"array","items":{"type":"string","description":"One limitation."},"description":"How to interpret this export, for example that it contains current values only and is not an atomic snapshot.","example":["Current stored values only; separate reads do not form an atomic snapshot"]}},"required":["included","excluded","limitations"],"additionalProperties":false,"title":"Export inventory","description":"Plain-English statements of what this export covers and how to read it, intended for audit records. The wording can change between releases, so do not parse it."},"scope":{"type":"string","const":"user","description":"Exported scope. Always `user` for this endpoint.","example":"user"},"configuration":{"type":"object","properties":{"id":{"type":"string","description":"The user's ID (a UUID).","example":"7d1f0c3e-2a4b-4e8f-9c61-5b2a8d4e7f10"},"name":{"description":"The user's display name. `null` when not set.","example":"Dr. Sam Lee","type":["string","null"]},"preferences":{"type":"object","properties":{"savedRecordingLanguageCodeSelection":{"description":"Recording language the user last chose, as a Vetnio language code (mostly ISO 639-1, such as `en` or `sv`; a few longer codes such as `yue` or `fil`). Pre-selects the language for new recordings. Absent when never set.","example":"sv","type":"string"},"savedTranslationLanguageCodeSelection":{"description":"Target language the user last chose when translating a document, as a language code from the same list as `savedRecordingLanguageCodeSelection`. Absent when never set.","example":"en","type":"string"},"savedPdfLanguageSelection":{"description":"Language the user last chose for PDF exports, which sets the PDF's labels and headings. One of `en`, `sv`, `de`, `it`, `fr`, `es`, `pt`, `no`, `nl`, `fi`, `da`. Absent when never set.","example":"en","type":"string"},"pdfExportPractitioner":{"title":"PDF practitioner details","description":"Practitioner details the user saved in the PDF export dialog, used to prefill the veterinarian block on exported PDFs. Absent when never saved.","type":"object","properties":{"name":{"description":"Practitioner name, up to 160 characters.","example":"Dr. Sam Lee","type":"string"},"email":{"description":"Practitioner email address as entered (not verified), up to 254 characters.","example":"sam.lee@example.com","type":"string"}},"additionalProperties":false},"preferredWorkspaceId":{"description":"ID of the workspace (clinic) the user opens by default, for example when launching Vetnio from a practice-management system. Absent when never set; the first workspace the user can access is then used.","example":"furunculotic-loud-chihuahua","type":"string"},"consultationsPerPage":{"description":"Number of consultations shown per page in the consultation list, from 1 to 100. Absent when never set; the default is 10.","example":25,"type":"number"},"savedTemplateIdsPerWorkspaceId":{"description":"Template choices remembered per workspace (clinic), keyed by workspace ID. Updated each time the user submits a consultation. Absent when never set.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"clinicalNote":{"description":"ID of the clinical-note template the user chose as their default in this workspace. New consultations there start with it.","example":"c2a7e5d4-1b3f-4a6e-8d9c-0f1e2a3b4c5d","type":"string"},"communication":{"description":"Communication template ID stored for this workspace by earlier app versions. Current versions no longer write it, so it appears only on older entries.","example":"5e8b1f2a-7c4d-4a9e-b3f6-2d1c0e9a8b7f","type":"string"}},"additionalProperties":false,"title":"Saved template selection","description":"Template IDs remembered for one workspace (clinic)."}},"phoneCallConversionSettingsPerWorkspaceId":{"description":"Settings remembered per workspace (clinic), keyed by workspace ID, for turning a phone call into a consultation. Absent when never set.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"recordingLanguageCode":{"description":"Language code the user last chose when turning a phone call into a consultation in this workspace.","example":"sv","type":"string"},"clinicalNoteTemplateId":{"description":"ID of the clinical-note template the user last chose for such a conversion in this workspace.","example":"c2a7e5d4-1b3f-4a6e-8d9c-0f1e2a3b4c5d","type":"string"}},"additionalProperties":false,"title":"Phone-call conversion settings","description":"Choices remembered for one workspace (clinic) when turning a phone call into a consultation."}},"customSystemInstructionGeneral":{"description":"The user's own instructions, added to every AI-generated document and VetsGPT chat they run. Stored verbatim, up to 50,000 characters. Absent when never set.","example":"Use metric units and British spelling.","type":"string"},"customSystemInstructionClinicalNotes":{"description":"The user's own instructions for generating clinical notes, added on top of `customSystemInstructionGeneral`. Stored verbatim, up to 50,000 characters. Absent when never set.","example":"List any vaccinations given at the end of the note.","type":"string"},"customSystemInstructionCommunications":{"description":"The user's own instructions for generating client communications, added on top of `customSystemInstructionGeneral`. Stored verbatim, up to 50,000 characters. Absent when never set.","example":"Address the owner by first name and keep a friendly tone.","type":"string"},"customSystemInstructionVetsGPT":{"description":"The user's own instructions for VetsGPT, the chat assistant, added on top of `customSystemInstructionGeneral`. Stored verbatim, up to 50,000 characters. Absent when never set.","example":"Cite the source of any dosage you mention.","type":"string"},"recordingAutoStopSeconds":{"description":"Personal recording auto-stop limit in seconds (60 to 86400). When set, it replaces the workspace's `recordingAutoStopSeconds` for this user's recordings. `null` when the user cleared their limit; absent when never set. In both cases the workspace limit applies, or 4 hours if the workspace has none.","example":3600,"type":["number","null"]},"recordingAutoStopPerSession":{"description":"How the personal auto-stop limit is measured. `true`: the timer restarts each time recording starts or resumes. `false`: the limit covers all audio recorded in the consultation. Only used together with a personal `recordingAutoStopSeconds`; `null` or absent means `true`.","example":true,"type":["boolean","null"]},"recordingSilenceAlertSound":{"description":"Sound played once when no microphone audio has been detected for 20 seconds during a recording:\n- `off` — no sound\n- `chime` — gentle chime\n- `doubleBeep` — double beep\n- `bell` — bell\nAbsent when never set, which means `off`.","example":"chime","type":"string"},"tipsEnabled":{"description":"Whether tips and suggestions are shown while notes are being generated. Absent when never set, which means tips are shown.","example":false,"type":"boolean"},"clinicalNoteGenerationNoticeEnabled":{"description":"Whether a notice is shown when a clinical note starts generating. Absent when never set, which means the notice is shown.","example":true,"type":"boolean"},"manualWritingEnabled":{"description":"Whether the user is offered to write clinical notes, client communications and referral letters themselves instead of recording or generating them. Only applies when the workspace allows it. Absent when never set, which means the option is offered.","example":true,"type":"boolean"},"noteEditorFontSize":{"description":"Text size in the note editor: `small`, `default`, `large` or `xlarge`. Display only; it does not change the stored note text. Absent when never set, which means `default`.","example":"large","type":"string"},"noteEditorFontFamily":{"description":"Typeface in the note editor: `default`, `serif` or `mono`. Display only; it does not change the stored note text. Absent when never set, which means `default`.","example":"serif","type":"string"},"copilotMode":{"description":"How VetsGPT applies the note edits it proposes:\n- `manual` — each change is shown in the note and applied only after the user approves it\n- `auto` — changes are applied at once and can be undone\nAbsent when never set, which means `manual`.","example":"manual","type":"string"},"colorMode":{"description":"App color theme: `light` or `dark`. Absent when the user has never chosen a theme.","example":"light","type":"string"},"provetExportTargets":{"description":"For Provet Cloud users, where exporting a clinical note writes it:\n- `clinicalNote` — the consultation's clinical note\n- `clinicalNoteAndImagingReferral` — both the clinical note and the imaging referral\n- `imagingReferral` — the imaging referral only\nAbsent when never set, which means `clinicalNote`.","example":"clinicalNote","type":"string"},"provetImagingReferralField":{"description":"Imaging referral field that receives the note when `provetExportTargets` includes the imaging referral:\n- `answer_remarks` — the referral's answer remarks\n- `diagnosis` — the referral's diagnosis\nAbsent when never set, which means `answer_remarks`.","example":"answer_remarks","type":"string"}},"additionalProperties":false,"title":"Personal preferences","description":"The user's stored personal preferences. Only allowlisted keys are exported. A key is absent when the user has never set it; the app then uses the default described on the field, which is not filled in here."}},"required":["id","name","preferences"],"additionalProperties":false,"title":"User configuration","description":"Identity and allowlisted personal preferences of the calling user."}},"required":["schemaVersion","exportedAt","scopeId","termList","inventory","scope","configuration"],"additionalProperties":false,"title":"User content export","description":"The calling user's current personal settings and personal transcription term list, with an inventory of what is included and excluded."},"WorkspaceContentExport":{"type":"object","properties":{"schemaVersion":{"type":"number","const":1,"description":"Version of the export format. Currently always `1`.","example":1},"exportedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When this export was produced (ISO 8601, UTC). Values are read separately, so this is not the time of an atomic snapshot.","example":"2026-09-28T08:15:00.000Z"},"scopeId":{"type":"string","description":"ID of the exported user, workspace or organization. Equal to `configuration.id`.","example":"furunculotic-loud-chihuahua"},"termList":{"$ref":"#/components/schemas/TranscriptionTermListOutput"},"inventory":{"type":"object","properties":{"included":{"type":"array","items":{"type":"string","description":"One included category."},"description":"Categories of content included in this response.","example":["Workspace identity, address and allowlisted settings","Current workspace transcription term list"]},"excluded":{"type":"array","items":{"type":"string","description":"One excluded category."},"description":"Categories deliberately left out of this response, such as credentials, billing identifiers and other owners' settings.","example":["Credentials, API keys, OAuth/session/password material and provider connection secrets"]},"limitations":{"type":"array","items":{"type":"string","description":"One limitation."},"description":"How to interpret this export, for example that it contains current values only and is not an atomic snapshot.","example":["Current stored values only; separate reads do not form an atomic snapshot"]}},"required":["included","excluded","limitations"],"additionalProperties":false,"title":"Export inventory","description":"Plain-English statements of what this export covers and how to read it, intended for audit records. The wording can change between releases, so do not parse it."},"scope":{"type":"string","const":"workspace","description":"Exported scope. Always `workspace` for this endpoint.","example":"workspace"},"configuration":{"type":"object","properties":{"id":{"type":"string","description":"ID of the workspace (clinic).","example":"furunculotic-loud-chihuahua"},"name":{"description":"Clinic display name. `null` when not set.","example":"Riverside Animal Clinic","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the workspace was created (ISO 8601, UTC).","example":"2026-09-28T08:15:00.000Z"},"address":{"description":"Street address of the clinic. `null` when not recorded.","example":"12 Harbour Street","type":["string","null"]},"city":{"description":"City of the clinic. `null` when not recorded.","example":"Riverside","type":["string","null"]},"stateProvince":{"description":"State, province or county of the clinic. `null` when not recorded.","example":"Riverside County","type":["string","null"]},"zipCode":{"description":"Postal or ZIP code of the clinic. `null` when not recorded.","example":"114 51","type":["string","null"]},"countryCode":{"description":"Two-letter ISO 3166-1 alpha-2 country code of the clinic, as stored (letter case is not normalized). `null` when not recorded.","example":"SE","type":["string","null"]},"taxId":{"description":"Tax identification number of the clinic, such as a VAT number. `null` when not recorded.","example":"SE556677889001","type":["string","null"]},"phone":{"description":"Clinic phone number, as entered. `null` when not recorded.","example":"+46 8 123 456 78","type":["string","null"]},"allowPasswords":{"type":"boolean","description":"Stored value of the workspace's allow-passwords flag. `true` unless it has been changed.","example":true},"templatePermissions":{"type":"string","description":"What members (non-admins) can do with templates:\n- `full_access` — view, use and edit templates created by other members (the default)\n- `view_only` — view and use templates created by others, but not edit them\n- `private` — edit only their own templates, and view only templates created by admins\n- `strict` — only view and use templates created by admins; members cannot create templates","example":"full_access"},"audioFileRetentionPeriodInDays":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Audio retention period in days set on this workspace. Consultation and meeting recordings older than this are deleted automatically. When linked organizations also set a period, the shortest one applies; export each organization to see its period. `null` when the workspace has no period of its own.","example":365},"isMeetingsEnabled":{"type":"boolean","description":"Whether the meetings feature (recording meetings with automatic note generation) is switched on for the workspace.","example":false},"manualPimsKind":{"description":"Practice-management system (PIMS) the clinic uses, recorded by Vetnio staff when no connected integration shows it. It takes precedence over detection:\n- `provet` — Provet Cloud\n- `link` — Link\n- `animana` — Animana\n- `vetmanager` — VetManager\n- `fuga` — Fuga\n- `other` — another system, named in `manualPimsName`\n- `none` — no PIMS\n`null` when not recorded.","example":"provet","type":["string","null"]},"manualPimsName":{"description":"Name of the practice-management system when `manualPimsKind` is `other`. `null` otherwise.","example":"ClinicDesk","type":["string","null"]},"settings":{"type":"object","properties":{"consultationVisibility":{"description":"Whether members can list consultations created by others:\n- `creator` — each member's consultation list shows only their own consultations\n- `workspace` — members can filter the list to show colleagues' or everyone's consultations\nAbsent when never set, which behaves as `creator`. This affects listing only; any workspace member can open an individual consultation either way.","example":"workspace","type":"string"},"dateFormat":{"description":"Date format the AI uses when writing dates in generated documents: `YYYY-MM-DD`, `DD-MM-YYYY` or `MM-DD-YYYY`. Absent when never set, which means `YYYY-MM-DD`.","example":"DD-MM-YYYY","type":"string"},"documentHeader":{"title":"Document header","description":"A short notice placed at the top of AI-generated documents of the selected types. Absent when never configured, which means no header.","type":"object","properties":{"headerType":{"type":"string","description":"Which header text is used. Preset texts are written in the document's language:\n- `none` — no header\n- `preset_1` — states that the document was generated with AI assistance and reviewed by a veterinary professional\n- `preset_2` — marks the document as a confidential veterinary medical record\n- `preset_3` — states that the document is AI-generated and that clinical details should be verified before use\n- `custom` — the text in `customText`","example":"preset_1"},"customText":{"description":"Header text used when `headerType` is `custom`, up to 500 characters. Inserted as plain text. Absent when not set.","example":"Riverside Animal Clinic. AI-assisted record, reviewed by the attending veterinarian.","type":"string"},"enabledDocumentTypes":{"type":"array","items":{"type":"string","description":"A document type: `clinical_note`, `communication` or `referral`.","example":"clinical_note"},"description":"Document types that receive the header. An empty array means no document receives it.","example":["clinical_note","referral"]}},"required":["headerType","enabledDocumentTypes"],"additionalProperties":false},"pdfExportClinicDetails":{"title":"PDF clinic details","description":"Clinic details saved from the PDF export dialog and used to prefill the clinic block on exported PDFs. Shared by all members of the workspace. Absent when never saved; empty fields are omitted.","type":"object","properties":{"clinic":{"description":"Clinic name to print, up to 500 characters.","example":"Riverside Animal Clinic","type":"string"},"address":{"description":"Clinic address to print, up to 500 characters.","example":"12 Harbour Street, Riverside","type":"string"},"zipCode":{"description":"Postal or ZIP code to print, up to 500 characters.","example":"114 51","type":"string"},"phone":{"description":"Clinic phone number to print, as entered, up to 500 characters.","example":"+46 8 123 456 78","type":"string"}},"additionalProperties":false},"pdfLetterhead":{"title":"PDF letterhead","description":"Letterhead layout for PDF exports of clinical notes and meeting notes. Absent when never configured, which means PDFs have no letterhead. The uploaded logo itself is exported in `configuration.letterheadAsset`.","type":"object","properties":{"templateId":{"type":"string","description":"Letterhead layout. Current layouts: `clean-letterhead` (the default), `sidebar-summary`, `centered-letterhead`, `teal-band`. Older layouts that are still supported: `logo-left`, `banner-above`, `logo-centered`. Unknown values are rendered as `clean-letterhead`.","example":"clean-letterhead"},"enabled":{"description":"`false` when the letterhead has been switched off; the other settings are kept. Absent or `true` means the letterhead is used.","example":true,"type":"boolean"},"includeClinicInfo":{"description":"Whether the clinic information block is printed on PDFs. Absent means `true`.","example":true,"type":"boolean"},"fontId":{"description":"Typeface for PDF text: `system-sans`, `humanist-sans`, `classic-serif` or `document-serif`. Absent means `system-sans`.","example":"classic-serif","type":"string"},"logoFit":{"description":"How the logo is scaled into its area:\n- `contain` — the whole logo is shown, keeping its proportions (the default when absent)\n- `cover` — the logo fills the area, keeping its proportions; edges may be cropped\n- `fill` — the logo is stretched to the area","example":"contain","type":"string"},"accentColor":{"description":"Accent color as a hex code (`#rgb` or `#rrggbb`). Absent when never set; the default is `#3d838b`.","example":"#2f6f8f","type":"string"}},"required":["templateId"],"additionalProperties":false},"globalTemplateInstructions":{"title":"Workspace template instructions","description":"Instructions the workspace adds to AI-generated documents on top of the chosen template. `general` applies to every document type; the other fields are added for their own document type only. Stored verbatim. Absent when never set.","type":"object","properties":{"general":{"description":"Instructions added to every AI-generated document, up to 4,000 characters. Absent when never set.","example":"Use metric units throughout.","type":"string"},"clinicalNote":{"description":"Instructions added when generating clinical notes, up to 4,000 characters. Absent when never set.","example":"Record body weight in kilograms with one decimal.","type":"string"},"referral":{"description":"Instructions added when generating referrals, up to 4,000 characters. Absent when never set.","example":"Start with the specific question for the receiving clinic.","type":"string"},"communication":{"description":"Instructions added when generating client communications, up to 4,000 characters. Absent when never set.","example":"Sign off as the Riverside Animal Clinic team.","type":"string"}},"additionalProperties":false},"patientMatchingEnabled":{"description":"Whether Vetnio looks for a matching patient record after a consultation's clinical note is generated, so it can be linked to that patient. Absent when never set, which means off.","example":true,"type":"boolean"},"aiTitlesEnabled":{"description":"Workspace setting for AI-generated consultation titles, written from the clinical note after it is saved. `true` or `false` takes precedence over the organization setting. Absent when never set at workspace level; titles are then generated only if a linked organization enables them (`aiTitlesEnabled` in its organization export).","example":true,"type":"boolean"},"aiTitlesUseAsName":{"description":"Whether an automatically generated title fills an unnamed consultation's name instead of appearing separately. Existing consultation names are preserved. Absent means false.","example":true,"type":"boolean"},"aiTitlesNamingStyle":{"description":"Automatic consultation naming style: patient name and case information, case information only, or custom instructions. Absent means case_only.","example":"patient_and_case","type":"string","enum":["patient_and_case","case_only","custom"]},"aiTitlesCustomPrompt":{"description":"Custom instructions for automatic consultation names, used when aiTitlesNamingStyle is custom. Up to 1,000 characters. Absent when never set.","example":"Use the patient name followed by the reason for the visit.","type":"string"},"recordingAutoStopSeconds":{"description":"Workspace recording auto-stop limit in seconds (60 to 86400). Applies to members who have no personal limit. Absent when never set or cleared; the default of 4 hours then applies.","example":7200,"type":"number"},"recordingView":{"description":"Recording display: waveform animation or a pre-visit briefing with a small recording indicator. An explicit workspace value overrides organization defaults. When absent, briefing is used if any linked organization selects it; otherwise waveform.","example":"briefing","type":"string","enum":["waveform","briefing"]},"liveTranscriptionEnabled":{"description":"Whether live transcription starts with consultation recording. An explicit workspace value overrides organization defaults. When absent, live transcription is disabled if any linked organization disables it; otherwise enabled. Audio recording and transcription after recording are unaffected.","example":false,"type":"boolean"},"recordingAutoStopPerSession":{"description":"How the workspace auto-stop limit is measured. `true`: the timer restarts each time recording starts or resumes. `false`: the limit covers all audio recorded in the consultation. Absent means `true`.","example":true,"type":"boolean"},"recordingConcurrencyControl":{"title":"Recording concurrency control","description":"Limits on simultaneous recordings in the workspace. Absent when never configured, which means no limit.","type":"object","properties":{"enabled":{"description":"Whether the limit is enforced. When `true`, the number of recordings active at the same time in the workspace is capped at its number of licensed seats (no cap during a trial or when no seat count is set). Absent means `false`.","example":true,"type":"boolean"},"limitActiveRecordingsPerUser":{"description":"When `true` and `enabled` is `true`, each user can have only one active recording at a time. Absent means `false`.","example":false,"type":"boolean"},"heartbeatTimeoutSeconds":{"description":"Seconds without a signal from the recording device after which an active recording no longer counts toward the limit. Values are clamped to 10 to 120 when applied; absent means 90.","example":90,"type":"number"}},"additionalProperties":false},"phoneCallIntegrationEnabled":{"description":"Whether a phone-call integration is switched on for the workspace. Used to show phone-call features, such as importing a call into the practice-management system from the browser extension. Absent means `false`.","example":true,"type":"boolean"},"telephonyEnabled":{"description":"Whether telephony is switched on for the workspace. With `phoneProvider` `telnyx_webrtc` it enables outbound calls from Vetnio's built-in phone; with `starface` it enables call import. Absent means `false`.","example":false,"type":"boolean"},"phoneProvider":{"description":"Phone system the workspace's calls come from:\n- `telnyx_webrtc` — Vetnio's built-in browser phone\n- `telavox` — Telavox\n- `nightcall` — Nightcall\n- `3cx` — 3CX\n- `xelion` — Xelion\n- `starface` — STARFACE\nAbsent when no provider has been selected.","example":"telavox","type":"string"},"phoneCallSpellingCorrection":{"title":"Phone-call spelling correction","description":"AI spelling correction applied to phone-call transcripts. Absent when never configured, which means correction is on with no extra context.","type":"object","properties":{"enabled":{"description":"`false` turns AI spelling correction of phone-call transcripts off. Absent means on.","example":true,"type":"boolean"},"employeeNames":{"description":"Staff names the correction should spell correctly. Absent when never set; an empty array means none.","example":["Sam Lee","Alex Morgan"],"type":"array","items":{"type":"string","description":"One name, as entered.","example":"Sam Lee"}},"additionalContext":{"description":"Free-text context given to the correction, for example product or place names. Absent when never set; an empty string means none.","example":"We often mention Librela and Bravecto.","type":"string"}},"additionalProperties":false},"phoneCallSummaryStyle":{"title":"Phone-call summary style","description":"Format of AI summaries of phone calls. Absent when never set, which means `paragraph` and `medium`.","type":"object","properties":{"format":{"description":"Layout of the summary:\n- `paragraph` — flowing prose (the default when absent)\n- `bullets` — a bulleted list","example":"bullets","type":"string"},"verbosity":{"description":"Length of the summary:\n- `short` — about 1 to 2 sentences, or 2 to 3 bullets\n- `medium` — about 3 to 5 sentences, or 4 to 6 bullets (the default when absent)\n- `long` — about 6 to 10 sentences, or 7 to 12 bullets","example":"medium","type":"string"}},"additionalProperties":false},"provetPhoneCalls":{"title":"Provet Cloud phone-call documentation","description":"Settings for drafting notes and tasks from phone calls and saving them to Provet Cloud. Absent when never configured.","type":"object","properties":{"enabled":{"description":"Whether drafting phone-call documentation and saving it to Provet Cloud is switched on.","example":true,"type":"boolean"},"providerId":{"description":"ID of the workspace's Provet Cloud connection in Vetnio, used to look up clients and save notes and tasks. Empty string when none is selected.","example":"0b7e3c9a-4f2d-4e1b-8a6c-9d5f2e1a7b3c","type":"string"},"departmentId":{"description":"Provet Cloud department ID used when saving notes and tasks. Absent when not set.","example":4,"type":"number"},"templatesText":{"description":"Phone-documentation templates as one text. Each template starts with a `## <name>` heading line followed by its body. Up to 25 templates and 60,000 characters.","example":"## Triage\nReason for call:\nAdvice given:","type":"string"},"routingInstructions":{"description":"Free-text rules the AI follows when choosing a template for a call, up to 12,000 characters.","example":"Use Triage for calls about acute illness or injury.","type":"string"},"timeZone":{"description":"IANA time zone used for the night window and for call times shown to the AI. The default is `Europe/Stockholm`.","example":"Europe/Stockholm","type":"string"},"night":{"title":"Night template rule","description":"Requires one template for calls that start inside a nightly time window. Absent when not configured.","type":"object","properties":{"startHour":{"type":"number","description":"Hour (0 to 23, in `timeZone`) at which the night window starts, inclusive.","example":20},"endHour":{"type":"number","description":"Hour (0 to 23, in `timeZone`) at which the night window ends, exclusive. Lower than `startHour` when the window spans midnight.","example":8},"templateName":{"type":"string","description":"Name of the template (a `##` heading in `templatesText`) that must be used for calls that start in the window.","example":"Triage"}},"required":["startHour","endHour","templateName"],"additionalProperties":false}},"additionalProperties":false},"provetExportMode":{"description":"Legacy stored preference, ignored by exports. All billing items are added as consultation items through Provet Cloud's per-type endpoints and billed when the consultation is finalized.","example":"consultation_items","type":"string"},"revenueRecoveryEnabled":{"description":"Whether Revenue Recovery, which suggests billable items from the consultation for the practice-management system invoice, is switched on. Absent means `false`.","example":false,"type":"boolean"},"revenueRecoverySuggestionPolicy":{"title":"Revenue Recovery suggestion policy","description":"Rules for which billable items Revenue Recovery suggests. Absent when never configured, which means bundles first, no excluded categories and no required billing lines.","type":"object","properties":{"bundlePolicy":{"description":"How Revenue Recovery treats Provet Cloud bundles:\n- `bundles_first` — prefer matching bundles over their individual items (the default)\n- `items_first` — prefer individual items; suggest a bundle only when it matches the service almost exactly\n- `hide_bundles` — never suggest bundles","example":"bundles_first","type":"string"},"excludedCategories":{"description":"Catalog categories that are never suggested: `procedure`, `medication`, `equipment`, `retail`, `lab`. Exported as stored; the older values `food` and `protocol` are treated as `retail` and `procedure`.","example":["retail","lab"],"type":"array","items":{"type":"string","description":"One catalog category.","example":"retail"}},"searchHiddenCategories":{"description":"Catalog categories also hidden from the invoice builder's manual search, using the same values as `excludedCategories`. A hidden category is never suggested either. Absent on policies saved before this setting existed, which hide every excluded category.","example":["lab"],"type":"array","items":{"type":"string","description":"One catalog category.","example":"lab"}},"requiredCategories":{"description":"Billing lines the clinic defined explicitly, such as a consultation fee. Up to 20.","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the billing line, unique within the policy (up to 64 characters).","example":"consultation-fee"},"label":{"type":"string","description":"Display name of the billing line (up to 80 characters).","example":"Consultation fee"},"instruction":{"description":"The clinic's instruction for choosing between the items, up to 600 characters.","example":"Choose by visit length: under 20 minutes is a short consultation.","type":"string"},"rule":{"description":"When the line is suggested:\n- `always_one` — on every consultation, with exactly one item chosen (the default)\n- `when_relevant` — only when the consultation supports it","example":"always_one","type":"string"},"itemIds":{"type":"array","items":{"type":"string","description":"One catalog item ID."},"description":"Catalog item IDs that can fill this line (1 to 12)."}},"required":["id","label","itemIds"],"additionalProperties":false,"title":"Required billing line","description":"A billing line the clinic defined explicitly, with the catalog items that can fill it."}}},"additionalProperties":false},"aiReceptionist":{"title":"AI receptionist","description":"Configuration of the clinic's AI receptionist, which can book appointments in the practice-management system. Absent when never configured. Practice-system connection details and provider identifiers are not exported.","type":"object","properties":{"enabled":{"description":"Whether the AI receptionist is switched on.","example":true,"type":"boolean"},"defaultLocale":{"description":"Default language of the AI receptionist: `en` or `sv-SE`.","example":"sv-SE","type":"string"},"timeZone":{"description":"IANA time zone of the clinic, used for appointment times.","example":"Europe/Stockholm","type":"string"},"emergencyPhone":{"description":"Emergency phone number configured for the AI receptionist, as entered. `null` when explicitly cleared; absent when never set.","example":"+46 8 123 456 78","type":["string","null"]},"pimsKind":{"description":"Practice-management system the AI receptionist books appointments in: `none`, `link` or `provet`.","example":"provet","type":"string"},"bookingConfig":{"title":"AI receptionist booking rules","description":"Booking rules for the AI receptionist. Absent when never set.","type":"object","properties":{"minimumNoticeMinutes":{"description":"Minimum time in minutes between the moment of booking and the start of a bookable slot. Absent when not set.","example":120,"type":"number"}},"additionalProperties":false}},"additionalProperties":false},"schedulingEnabled":{"description":"Whether the staff scheduler (for admins) and Vetnio's own appointment book (for every member) are available. Absent means `false`.","example":false,"type":"boolean"},"provetScheduleEnabled":{"description":"Whether members see their Provet appointments in the calendar, read-only and independently of `schedulingEnabled`. Absent means `false`.","example":false,"type":"boolean"},"personalizationsDisabled":{"description":"`true` when personalization is switched off for the whole workspace: Vetnio then neither learns from members' note edits nor applies learned writing style. Absent or `false` means personalization is on, unless it is switched off for an individual user.","example":false,"type":"boolean"},"manualWritingEnabled":{"description":"Whether members are offered to write clinical notes, client communications and referral letters themselves instead of recording or generating them. Set by Vetnio. Absent means `false`.","example":false,"type":"boolean"},"saveAnimanaPatients":{"description":"Whether patient details from Animana are saved to Vetnio when a consultation is started from Animana. Absent means `true`.","example":true,"type":"boolean"}},"additionalProperties":false,"title":"Workspace settings","description":"The workspace's stored shared settings. Only allowlisted keys are exported; credentials, provider connection details and internal state are left out. A key is absent when it has never been set; the default described on each field then applies and is not filled in here."},"pimsDepartmentMappings":{"type":"array","items":{"type":"object","properties":{"instanceId":{"type":"string","description":"ID of the practice-management system instance, for example a Provet Cloud instance number.","example":"8070"},"departmentId":{"type":"string","description":"Department ID within that instance, as a numeric string.","example":"4"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the mapping was created (ISO 8601, UTC).","example":"2026-09-28T08:15:00.000Z"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the mapping was last changed (ISO 8601, UTC).","example":"2026-09-28T08:15:00.000Z"}},"required":["instanceId","departmentId","createdAt","updatedAt"],"additionalProperties":false,"title":"PIMS department mapping","description":"Links one department of a practice-management system instance to this workspace."},"description":"Practice-management system departments linked to this workspace. When a user opens Vetnio from a linked Provet Cloud department, this workspace is opened. Ordered by `instanceId`, then `departmentId`. Empty when there are none."},"catalogSwitches":{"description":"Suggest and Search switches for catalog items and bundles. Absent when the workspace has none.","type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","description":"ID of the canonical catalog item.","example":"4b1d7c2e-9a3f-4e8b-b6d1-2c5f8e9a7b30"},"suggest":{"anyOf":[{"type":"string","enum":["on","off"]},{"type":"null"}],"description":"Whether Revenue Recovery may suggest it: `on`, `off`, or `null` to follow the category default.","example":"on"},"search":{"anyOf":[{"type":"string","enum":["on","off"]},{"type":"null"}],"description":"Whether vets can find it in the invoice builder's manual search: `on`, `off`, or `null` to follow the category default.","example":null}},"required":["itemId","suggest","search"],"additionalProperties":false,"title":"Catalog item switch","description":"The clinic's explicit Suggest and Search choice for one catalog item and every Provet item mapped to it."},"description":"Item switches, ordered by `itemId`. Empty when there are none."},"bundles":{"type":"array","items":{"type":"object","properties":{"bundleId":{"type":"string","description":"ID of the catalog bundle.","example":"9e2f5d1b-7a9c-4e42-8b4d-3f6c2a1e0c7a"},"sourceTemplateId":{"description":"ID of the bundle's template in the practice-management system. `null` when it is not known.","example":"117","type":["string","null"]},"suggest":{"anyOf":[{"type":"string","enum":["on","off"]},{"type":"null"}],"description":"Whether Revenue Recovery may suggest it: `on`, `off`, or `null` to follow the category default.","example":"on"},"search":{"anyOf":[{"type":"string","enum":["on","off"]},{"type":"null"}],"description":"Whether vets can find it in the invoice builder's manual search: `on`, `off`, or `null` to follow the category default.","example":null}},"required":["bundleId","sourceTemplateId","suggest","search"],"additionalProperties":false,"title":"Catalog bundle switch","description":"The clinic's explicit Suggest and Search choice for one bundle."},"description":"Bundle switches, ordered by `bundleId`. Empty when there are none."}},"required":["items","bundles"],"additionalProperties":false,"title":"Catalog switches"},"catalogNotes":{"description":"Notes for Vetnio on catalog items and bundles. Absent when the workspace has none.","type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","description":"ID of the canonical catalog item.","example":"4b1d7c2e-9a3f-4e8b-b6d1-2c5f8e9a7b30"},"description":{"type":"string","description":"The note as the clinic or Vetnio wrote it (at most 500 characters).","example":"Every senior work-up. Not for rechecks."},"updatedAt":{"type":"string","description":"When the note was last changed (ISO 8601, UTC).","example":"2026-10-20T09:00:00.000Z"}},"required":["itemId","description","updatedAt"],"additionalProperties":false,"title":"Catalog item note","description":"The clinic's note for Vetnio on one catalog item and every Provet item mapped to it."},"description":"Item notes, ordered by `itemId`. Empty when there are none."},"bundles":{"type":"array","items":{"type":"object","properties":{"bundleId":{"type":"string","description":"ID of the catalog bundle.","example":"9e2f5d1b-7a9c-4e42-8b4d-3f6c2a1e0c7a"},"sourceTemplateId":{"description":"ID of the bundle's template in the practice-management system. `null` when it is not known.","example":"117","type":["string","null"]},"description":{"type":"string","description":"The note as the clinic or Vetnio wrote it (at most 500 characters).","example":"Every senior work-up. Not for rechecks."},"updatedAt":{"type":"string","description":"When the note was last changed (ISO 8601, UTC).","example":"2026-10-20T09:00:00.000Z"}},"required":["bundleId","sourceTemplateId","description","updatedAt"],"additionalProperties":false,"title":"Catalog bundle note","description":"The clinic's note for Vetnio on one bundle."},"description":"Bundle notes, ordered by `bundleId`. Empty when there are none."}},"required":["items","bundles"],"additionalProperties":false,"title":"Catalog notes"},"letterheadAsset":{"anyOf":[{"type":"object","properties":{"mimeType":{"type":"string","const":"image/png","description":"Media type of `content`. Always `image/png`.","example":"image/png"},"encoding":{"type":"string","const":"base64","description":"Encoding of `content`. Always `base64`.","example":"base64"},"content":{"type":"string","description":"The PNG file, base64-encoded (standard alphabet with padding)."}},"required":["mimeType","encoding","content"],"additionalProperties":false,"title":"Letterhead image","description":"The workspace's uploaded letterhead logo as a base64-encoded PNG file."},{"type":"null"}],"description":"The workspace's uploaded letterhead logo, re-encoded as PNG and scaled down to fit within 1800 x 900 pixels (at most 2 MB). Included even when the letterhead is switched off. `null` when no logo is configured."}},"required":["id","name","createdAt","address","city","stateProvince","zipCode","countryCode","taxId","phone","allowPasswords","templatePermissions","audioFileRetentionPeriodInDays","isMeetingsEnabled","manualPimsKind","manualPimsName","settings","pimsDepartmentMappings","letterheadAsset"],"additionalProperties":false,"title":"Workspace configuration","description":"Identity, address, shared settings, PIMS department mappings and letterhead image of the workspace (clinic)."}},"required":["schemaVersion","exportedAt","scopeId","termList","inventory","scope","configuration"],"additionalProperties":false,"title":"Workspace content export","description":"The workspace's (clinic's) current stored settings and workspace transcription term list, with an inventory of what is included and excluded."},"OrganizationContentExport":{"type":"object","properties":{"schemaVersion":{"type":"number","const":1,"description":"Version of the export format. Currently always `1`.","example":1},"exportedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When this export was produced (ISO 8601, UTC). Values are read separately, so this is not the time of an atomic snapshot.","example":"2026-09-28T08:15:00.000Z"},"scopeId":{"type":"string","description":"ID of the exported user, workspace or organization. Equal to `configuration.id`.","example":"furunculotic-loud-chihuahua"},"termList":{"$ref":"#/components/schemas/TranscriptionTermListOutput"},"inventory":{"type":"object","properties":{"included":{"type":"array","items":{"type":"string","description":"One included category."},"description":"Categories of content included in this response.","example":["Workspace identity, address and allowlisted settings","Current workspace transcription term list"]},"excluded":{"type":"array","items":{"type":"string","description":"One excluded category."},"description":"Categories deliberately left out of this response, such as credentials, billing identifiers and other owners' settings.","example":["Credentials, API keys, OAuth/session/password material and provider connection secrets"]},"limitations":{"type":"array","items":{"type":"string","description":"One limitation."},"description":"How to interpret this export, for example that it contains current values only and is not an atomic snapshot.","example":["Current stored values only; separate reads do not form an atomic snapshot"]}},"required":["included","excluded","limitations"],"additionalProperties":false,"title":"Export inventory","description":"Plain-English statements of what this export covers and how to read it, intended for audit records. The wording can change between releases, so do not parse it."},"scope":{"type":"string","const":"organization","description":"Exported scope. Always `organization` for this endpoint.","example":"organization"},"configuration":{"type":"object","properties":{"id":{"type":"string","description":"ID of the organization (a UUID).","example":"3f6c2a1e-8b4d-4c7a-9e2f-5d1b7a9c0e42"},"name":{"type":"string","description":"Organization name.","example":"Riverside Veterinary Group"},"address":{"anyOf":[{"type":"object","properties":{"street":{"description":"Street address line. Absent when not set.","example":"12 Harbour Street","type":"string"},"attention":{"description":"Attention line of the address, for example a department or contact person. Absent when not set.","example":"Accounts Payable","type":"string"},"city":{"description":"City. Absent when not set.","example":"Riverside","type":"string"},"stateProvince":{"description":"State, province or county. Absent when not set.","example":"Riverside County","type":"string"},"zipCode":{"description":"Postal or ZIP code, as entered. Absent when not set.","example":"114 51","type":"string"},"countryCode":{"description":"Two-letter ISO 3166-1 alpha-2 country code. Absent when not set.","example":"SE","type":"string"}},"additionalProperties":false,"title":"Organization address","description":"Postal address stored for the organization. Every part is optional and omitted when not set. When the organization is billed as one legal entity (`preferences.billingLegalName` is set), invoices are addressed here."},{"type":"null"}],"description":"Postal address stored for the organization, with unset parts omitted. When the organization is billed as one legal entity (`preferences.billingLegalName` is set), invoices are addressed here. `null` when no address has been stored."},"customDomains":{"type":"array","items":{"type":"string","description":"One email domain, in lowercase.","example":"riverside-vet.example"},"description":"Email domains that belong to the organization. When a user with an address at one of these domains creates a workspace, or joins one through domain matching, that workspace is linked to the organization. Empty when there are none.","example":["riverside-vet.example"]},"audioFileRetentionPeriodInDays":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Audio retention period in days set by the organization (1 to 3650). Consultation and meeting recordings in its clinics older than this are deleted automatically; a clinic's own shorter period still applies. `null` when not set. Pending change requests are not included.","example":365},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the organization was created (ISO 8601, UTC).","example":"2026-09-28T08:15:00.000Z"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the organization's stored details were last changed (ISO 8601, UTC).","example":"2026-09-28T08:15:00.000Z"},"preferences":{"type":"object","properties":{"billingLegalName":{"description":"Legal entity name that invoices for the organization's clinics are addressed to, at the organization `address`. Absent when each clinic is billed under its own details.","example":"Riverside Veterinary Group AB","type":"string"},"billingTaxExempt":{"description":"VAT treatment of the billing entity, overriding the treatment derived from its country:\n- `none` — VAT is charged\n- `reverse` — reverse charge\n- `exempt` — VAT-exempt\nAbsent when the country-based treatment applies.","example":"reverse","type":"string"},"billingTaxId":{"description":"VAT number of the billing entity. It replaces each clinic's own VAT number on invoices. Absent when not set.","example":"SE556677889901","type":"string"},"billingClinicAttentionLine":{"description":"When `true`, each clinic's name is put on the invoice's attention line so a central accounts-payable team can route the cost. Absent means `false`.","example":true,"type":"boolean"},"deepResearchUpgradeRequestsEnabled":{"description":"Whether users in the organization's clinics can request the paid Deep Research add-on when their monthly Deep Research quota runs out. A clinic linked to several organizations allows requests if any of them enables this. Absent means `false`.","example":false,"type":"boolean"},"aiTitlesEnabled":{"description":"Default for AI-generated consultation titles in the organization's clinics. A clinic's own `aiTitlesEnabled` setting takes precedence; a clinic without one gets titles if any linked organization has `true`. Absent means not enabled by this organization.","example":true,"type":"boolean"},"recordingView":{"description":"Default recording display for the organization's clinics. Each clinic can override it. If several linked organizations specify different defaults, briefing takes precedence. Absent means waveform unless another linked organization selects briefing.","example":"briefing","type":"string","enum":["waveform","briefing"]},"liveTranscriptionEnabled":{"description":"Default for starting live transcription with consultation recording. Each clinic can override it. If several linked organizations specify different defaults, false takes precedence. Absent means enabled unless another linked organization disables it. Audio recording and transcription after recording are unaffected.","example":false,"type":"boolean"}},"additionalProperties":false,"title":"Organization preferences","description":"The organization's stored preferences. Only allowlisted keys are exported; billing-provider identifiers and integration credentials are left out. A key is absent when never set, and an organization with no stored preferences exports `{}`."}},"required":["id","name","address","customDomains","audioFileRetentionPeriodInDays","createdAt","updatedAt","preferences"],"additionalProperties":false,"title":"Organization configuration","description":"Identity, address, email domains, audio retention policy and allowlisted preferences of the organization."}},"required":["schemaVersion","exportedAt","scopeId","termList","inventory","scope","configuration"],"additionalProperties":false,"title":"Organization content export","description":"The organization's current stored settings and organization transcription term list, with an inventory of what is included and excluded."},"WorkspaceTemplateExportPage":{"type":"object","properties":{"nextCursor":{"description":"Pass this value as `cursor` to fetch the next page. `null` when this is the last page.","example":null,"type":["string","null"]},"expiresInSeconds":{"type":"number","description":"Lifetime of every `contentUrl` on this page, in seconds.","example":3600},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the `contentUrl` links on this page stop working (ISO-8601 UTC). Download before then. Expiry does not affect the stored content.","example":"2026-09-28T09:15:00.000Z"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Template ID. Pass it as `templateId` to the versions endpoints.","example":"5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20"},"workspaceId":{"type":"string","description":"ID of the workspace (clinic) that owns the template.","example":"furunculotic-loud-chihuahua"},"name":{"description":"Template name shown in the app, or null if it was never named.","example":"Standard consultation note","type":["string","null"]},"type":{"type":"string","enum":["clinical_note","referral","client_communication"],"description":"What the template produces:\n- `clinical_note` — the clinical note (medical record entry) for a consultation.\n- `referral` — a referral letter to another clinic or specialist.\n- `client_communication` — a message to the pet owner.","example":"clinical_note"},"creatorId":{"type":"string","description":"User ID (UUID) of the person who created the template.","example":"0f8fad5b-d9cb-469f-a165-70867728950e"},"creatorRole":{"type":"string","enum":["member","admin","superadmin"],"description":"Workspace role the creator had when creating the template:\n- `member` — clinician.\n- `admin` — workspace administrator.\n- `superadmin` — workspace owner-level administrator.","example":"admin"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the template was created (ISO-8601 UTC).","example":"2026-03-14T10:02:11.000Z"},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the template was last changed (ISO-8601 UTC), or null if never changed after creation.","example":"2026-09-02T14:30:00.000Z"},"updatedBy":{"description":"User ID of the person who last changed the template, or null.","example":"0f8fad5b-d9cb-469f-a165-70867728950e","type":["string","null"]},"isManaged":{"type":"boolean","description":"`true` when Vetnio or the clinic's organization provisioned the template (for example from an organization template or an integration) rather than a clinic user writing it.","example":false},"isDefault":{"type":"boolean","const":false,"description":"Always `false`: Vetnio's read-only default catalog templates are excluded from this export.","example":false},"jsonTemplateId":{"description":"Linked JSON template ID only when the schema belongs to this workspace and is included in its JSON template export.","type":["string","null"]},"hasExcludedJsonTemplate":{"type":"boolean","description":"`true` when the template links to a structured (JSON) schema that is not part of this workspace's export, such as a Vetnio-provided schema. That schema's ID and body are not exposed.","example":false},"instructionsArtifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Stored imported-template instructions and section strategies, when present."},"artifact":{"anyOf":[{"type":"object","properties":{"contentUrl":{"type":"string","description":"Signed HTTPS URL that downloads the stored body without further authentication. It expires at the page's `expiresAt` (one hour); fetch the page again for a fresh link. Treat it as a secret.","example":"https://storage.example.com/templates/furunculotic-loud-chihuahua/5b0d7a3e-2c41-4f0e-9a77-1f3c9e6b8d20?X-Amz-Expires=3600&X-Amz-Signature=…"},"currentVersionId":{"description":"The downloaded version. Null means storage supplied no immutable version ID, including the legacy null version, so the URL follows the current object.","type":["string","null"]},"contentType":{"description":"Media type of the stored body as recorded by storage, for example `text/html` or `application/json`, or null if none was recorded.","example":"text/html","type":["string","null"]},"size":{"description":"Size of the stored body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the current body was last written (ISO-8601 UTC), or null if unknown.","example":"2026-09-28T08:15:00.000Z"}},"required":["contentUrl","currentVersionId","contentType","size","lastModified"],"additionalProperties":false,"title":"Template export artifact","description":"A downloadable stored body of a template: a short-lived link plus its storage metadata."},{"type":"null"}],"description":"Null when the current body is absent. Retained versions may still exist."}},"required":["id","workspaceId","name","type","creatorId","creatorRole","createdAt","updatedAt","updatedBy","isManaged","isDefault","jsonTemplateId","hasExcludedJsonTemplate","instructionsArtifact","artifact"],"additionalProperties":false,"title":"Exported workspace template","description":"One clinical-note, referral or client-communication template owned by the workspace."},"description":"Templates on this page, ordered by ascending ID."}},"required":["nextCursor","expiresInSeconds","expiresAt","items"],"additionalProperties":false,"title":"Workspace template export page","description":"One page of the workspace's note templates with download links."},"TemplateVersionHistory":{"type":"object","properties":{"currentVersionId":{"description":"Version ID of the template's current body at the time of the request, or null when there is no current body. Unlike `artifact.currentVersionId`, a legacy unversioned body is reported here as the literal string `\"null\"`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY","type":["string","null"]},"versions":{"type":"array","items":{"type":"object","properties":{"versionId":{"type":"string","description":"Opaque stored version ID. A literal null version belongs to unversioned or suspended storage and can be overwritten."},"isLatest":{"type":"boolean","description":"`true` when this version is the template's current body.","example":true},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When this version was stored (ISO-8601 UTC), or null if unknown.","example":"2026-09-02T14:30:00.000Z"},"size":{"description":"Size of this version's body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"audit":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the audit-log entry (UUID).","example":"c4e1a7b2-9d3f-4e8a-b6c5-2f1e0d9c8b7a"},"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the change was made (ISO-8601 UTC).","example":"2026-09-02T14:30:00.000Z"},"actorName":{"description":"Display name of the person who made the change, or null when unknown or for system changes. For changes made by Vetnio support on a customer's behalf, this is the support staff member.","example":"Dr. Sam Lee","type":["string","null"]},"actorType":{"type":"string","enum":["user","vetnio_staff","system"],"description":"Who made the change:\n- `user` — a member of the customer's team.\n- `vetnio_staff` — Vetnio staff, for example while providing support.\n- `system` — an automated process.","example":"user"},"action":{"type":"string","description":"Audit action that saved this version, for example `template.created`, `template.content_updated` or `template.restored`.","example":"template.content_updated"},"s3VersionId":{"type":"string","description":"The stored version ID the audit entry refers to; equals the version's `versionId`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"}},"required":["id","occurredAt","actorName","actorType","action","s3VersionId"],"additionalProperties":false},{"type":"null"}],"title":"Template version audit","description":"Audit details of the edit that saved this version. Only available for workspace note templates and `part=content`; `null` otherwise, or when no matching audit entry exists. Not a clinical approval or accuracy classification."}},"required":["versionId","isLatest","lastModified","size","audit"],"additionalProperties":false,"title":"Retained template version","description":"Metadata of one retained version of a template body."},"description":"Retained versions on this page, newest first. A page can hold fewer than 50 versions even when more follow."},"nextCursor":{"description":"Pass this value as `cursor` to fetch older versions. `null` when the history is complete.","example":null,"type":["string","null"]}},"required":["currentVersionId","versions","nextCursor"],"additionalProperties":false,"title":"Template version history","description":"One page of a template's retained stored versions."},"TemplateVersionSnapshot":{"type":"object","properties":{"currentVersionId":{"description":"Version ID of the template's current body at the time of the request, or null when there is no current body. Unlike `artifact.currentVersionId`, a legacy unversioned body is reported here as the literal string `\"null\"`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY","type":["string","null"]},"version":{"type":"object","properties":{"versionId":{"type":"string","description":"Opaque stored version ID. A literal null version belongs to unversioned or suspended storage and can be overwritten."},"isLatest":{"type":"boolean","description":"`true` when this version is the template's current body.","example":true},"lastModified":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When this version was stored (ISO-8601 UTC), or null if unknown.","example":"2026-09-02T14:30:00.000Z"},"size":{"description":"Size of this version's body in bytes, or null if unknown.","example":2048,"type":["number","null"]},"contentType":{"description":"Media type of this version's body as recorded by storage, for example `text/html` or `application/json`, or null.","example":"text/html","type":["string","null"]},"audit":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the audit-log entry (UUID).","example":"c4e1a7b2-9d3f-4e8a-b6c5-2f1e0d9c8b7a"},"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$","description":"When the change was made (ISO-8601 UTC).","example":"2026-09-02T14:30:00.000Z"},"actorName":{"description":"Display name of the person who made the change, or null when unknown or for system changes. For changes made by Vetnio support on a customer's behalf, this is the support staff member.","example":"Dr. Sam Lee","type":["string","null"]},"actorType":{"type":"string","enum":["user","vetnio_staff","system"],"description":"Who made the change:\n- `user` — a member of the customer's team.\n- `vetnio_staff` — Vetnio staff, for example while providing support.\n- `system` — an automated process.","example":"user"},"action":{"type":"string","description":"Audit action that saved this version, for example `template.created`, `template.content_updated` or `template.restored`.","example":"template.content_updated"},"s3VersionId":{"type":"string","description":"The stored version ID the audit entry refers to; equals the version's `versionId`.","example":"3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY"}},"required":["id","occurredAt","actorName","actorType","action","s3VersionId"],"additionalProperties":false},{"type":"null"}],"title":"Template version audit","description":"Audit details of the edit that saved this version. Only available for workspace note templates and `part=content`; `null` otherwise, or when no matching audit entry exists. Not a clinical approval or accuracy classification."}},"required":["versionId","isLatest","lastModified","size","contentType","audit"],"additionalProperties":false,"title":"Retained template version details","description":"Metadata of the requested version."},"content":{"type":"string","description":"The exact retained body as UTF-8 text, including HTML instructions or the original JSON schema."}},"required":["currentVersionId","version","content"],"additionalProperties":false,"title":"Template version snapshot","description":"The exact saved body of one retained template version, with its metadata."},"WorkspaceCreated":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the newly created workspace. Use it as `workspaceId` in subsequent workspace-scoped calls, for example to create consultations.","example":"furunculotic-loud-chihuahua"}},"required":["id"],"additionalProperties":false,"title":"Workspace created","description":"Confirmation returned after a workspace (veterinary clinic) is created. Contains only the new workspace ID; it also appears in `GET /workspaces` from now on."},"JsonTemplateMetadataItem":{"type":"object","properties":{"id":{"type":"string","description":"ID of the JSON template (a UUID). Pass it as `jsonTemplateId` to Get JSON template detail, Generate a structured document or Create a template. Built-in templates have the same ID in every workspace.","example":"2a859133-0e04-4f63-88d2-aa0ee318cd8d"},"name":{"description":"Name of the structured template as shown in Vetnio. `null` if it was saved without a name.","example":"Soap Note for Dog","type":["string","null"]},"description":{"description":"Short description of the template's purpose. Only built-in templates have one; the field is absent for templates created in the workspace.","example":"A template for a soap note for a dog.","type":"string"}},"required":["id","name"],"additionalProperties":false,"title":"JSON template summary","description":"A structured template's ID and name, without its schema."},"JsonTemplateDetail":{"type":"object","properties":{"id":{"type":"string","description":"ID of the JSON template (a UUID).","example":"2a859133-0e04-4f63-88d2-aa0ee318cd8d"},"name":{"description":"Name of the structured template as shown in Vetnio. `null` if it was saved without a name.","example":"Soap Note for Dog","type":["string","null"]},"jsonTemplateSchema":{"type":"object","properties":{"type":{"default":"object","description":"JSON Schema type of the document root. `object` for every structured template; a schema saved without a valid type is reported as `object`.","example":"object","type":"string"},"title":{"description":"Optional schema title.","example":"Lameness examination","type":"string"},"description":{"description":"Optional description of the whole document.","example":"Structured lameness work-up for horses.","type":"string"},"properties":{"description":"The template's fields, keyed by the exact key that appears in generated documents. Each value is a JSON Schema property: `type` (`string`, `number`, `integer`, `boolean`, `array` or `object`), a `description` telling the AI what to extract and what to do when it is missing, and optionally `title`, `enum` (permitted answers, the Single choice and Multiple choice section types in Vetnio), `items` for arrays and nested `properties` for objects. Always present (possibly empty) when `type` is `object`.","example":{"anamnesis":{"type":"string","title":"Anamnesis","description":"History and presenting complaint as discussed. Leave empty if not mentioned."},"weight_kg":{"type":"number","description":"Body weight in kilograms, if stated."},"contact_preference":{"type":"string","enum":["Phone","Email"],"description":"How the owner wants to be contacted."}},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"required":{"description":"Keys of `properties` that generated documents must always contain. When a field is required but nothing relevant was said, generation leaves it empty rather than inventing a value.","example":["anamnesis"],"type":"array","items":{"type":"string"}},"enum":{"description":"Permitted values for the document root. Not used by structured templates in practice, which put `enum` on individual properties instead.","type":"array","items":{"type":["string","number","boolean"]}}},"required":["type"],"additionalProperties":{},"title":"JSON template schema","description":"The JSON Schema that generated documents follow: one property per field, with the instructions the AI uses to fill it."},"createdAt":{"description":"When the template was created, as an ISO-8601 UTC timestamp. Built-in templates report `1970-01-01T00:00:00.000Z`.","example":"2026-08-21T13:05:00.000Z","type":"string"}},"required":["id","name","jsonTemplateSchema","createdAt"],"additionalProperties":false,"title":"JSON template detail","description":"A structured template with its full schema. A structured template defines separate output fields (for example Anamnesis, Examination, Treatment) that Vetnio fills from a consultation, either as a structured clinical note or through Generate a structured document."},"ConsultationListItemOutput":{"type":"object","properties":{"id":{"type":"string","description":"Consultation ID (UUID).","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"workspaceId":{"type":"string","description":"ID of the workspace (clinic) that owns the consultation.","example":"furunculotic-loud-chihuahua"},"creatorId":{"type":"string","description":"User ID of the person who created the consultation. Always the caller for this endpoint.","example":"b8c9d0e1-f2a3-4456-bcde-678901234567"},"name":{"type":"string","description":"Display name of the consultation; may be an empty string.","example":"Bella - annual checkup"},"aiTitle":{"description":"Separate AI-generated title describing the consultation, refreshed after clinical-note saves when automatic naming is enabled. May be `null` when no title is generated or when the workspace uses generated titles as consultation names instead.","example":"Annual vaccination and dental check","type":["string","null"]},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp. The list is sorted by this value, newest first.","example":"2026-09-14T08:30:00.000Z","type":"string"},"recordingLanguageCode":{"description":"Language code chosen when the consultation was created (for example `sv`, `en`, `de`). Each uploaded recording carries its own language code, which is what transcription uses.","example":"en","type":["string","null"]},"recordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed. Same value as `uploadedRecordingDurationInMilliseconds`.","example":754000},"uploadedRecordingDurationInMilliseconds":{"type":"number","description":"Total length of all audio uploaded to the consultation, in milliseconds, including silence. Vetnio's audio processor updates it shortly after each upload; it is `0` until the first upload has been processed.","example":754000},"isGeneratingClinicalNote":{"type":"boolean","description":"`true` while Vetnio is generating the clinical note for this consultation; set back to `false` when generation ends. Poll it to detect when a requested note is ready.","example":false},"isGeneratingCommunication":{"type":"boolean","description":"`true` while Vetnio is generating the owner communication (the client-facing summary) for this consultation; set back to `false` when generation ends.","example":false},"hasClinicalNote":{"type":"boolean","description":"`true` when a clinical note has been saved for the consultation (generated or written manually).","example":true},"hasCommunication":{"type":"boolean","description":"`true` when an owner communication has been saved for the consultation.","example":false},"discussionStatus":{"description":"Legacy field kept for backward compatibility. Current consultations always report `missing`; do not rely on it.","example":"missing","type":["string","null"]},"rating":{"description":"Legacy feedback field that current Vetnio clients no longer set; normally `null`.\n- `like` — the user rated the consultation output positively.\n- `dislike` — the user rated it negatively.","example":null,"anyOf":[{"type":"string","enum":["like","dislike"]},{"type":"null"}]},"ratingReason":{"description":"Legacy free-text reason for `rating`; normally `null`.","example":null,"type":["string","null"]},"clinicalNoteTemplateId":{"description":"ID of the template used to generate the clinical note, or `null` when none is selected.","example":"6a4dd7d0-0fe8-4f73-8e05-8898748da1ce","type":["string","null"]},"communicationTemplateId":{"description":"ID of the template used to generate the owner communication, or `null` when none is selected.","example":null,"type":["string","null"]},"referralTemplateId":{"description":"ID of the template used to generate a referral letter, or `null` when none is selected.","example":null,"type":["string","null"]},"clinicalNoteJsonTemplateId":{"description":"ID of the JSON (structured document) template bound to the clinical note, or `null`.","example":null,"type":["string","null"]},"isGeneratingReferral":{"description":"`true` while a referral letter is being generated for this consultation.","example":false,"type":"boolean"},"lastTranscribedRecordingId":{"description":"Recording ID (`<epoch-ms>-<language>`) of the latest recording included in the transcript, or `null` if nothing has been transcribed. Recordings whose ID sorts at or before this value are treated as already transcribed.","example":"1726302600000-en","type":["string","null"]},"lastSubmittedRecordingId":{"description":"Value of `lastTranscribedRecordingId` when the user last submitted the consultation for note generation in the Vetnio app. A different `lastTranscribedRecordingId` means audio was added since; `null` if never submitted.","example":"1726302600000-en","type":["string","null"]},"uploadedRecordingDurationInMillisecondsExcludingSilence":{"description":"Same as `recordingDurationInMilliseconds`, but with silent stretches (quieter than -40 dB) removed. `0` until the first upload has been processed.","example":612400,"type":"number"},"clientId":{"description":"ID of the client (pet owner) linked directly to the consultation by some practice-management integrations; usually `null`. Prefer `patientId` and the patient's owner.","example":null,"type":["string","null"]},"patientId":{"description":"ID of the patient linked to the consultation, or `null` if no patient is linked.","example":"c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f","type":["string","null"]},"isDeleted":{"description":"Whether the consultation is archived. Always `false` here because archived consultations are excluded from this list.","example":false,"type":"boolean"},"isHidden":{"description":"Whether the consultation was deleted (moved out of view) in the Vetnio app. Always `false` here because such consultations are excluded.","example":false,"type":"boolean"},"recordingDurationInMillisecondsExcludingSilence":{"description":"Same as `recordingDurationInMilliseconds`, but with silent stretches (quieter than -40 dB) removed. `0` until the first upload has been processed. Same value as `uploadedRecordingDurationInMillisecondsExcludingSilence`.","example":612400,"type":"number"},"searchableContent":{"description":"Plain-text copy of the latest saved clinical note (HTML tags removed, whitespace collapsed, at most 100,000 characters), kept for search. `null` until a clinical note is saved. Use `GET .../records` for the formatted note.","example":"Bella, 6-year-old Labrador, presented for annual vaccination. Weight 31 kg. Mild tartar on upper premolars.","type":["string","null"]},"externalId":{"description":"Identifier of the matching visit or consultation in the clinic's practice-management system, or `null` if the consultation is not linked to one. Free text; not unique.","example":"123456","type":["string","null"]}},"required":["id","workspaceId","creatorId","name","createdAt","recordingDurationInMilliseconds","uploadedRecordingDurationInMilliseconds","isGeneratingClinicalNote","isGeneratingCommunication","hasClinicalNote","hasCommunication"],"additionalProperties":false,"title":"Consultation list item","description":"A consultation as returned by the paginated list, with template IDs, audio duration, generation flags and a plain-text copy of the clinical note."},"ConsultationExportItemOutput":{"type":"object","properties":{"structuredDocument":{"description":"Presigned GET URL for the separately stored structured JSON document, or null if none exists. The payload matches the JSON template used to generate it; it is not the rendered clinical note.","type":["string","null"]},"communication":{"description":"Presigned GET URL for the owner communication in its stored format, or null if none exists.","type":["string","null"]},"referral":{"description":"Presigned GET URL for the referral letter in its stored format, or null if none exists.","type":["string","null"]},"id":{"type":"string","description":"Consultation ID (UUID).","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Display name of the consultation; may be an empty string.","example":"Bella - annual checkup"},"creatorId":{"type":"string","description":"User ID of the person who created the consultation.","example":"b8c9d0e1-f2a3-4456-bcde-678901234567"},"createdAt":{"description":"When the consultation was created, as an ISO-8601 UTC timestamp. The `createdAtFrom`/`createdAtBefore` filters and the sort order use this value.","example":"2026-09-14T08:30:00.000Z","type":"string"},"externalId":{"description":"Identifier of the matching visit in the clinic's practice-management system, or `null` if the consultation is not linked to one.","example":"123456","type":["string","null"]},"clinicalNoteTemplateId":{"description":"ID of the clinical note template selected for the consultation, or `null` if none is selected.","example":"6a4dd7d0-0fe8-4f73-8e05-8898748da1ce","type":["string","null"]},"audioRecording":{"description":"Presigned GET URL for the full consultation audio (all uploaded recordings joined into one 16 kHz mono WAV file), or `null` if no audio exists or it was removed by the clinic's audio-retention policy. Creator-only playback settings do not apply to authorized admin exports.","type":["string","null"]},"transcription":{"description":"Presigned GET URL for the full transcript as a UTF-8 plain-text file, or `null` if nothing has been transcribed yet.","type":["string","null"]},"clinicalNote":{"description":"Presigned GET URL for the stored clinical note (HTML, or JSON for structured notes), or `null` if no note has been saved yet.","type":["string","null"]}},"required":["structuredDocument","communication","referral","id","name","creatorId","createdAt","externalId","clinicalNoteTemplateId","audioRecording","transcription","clinicalNote"],"additionalProperties":false,"title":"Consultation export item","description":"One consultation in the export list with its metadata and presigned download URLs. Archived and deleted consultations are included and are not flagged."},"TemplateListItemOutput":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template (a UUID). Pass it as `templateId` when generating a record or managing the template.","example":"3f6c2a1e-8b4d-4c7a-9e21-5d0b7f9a6c13"},"name":{"type":"string","description":"Template Name shown in Vetnio's template lists and pickers. Not unique within a clinic. An empty string when the template has no name.","example":"Follow-up - clinical team"},"type":{"anyOf":[{"type":"string","enum":["clinical_note","referral","client_communication"],"description":"The Template Type: which kind of document the template writes. It decides where Vetnio offers the template and which instructions its AI template assistant follows.\n- `clinical_note` — Clinical Note: the medical record of the visit, for the clinical team (record type `clinical note`).\n- `client_communication` — Client Communication: an owner-facing message about the visit (record type `communication`).\n- `referral` — Referral: a letter to or from another clinician or clinic (record type `referral`).","example":"clinical_note"},{"type":"null"}],"description":"The Template Type: which kind of document the template writes (`clinical_note`, `client_communication` or `referral`). Always set in practice; templates created without a type are `clinical_note`.","example":"clinical_note"},"creatorId":{"type":"string","description":"User ID (a UUID) of the person who created the template, or who duplicated it from another template. For templates Vetnio added to the clinic, the user who triggered that provisioning.","example":"5b1e9d3c-27a4-4f0e-8c6d-2e9f71a4b852"},"creatorRole":{"type":"string","enum":["member","admin","superadmin"],"description":"The creator's role in the clinic when the template was created; it is not updated if their role changes later. Members' access to a template depends on it under the clinic's template permissions.\n- `member` — created by a regular clinic member.\n- `admin` — created by a clinic admin, or provisioned by Vetnio.\n- `superadmin` — created by a clinic super-admin.","example":"admin"},"createdAt":{"description":"When the template was created, as an ISO-8601 UTC timestamp.","example":"2026-09-14T08:30:00.000Z","type":"string"},"jsonTemplateId":{"description":"ID of the JSON template (structured template) linked to this template, or `null`. When set, clinical notes generated on consultations that use this template are produced as structured JSON documents following that JSON template, with this template's instructions guiding the field content.","example":null,"type":["string","null"]},"isDefault":{"type":"boolean","description":"`true` for a Vetnio default template, added to the clinic from Vetnio's default template library. Default templates are read-only: updating or deleting one returns 403. Duplicate it to get an editable copy.","example":false},"isHidden":{"type":"boolean","description":"`true` when the calling user has hidden this template from their own picker.","example":false},"isPinned":{"type":"boolean","description":"`true` when the calling user has starred this template.","example":false},"isManaged":{"type":"boolean","description":"`true` when Vetnio or the clinic's organization provisioned the template (Vetnio defaults, organization templates, practice-management-system integrations) rather than a clinic user writing it. Managed templates stay visible to members under every template-permission mode, and members cannot edit them unless they created them.","example":false}},"required":["id","name","type","creatorId","creatorRole","createdAt","jsonTemplateId","isDefault","isHidden","isPinned","isManaged"],"additionalProperties":false,"title":"Template","description":"A prompt template: reusable writing instructions (headings plus guidance on what belongs under each) that Vetnio follows when it generates a clinical note, client communication or referral letter. The template body is not included."},"ClientOutput":{"type":"object","properties":{"id":{"type":"string","description":"Client id (UUID), generated by Vetnio.","example":"e1f2a3b4-c5d6-4789-efab-901234567890"},"name":{"description":"The owner's full name, free text. `null` when not recorded, for example for the placeholder owner created with a patient that had no owner details.","example":"Alex Morgan","type":["string","null"]},"address":{"description":"The owner's street address, free text. `null` when not recorded.","example":"12 Harbour Street, Riverside","type":["string","null"]},"zipCode":{"description":"The owner's postal code, free text. `null` when not recorded.","example":"114 51","type":["string","null"]},"phoneNumbers":{"type":"array","items":{"type":"string","description":"One phone number, as stored.","example":"+46701234567"},"description":"The owner's phone numbers, stored as given (no normalisation). E.164 format such as `+46701234567` is recommended. Empty array when none are recorded."},"email":{"description":"The owner's email address. Stored as given; the format is not validated. `null` when not recorded.","example":"alex.morgan@example.com","type":["string","null"]}},"required":["id","name","address","zipCode","phoneNumbers","email"],"additionalProperties":false,"title":"Client (pet owner)","description":"An animal owner registered in the workspace. A client can own any number of patients. Clients are shared by every member of the workspace and are also created automatically when patients are synced from a connected practice-management system."},"WorkspaceListItemOutput":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the workspace (veterinary clinic), generated by Vetnio as three lowercase words joined by hyphens. Pass it as the `workspaceId` path parameter of every workspace-scoped endpoint.","example":"furunculotic-loud-chihuahua"},"name":{"type":"string","description":"Display name of the clinic, as set by its admins. An empty string if no name was ever set.","example":"Riverside Animal Clinic"},"role":{"type":"string","enum":["member","admin","superadmin"],"description":"The authenticated user's own membership role in this workspace. Roles are cumulative and decide which endpoints the user may call:\n- `member` — clinician access: consultations, recordings, notes, patients and VetsGPT.\n- `admin` — everything a member can do, plus member management, billing, workspace settings and the workspace data-export endpoints.\n- `superadmin` — everything an admin can do, plus deleting the workspace and changing other superadmins' roles. The creator of a workspace starts as its superadmin, and a workspace always keeps at least one.","example":"admin"},"phoneCallIntegrationEnabled":{"description":"Whether the clinic receives phone calls into Vetnio through a telephony integration. Use it to show phone-call features only for clinics that have them. Always present in practice.","example":false,"type":"boolean"},"revenueRecoveryEnabled":{"description":"Whether revenue recovery (suggestions for billable items missed in a consultation) is enabled for the clinic. Use it to show those features only where they are switched on. Always present in practice.","example":false,"type":"boolean"}},"required":["id","name","role"],"additionalProperties":false,"title":"Workspace list item","description":"A workspace the authenticated user belongs to, with the user's role in it."},"TranscriptionTermListOutput":{"type":"object","properties":{"terms":{"type":"array","items":{"type":"string","description":"One term, in its stored spelling.","example":"Librela"},"description":"Terms in their stored spelling and order. Up to 200 terms, each at most 50 characters and four words. Empty when no list is saved.","example":["Librela","Apoquel","Bravecto"]},"version":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Edit-concurrency revision of the list: 1 or higher for a saved list, 0 when none is saved. It increases with each save; earlier contents are not retained.","example":3},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\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))$"},{"type":"null"}],"description":"When the list was last saved (ISO 8601, UTC). `null` when no list is saved.","example":"2026-09-28T08:15:00.000Z"},"updatedBy":{"description":"ID of the user who last saved the list (a UUID). `null` when no list is saved or that user's account has been deleted.","example":"7d1f0c3e-2a4b-4e8f-9c61-5b2a8d4e7f10","type":["string","null"]}},"required":["terms","version","updatedAt","updatedBy"],"additionalProperties":false,"title":"Transcription term list","description":"The scope's current custom transcription vocabulary: names, abbreviations and specialist terms used as spelling and recognition hints. When no list has been saved, `terms` is empty, `version` is 0 and `updatedAt` and `updatedBy` are `null`."},"VetsgptChat":{"type":"object","properties":{"chat_id":{"type":"string","description":"Chat id (UUID). Use it as `chatId` in the other VetsGPT endpoints.","example":"3f9c2a71-5b8e-4d1a-9c47-0e6b2d8f1a53"},"user_id":{"type":"string","description":"Id of the Vetnio user who owns the chat, i.e. the caller.","example":"6c1d2e3f-4a5b-4c7d-8e9f-0a1b2c3d4e5f"},"workspace_id":{"type":"string","description":"Workspace the chat belongs to.","example":"furunculotic-loud-chihuahua"},"title":{"type":"string","description":"Chat 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.","example":"NSAID dosing in a dog with CKD"},"created_at":{"type":"string","description":"When the chat was created (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z"},"last_updated_at":{"type":"string","description":"When the chat last changed (ISO-8601 UTC).","example":"2026-10-04T09:12:31.000Z"},"messages":{"type":"array","items":{"type":"object","properties":{"message_id":{"type":"string","description":"Message id, unique within the chat. Use it with the feedback endpoint.","example":"rest-assistant-message-9d2e7c1b4a6f8e0d3c5b7a9f1e2d4c6b"},"timestamp":{"type":"string","description":"When the message was stored (ISO-8601 UTC).","example":"2026-10-04T09:12:58.000Z"},"type":{"type":"string","enum":["user_message","bot_message"],"description":"Who wrote the message:\n- `user_message` — the vet.\n- `bot_message` — VetsGPT.","example":"bot_message"},"content":{"type":"object","properties":{"text":{"type":"string","description":"Message text. Assistant answers are Markdown with inline source citations (see the ask endpoint).","example":"What is the meloxicam dose for a 24 kg dog?"},"attachments":{"description":"Files 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.","example":["data:application/pdf;name=bloodwork.pdf;base64,JVBERi0xLjcK..."],"type":"array","items":{"type":"string"}}},"required":["text"],"additionalProperties":false,"title":"VetsGPT message content","description":"Text and attachments of a stored VetsGPT message."},"feedback":{"type":"string","enum":["positive","negative","none"],"description":"The vet's rating of the message:\n- `positive` — rated helpful (thumbs up).\n- `negative` — rated unhelpful (thumbs down).\n- `none` — not rated, or the rating was cleared.","example":"positive"},"isAttachmentAnalysis":{"description":"Internal 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.","example":false,"type":"boolean"},"copilotProposals":{"description":"Edits 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.","type":"array","items":{"type":"object","properties":{"proposalId":{"type":"string","minLength":1,"description":"Id of the proposal, unique within the message.","example":"cp_7f3a9c21"},"tool":{"type":"string","enum":["edit_clinical_note","edit_communication"],"description":"The editing tool VetsGPT used:\n- `edit_clinical_note` — edits the consultation's clinical note.\n- `edit_communication` — edits the consultation's client communication.","example":"edit_clinical_note"},"target":{"type":"string","enum":["clinical_note","communication"],"description":"Which document the edit applies to:\n- `clinical_note` — the clinical note.\n- `communication` — the client communication.","example":"clinical_note"},"summary":{"type":"string","minLength":1,"maxLength":300,"description":"Short description of the change shown to the vet (up to 300 characters).","example":"Add the meloxicam dose to the treatment plan"},"operation":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"patch"},"edits":{"readOnly":true,"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"find":{"type":"string","minLength":1,"description":"The line, or the consecutive lines, being replaced — their text exactly as it reads in the current content, one per <br />."},"replace":{"type":"string","description":"What those lines become. Empty removes them."}},"required":["find","replace"],"additionalProperties":false}}},"required":["kind","edits"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace_all"},"html":{"type":"string","minLength":1}},"required":["kind","html"],"additionalProperties":false}],"description":"The 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.","type":"object"},"source":{"description":"Where the content of the edit came from:\n- `consultation` — this consultation's data.\n- `vetsgpt_knowledge` — VetsGPT's own veterinary knowledge, flagged to the vet for review.\nAbsent on older proposals, which count as `consultation`.","example":"consultation","type":"string","enum":["consultation","vetsgpt_knowledge"]},"mode":{"type":"string","enum":["auto","manual"],"description":"How the vet had VetsGPT apply edits when the proposal was made:\n- `auto` — applied immediately (\"Write it\").\n- `manual` — waits for the vet to accept (\"Ask first\").","example":"manual"},"baseHash":{"type":"string","minLength":1,"description":"Fingerprint of the document version the edit was written against. Used to detect that the document changed since.","example":"9b1e4c7a"},"status":{"type":"string","enum":["pending","applied","accepted","rejected","undone","stale"],"description":"Review state of the proposal:\n- `pending` — waiting for the vet.\n- `applied` — applied automatically.\n- `accepted` — accepted by the vet and applied.\n- `rejected` — declined by the vet.\n- `undone` — applied, then reverted.\n- `stale` — could not be applied because the document changed (shown as Outdated).","example":"accepted"}},"required":["proposalId","tool","target","summary","operation","mode","baseHash","status"],"additionalProperties":false,"title":"VetsGPT edit proposal","description":"An edit to a consultation's clinical note or client communication that VetsGPT proposed in the web app's consultation panel. Read-only through the REST API."}}},"required":["message_id","timestamp","type","content","feedback"],"additionalProperties":false,"title":"Stored VetsGPT message","description":"One stored message of a VetsGPT chat."},"description":"Messages in the chat, oldest first. Always empty for a newly created chat."},"searchable_content":{"description":"Plain-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.","type":"string"}},"required":["chat_id","user_id","workspace_id","title","created_at","last_updated_at","messages"],"additionalProperties":false,"title":"VetsGPT chat","description":"A VetsGPT conversation, private by default. Only its owner and explicitly granted current workspace members can access it; administrators have no implicit access."},"Patient":{"type":"object","properties":{"id":{"type":"string","description":"Patient id (UUID), generated by Vetnio.","example":"f2a3b4c5-d6e7-4890-fabc-012345678901"},"name":{"description":"The animal's name. Free text; Vetnio does not enforce uniqueness. `null` when not recorded.","example":"Bella","type":["string","null"]},"species":{"description":"Species, free text. The Vetnio web app stores the English species name, followed by ` - <breed>` when a breed is chosen (for example `Dog` or `Dog - Labrador Retriever`); patients synced from a practice-management system may use that system's values. `null` when not recorded.","example":"Dog - Labrador Retriever","type":["string","null"]},"breed":{"description":"Breed, free text. `null` when not recorded.","example":"Labrador Retriever","type":["string","null"]},"dateOfBirth":{"description":"Date of birth (`YYYY-MM-DD`), or `null` when not recorded.","example":"2018-04-12","type":["string","null"]},"gender":{"description":"Sex and neuter status, free text. The Vetnio web app uses `Male`, `Female`, `Male Neutered` and `Female Neutered`; use the same values so the patient list's gender filter and the UI stay consistent. `null` when not recorded.","example":"Female Neutered","type":["string","null"]},"weight":{"description":"Body weight as free text including the unit, as the web app writes it (for example `24.5 kg`). Not parsed or converted. `null` when not recorded.","example":"24.5 kg","type":["string","null"]},"identifier":{"description":"The animal's identifier, typically a microchip (transponder) number, but it can be a tattoo, registration number or practice-management-system id. Free text, not unique; matched by the patient list search. `null` when not recorded.","example":"752098100012345","type":["string","null"]},"insurance":{"description":"Name of the animal's insurance company, free text. `null` when the animal is uninsured or it is not recorded.","example":"Agria","type":["string","null"]},"clientId":{"description":"Id of the owner (client). Patients created through the API always have one (an empty placeholder owner when no owner details were given); `null` only for patients created without an owner by other flows.","example":"e1f2a3b4-c5d6-4789-efab-901234567890","type":["string","null"]},"createdAt":{"description":"When the patient was created (ISO-8601). May be `null` for very old records.","example":"2026-09-12T08:41:07.000Z","type":["string","null"]},"updatedAt":{"description":"When the patient was last changed (ISO-8601). Set on every update, even one that changes nothing, and by practice-management-system syncs.","example":"2026-10-01T14:03:22.000Z","type":["string","null"]}},"required":["id","name","species","breed","dateOfBirth","gender","weight","identifier","insurance","clientId","createdAt","updatedAt"],"additionalProperties":false,"title":"Patient","description":"An animal registered in the workspace. A patient has one owner (client) and can be linked to any number of consultations, which make up its history; each consultation has at most one patient. Patients are shared by every member of the workspace."},"WorkspaceUpdated":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the workspace that was updated.","example":"furunculotic-loud-chihuahua"}},"required":["id"],"additionalProperties":false,"title":"Workspace updated","description":"Confirmation payload returned after a workspace's details have been updated. The Stripe customer record is also updated asynchronously."}},"securitySchemes":{"Authorization":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"A Vetnio API key (`sk_live_…`, `sk_org_…` or `sk_ws_…`) sent as `Authorization: Bearer <key>`. Personal keys stay valid until deleted; organization and clinic keys until revoked or expired, and a rotated one keeps working for up to 24 hours."}}}}