Skip to content

Changelog

Every change to the /v1 contract, newest first. Additive changes ship without notice; see Versioning for what that covers and what it does not.

2026-09-11 (wave 6b-3)

Video visits. A patient can now be booked into a live video consult with a licensed clinician. GET /v1/visits/slots returns bookable slot starts for a patient's state over a window of at most fourteen days, POST /v1/visits claims one, GET /v1/visits/{id} reads it back, and POST /v1/visits/{id}/cancel and /reschedule move it while it is still scheduled; a reschedule keeps the visit's id. GET /v1/visits/{id}/join mints the link the patient joins through: it is patient-bound, lives fifteen minutes, opens an hour before the visit, and is meant to be fetched at join time rather than stored. Two new scopes, visits:read and visits:write.

Six new event types ride the existing feed and your existing endpoints: visit.booked.v1, visit.rescheduled.v1, visit.cancelled.v1, visit.started.v1, visit.completed.v1 and visit.no_show.v1. A new charge kind, video_visit, is raised on visit.completed.v1 and on nothing else; a no-show is unpriced for now. Test mode plays the clinician at POST /v1/test/visits/{id}/start, /complete and /no_show, against sandbox availability generated from a fixed weekday template.

Additive throughout: an existing caller is unaffected. The MCP server gains nine tools for the same operations, and both SDKs and the CLI carry the resource. See Visits, Events and realtime and Billing.

2026-09-11 (wave 6a-2)

A person can sign in from a machine with no browser. The authorization server now offers the RFC 8628 device grant: POST /api/auth/device/code with a client_id, the scopes and a resource, then a poll of /oauth2/token with grant_type=urn:ietf:params:oauth:grant-type:device_code at the interval the server states. The person confirms the code at developers.cuvo.co/device as a signed-in member with a second factor, and approves the request whole or denies it: the device grant does not narrow. The CLI uses it as cuvo login --device. A device token is a member's token, so it is test mode; live data still needs a live client or a live key. Nothing about the /v1 contract changed. See Authentication and CLI.

2026-09-11 (wave 6a-1)

The CLI listens locally, completes itself and scaffolds a starter. cuvo webhooks listen --forward-to http://localhost:3000/hooks subscribes to your integration's realtime channel and POSTs every event to the local URL, signed with a session secret it prints once, so the handler verifies with the SDK exactly as it will in production. It is a mirror of the event stream, not a delivery: nothing is retried and no delivery row is written. cuvo completion zsh|bash|fish prints a completion script from the command tree, and cuvo init [dir] writes a TypeScript or Python starter with a sandbox smoke script and a verifying webhook handler. The TypeScript SDK gains signWebhook, the sender's half of the signature scheme. Nothing about the /v1 contract changed. See CLI.

2026-09-11 (wave 6a-3)

The MCP server publishes resources and every tool carries annotations. resources/list now returns every guide on this site as cuvo://docs/<slug> (text/markdown) and the contract as cuvo://openapi/v1.yaml (application/yaml); resources/read serves them, and a read leaves an audit row exactly as a tool call does. Every tool declares the four MCP hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), derived from its operation's method and verb, so a client that asks before a destructive call can ask correctly. docs_search stays. Nothing about the /v1 contract changed. See MCP.

2026-09-09

The clients are published. Both are prerelease and both install with one command.

  • TypeScript: pnpm add @cuvo-health-us/api@next, version 0.1.0-next.0.
  • Python: pip install --pre cuvo, version 0.1.0a1, on PyPI since 2026-09-08.
  • Command line: pnpm add -g @cuvo-health-us/cli@next, version 0.1.0-next.0.

The npm scope is @cuvo-health-us, not @cuvo. The @cuvo scope on npm belongs to someone else, so the packages take the scope Cuvo owns. If your Cuvo contact handed you a tarball named @cuvo/api or @cuvo/cli before today, uninstall it and install the published package: the code is the same, the name is not. The cuvo command the CLI installs is unchanged, and so is the Python package name.

Nothing about the /v1 contract changed with this release. See SDKs and CLI.

2026-09-08 (wave 5b)

The patient export opened in live mode. POST /v1/patients/{id}/exports and GET /v1/patients/{id}/exports/{job} now answer in live mode, and the job comes back already completed: a chart is bounded, so there is nothing to wait for. Its url is the new download below, good for 24 hours, which is the life of the document links inside the bundle. Nothing about the job shape changed, so a caller who wrote the polling loop keeps it.

