Skip to content

Notes ​

Turning one consult recording into one clinical note.

Submit a consult recording ​

POST/v1/notes

One complete recording, one note. Relay the audio from your backend rather than from the vet's browser.

Returns immediately; transcription and generation continue without you. The note's note_id is the Idempotency-Key you sent, so you already hold it. Entitlement is checked here, before any work starts, so a 402 always arrives before you have spent anything.

Parameters ​

Idempotency-Keystringrequired

header · max 128 characters^[A-Za-z0-9._~-]{1,128}$

A UUID you generate per consult. Reuse it verbatim when retrying the same upload: we return the original note rather than generating a second one. A genuinely new consult must use a new key.

This is also the note's address. GET /v1/notes/{note_id} takes this key, so store it against your consult before you call us and you can poll even if our 202 never reaches you. We mint no identifier of our own.

A UUID is what we recommend, but any 1–128 characters of A-Z a-z 0-9 - _ . ~ are accepted, except . and .. on their own. Anything else cannot survive a URL path, because proxies and routers rewrite it, so it is refused here rather than buying a note you could not read back.

Example: "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18"

Request body ​

multipart/form-data

audiostring (binary)required

The complete consult recording as a single file. Three formats are accepted: Ogg Opus, MP4/M4A, or WAV; and WAV must be 16 kHz mono PCM16.

Opus is the smallest and the one we recommend relaying. Duration is read from the container for Opus and MP4; for WAV it is computed from the byte count, which is why that one format is pinned: a WAV at another sample rate, or in stereo, is rejected rather than accepted and transcribed wrongly. Send Opus if you cannot produce 16 kHz mono PCM16.

languageLanguagerequired

One of: en.

note_formatNoteFormatrequired

One of: soap.

pet_namestring

The patient's name as your system holds it. Generation reads the name from this field rather than from the transcript, so a name mispronounced or misheard during the consult never reaches the record. Worth sending whenever you have it.

Example: "Willow"

pet_typestring

Species of the patient. Shapes the terminology the note is written in: the right words for the right animal. Send it when you have it; nothing breaks without it.

Example: "rabbit"

external_refstring

max 128 characters

Your own identifier for this consultation. Stored, echoed back on every response for this note, and the fastest way to find a note in a support conversation. We never interpret it.

Example: "acme_consult_44192"

captured_secondsnumber

How long your recorder believes it captured, start to stop. We compare it against the audio that actually arrived; a shortfall means part of the consult was lost in transit, and the vet is warned before filing a record that may be incomplete.

Omit it and that check cannot run: we have no way to tell a short consult from a truncated one.

Example: 276.4

Responses ​

Every failure below returns the Error shape.

202

Accepted. Generation has started.

Returns NoteAccepted.

400Bad Request

The request was rejected. Do not retry unchanged.

401Unauthorized

The token is missing, malformed, or no longer valid. connection_revoked means the vet disconnected or left the practice, so clear the stored token and send them through the connect flow again.

partner_disabled is different and reconnecting will not fix it: your integration itself is switched off, and every token you hold stops at once. Stop retrying and contact us.

402

The practice does not have an active WisePaws subscription.

json
{
  "error": "Neighbourhood Vet does not have an active WisePaws subscription.",
  "code": "subscription_inactive"
}

409

The same Idempotency-Key was used with a different payload.

json
{
  "error": "That idempotency key was already used for a different recording.",
  "code": "idempotency_key_reused"
}

413

The recording exceeds the accepted size. Compress before retrying.

json
{
  "error": "That recording is too large to accept.",
  "code": "audio_too_large"
}

422

The file could not be decoded as audio. Confirm the upload completed before retrying.

json
{
  "error": "That file could not be read as audio.",
  "code": "audio_unreadable"
}

429Rate Limited

On the note endpoints the ceiling is per connection, and submitting a recording is held far tighter than polling, which the contract asks you to do every 3 seconds. On /v1/connections/exchange, which has no connection yet, it is per source address. A platform-wide backstop sits above both; it is sized so that normal traffic never reaches it. Back off and respect Retry-After.

502Server Error

Something failed on our side before your request could be judged. Retry shortly: nothing was consumed, and no note was created.

Poll until the note is ready ​

GET/v1/notes/{note_id}

Poll every 3 seconds. Most consults are ready within 90 seconds; a long one can take several minutes. Treat anything past 5 minutes as failed and tell the vet rather than polling indefinitely.

sections and duration_seconds arrive with ready. transcript arrives as soon as transcription succeeds, including on a failed note, which is what stops a lost consult being lost entirely.

Parameters ​

note_idstringrequired

path · max 128 characters^[A-Za-z0-9._~-]{1,128}$

The Idempotency-Key you submitted the consult under. We do not mint an identifier of our own, so you can poll without having seen our 202: if that response is lost in transit the consult is still reachable.

Example: "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18"

Responses ​

Every failure below returns the Error shape.

200

The note in its current state.

Returns Note.

Still generating

json
{
  "note_id": "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18",
  "status": "processing",
  "external_ref": "acme_consult_44192",
  "created_at": "2026-09-26T09:12:41Z"
}

Ready

