Metadata-Version: 2.4
Name: healthcloud-sdk
Version: 2.0.1
Summary: Python SDK for HealthCloud APIs.
Author: Healthcheck Systems Inc
License-Expression: MIT
Keywords: api,health-cloud,healthcare,healthcloud,sdk
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# HealthCloud SDK for Python

Typed Python SDK for HealthCloud services and the HealthCloud Connectors gateway.

## Installation

```bash
pip install healthcloud-sdk
```

For local development:

```bash
pip install -e ./packages/pip
```

Python 3.9 or newer is required.

## Create and authenticate a client

The current API uses typed request objects. Authentication returns typed response
objects; after registration or login, explicitly share the access token with the
whole SDK by calling `set_access_token`.

```python
from healthcloud import HCSDK, LoginRequest, RegisterPatientRequest

sdk = HCSDK(environment="dev", tenant_id="your-tenant-id")

registration = sdk.auth.register(RegisterPatientRequest(
    first_name="Jane",
    last_name="Doe",
    email="patient@example.com",
    password="SecurePassword123!",
    date_of_birth="1990-06-15",
    sex_at_birth="female",
))

token = registration.access_token
if not token:
    login = sdk.auth.login(LoginRequest(
        email="patient@example.com",
        password="SecurePassword123!",
    ))
    token = login.access_token

sdk.set_access_token(token)
```

In UAT and production, complete email verification before login when the register
response reports that verification is required.

```python
from healthcloud import VerifyOtpRequest

sdk.auth.verify_email(VerifyOtpRequest(
    user_id=registration.cognito_sub,
    otp="123456",
))
```

`sdk.auth` also exposes the password-reset pair — both public (no bearer
required) and POSTed to `/auth/reset-password` and `/auth/confirm-reset-password`:

```python
from healthcloud import ResetPatientPasswordRequest, ConfirmPatientPasswordRequest

sdk.auth.reset_password(ResetPatientPasswordRequest(email="patient@example.com"))
sdk.auth.confirm_password(ConfirmPatientPasswordRequest(
    email="patient@example.com",
    code="123456",
    new_password="NewSecurePassword123!",
))
```

## Service clients

One `HCSDK` instance exposes these clients:

```python
sdk.auth               # register / login / verify_email / reset_password / confirm_password
                       # (login does NOT auto-persist the token)
sdk.person             # full Person identity client (register / login / verify_email /
                       # reset_password / confirm_password, update_phone / verify_sms,
                       # get_person / update_person, photo) — see Person section
sdk.patient            # profile / dashboard, phone / sms, demographics, photo / vision
                       # face-compare, identity-document OCR, insurance, medications,
                       # encounters, questionnaires, nearest locations, assistant,
                       # CareConnect communications, import (CCDA / health-record /
                       # vitals / activity), preferred pharmacy, dependents, notifications,
                       # agent configuration / current care session / check-in / sidebar,
                       # current screening symptoms
sdk.provider           # full Practitioner identity client (register / login / verify_email /
                       # reset_password / confirm_password, update_phone / verify_sms,
                       # get / update, photo) — see Provider section
sdk.vitals             # connect, submit, get_vitals
sdk.diagnostics        # connect, list_diagnostics, create_rapid_test, lookup_by_gs1,
                       # get_scan_upload_url, get_test_result
sdk.appointments       # connect, list_slots, create_slot, book, cancel, reschedule,
                       # list_patient_appointments — see Appointments section
sdk.telehealth         # connect, create_channel, create_patient_token,
                       # create_provider_token, fetch_rtc_token — see Telehealth section
sdk.fieldagent         # connect, register / login / reset_password / confirm_password /
                       # verify_email / verify_sms, get_agent / update_agent, dashboard,
                       # photo, list_patients, list_encounters
sdk.mcp                # connect + JSON-RPC proxy (patient / fieldagent / assistant /
                       # communications / person audiences)
sdk.assistant          # classify / ocr / chat against the assistant API
sdk.communications     # CareConnect presence / groups / conversations / messages
sdk.connectivity       # connectivity helpers
sdk.graph              # provider / health plan / document / medical concept search / cypher,
                       # medical concept list / detail / hierarchy, policy documents

# Service clients whose public SDK surface is connect-only stubs:
sdk.ehr
sdk.rppg
sdk.session
```