GET /v1/exports/{id} and GET /v1/exports/{id}/download. Added. The first is the same job, read by the id you kept rather than through the patient; the second streams the bundle as a file, with the same credential and the same patients:read scope. The bundle holds the patient, their cases, consents, files, prescriptions and orders in the shapes this API already publishes, plus a download link per document.

410 gone. Added to the problem codes. A download past expires_at answers with it: the export existed, and its bundle and the links inside it were deleted together. Start another one. No other operation can answer 410. See Errors.

2026-09-08

OAuth clients. Added. A platform can now exchange a client id and secret for a one hour access token at https://developers.cuvo.co/api/auth/oauth2/token and present it wherever an API key goes. Dynamic client registration is open with PKCE required, and a portal member can consent an agent to one integration in test mode. API keys are unchanged. See Authentication.

MCP server. Added at https://mcp.cuvo.co/mcp. Thirty-seven tools over the same credential, the same scopes and the same audit as the REST API. See MCP server.

GET /v1/invoices/{id}. Added. Returns the invoice the list already returned, plus charges: one line per billable event, with its kind, the resource it was raised for, its amount and the charge it reverses. GET /v1/invoices is unchanged.

Files require a patient. Changes a test-only shape: a breaking change for sandbox callers, and the only one in this release. Until today the file resource answered in test mode alone, so nothing in production spoke this shape and it could be corrected rather than versioned.

  • POST /v1/files now requires patient. A request without it is refused with 400 invalid_request, and the File resource carries the field on every read.
  • POST /v1/files/{id}/confirm, which previously took an empty body, now requires patient, kind and filename, repeating what the reservation was made with.
  • mime is now one of application/pdf, image/jpeg, image/png and image/heic rather than any string.
  • FileUpload gained upload_headers. The upload URL is signed for them, so a PUT without them is refused by storage.

Files opened in live mode. POST /v1/files, its confirmation and GET /v1/files/{id} now answer in live mode, which is what naming the patient bought. Three rules come with it:

  • In live mode the file id changes at confirmation. What the reservation answered with identifies the reservation; what the confirmation answers with identifies the filed document, and on the chart those are two different things. Use the id from the response you last received. A reservation is not readable through GET /v1/files/{id} once it has been confirmed. In the sandbox the two ids happen to be the same, so code written against this rule works in both.
  • DELETE /v1/files/{id} stays test only, and answers 501 live_not_available in live mode, because the internal clinical contract has no delete.
  • A live POST /v1/cases still refuses a non-empty files array.

See Files.

Developer documentation. Added: these guides, the reference, a Postman collection, /llms.txt, /llms-full.txt, and the agent skill at /skills/cuvo-api/SKILL.md.

Requesting access to an organization. Added to the developer portal. Send a clinic's org_… id, the scopes you need and a note, and the request appears as a pending grant.

SDKs built; publication pending. The Python client, cuvo, is written and generated from the same document as the TypeScript client, and both are built and gated in CI. Neither is published: @cuvo-health-us/api@next and cuvo==0.1.0a1 are the names they will take, and until Cuvo releases them a partner installs the build their Cuvo contact hands them. See SDKs.

2026-09-07

Billing reads. Added. GET /v1/usage aggregates the charge ledger over a window by kind, and GET /v1/invoices mirrors the invoices raised against the integration. Both need billing:read and both answer in either mode; a test credential gets an empty answer rather than a refusal. The charge.created.v1 event, published with the v1 catalog, is emitted from this date. See Billing.

2026-09-07 (earlier)

Live mode. Added for patients, consents, cases, messages, prescriptions, orders and the catalog. A cuvo_sk_live_ credential reaches the clinical plane instead of the sandbox, once the integration has accepted the business associate agreement in force. Nothing about the request or response shape differs between the two modes. What is not yet open answers 501 live_not_available: the patient export, and at that date the whole file resource.

2026-09-06

/v1 published. The first public contract: organizations, catalog, patients, consents, files, cases, messages, prescriptions, orders, webhook endpoints, events and realtime tokens, all in test mode against the sandbox, with the simulated clinician and pharmacy under /v1/test. Cursor pagination, RFC 9457 problem bodies, required idempotency keys on writes, and signed at-least-once webhook delivery date from here.