Workflows
Document a visit end to end
Create a consultation, upload the visit's audio, transcribe it, generate the clinical note and write the vet's edits back, with the polling and retry rules for each step.
This guide follows one visit from start to finish: you create a consultation for an appointment in your practice system, upload the audio, let Vetnio transcribe it, generate the clinical note and write the vet's corrections back. It is written for teams building a recording client or a practice-system integration.
The requests below were run against a Vetnio instance with synthetic data. Transcription and note generation call AI providers that this instance does not have, so those two results are written to match the API exactly and are marked as such.
Before you start
You need a personal API key and the ID of the clinic (workspace) you work in; Quickstart covers both. The examples read the key from VETNIO_API_KEY and use the clinic demo-north-clinic. Read Consultations for the states this guide moves through.
The whole flow at a glance:
1. Create the consultation
Send your appointment ID as externalId. If the request times out and you send it again, Vetnio returns the same consultation instead of creating a second one. Without an appointment ID, generate a UUID and send it as clientConsultationId for the same protection; see Consultations.
curl -X POST https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Bella - lameness left hind",
"recordingLanguageCode": "en",
"externalId": "pims-appt-58213"
}'{
"consultationId": "4b2730b1-3e78-4d82-9114-030a055e8581",
"recordingUploadUrl": "https://storage.example.com/recordings/demo-north-clinic/4b2730b1-3e78-4d82-9114-030a055e8581/1791130536828-en?X-Amz-Expires=86400&X-Amz-Signature=…",
"consultation": {
"id": "4b2730b1-3e78-4d82-9114-030a055e8581",
"name": "Bella - lameness left hind",
"createdAt": "2026-10-04T16:15:36.818Z",
"recordingDurationInMilliseconds": 0,
"uploadedRecordingDurationInMilliseconds": 0,
"isGeneratingClinicalNote": false,
"isGeneratingCommunication": false,
"externalId": "pims-appt-58213"
}
}recordingLanguageCode is the language spoken in the room. Use one of the codes listed for languageCode in POST/workspaces/{workspaceId}/consultations/{consultationId}/partial-transcriptions; the same list is offered in the Vetnio app. Here and on the upload-URL endpoint in step 3, a value that is not a two- or three-letter code, optionally followed by subtags such as pt-BR, returns 400 Input validation failed; an empty value means English. The externalId match is clinic-wide and ignores clinicalNoteTemplateId, so choose the template in step 8. Consultations lists the edge cases.
2. Link the patient
Generation uses the linked patient's details and the notes from earlier visits, so link the patient before you generate. Find or create the patient first, as described in Sync patients.
curl -X POST https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/patient \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "patientId": "4abb3048-6693-41d0-bf7d-7d6b09556c09" }'{
"success": true
}Linking replaces any patient linked before. A patient that does not exist in this clinic returns 404 Resource not found.
3. Upload the audio
Audio goes straight to storage with a pre-signed URL, not through the API. Send the raw bytes as the body of a single PUT, with no Authorization header and no multipart encoding. Any format FFmpeg can decode works; the Vetnio apps upload WebM/Opus or MP4/AAC.
Upload the first segment
The create response already contains a URL for the first segment:
curl -X PUT --upload-file part-1.webm \
"https://storage.example.com/recordings/demo-north-clinic/4b2730b1-3e78-4d82-9114-030a055e8581/1791130536828-en?X-Amz-Expires=86400&X-Amz-Signature=…"Storage answers 200 with an empty body.
Upload further segments
You can upload a visit as one file or as several segments. The Vetnio apps cut long visits into segments of about three minutes, which are transcribed in parallel and joined in order. Get a new URL for every further segment:
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/recording-upload-url?recordingLanguageCode=en" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"recordingUploadUrl": "https://storage.example.com/recordings/demo-north-clinic/4b2730b1-3e78-4d82-9114-030a055e8581/1791130555609-en?X-Amz-Expires=86400&X-Amz-Signature=…"
}The last path segment, 1791130555609-en, is the recording ID: the time the URL was issued plus the segment's language. Segments are transcribed and joined in recording-ID order, and each one is transcribed in its own language.
Each URL is valid for 24 hours. If one expires, storage answers 403; request a new URL.
4. Start transcription
Uploading never starts transcription. When the segments you have so far are uploaded, call POST/workspaces/{workspaceId}/consultations/{consultationId}/transcriptions/start:
curl -X POST https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/transcriptions/start \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'{
"message": "Transcription process started",
"recordingsProcessed": 2
}The call returns at once and the work continues in the background. For each waiting segment, Vetnio converts the audio to 16 kHz mono, removes silence, runs speech-to-text with the Transcription terms of the clinic and of the key's user, and corrects common misspellings. recordingsProcessed counts the segments waiting; when there are none, the message is No untranscribed recordings found and the count is 0.
Calling start again is always safe: finished segments are skipped, a segment is never transcribed twice at the same time, and failed segments are retried up to three attempts in total. You can call it after every segment if you want text while the visit is still going.
5. Wait for transcription to finish
Poll GET/workspaces/{workspaceId}/consultations/{consultationId} every 3 to 5 seconds. While segments are waiting, transcriptionStatus is processing:
{
"id": "4b2730b1-3e78-4d82-9114-030a055e8581",
"name": "Bella - lameness left hind",
"createdAt": "2026-10-04T16:15:36.818Z",
"recordingDurationInMilliseconds": 0,
"recordingDurationInMillisecondsExcludingSilence": 0,
"isGeneratingClinicalNote": false,
"isGeneratingCommunication": false,
"isReadyForGeneration": false,
"clinicalNoteJsonTemplateId": null,
"linkEntryId": null,
"linkJournalId": null,
"transcriptionStatus": "processing",
"transcriptionFailureReason": null
}When the work finishes, the status changes. This response was written to match the API, because the example instance cannot transcribe:
{
"id": "4b2730b1-3e78-4d82-9114-030a055e8581",
"name": "Bella - lameness left hind",
"createdAt": "2026-10-04T16:15:36.818Z",
"recordingDurationInMilliseconds": 412000,
"recordingDurationInMillisecondsExcludingSilence": 356400,
"isGeneratingClinicalNote": false,
"isGeneratingCommunication": false,
"isReadyForGeneration": true,
"clinicalNoteJsonTemplateId": null,
"linkEntryId": null,
"linkJournalId": null,
"transcriptionStatus": "completed",
"transcriptionFailureReason": null
}Stop polling on completed or failed. Transcription time grows with segment length; segments run in parallel, so the slowest one sets the pace.
failedmeans at least one segment failed permanently;transcriptionFailureReasonsays why. The other segments' text is in the transcript and you can still generate. To recover the lost part, upload the audio again with a new URL and call start. The consultation keeps reportingfailedafter that, so confirm the replacement by finding its recording ID in GET/workspaces/{workspaceId}/consultations/{consultationId}/partial-transcriptions.- Still
processingafter about 10 minutes means a background run stopped early. Call start again: segments that have been running for more than 5 minutes are picked up again. A clinical-note generation or awaitForTranscriptions=truerequest also picks them up while it waits; nothing retries them in the background.
6. Read the transcript
curl https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/transcription \
-H "Authorization: Bearer $VETNIO_API_KEY"Written to match the API:
{
"transcription": "So this is Bella, she's eight now. What brings you in today?\n\nShe's been limping on her back left leg since the weekend, mostly after walks.\n\nAny vomiting or change in appetite?\n\nNo, she's eating normally. Temperature is 38.6. She's sore when I extend the left stifle, but there's no swelling over the joint. Let's start her on Rimadil (Rimadyl?), two milligrams per kilo twice a day for a week, and see her again in two weeks."
}The transcript is plain text in segment order. Speakers are not labeled: within a segment, a change of speaker starts a new paragraph (a blank line), and segments are joined with a single space. When the spelling check is confident a medical term was misheard, it keeps the original and adds its suggestion in parentheses, as in Rimadil (Rimadyl?). The transcript is an empty string until something is transcribed.
To start transcription and read the result in one request, add waitForTranscriptions=true. The request then stays open until every segment has settled, which can take minutes and is bounded by the request time limit in Limits; check transcriptionStatus afterwards, because the response does not say whether everything finished.
7. Add context (optional)
Two kinds of text improve the note without audio:
- Additional info is background the conversation does not contain, such as history from another clinic. It is used by every generation but is not part of the transcript. 1 to 10,000 characters; each call replaces the previous value.
- Partial transcriptions add text to the transcript itself: notes typed during the visit, an owner's message, or text from your own speech-to-text if you already transcribe live. A consultation with only text is ready for generation without any audio.
curl -X POST https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/partial-transcriptions \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Owner reports Bella has been limping on the left hind leg for 3 days, worse after walks.",
"languageCode": "en"
}'{
"success": true,
"recordingId": "1791130593648-739aece5-740d-4d32-8db3-60ddf30366d0-text-en",
"message": "Partial transcription created successfully. It will be included in document generation."
}The text is added verbatim and placed by creation time among the audio segments. Partial transcriptions cannot be edited or removed, and every call adds one, so retry only when you know the first call failed. A 409 with The consultation is being moved or erased; try again later. stores nothing, so retry later. If the move or erasure starts just after the text is stored, the call still succeeds, but message says the text is not in the transcript yet; it is added the next time a recording, text or phone-call import updates the transcript. Save additional info with PUT/workspaces/{workspaceId}/consultations/{consultationId}/additional-info and a body of { "additionalInfo": "…" }.
8. Generate the clinical note
POST/workspaces/{workspaceId}/consultations/{consultationId}/clinical-note/generate writes the note and saves it as the consultation's clinical note. It first transcribes any segment still waiting and waits for all of them, so you can call it straight after the last upload. Generation itself usually takes under a minute.
curl -X POST https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/clinical-note/generate \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "templateId": "7ce0fa1b-777b-55f9-a58b-7fcabc410504" }'The request blocks until the note is saved. Written to match the API:
{
"clinicalNote": "<strong>Subjective</strong><br />Bella, 8-year-old Labrador. Left hind lameness for 3 days, worse after walks. Eating normally, no vomiting.<br /><br /><strong>Objective</strong><br />• T 38.6 °C<br />• Pain on extension of the left stifle, no joint swelling<br /><br /><strong>Assessment</strong><br />Left stifle pain; cause not yet determined.<br /><br /><strong>Plan</strong><br />• Carprofen 2 mg/kg PO q12h for 7 days<br />• Recheck in 14 days"
}The note uses the transcript, additional info, analyzed uploaded files, the template, the linked patient and earlier visits, and the clinic-wide and personal AI instructions. Generated notes are HTML with <strong> headings, <br /> line breaks and • bullets.
| Field | Effect |
|---|---|
templateId | A template from Templates. It is also saved as the consultation's template. Omit it to use the template already selected, or none; pass auto to write without a template. An unknown ID is not rejected: the note is written without a template and the selection is cleared. |
shouldGenerateFromScratch | Default true rewrites the note from the full transcript. false keeps the existing note, including edits, and adds what was said since the last generation. |
callbackUrl | Switches to callback mode, described below. |
A consultation with an empty transcript returns 400 with No transcription available for document generation…. Uploaded files and additional info alone are not enough here. Every call runs the model again and saves a new version, so do not retry blindly.
Receive the note by callback
Holding a connection open for transcription and generation is fragile. Pass callbackUrl and the request returns at once:
{
"message": "Callback URL has been queued"
}When the job ends, Vetnio sends a POST with a JSON body to your URL. The header X-Vetnio-Callback-Status is success, with { "clinicalNote": "<strong>Subjective</strong>…" }, or error, with { "error": { "code", "message" }, "workspaceId", "consultationId" }. Vetnio makes one attempt with a 30-second timeout and does not retry or sign callbacks, so put a secret token in the URL and answer 2xx quickly.
The whole job, transcription wait included, must finish within the request time limit in Limits. If it does not, a synchronous request ends with a gateway timeout and callback mode sends nothing. Either way the note may already be saved, so read it before you retry. In callback mode, isGeneratingClinicalNote turns true only after the transcription wait, so it cannot tell you a callback was lost. If nothing has arrived a few minutes after transcriptionStatus settled, read the record before you generate again.
If the consultation's template produces a structured note, the response is { "message": "Structured document generation initiated" } and the note is written in the background. Poll GET/workspaces/{workspaceId}/consultations/{consultationId} until isGeneratingClinicalNote is false, then read the record, which is a JSON object. See Structured documents.
9. Write back the vet's edits
When the vet corrects the note in your system, send the full new text with PUT/workspaces/{workspaceId}/consultations/{consultationId}/records:
curl -X PUT https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/records \
-H "Authorization: Bearer $VETNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recordType": "clinical note",
"content": "<strong>Subjective</strong><br />Bella, 8-year-old Labrador. Left hind lameness for 3 days, worse after walks. Eating normally, no vomiting.<br /><br /><strong>Objective</strong><br />• T 38.6 °C<br />• Pain on extension of the left stifle, no joint swelling<br /><br /><strong>Assessment</strong><br />Suspected cranial cruciate ligament injury, left stifle.<br /><br /><strong>Plan</strong><br />• Carprofen 2 mg/kg PO q12h for 7 days<br />• Recheck in 14 days; radiographs of the left stifle if not improved"
}'{
"success": true
}The update replaces the whole note, keeps the previous text as a retained version, and is saved as a manual edit. There is no concurrency check: the last write wins. Vetnio removes unsafe markup and turns paragraphs into <br /> line breaks.
Read the current note at any time with GET/workspaces/{workspaceId}/consultations/{consultationId}/records. The body is the note itself, not an envelope: an HTML string, a JSON object for a structured note, or null if there is none.
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/consultations/4b2730b1-3e78-4d82-9114-030a055e8581/records?recordType=clinical%20note" \
-H "Authorization: Bearer $VETNIO_API_KEY""<strong>Subjective</strong><br />Bella, 8-year-old Labrador. Left hind lameness for 3 days, worse after walks. Eating normally, no vomiting.<br /><br /><strong>Objective</strong><br />• T 38.6 °C<br />• Pain on extension of the left stifle, no joint swelling<br /><br /><strong>Assessment</strong><br />Suspected cranial cruciate ligament injury, left stifle.<br /><br /><strong>Plan</strong><br />• Carprofen 2 mg/kg PO q12h for 7 days<br />• Recheck in 14 days; radiographs of the left stifle if not improved"For the client communication, call POST/workspaces/{workspaceId}/consultations/{consultationId}/records with { "recordType": "communication" } after transcription has finished; it does not wait for pending segments. Referral letters can be read but not written through the API. Records covers all record types and version history.
Alternative: submit recordings as one durable operation
Steps 3 to 8 expect a client that uploads segments in order and stays connected while it drives each step. A recording client that works offline or on unreliable networks, such as a phone app, can instead hand the whole job to Vetnio as one recording operation. The operation keeps running on the server after the client disconnects, and every request in it is safe to repeat.
- Register and upload each chunk. Give each chunk of audio a UUID
id, thesessionIdandindexof the recording it belongs to,recordedAt(Unix epoch milliseconds), itslanguageCode, itssizein bytes (at most 2 GiB) and the lowercase hexadecimalsha256of its bytes. POST/workspaces/{workspaceId}/consultations/{consultationId}/recording-chunksreturns anuploadUrl, valid for 15 minutes, and theheadersto send with a singlePUTof the bytes. Repeating the call returns a fresh URL, oralreadyUploaded: trueonce the bytes are stored. Reusing a chunkidfor different audio returns409. - Submit the operation. POST
/workspaces/{workspaceId}/consultations/{consultationId}/recording-operationstakesprotocolVersion: 1, anoperationIdyou generate, up to 2,000chunks,generateClinicalNoteand an optionaltemplateId. Store theoperationIdbefore you send it, and repeat the identical request after a lost response: it returns the same receipt. The sameoperationIdwith a different payload returns409. - Poll for the result. Call GET
/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}every few seconds untilstatusissucceededorfailed.retryingmeans a step failed and Vetnio retries it by itself;errorthen names the failure being retried.skippedChunkslists chunks left out of the transcript, with the reason.
Operations on one consultation run one at a time, in the order they were submitted. Chunks are placed in the transcript by recordedAt. With generateClinicalNote: true, the new audio is merged into the consultation's current note, so earlier edits are kept. If the vet edits the note while the operation is generating, the edit is kept, the operation fails with note_conflict, and the generated note can still be read from GET/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}/result. On /api/v1, the submit call answers 202 Accepted with Location and Retry-After headers while the operation runs; see Versioning.
Common errors
| Status | Message | Cause | Fix |
|---|---|---|---|
400 | Input validation failed | A missing or mistyped field | Read issues[] for the field. |
400 | No transcription available for document generation… | Empty transcript when generating | Upload audio and wait for transcription, or add a partial transcription. |
403 | You cannot modify this consultation | The consultation is archived (reason: archived_consultation) | Create a new consultation. |
403 | Storage error (XML) on PUT | The upload URL expired or was altered | Request a new upload URL. |
404 | Consultation not found | Wrong ID, another clinic, or no access | Check workspaceId and consultationId. |
404 | Resource not found | Linking a patient that is not in this clinic | Create or look up the patient in this clinic. |
409 | consultationIdentityConflict#71946238: … | clientConsultationId belongs to another consultation, or the one it created was archived | Generate a new UUID for a new consultation. |
415 | Missing content-type header | A POST, PUT or PATCH without a JSON body | Send Content-Type: application/json and at least {}. |
500 | An unexpected error occurred | A model or storage failure | Read the record before retrying. |
504 | Gateway timeout | The job ran past the time limit | Read the record; switch to callback mode. |
See Errors for the error format.
Clean up
Test consultations stay in the clinic's list. Archive them with DELETE/workspaces/{workspaceId}/consultations/{consultationId}; archived consultations are read-only and can be restored in the Vetnio app.
End-to-end script
The script below runs steps 1 to 8 for one visit, without the optional step 7. It needs Node.js 18 or later and nothing else.
// document-visit.mjs: Node.js 18 or later, no dependencies.
// VETNIO_API_KEY=sk_live_… node document-visit.mjs <workspaceId> <externalId> part-1.webm [part-2.webm …]
import { readFile } from "node:fs/promises";
const BASE_URL = process.env.VETNIO_BASE_URL ?? "https://vetnio.com/api/v2";
const API_KEY = process.env.VETNIO_API_KEY;
const PATIENT_ID = process.env.VETNIO_PATIENT_ID; // optional
const LANGUAGE = "en";
const [workspaceId, externalId, ...audioFiles] = process.argv.slice(2);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function api(method, path, body) {
const hasBody = method !== "GET" && method !== "DELETE";
const response = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
...(hasBody ? { "Content-Type": "application/json" } : {}),
},
body: hasBody ? JSON.stringify(body ?? {}) : undefined,
});
const payload = await response.json();
if (!response.ok) {
throw new Error(`${method} ${path} failed with ${response.status}: ${payload.message}`);
}
return payload;
}
async function uploadSegment(url, file) {
const response = await fetch(url, { method: "PUT", body: await readFile(file) });
if (!response.ok) throw new Error(`Uploading ${file} failed with ${response.status}`);
}
// Step 1: create the consultation, or get the existing one for this externalId.
const created = await api("POST", `/workspaces/${workspaceId}/consultations`, {
name: "Bella - lameness left hind",
recordingLanguageCode: LANGUAGE,
externalId,
});
const consultation = `/workspaces/${workspaceId}/consultations/${created.consultationId}`;
console.log(`Consultation ${created.consultationId}`);
// Step 2: link the patient first, so generation can use the animal's details and history.
if (PATIENT_ID) await api("POST", `${consultation}/patient`, { patientId: PATIENT_ID });
// Step 3: upload the segments in order, each with a URL fetched just before its upload.
for (const [index, file] of audioFiles.entries()) {
const url = index === 0
? created.recordingUploadUrl
: (await api("GET", `${consultation}/recording-upload-url?recordingLanguageCode=${LANGUAGE}`)).recordingUploadUrl;
await uploadSegment(url, file);
}
// Steps 4 to 6: start transcription, poll until nothing is waiting, read the transcript.
await api("POST", `${consultation}/transcriptions/start`, {});
let lastStart = Date.now();
const deadline = Date.now() + 30 * 60_000;
let status = await api("GET", consultation);
while (status.transcriptionStatus === "processing") {
if (Date.now() > deadline) throw new Error("Transcription did not finish in 30 minutes");
if (Date.now() - lastStart > 10 * 60_000) {
await api("POST", `${consultation}/transcriptions/start`, {}); // picks up stalled segments
lastStart = Date.now();
}
await sleep(4_000);
status = await api("GET", consultation);
}
if (status.transcriptionStatus === "failed") {
console.warn(`A segment failed permanently (${status.transcriptionFailureReason}); using the rest.`);
}
const { transcription } = await api("GET", `${consultation}/transcription`);
console.log(`Transcript: ${transcription.length} characters`);
// Step 8: generate the clinical note. This request blocks until the note is saved.
const generated = await api("POST", `${consultation}/clinical-note/generate`, {});
let note = generated.clinicalNote;
if (note === undefined) {
// Structured template: the note is written in the background.
do {
await sleep(3_000);
} while ((await api("GET", consultation)).isGeneratingClinicalNote);
note = await api("GET", `${consultation}/records?recordType=${encodeURIComponent("clinical note")}`);
}
console.log(note);Next steps
- Attach files: add lab results and referral letters that the note can draw on.
- Structured documents: fill your practice system's fields from a structured template.
- Practice systems: how Vetnio's built-in practice-system integrations use
externalId. - Records: record types, formats and version history.
Endpoints used in this guide
- POST
/workspaces/{workspaceId}/consultationsCreate a new consultation - POST
/workspaces/{workspaceId}/consultations/{consultationId}/patientLink a patient to a consultation - GET
/workspaces/{workspaceId}/consultations/{consultationId}/recording-upload-urlGet a signed URL to upload a recording - POST
/workspaces/{workspaceId}/consultations/{consultationId}/transcriptions/startStart transcription - GET
/workspaces/{workspaceId}/consultations/{consultationId}Get consultation details - GET
/workspaces/{workspaceId}/consultations/{consultationId}/transcriptionGet consultation transcript - GET
/workspaces/{workspaceId}/consultations/{consultationId}/partial-transcriptionsList partial transcriptions - POST
/workspaces/{workspaceId}/consultations/{consultationId}/partial-transcriptionsCreate partial transcription - PUT
/workspaces/{workspaceId}/consultations/{consultationId}/additional-infoUpdate additional info - POST
/workspaces/{workspaceId}/consultations/{consultationId}/clinical-note/generateGenerate a clinical note - GET
/workspaces/{workspaceId}/consultations/{consultationId}/recordsGet a record - PUT
/workspaces/{workspaceId}/consultations/{consultationId}/recordsUpdate a record - POST
/workspaces/{workspaceId}/consultations/{consultationId}/recordsCreate a record - DELETE
/workspaces/{workspaceId}/consultations/{consultationId}Archive a consultation - POST
/workspaces/{workspaceId}/consultations/{consultationId}/recording-chunksPrepare an immutable recording chunk upload - POST
/workspaces/{workspaceId}/consultations/{consultationId}/recording-operationsDurably accept an idempotent recording submission - GET
/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}Get the authoritative recording operation status - GET
/workspaces/{workspaceId}/consultations/{consultationId}/recording-operations/{operationId}/resultRetrieve a generated result, including one preserved after an edit conflict
Last reviewed against the API on 2026-10-30.