json
{
  "note_id": "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18",
  "status": "ready",
  "external_ref": "acme_consult_44192",
  "created_at": "2026-09-26T09:12:41Z",
  "duration_seconds": 276,
  "warnings": [],
  "sections": [
    {
      "key": "subjective",
      "heading": "Subjective",
      "content": "Owner reports reduced appetite since yesterday evening and noticeably fewer faecal pellets this morning. Willow is quieter than usual but remains responsive and is still drinking."
    },
    {
      "key": "objective",
      "heading": "Objective",
      "content": "Bright, alert and responsive. Mild discomfort on abdominal palpation. Gut sounds reduced on auscultation. BW 6.4 kg, T 38.9 C, HR 180 bpm."
    },
    {
      "key": "assessment",
      "heading": "Assessment",
      "content": "Reduced appetite and faecal output consistent with gastrointestinal hypomotility. Underlying cause not yet established."
    },
    {
      "key": "plan",
      "heading": "Plan",
      "content": "Analgesia and prokinetic support, assisted feeding and subcutaneous fluids as discussed. Radiographs if no improvement within 24 hours."
    }
  ],
  "transcript": "Clinician: Right, let's have a look at Willow...\nClient: She's been off her food since yesterday..."
}

The note failed, but the transcript survived

json
{
  "note_id": "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18",
  "status": "failed",
  "external_ref": "acme_consult_44192",
  "created_at": "2026-09-26T09:12:41Z",
  "transcript": "Clinician: Right, let us have a look at Willow. How long has she been off her food?",
  "error": {
    "error": "The note could not be written from this consult. The transcript is available.",
    "code": "note_generation_failed"
  }
}

Transcription itself failed, so there is nothing to show

json
{
  "note_id": "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18",
  "status": "failed",
  "external_ref": "acme_consult_44192",
  "created_at": "2026-09-26T09:12:41Z",
  "error": {
    "error": "That recording could not be transcribed. Check the microphone before the next consult.",
    "code": "transcription_failed"
  }
}

401Unauthorized

The token is missing, malformed, or no longer valid. connection_revoked means the vet disconnected or left the practice, so clear the stored token and send them through the connect flow again.

partner_disabled is different and reconnecting will not fix it: your integration itself is switched off, and every token you hold stops at once. Stop retrying and contact us.

404Note Not Found

No note with that id belongs to this connection.

429Rate Limited

On the note endpoints the ceiling is per connection, and submitting a recording is held far tighter than polling, which the contract asks you to do every 3 seconds. On /v1/connections/exchange, which has no connection yet, it is per source address. A platform-wide backstop sits above both; it is sized so that normal traffic never reaches it. Back off and respect Retry-After.

502Server Error

Something failed on our side before your request could be judged. Retry shortly: nothing was consumed, and no note was created.

Tell us what the vet did with the note ​

POST/v1/notes/{note_id}/outcome

Send this once, when the vet saves or discards the note. Idempotent: the last call wins, so a vet who reopens and edits again can be reported again.

Optional, and the only signal we ever get about whether a generated note was any good. Sending the filed text lets us report back to the practice how much of each section their vets keep, and it is what improves the notes they see over time. discarded is equally useful and needs no body.

Parameters ​

note_idstringrequired

path · max 128 characters^[A-Za-z0-9._~-]{1,128}$

The Idempotency-Key you submitted the consult under. We do not mint an identifier of our own, so you can poll without having seen our 202: if that response is lost in transit the consult is still reachable.

Example: "7c1e0a44-9b2f-4de6-8a31-5f0c2d9e7b18"

Request body ​

application/json

outcomeOutcomerequired

One of: filed, discarded.

sectionsarray of FiledSection

The text as the vet actually filed it. Send on filed whenever you have it: the difference between this and what we generated is the only measure of accuracy either of us gets. Omit on discarded; sections sent with a discard are ignored.

On filed, every section must carry both fields and a distinct SectionKey; anything else is a 400 for the whole request. We would rather refuse the report than store half of it under an outcome that claims to be the filed note. On discarded they are not interpreted. Send content: "" for a section the vet deleted: that is data, and it is not the same as leaving the field out.

Saved to the patient record, lightly edited

json
{
  "outcome": "filed",
  "sections": [
    {
      "key": "subjective",
      "content": "Owner reports reduced appetite since yesterday evening..."
    },
    {
      "key": "objective",
      "content": "BAR. Mild discomfort on abdominal palpation. Gut sounds reduced..."
    },
    {
      "key": "assessment",
      "content": "Reduced appetite and faecal output consistent with GI hypomotility..."
    },
    {
      "key": "plan",
      "content": "Analgesia, prokinetic support and assisted feeding..."
    }
  ]
}

Rejected, written by hand instead

json
{
  "outcome": "discarded"
}

Responses ​

Every failure below returns the Error shape.

200

Recorded.

Returns NoteOutcomeRecorded.

400Bad Request

The request was rejected. Do not retry unchanged.

401Unauthorized

The token is missing, malformed, or no longer valid. connection_revoked means the vet disconnected or left the practice, so clear the stored token and send them through the connect flow again.

partner_disabled is different and reconnecting will not fix it: your integration itself is switched off, and every token you hold stops at once. Stop retrying and contact us.

404Note Not Found

No note with that id belongs to this connection.

429Rate Limited

On the note endpoints the ceiling is per connection, and submitting a recording is held far tighter than polling, which the contract asks you to do every 3 seconds. On /v1/connections/exchange, which has no connection yet, it is per source address. A platform-wide backstop sits above both; it is sized so that normal traffic never reaches it. Back off and respect Retry-After.

502Server Error

Something failed on our side before your request could be judged. Retry shortly: nothing was consumed, and no note was created.