`sdk.auth`, `sdk.person`, `sdk.patient`, `sdk.provider`, and `sdk.fieldagent`
each have their own register/login flow. A single `HCSDK` instance holds one
bearer token; calling `sdk.set_access_token(token)` propagates the token to
every authenticated service client and every connector client already created.
If your application needs multiple authenticated sessions concurrently
(patient + field agent, person + provider, ...), construct one `HCSDK`
instance per session.

## Graph API

`sdk.graph` exposes 19 public methods, one for each Graph API route. The eight
Search/Cypher methods use the `rag` field already present on their request
models. Setting `rag=True` calls the same POST endpoint and returns a typed
`GraphRagResponse`; there are no separate `rag_*` wrapper methods.

```python
from healthcloud import CypherQueryRequest, ProviderSearchRequest

# Standard structured response
providers = sdk.graph.search_providers(ProviderSearchRequest(
    phrase="cardiology",
    state_code="CA",
    limit=20,
))

# Same endpoint, Graph-RAG response
provider_answer = sdk.graph.search_providers(ProviderSearchRequest(
    phrase="cardiology",
    state_code="CA",
    limit=20,
    rag=True,
))

concept_answer = sdk.graph.search_medical_concepts_cypher(CypherQueryRequest(
    query="How many medical concepts are available?",
    limit=20,
    rag=True,
))
```

Search/Cypher methods:

- `search_providers`, `search_providers_cypher`
- `search_health_plans`, `search_health_plans_cypher`
- `search_document_summaries`, `search_document_summaries_cypher`
- `search_medical_concepts`, `search_medical_concepts_cypher`

Additional GET-backed methods:

- `search_medical_concepts_faceted`, `list_medical_concept_vocabularies`
- `list_medical_concepts`, `get_medical_concept`
- `list_medical_concept_relationships`, `list_medical_concept_ancestors`,
  `list_medical_concept_descendants`
- `list_policy_documents`, `search_policy_documents`, `get_policy_document`

Together with `connect`, this is 19 public SDK methods. The live suite executes
29 scenarios because it tests all eight POST methods both with and without RAG,
and runs faceted medical-concept search for SNOMED, RXNORM, and MESH.

All typed methods accept the request model shown in their signature and return a
typed response model. Examples:

```python
from healthcloud import SubmitVitalsRequest, UpdatePhoneRequest

patient = sdk.patient.get_patient()  # self-service: resolved from the Bearer token

phone = sdk.patient.set_phone(
    UpdatePhoneRequest(phone="+15550001234"),
)

vitals = sdk.vitals.submit(
    "patient-id",
    SubmitVitalsRequest(
        heart_rate=72,
        systolic=120,
        diastolic=80,
    ),
)

history = sdk.vitals.get_vitals("patient-id")
tools = sdk.mcp.list_tools("patient")
```

### Patient extension routes (raw payloads)

A growing set of patient routes are reachable via typed client methods but
return **untyped `dict` payloads** — the contracts aren't fully stabilized,
so responses are not yet generated models. The methods are:

| Area | Methods | Routes |
|---|---|---|
| Health-record / CCDA import | `import_health_record`, `import_ccda` | `POST /patients/health-record/import` |
| Vitals / activity import | `import_vitals`, `import_activity`, `list_activity`, `delete_activity` | `/patients/vitals/import`, `/patients/activity*` |
| Preferred pharmacy | `get_preferred_pharmacy`, `set_preferred_pharmacy` | `GET\|PUT /patients/preferred-pharmacy` |
| Dependents | `list_dependents`, `save_dependent`, `delete_dependent` | `/patients/dependents*` |
| Notifications | `list_notifications`, `save_notification`, `delete_notification` | `/patients/notifications*` |
| Insurance listing | `list_patient_insurances` | `GET /patients/insurance` |
| Boolean flags | `get_flags`, `update_flags` | `GET\|PATCH /patients/flags` |
| Agent configuration | `get_agent_configuration`, `get_agent` | `GET /agentconfiguration`, `GET /agent` |
| Care session / check-in / sidebar | `get_checkin`, `get_care_sessions_current`, `get_patient_sidebar` | `GET /checkin`, `GET /care-sessions/current`, `GET /patient/sidebar` |
| Current screening symptoms | `create_screening_current_symptoms` | `POST /screenings/current/symptoms` |

`import_ccda` accepts a CCDA XML document as a UTF-8 string and internally
base64-encodes it into a FHIR `Binary` payload before posting.
`import_vitals` / `import_activity` take an opaque `source` vendor identifier
and an arbitrary JSON `payload`; `save_dependent` / `save_notification` switch
between create (POST) and update (PUT) based on whether an id is passed.
These will be promoted to fully-typed models in a future release.

