---
name: cuvo-api
description: Build on the Cuvo Integrations API, the telehealth consult platform at api.cuvo.co. Use when creating patients, recording consents, filing cases for a clinician to decide, booking video visits, following prescriptions and orders, wiring webhooks, or driving the sandbox. Covers authentication, scopes, idempotency, pagination, errors, and the MCP server at mcp.cuvo.co.
---

# Cuvo Integrations API

One REST surface at `https://api.cuvo.co`. A partner creates patients, records the consents they
accepted, files cases for a licensed clinician to decide, books video visits with one, and follows
prescriptions and orders through events and webhooks. Test mode runs the whole loop against a sandbox.

## When to use this

Reach for it when the task involves telehealth consults, prescriptions, pharmacy orders, patient
intake, or anything under `api.cuvo.co`, `developers.cuvo.co` or `mcp.cuvo.co`. Do not guess at
shapes: this API publishes its contract, and `spec_lookup` or `/docs/openapi.yaml` is always
cheaper than a wrong request.

## Authenticate

`Authorization: Bearer <credential>` on every call. Two kinds, both the same header:

- **API key.** `cuvo_sk_test_…` reaches the sandbox, `cuvo_sk_live_…` reaches production. Minted in
  the developer portal, shown once, expires after 90 days.
- **OAuth access token.** `POST https://developers.cuvo.co/api/auth/oauth2/token` with
  `grant_type=client_credentials`, the client id and secret as HTTP Basic credentials, a `resource`
  naming the API the token is for, and the scopes you need. One hour JWT.

Add `Cuvo-Organization: org_…` whenever the credential holds more than one approved grant. A live
credential is refused until the integration has accepted the current business associate agreement.

**Never write a live key into a file, a log, or a message. Start in test mode.**

## Rules that will bite you

1. **Every write needs an `Idempotency-Key` header**, 16 to 128 printable ASCII, on every POST,
   PATCH and DELETE except `POST /v1/realtime/tokens`. Derive it from the thing being created, not
   from the moment of the attempt. Reuse it for every retry of that same attempt.
2. **A case needs current telehealth and privacy consents.** Filing without them answers `409
   consent_required`. Record the consents first.
3. **Scopes are intersected.** The credential's scopes meet the organization's grant; the smaller
   set wins. `GET /v1/organization` tells you the effective set.
4. **Switch on `code`, not on `detail`.** Failures are RFC 9457 problem bodies. Retry 429 after
   `Retry-After`, retry 5xx with backoff, retry nothing else.
5. **Lists are cursor paged.** `limit` up to 100, then pass the last id as `starting_after` until
   `has_more` is false. There is no total.
6. **Webhook delivery is at-least-once.** Dedupe on `Cuvo-Event-Id`. Verify `Cuvo-Signature` over
   the raw body before parsing.

## MCP

`https://mcp.cuvo.co/mcp`, Streamable HTTP, same bearer credential. Forty-six tools:

- **build**: `docs_search` and `spec_lookup` (no credential spent), plus the simulated clinician and
  pharmacy (`test_approve_case`, `test_ship_order`, `test_set_autopilot`, `test_reset`, and the
  rest). Test mode only.
- **operate**: usage, invoices, webhook endpoints, deliveries, events, redelivery.
- **runtime**: organization, catalog, patients, consents, cases, messages, orders, visits.

`tools/list` shows only what the credential admits. No tool mints a credential or touches a signing
secret. A token minted by user consent is always a test mode principal.

## Workflows

**File a consult.** `POST /v1/patients` → `POST /v1/patients/{id}/consents` twice, `telehealth` and
`privacy` → `POST /v1/cases` with the patient, the consent ids, requested medications from
`GET /v1/medications`, and the intake answers. Then follow the case with events.

**Drive it without a clinician.** With a test key: `POST /v1/test/cases/{id}/decision` to approve,
decline or ask a question, `/ship` and `/deliver` to move the order. Or `PATCH /v1/test/autopilot`
with `approve_after_s` and `ship_after_s` and let timers do it.

**Receive events.** `POST /v1/webhook_endpoints` with the types you want, keep the `whsec_` secret,
verify `t=<unix>,v1=<hex hmac_sha256(secret, "${t}.${rawBody}")>` before parsing, dedupe on the
event id. Back it with `GET /v1/events?since=…` so an outage costs you nothing.

**Book a video visit.** `GET /v1/visits/slots` with the patient's state and a window of at most
fourteen days → `POST /v1/visits` with the patient, a `slot_start` from that list, and the case when
there is one → `GET /v1/visits/{id}/join` at the moment the patient is ready, because the link lives
fifteen minutes and opens an hour before the visit. Never store it. `visit.completed.v1` is the
event that is billed.

**Attach a file.** `POST /v1/files` with the patient, kind, filename, mime and size → `PUT` the
bytes to `upload_url` with every header in `upload_headers` → `POST /v1/files/{id}/confirm`
repeating patient, kind and filename. In live mode the id changes at confirmation; use the id from
the last response.

## Guides

<https://developers.cuvo.co/docs> is the index. Start with `getting-started`, then
`authentication`, `scopes-and-organizations`, `test-mode`, `cases`, `patients-and-consents`,
`files`, `visits`, `webhooks`, `events-and-realtime`, `billing`, `errors`,
`rate-limits-and-idempotency`, `pagination`, `versioning`, `mcp`, `sdks`, `cli`.

The whole contract is also a command: `@cuvo-health-us/cli` publishes `cuvo <group> <verb>` for all 65
operations, answers JSON on stdout, and signs in with `cuvo login`. See `cli` in the guides.

Machine readable: <https://developers.cuvo.co/llms.txt> indexes them,
<https://developers.cuvo.co/llms-full.txt> is all of them concatenated, and
<https://developers.cuvo.co/docs/openapi.yaml> is the contract itself.