Build on the clinical record layer

Five things you can do with our API, each one a flow with a screen at one end. If what you want is not here, it is not because we have not got round to it.

Read a record under a grant

Your clinician reads a patient's record exactly as ours does, because the patient granted it to them by name and can revoke it. There is no key that reads a record: the key tells you who may, and your clinician signs in to do it. The patient can claim their record and leave at any time, including leaving you.

An example

GET /api/partner/v1/subjects/YOUR-REF/readers

200 { "readers": [ { "clinicianId": "...", "grantedAt": "..." } ] }

POST /api/partner/v1/launch
{ "clinician": "dr@example.com", "target": "patients" }

200 { "url": "https://.../api/partner/launch?token=..." }
open it in a new window: single use, two minutes,
then a one-hour session for that clinician
targets: dashboard, patients, sessions, notes

Session writeback

A session held on your platform lands in our record, attributed to your platform. We record that it happened, when, and with whom. We do not accept a note or a transcript from a server, because content in a chart needs a clinician who approved that exact text.

An example

POST /api/partner/v1/sessions

{ "subjectRef": "YOUR-REF",
  "clinicianEmail": "dr@example.com",
  "startedAt": "2026-09-12T14:00:00Z",
  "durationMinutes": 50,
  "externalMeetingId": "M-8814" }

201 { "sessionId": "..." }
same externalMeetingId again -> the same sessionId

Note delivery

A finished, clinician-approved note is collected by you. Never a draft. Never model output nobody signed. A webhook tells you there is one; a key collects it.

An example

note.approved -> { "event": "note.approved", "id": "...", "at": "..." }

GET /api/partner/v1/notes/<sessionId>

200 { "approvedAt": "...", "content": "..." }
404 while it is a draft, and while nobody has approved it

A session, end to end

Six calls. The order is not a convention: each one refuses until the one before it has happened, because what they add up to is a clinical document somebody put their name to.

  1. 1

    Ask your patient, before the session

    Show our consent question on your own interface and send us the answer. Until you do, we record nothing at all. Somebody who says yes ten minutes in sends the same call with an offset, and the note covers from then.

    POST /api/partner/v1/consent

  2. 2

    Send us the audio

    By upload or by stream, as the session runs or afterwards. Your video never leaves your infrastructure: everything we produce is made from audio, and a therapy room on our disks is a thing nobody asked us to hold.

    POST /api/partner/v1/sessions/<ref>/media

  3. 3

    Read the transcript

    Diarised, with the sentence about what was recorded travelling beside it. A transcript that starts ten minutes in looks exactly like a session that started late, and the difference matters.

    GET /api/partner/v1/sessions/<ref>/transcript

  4. 4

    Show your clinician the draft

    A SOAP note written from the transcript, in plain text your own chart can take. It is a draft: this endpoint calls it one, and so does the field name.

    GET /api/partner/v1/sessions/<ref>/note

  5. 5

    Your clinician approves the text

    Send back what they actually approved, which may differ from our draft in any way including entirely, and your id for the person who approved it. A note with nobody's name on it is not a note, and we refuse it.

    POST /api/partner/v1/sessions/<ref>/note

  6. 6

    Deliver the summary to your patient

    Written for the patient rather than for a chart, reviewed by the same clinician. It does not exist until the note is approved, because a patient hearing about their own therapy from a model with nobody in between is not something we will do.

    POST /api/partner/v1/sessions/<ref>/summary

Consent during a session

The case an integration is most likely to miss, because the obvious build is a true or false. Somebody can agree ten minutes in. Send the offset and we start from there: the note says the session was partly recorded and when it began, rather than implying we heard the first ten minutes.

POST /api/partner/v1/consent
{ "session": "S-1024", "subject": "P-77",
  "state": "given", "answered_at": "2026-09-14T10:40:00Z",
  "offset_seconds": 600 }

200 { "recording_from_seconds": 600,
      "coverage": "Recording started 10 minutes into this
                   session. Nothing before that was recorded,
                   and nothing here was written from it.",
      "stopped_reason": null }

The copilot, and your clinician's own choice

A clinician on your platform turns it on for themselves, and then asks about a patient from the sessions you ran with them. We do not decide who is a therapist on your platform: the opt-in says what it is for and the right people find it. Every answer cites your session references, so a citation resolves in your own interface.

PUT /api/partner/v1/copilot
{ "clinician": "C-9", "enabled": true }

POST /api/partner/v1/copilot
{ "subject": "P-77", "clinician": "C-9",
  "question": "What did we agree in March?" }

200 { "answer": "...[S-1024]...", "citations": ["S-1024"] }

GET /api/partner/v1/subjects/<ref>/memory
200 { "sessions": [ { "session": "S-1024", "note": "..." } ] }

The limit is yours, and we stop at it

You set a number of sessions a month and we never go past it. We alert your contact at 80% and again at 90%. At the limit your own product carries on exactly as it does now and ours stops: no transcription, no note, no summary, no copilot. We do not bill for a session we did not do, and there is no overage charge, because a bill you did not authorise is not a business we want.

409 { "error": "This account has reached the monthly
                 session limit it set (500). Your session is
                 unaffected and is held on your own platform.
                 Raise the limit to turn the AI back on." }

The embedded widget

A button in your product opens our panel in its own window, signed in as your clinician, with no second login and no credential of ours in your hands. It is a window rather than a frame on purpose: a record inside a document your page controls is a record somebody can be tricked into acting on. And no video by default, because you have your own, and two video products on one screen is worse for a patient than either alone.

What there is no endpoint for

Not held back, not on a roadmap: there is no route and no argument that would take one. No list of who is enrolled anywhere. No list of anybody's patients. No record read by a key. No note that a clinician has not approved. No transcript accepted from a server. No payload on a webhook.

The four promises this page made before any of this existed

They were the conditions for opening an API at all. Each one now names the thing that keeps it, so you can check rather than trust.

  • A version that does not move under you

    Every path carries v1. A scope is added rather than a response reshaped, and a key names the scopes it was issued with, so a new capability cannot arrive inside a call you already make.

  • Identity that does not collide

    Two platforms will both send us a patient called P123. Your reference is stored against your account and resolved only within it, so yours and theirs are different rows and neither can be used to reach the other.

  • Consent that survives the boundary

    No key reads a record. A key asks who may read one, and the answer is the clinicians the patient granted by name. Your clinician then signs in as themselves to read it, and a revoked grant closes that door in the same instant it closes ours.

  • An audit trail on both sides

    Every call is recorded with the key that made it and, for a launch, the clinician it was on behalf of. A read of a record appears in the patient's own access log, exactly as ours does, naming your platform.

Keys are hashed, scoped to one use case at a time, rotatable, and issued after a call. There is no self-serve key, and a therapist never sees one.

Live keys are limited per minute, and crossing that limit suspends the key rather than slowing it down. Build for one call inside one flow, not for a sweep.

Ask us for an account