`update_flags` performs a **partial merge, not a replace**: only the flag
names passed in `flags` are changed, every other existing flag on the patient
is left unchanged, and it returns the complete flags dictionary after the
merge. Setting the same value again is idempotent.

```python
# Self-service: the patient is resolved from the caller's Bearer token — no
# patient id is passed to any of these.
flags = sdk.patient.get_flags()          # {} if none are set
sdk.patient.update_flags({"imported_vitals": True})
merged = sdk.patient.update_flags({"onboarding_completed": True})
# merged == {"imported_vitals": True, "onboarding_completed": True}
```

Use `sdk.set_access_token(new_token)` whenever a token changes. This updates every
authenticated service client and every connector client on the SDK instance.

`sdk.auth.login` returns the token but **does not** auto-persist it; the same
applies to `sdk.person.login` / `sdk.provider.login` / `sdk.fieldagent.login`.
Always call `sdk.set_access_token(...)` after any successful login or register
before making further authenticated calls.

## Person

`sdk.person` is the HC Person identity client (`*-api-person.health.cloud`,
separate host from the Patient API). It mirrors the Auth surface with its own
register/login/verify-email/reset-password flow, plus identity CRUD and photo
management. Routes are scoped to `/persons/{person_id}`.

`PersonLoginResponse` includes `fhir_person_id: str`. Use this returned id
(not any value cached on the client) as the path id for subsequent
`/persons/{person_id}/...` calls — on a fresh launch the cache is missing,
which is the most common cause of downstream `4xx` errors.

Public methods (all auth routes are public; CRUD and photo require a bearer):

- Auth: `register`, `login`, `verify_email`, `reset_password`, `confirm_password`
- Identity CRUD: `update_phone`, `verify_sms`, `get_person`, `update_person`
- Photo: `get_photo_upload_url`, `upload_photo`, `get_photo`

```python
from healthcloud import HCSDK, RegisterPersonRequest, PersonLoginRequest

sdk = HCSDK(environment="dev", tenant_id="my-tenant")

reg = sdk.person.register(RegisterPersonRequest(
    first_name="Jane",
    last_name="Doe",
    email="jane@example.com",
    password="SecurePassword123!",
    date_of_birth="1990-06-15",
))
if not reg.access_token:
    login = sdk.person.login(PersonLoginRequest(
        email="jane@example.com",
        password="SecurePassword123!",
    ))
    token = login.access_token
else:
    token = reg.access_token
sdk.set_access_token(token)              # <-- required

me = sdk.person.get_person(reg.fhir_person_id)
sdk.person.update_person(me.person_id, UpdatePersonRequest(phone="+15551234567"))
```

## Provider

`sdk.provider` is the HC Provider (Practitioner) identity client
(`*-api-provider.health.cloud`). Identity and photo routes use
`/practitioners/{practitioner_id}`; auth routes (`/auth/register`,
`/auth/login`, ...) are shared with the Person/Patient hosts.

`PractitionerLoginResponse` includes `fhir_provider_id: str`
(note: `fhir_provider_id`, **not** `fhir_practitioner_id`). Use it as the
path id for all `/practitioners/{practitioner_id}/...` calls.

Public methods:

- Auth: `register`, `login`, `verify_email`, `reset_password`, `confirm_password`
- Practitioner CRUD: `update_phone`, `verify_sms`, `get`, `update`
- Photo: `get_photo_upload_url`, `upload_photo`, `get_photo`

```python
from healthcloud import HCSDK, PractitionerLoginRequest

sdk = HCSDK(environment="dev", tenant_id="my-tenant")

login = sdk.provider.login(PractitionerLoginRequest(
    email="dr@example.com",
    password="Secure123!",
))
sdk.set_access_token(login.access_token)   # <-- required

p = sdk.provider.get(login.fhir_provider_id)
sdk.provider.update(p.practitioner_id, UpdatePractitionerRequest(phone="+15551234567"))
```

## Appointments

`sdk.appointments` exposes a typed Slot + Booking surface on
`*-api-appointments.health.cloud`:

- Slots: `list_slots(...)`, `create_slot(request)`
- Bookings: `book(request)`, `cancel(appointment_id)`, `reschedule(appointment_id, request)`
- Per-patient: `list_patient_appointments(patient_id, status=None)`

```python
from healthcloud import HCSDK

sdk = HCSDK(environment="dev", tenant_id="my-tenant")
# authenticate as a patient or provider first...

slots = sdk.appointments.list_slots(date_from="2026-08-16T09:00:00")

booked = sdk.appointments.book(BookAppointmentRequest(
    slot_id=slots["slots"][0]["slot_id"],
    patient_id=patient_id,
    reason_code="routine",
))

upcoming = sdk.appointments.list_patient_appointments(patient_id, status="scheduled")
```

The full typed request/response models (`BookAppointmentRequest`,
`CreateSlotRequest`, `ListSlotsQuery`, `ListPatientAppointmentsQuery`,
`RescheduleAppointmentRequest`, `Appointment`) live in
`healthcloud.models.generated.appointments`.

## Telehealth

`sdk.telehealth` exposes the backend's channel and RTC-token routes on
`*-api-telehealth.health.cloud`:

- `connect()`
- `create_channel()` → `TelehealthChannelResponse`
- `create_patient_token(request)` → `TelehealthTokenResponse`
- `create_provider_token(request)` → `TelehealthTokenResponse`
- `fetch_rtc_token(request)` → `LegacyRtcTokenResponse`

Authentication notes:

- `create_patient_token` requires a patient-scoped bearer token and is intended
  for patient-side video sessions.
- `create_provider_token` requires a provider-scoped bearer token and is
  intended for clinician-side video sessions.
- `create_channel` and `fetch_rtc_token` do not require the same role-specific
  token semantics as the minting methods, but they still use the shared SDK
  auth flow.
- `fetch_rtc_token` accepts the legacy `{ channel_name, uid, role }` payload
  and returns the compatibility response (`LegacyRtcTokenRequest` /
  `LegacyRtcTokenResponse`).

## Connectors

Connector methods are called through `sdk.connectors`; they are not raw HTTP helpers.
The package contains 32 connector clients.

### Architecture

Connector clients are created in three explicit steps:

1. Configure HealthCloud once through `HCSDK` (environment, tenant, access token).
2. Create an isolated connector client with that connector's vendor credentials via
   `sdk.connectors.<name>.create_client(...)`.
3. Call typed operation methods with operation-specific parameters only.

The connector gateway URL is resolved internally from the HealthCloud environment;
applications never pass connector base URLs or the HealthCloud bearer token again
when creating a connector client. Each client holds its vendor credentials only on
that instance and forwards them to the HealthCloud Connectors gateway
(`POST /connectors/<slug>/<operation>`) with every request. Connector-scoped
secrets cannot be overridden by operation input, and gateway errors are redacted
before being raised.

Create a credential-scoped connector client explicitly. The SDK never reads connector
credentials implicitly; applications can load them from their own secret manager or
the local `.env` used by integration tests. Do not hardcode credentials in source
code and do not create connector clients in client-side code.

### Usage

```python
import os

from healthcloud import HCSDK

sdk = HCSDK(
    environment="dev",
    tenant_id="your-tenant-id",
    access_token="cognito-access-token",
)

athena = sdk.connectors.athena_health.create_client(
    secret_key=os.environ["HC_ATHENA_SECRET_KEY"],
    practice_id=os.environ["HC_ATHENA_PRACTICE_ID"],
    department_id=os.environ["HC_ATHENA_DEPARTMENT_ID"],
    provider_id=os.environ["HC_ATHENA_PROVIDER_ID"],
)
patients = athena.search_patients(
    last_name="Smith",
    limit=5,
)

stripe = sdk.connectors.stripe.create_client(api_key=os.environ["HC_STRIPE_API_KEY"])
stripe_status = stripe.verify_connection()

# Public connector — no vendor credentials required
nppes = sdk.connectors.nppes.create_client()
provider = nppes.verify_provider(npi="1234567890")

# OAuth-style connector
whoop = sdk.connectors.whoop.create_client(
    client_id=os.environ["HC_WHOOP_CLIENT_ID"],
    client_secret=os.environ["HC_WHOOP_CLIENT_SECRET"],
)
```

Pass `mode="live"` only when required; `mode="sandbox"` is the default for
mode-aware connectors. Calling `sdk.set_access_token(...)` propagates the new
HealthCloud token to every connector client already created.

### Available connectors

The table lists each connector's required credential keyword arguments and the
conventional `HC_*` environment variable names used by the live test suite
(names only — never commit values). Parameters marked `mode?` accept
`"sandbox"` (default) or `"live"`.

| Connector | Purpose | `create_client` credentials | Suggested env vars | Called via |
|---|---|---|---|---|
| `anthropic` | Anthropic (Claude) LLM completions | `api_key`, `mode?` | `HC_ANTHROPIC_API_KEY` | `sdk.connectors.anthropic.create_client(...)` |
| `apple_auth` | Sign in with Apple token exchange | `team_id`, `client_id`, `key_id`, `redirect_uri`, `private_key` | `HC_APPLE_AUTH_TEAM_ID`, `HC_APPLE_AUTH_CLIENT_ID`, `HC_APPLE_AUTH_KEY_ID`, `HC_APPLE_AUTH_REDIRECT_URI`, `HC_APPLE_AUTH_PRIVATE_KEY` | `sdk.connectors.apple_auth.create_client(...)` |
| `athena_health` | athenahealth EHR (patients, appointments) | `secret_key`, `practice_id`, `department_id`, `provider_id`, `mode?` | `HC_ATHENA_SECRET_KEY`, `HC_ATHENA_PRACTICE_ID`, `HC_ATHENA_DEPARTMENT_ID`, `HC_ATHENA_PROVIDER_ID` | `sdk.connectors.athena_health.create_client(...)` |
| `cal` | Cal.com scheduling and bookings | `api_key` | `HC_CAL_API_KEY` | `sdk.connectors.cal.create_client(...)` |
| `carequality` | Carequality health information exchange | `api_key`, `initiator_url` | `HC_CAREQUALITY_API_KEY`, `HC_CAREQUALITY_INITIATOR_URL` | `sdk.connectors.carequality.create_client(...)` |
| `cms` | CMS (Centers for Medicare & Medicaid) data | `api_key` | `HC_CMS_API_KEY` | `sdk.connectors.cms.create_client(...)` |
| `connecture` | ConnectureDRX Medicare plan shopping | `basic_token`, `client_key`, `client_secret` | `HC_CONNECTURE_BASIC_TOKEN`, `HC_CONNECTURE_CLIENT_KEY`, `HC_CONNECTURE_CLIENT_SECRET` | `sdk.connectors.connecture.create_client(...)` |
| `elevenlabs` | ElevenLabs text-to-speech | `api_key` | `HC_ELEVENLABS_API_KEY` | `sdk.connectors.elevenlabs.create_client(...)` |
| `fedex` | FedEx shipping and tracking | `client_id`, `client_secret`, `account_number`, `mode?` | `HC_FEDEX_CLIENT_ID`, `HC_FEDEX_CLIENT_SECRET`, `HC_FEDEX_ACCOUNT_NUMBER` | `sdk.connectors.fedex.create_client(...)` |
| `google_ai` | Google AI (Gemini) LLM | `api_key` | `HC_GOOGLE_AI_API_KEY` | `sdk.connectors.google_ai.create_client(...)` |
| `google_places` | Google Places search/geocoding | `api_key`, `mode?` | `HC_GOOGLE_PLACES_API_KEY` | `sdk.connectors.google_places.create_client(...)` |
| `grok` | xAI Grok LLM | `api_key` | `HC_GROK_API_KEY` | `sdk.connectors.grok.create_client(...)` |
| `healthie` | Healthie EHR / practice management | `secret_key`, `mode?`, `shard_id?` | `HC_HEALTHIE_SECRET_KEY`, `HC_HEALTHIE_AUTHORIZATION_SHARD` | `sdk.connectors.healthie.create_client(...)` |
| `impilo` | Impilo remote patient monitoring logistics | `api_key` | `HC_IMPILO_API_KEY` | `sdk.connectors.impilo.create_client(...)` |
| `junction` | Junction (Vital) lab testing and wearables | `api_key` | `HC_JUNCTION_API_KEY` | `sdk.connectors.junction.create_client(...)` |
| `nppes` | NPPES NPI registry lookup (public, no credentials) | — | — | `sdk.connectors.nppes.create_client()` |
| `openai` | OpenAI LLM completions | `api_key` | `HC_OPENAI_API_KEY` | `sdk.connectors.openai.create_client(...)` |
| `oura` | Oura ring wearable data (OAuth) | `client_id`, `client_secret`, `mode?` | `HC_OURA_CLIENT_ID`, `HC_OURA_CLIENT_SECRET` | `sdk.connectors.oura.create_client(...)` |
| `plaid` | Plaid identity / financial verification | `client_id`, `secret`, `template_id`, `mode?` | `HC_PLAID_CLIENT_ID`, `HC_PLAID_SECRET`, `HC_PLAID_TEMPLATE_ID` | `sdk.connectors.plaid.create_client(...)` |
| `quest` | Quest Diagnostics — REST-style orders/results/catalog **and** HL7 orders, results, compendium | `client_id`, `client_secret`, `mode?` | `HC_QUEST_CLIENT_ID`, `HC_QUEST_CLIENT_SECRET` | `sdk.connectors.quest.create_client(...)` |
| `salesforce` | Salesforce CRM records and queries | `client_id`, `client_secret`, `username`, `password`, `mode?` | `HC_SALESFORCE_CLIENT_ID`, `HC_SALESFORCE_CLIENT_SECRET`, `HC_SALESFORCE_USERNAME`, `HC_SALESFORCE_PASSWORD` | `sdk.connectors.salesforce.create_client(...)` |
| `scrapfly` | Scrapfly web scraping | `api_key` | `HC_SCRAPFLY_API_KEY` | `sdk.connectors.scrapfly.create_client(...)` |
| `senaite` | SENAITE LIMS (lab information management) | `base_url`, `username`, `password` | `HC_SENAITE_BASE_URL`, `HC_SENAITE_USERNAME`, `HC_SENAITE_PASSWORD` | `sdk.connectors.senaite.create_client(...)` |
| `sendgrid` | SendGrid transactional email | `api_key`, `mode?` | `HC_SENDGRID_API_KEY` | `sdk.connectors.sendgrid.create_client(...)` |
| `steadymd` | SteadyMD telehealth clinician network | `api_key` **or** `token` (exactly one), `mode?`, `api_url?` | `HC_STEADYMD_API_KEY` or `HC_STEADYMD_TOKEN`, `HC_STEADYMD_API_URL` | `sdk.connectors.steadymd.create_client(...)` |
| `stedi` | Stedi insurance eligibility (X12/EDI) | `api_key` | `HC_STEDI_API_KEY` | `sdk.connectors.stedi.create_client(...)` |
| `stripe` | Stripe payments and subscriptions | `api_key` | `HC_STRIPE_API_KEY` | `sdk.connectors.stripe.create_client(...)` |
| `twilio` | Twilio SMS / voice messaging | `account_sid`, `auth_token`, `from_number`, `mode?` | `HC_TWILIO_ACCOUNT_SID`, `HC_TWILIO_AUTH_TOKEN`, `HC_TWILIO_FROM_NUMBER` | `sdk.connectors.twilio.create_client(...)` |
| `uber` | Uber Direct / Health rides and deliveries | `client_id`, `client_secret`, `customer_id`, `mode?` | `HC_UBER_CLIENT_ID`, `HC_UBER_CLIENT_SECRET`, `HC_UBER_CUSTOMER_ID` | `sdk.connectors.uber.create_client(...)` |
| `whoop` | WHOOP wearable data (OAuth) | `client_id`, `client_secret`, `mode?` | `HC_WHOOP_CLIENT_ID`, `HC_WHOOP_CLIENT_SECRET` | `sdk.connectors.whoop.create_client(...)` |
| `zocdoc` | Zocdoc provider search and booking | `api_key` | `HC_ZOCDOC_API_KEY` | `sdk.connectors.zocdoc.create_client(...)` |
| `zus` | Zus Health aggregated patient data | `client_id`, `client_secret`, `mode?` | `HC_ZUS_CLIENT_ID`, `HC_ZUS_CLIENT_SECRET` | `sdk.connectors.zus.create_client(...)` |

> Note: the single `quest` connector covers both the REST-style
> order/results/catalog operations and the HL7 message-based operations,
> all routing to the gateway's `quest` slug with the same credentials.

## Errors and cleanup

```python
from healthcloud import HealthCloudHTTPError, HealthCloudNetworkError

try:
    stripe.verify_connection()
except HealthCloudHTTPError as exc:
    print(exc.status_code, str(exc))
except HealthCloudNetworkError as exc:
    print(str(exc))
finally:
    sdk.close()
```

## Verification

From `packages/pip`:

```powershell
.\.venv\Scripts\python.exe -m pytest -q -m "not live"
```

Live integration tests are opt-in and use package methods:

```powershell
$env:HC_RUN_INTEGRATION="true"
$env:HC_ALLOW_REGISTER="true"
.\.venv\Scripts\python.exe -m pytest -q -m live
```

Do not commit `.env` files or connector credentials.
