@healthcloudai/hc-ehr-steadymd
v0.2.4
Published
Healthcheck SteadyMD EHR connector SDK with TypeScript
Maintainers
Readme
Healthcheck SteadyMD EHR Connector
SDK client for the Healthcheck SteadyMD EHR integration.
HCSteadyMDClient uses a configured and authenticated HCLoginClient for tenant, environment, and auth headers. Methods return the shared Healthcheck API envelope.
Installation
npm install @healthcloudai/hc-ehr-steadymd \
@healthcloudai/hc-login-connector \
@healthcloudai/hc-httpImport
import { HCSteadyMDClient } from "@healthcloudai/hc-ehr-steadymd";
import { HCLoginClient } from "@healthcloudai/hc-login-connector";
import { FetchClient } from "@healthcloudai/hc-http";
import type {
APIResponse,
SteadyMDPatient,
SteadyMDEpisode,
SteadyMDConsult,
SteadyMDIntake,
} from "@healthcloudai/hc-ehr-steadymd";Setup
const httpClient = new FetchClient();
const loginClient = new HCLoginClient(httpClient);
loginClient.configure("healthcheck", "dev");
await loginClient.login("[email protected]", "ExamplePassword123!");
const steadymdClient = new HCSteadyMDClient(httpClient, loginClient);API Key
If the environment requires an API key, configure it once:
steadymdClient.setApiKey("x-api-key", process.env.HEALTHCLOUD_API_KEY ?? "");After it is set, the API key header is included automatically with every request.
Response Format
Most methods return:
type APIResponse<T> = {
Data: T | null;
IsOK: boolean;
ErrorMessage: string | null;
};getLabResultPdf is the exception — it returns a raw Promise<ArrayBuffer>.
Methods that accept payloads wrap them in { Data: payload } internally. Pass the raw object to the method, not a wrapped version:
// Correct
await steadymdClient.createConsult({ programGuid, consultType, usState });
// Wrong — do NOT wrap in { Data: ... }
await steadymdClient.createConsult({ Data: { programGuid, consultType, usState } });Order of Execution
The methods below generally follow the documented flow from the "Healthcheck SteadyMD + Impilo APIs" Postman collection. Steps must be run in order because later steps depend on GUIDs produced by earlier ones.
Deviation from the Postman order: run Lab Order (steps 10–11) before Intake (steps 7–8).
createLabOrder()returns a usableLabRequisitions[].Guidsynchronously, while the documented step-6→7 path (createEpisodeLabRequisition→ pollgetIntake) relies on an async vendor link that does not reliably populate. Running Lab Order first letsupdateIntake()use a real, immediately-availablelabRequisitionGuidinstead of depending on that unreliable async link. See Lab Requisition GUID is created asynchronously below for the full explanation.
| Step | Area | Action |
|------|------|--------|
| 1 | Patient | getMyPatient() — confirm the patient record exists |
| 2–3 | Program | listPrograms() → getProgram() → getProgramConsultOptions() → getProgramLabs() → listProgramClinicians() → getProgramAppointments() |
| 2–3 | Pharmacy / Clinician | listPharmacies() / getClinician() — lookup only |
| 4 | Episode | createEpisode() → getEpisode() |
| 5 | Consult | createConsult() → getConsult() → getConsultAvailability() → scheduleConsultAppointment() → getConsultPatientUI() → sendConsultMessage() → createConsultIssue() |
| 6 | Episode | updateEpisode() / patchEpisode() → createEpisodeLabRequisition() → getEpisodeSignedDocuments() |
| 10–11 | Lab Order | createLabOrder() → getLabOrder() → getLabOrderPdf() → listLabOrderResults() → createLabOrderResult() → getLabOrderResult() → getLabResultPdf() — run before Intake; capture labRequisitionGuid from createLabOrder()'s response (see deviation note above) |
| 7–8 | Intake | createIntake() (draft) → getIntake() → updateIntake(..., { LabRequisitionGuid: <guid captured from createLabOrder> }) (final) → addAllergyIntolerance() |
| 9 | Identity | claimIdentityVerification() (optional KYC) |
| 12–13 | Consult | updateConsultStatus() |
| 14 | Message | createMessage() (episode-level) → getMessage() |
Known Vendor Limitations
Lab Requisition GUID is created asynchronously — do not read it from createEpisodeLabRequisition
POST /episode/{guid}/lab/requisition returns {"Guid": null, ...}. The vendor creates the requisition asynchronously and is supposed to link it to the episode's intake some time later (GET /intake/{guid} → Data.LabRequisitionGuid).
This async link does not reliably populate — Data.LabRequisitionGuid from getIntake can remain null indefinitely after calling createEpisodeLabRequisition. Since updateIntake requires a non-null LabRequisitionGuid to finalize an intake (IsDraft: false), relying on the documented flow can leave updateIntake permanently blocked.
Workaround — get the guid from createLabOrder instead:
createLabOrder() (steps 10–11) embeds the newly created requisition directly in its response as Data.LabRequisitions[0].Guid, populated synchronously — no polling required. Run the Lab Order section before Intake (see Order of Execution), capture labRequisitionGuid = response.Data.LabRequisitions[0].Guid from createLabOrder, and feed that directly into updateIntake:
// 1. Create a lab order — its response carries a usable requisition guid immediately:
const labOrderResponse = await steadymdClient.createLabOrder({ EpisodeGuid: episodeGuid, /* ... */ });
const labRequisitionGuid = labOrderResponse.Data?.LabRequisitions?.[0]?.Guid;
// 2. Use it directly to finalize the intake — no need to poll getIntake:
await steadymdClient.updateIntake(intakeGuid, {
EpisodeGuid: episodeGuid,
LabRequisitionGuid: labRequisitionGuid,
IsDraft: false,
// ...
});This does not replace createEpisodeLabRequisition in the documented flow — it is a practical alternative for unblocking updateIntake when the async link does not populate in a reasonable time. createEpisodeLabRequisition itself still returns {"Guid": null} as documented, and getEpisodeLabRequisition / polling getIntake remain the vendor-documented way to retrieve that requisition's guid if/when the link completes.
createEpisodeLabRequisition — payload must be FLAT (labOrderCode/labOrderName at the top level), not the documented Tests[] array
The SDK type SteadyMDLabRequisitionCreateRequest (and the Postman collection) describe this endpoint's body as { Laboratory, Tests: [{ LabOrderCode, LabOrderName }], Icd10Codes } — an array of tests, PascalCase keys, matching the convention used by every other non-Consult endpoint.
The live dev backend rejects that shape. Both the documented PascalCase Tests: [{ LabOrderCode, LabOrderName }] and a lowercase-keyed Tests: [{ labOrderCode, labOrderName }] variant 400 with:
SteadyMD POST → 400: {"labOrderCode":["This field is required."],"labOrderName":["This field is required."]}Note that the error reports labOrderCode/labOrderName as top-level required fields — not nested under "Tests"/"tests" — which reveals the endpoint actually validates a flat, single-test payload. Sending the fields directly at the root, lowercase, alongside Laboratory, succeeds (IsOK: true):
// Cast around the SDK type — it does not match what this endpoint accepts:
const payload = {
Laboratory: "LABCORP",
labOrderCode: "001453",
labOrderName: "Hemoglobin A1c",
Icd10Codes: ["E11.9"],
} as unknown as SteadyMDLabRequisitionCreateRequest;
await steadymdClient.createEpisodeLabRequisition(episodeGuid, payload);This is a vendor-side schema/documentation mismatch — only this endpoint's request body behaves this way; createLabOrder's LabRequisitions[] array correctly accepts the documented PascalCase LabOrderCode/LabOrderName shape.
getProgramConsultOptions — only options with IsScheduled: true AND InteractionMode: "video_chat" support the full scheduled flow
getProgramConsultOptions can return several ConsultType/InteractionMode combinations (e.g. phone_callback / phone_call, scheduled_video_visit / video_chat, async types, etc.) — only options with IsScheduled: true and InteractionMode: "video_chat" support the full scheduled flow (availability, appointment scheduling, and patient UI).
Picking an arbitrary option (e.g. Data[0]) can select a non-schedulable, non-video option and cascade into failures in getConsultAvailability, scheduleConsultAppointment, and getConsultPatientUI (see below — all three have hard requirements tied to the chosen option's IsScheduled/InteractionMode). Select deliberately:
const { Data: options } = await steadymdClient.getProgramConsultOptions(programGuid);
const option = options?.find((o) => o.IsScheduled === true && o.InteractionMode === "video_chat") ?? options?.[0];getConsultAvailability — returns 400 for consults not in a schedulable VisitStatus
GET /consult/{guid}/schedule/availability returns 400 when the target consult's VisitStatus is not waiting_to_schedule or scheduled:
SteadyMD GET → 400: {"status": "Cannot get availability for consult that's not in waiting_to_schedule or scheduled status"}This is closely related to — but distinct from — "non-schedulable consult type": even a scheduled_video_visit consult (created with IsScheduled: true) returns this 400 once its VisitStatus moves out of waiting_to_schedule/scheduled (e.g. after being canceled or resolved). Check getConsult's VisitStatus before calling this, in addition to checking getProgramConsultOptions's IsScheduled flag.
scheduleConsultAppointment — startsAt must be an exact slot from getConsultAvailability
POST /consult/{guid}/schedule/appointment rejects arbitrary timestamps. Always use a slot from GET /consult/{guid}/schedule/availability. Only call this for consult types where IsScheduled: true (see above). If Data is an empty array, show the user "No times available" and do not call scheduleConsultAppointment.
const { Data: slots } = await steadymdClient.getConsultAvailability(consultGuid);
if (!slots || slots.length === 0 || !slots[0]?.Availability?.length) {
// Show "No times available"
return;
}
const startsAt = slots[0].Availability[0];
await steadymdClient.scheduleConsultAppointment(consultGuid, { clinicianGuid, startsAt });If getConsultAvailability returns an empty Availability array (no open slots configured for the program/clinician), treat this as an expected condition and show the user "No times available" rather than treating it as a failure.
getConsultPatientUI — 400 unless the consult's InteractionMode is video_chat
POST /consult/{guid}/patient-ui returns 400 for consults whose InteractionMode is not video_chat:
SteadyMD POST → 400: {"status": "Cannot return video chat url for consult that's not a video chat consult"}Only call this for consults created from a getProgramConsultOptions option with InteractionMode: "video_chat" (see above — typically the scheduled_video_visit option). For any other interaction mode, skip the call rather than treating the 400 as an error.
sendConsultMessage — blocked patient-wide until the previous consult is in RESOLVED_STATUS
POST /consult/{guid}/message returns 400 when the previous consult is not resolved:
SteadyMD POST → 400: {"status": "You cannot create a message consult if the previous consult is not in a RESOLVED_STATUS"}Root cause: this "previous consult" check is evaluated across the whole patient, not scoped to the current episode. listConsults({ episodeGuid }) can return results whose EmrUri values belong to entirely different episodes — the vendor ignores the episodeGuid filter (the parameter is echoed back correctly in the Next pagination URL, yet the result set is unfiltered). If any of the patient's historical consults — regardless of episode — sits in rejected (a non-resolved) status, it counts as the "previous consult" and blocks the new one.
Net effect: a new consult can be blocked from sending a message because some historical consult — possibly unrelated to the current episode — is sitting in rejected status. This cannot be fixed from the client side; it requires either (a) a vendor-side bulk cleanup/resolution of the patient's historical consults, or (b) a vendor fix to scope the RESOLVED_STATUS check (and the listConsults episodeGuid filter) to the episode rather than the whole patient. Treat a 400 with this exact message as a data/environment condition, not an application bug — log it and continue rather than failing the flow.
Note:
updateConsultStatus(see below) can succeed despite being a known limitation (HTML 500 / 502) — this vendor-side issue is intermittent / environment-state-dependent rather than a hard, permanent blocker. Don't assume the error always reproduces; always handle both outcomes.
updateConsultStatus — full-integration consults can intermittently throw HTML 500 (502 from our filter)
For full-integration consults, SteadyMD can return an HTML 500 on status changes, surfaced as a 502 Bad Gateway by our filter. This is an intermittent vendor-side condition rather than a hard block (see note above). When updateConsultStatus throws, fall back to getConsult and display the last known status:
try {
await steadymdClient.updateConsultStatus(consultGuid, { status: "canceled" });
} catch {
const { Data } = await steadymdClient.getConsult(consultGuid);
console.log("Latest status:", Data?.VisitStatus);
}getLabOrderPdf — returns 404 until lab results are processed
GET /lab-order/{guid}/pdf returns 404 while results are pending. Catch a 404 and display "Pending lab results" instead of surfacing an error to the user.
try {
const pdf = await steadymdClient.getLabOrderPdf(labOrderGuid);
// use pdf.Data?.File (base64 or URL)
} catch (err: any) {
if (err?.statusCode === 404) {
// Show "Pending lab results"
}
}What needs to be resolved (vendor-side) for the full documented flow to work end-to-end
These are blockers that cannot be fixed from this SDK — they require vendor (SteadyMD) action, either in their environment or in their API/docs:
- Async lab requisition → intake link does not reliably populate (see Lab Requisition GUID is created asynchronously). Until the vendor's async linkage reliably populates
getIntake().Data.LabRequisitionGuidwithin a reasonable time, the documentedcreateEpisodeLabRequisition→ pollgetIntake→updateIntakeflow cannot be relied on end-to-end; thecreateLabOrder-based workaround above is the only reliable path to finalizeupdateIntake. createEpisodeLabRequisitionrequest schema mismatch (see entry above) — the vendor needs to either fix the endpoint to accept the documentedTests: [{ LabOrderCode, LabOrderName }]shape, or correct the Postman collection / docs to describe the flatlabOrderCode/labOrderNameshape it actually validates.- Patients can accumulate historical consults stuck in
rejectedstatus, which blocksendConsultMessagepatient-wide for every new consult (see entry above). A bulk cleanup/resolution pass on the patient's consult history — or a vendor fix scoping the RESOLVED_STATUS check to the episode — is required before this method can be used reliably against a fresh consult. listConsultsignores theepisodeGuidquery filter (discovered while investigating #3 above) — the parameter is accepted and echoed in pagination URLs but not applied to the result set. Any client code that relies onlistConsults({ episodeGuid })to scope results to one episode will silently receive unrelated results; this needs a vendor-side fix before episode-scoped consult listing can be trusted.- No schedulable time slots configured —
getConsultAvailabilitycan returnAvailability: []even for a freshly createdscheduled_video_visitconsult, soscheduleConsultAppointmentcannot be used end-to-end until open slots are configured for at least one program/clinician.
Important Notes
- The login client must be configured and authenticated before calling any SteadyMD method.
- Do not pass raw backend routes to SDK methods. Use the public methods only.
- Casing: Consult request body fields are camelCase (
programGuid,consultType,usState,text,startsAt,status,level). All other SteadyMD request types are PascalCase (EpisodeGuid,Laboratory,EpisodeGuid, etc.) — exceptcreateEpisodeLabRequisition, whoseTests[]items the live backend validates as flat, lowercase, top-levellabOrderCode/labOrderNamefields rather than the documented PascalCase array shape (a vendor schema/doc mismatch specific to that one endpoint — see Known Vendor Limitations). - Response field names are always PascalCase (
EpisodeGuid,Guid,VisitStatus, etc.). - Response examples below are sanitized. Real GUIDs, names, and URLs are replaced with placeholders.
Patient Methods
getMyPatient() — GET
Returns the SteadyMD patient record for the authenticated Healthcheck user. The patientGuid is resolved server-side from the user's RecordMapping (STEADY_MD_ID) — clients never pass it.
const response = await steadymdClient.getMyPatient();Returns Promise<APIResponse<SteadyMDPatient>>.
Example response:
{
"Data": {
"Guid": "11111111-1111-4111-8111-111111111111",
"FirstName": "John",
"LastName": "Smith",
"Email": "[email protected]",
"Phone": "+15555550123",
"Address1": "123 Example St",
"Address2": null,
"City": "Oak Park",
"UsState": "CA",
"ZipCode": "91377",
"BirthDate": "1978-10-10",
"Gender": "male",
"MaritalStatus": "UNK"
},
"ErrorMessage": null,
"IsOK": true
}Program Methods
listPrograms(options?) — GET
Lists programs. Optional filters: clinicianGuid, snomed, complaintsSnomed, programPopulation, limit, offset.
const response = await steadymdClient.listPrograms({ limit: 10 });Returns Promise<APIResponse<SteadyMDProgramListResponse>>.
Example response:
{
"Data": {
"Count": 1,
"Next": null,
"Previous": null,
"Results": [
{
"Guid": "66666666-6666-4666-8666-666666666666",
"Name": "Safe Health Sandbox",
"Description": "",
"IdentityVerificationType": "sync_see_id",
"ConsultTypes": [
"async_messaging",
"chart_review",
"phone_callback",
"scheduled_video_visit",
"video_visit"
]
}
]
},
"ErrorMessage": null,
"IsOK": true
}getProgram(programGuid) — GET
Returns one program by GUID.
const response = await steadymdClient.getProgram("66666666-6666-4666-8666-666666666666");Returns Promise<APIResponse<SteadyMDProgram>>.
Example response:
{
"Data": {
"Guid": "66666666-6666-4666-8666-666666666666",
"Name": "Safe Health Sandbox",
"Description": "",
"IdentityVerificationType": "sync_see_id",
"ConsultTypes": [
"async_messaging",
"chart_review",
"phone_callback",
"scheduled_video_visit",
"video_visit"
]
},
"ErrorMessage": null,
"IsOK": true
}getProgramAppointments(programGuid, consultType, usState, clinicianGuid?) — GET
Returns available appointment slots for a program, consult type, and US state. All three required params must be provided or SteadyMD returns 400.
const response = await steadymdClient.getProgramAppointments(
"66666666-6666-4666-8666-666666666666",
"scheduled_video_visit",
"GA"
);Returns Promise<APIResponse<SteadyMDAvailableAppointment[]>>.
Example response:
{
"Data": [
{
"DurationMinutes": 30,
"Availability": []
}
],
"ErrorMessage": null,
"IsOK": true
}
Availabilitymay be empty if no slots exist for this consult type or state.
listProgramClinicians(programGuid, options?) — GET
Lists clinicians for a program. Optional filters: usState, complaintsSnomed, programPopulation, limit, offset.
const response = await steadymdClient.listProgramClinicians(
"66666666-6666-4666-8666-666666666666",
{ usState: "GA", limit: 10 }
);Returns Promise<APIResponse<SteadyMDClinicianListResponse>>.
Example response:
{
"Data": {
"Count": 3,
"Next": null,
"Previous": null,
"Results": [
{
"Guid": "88888888-8888-4888-8888-888888888888",
"FirstName": "Jane",
"LastName": "Clinician",
"ClinicianSuffixes": "MD, NP",
"Email": "[email protected]",
"Headshot": "https://example.com/headshots/jane.jpg",
"ClinicianType": "Medical Doctor",
"ClinicianTypes": [
{ "ClinicianType": "Medical Doctor", "Suffix": "MD" }
],
"ClinicianSpecialties": ["Internal Medicine"],
"NpiNumber": "1234567890"
}
]
},
"ErrorMessage": null,
"IsOK": true
}getProgramConsultOptions(programGuid, usState, consultType?) — GET
Returns consult options for a program and state. Use the returned ConsultType and UsState to drive createConsult.
Don't pick an option blindly (e.g.
Data[0]). SeveralConsultType/InteractionModecombinations can be returned, but only the option withIsScheduled: trueANDInteractionMode: "video_chat"(typicallyscheduled_video_visit) supports the full scheduled + video flow. Picking a different option (e.g.phone_callback/IsScheduled: false) cascades into 400s fromgetConsultAvailability,scheduleConsultAppointment, andgetConsultPatientUI— each of which has its own hard requirement on these flags (see their entries below and in Known Vendor Limitations). Select deliberately:const option = response.Data?.find( (o) => o.IsScheduled === true && o.InteractionMode === "video_chat" ) ?? response.Data?.[0];
const response = await steadymdClient.getProgramConsultOptions(
"66666666-6666-4666-8666-666666666666",
"GA",
"video_visit"
);Returns Promise<APIResponse<SteadyMDConsultOption[]>>.
Example response:
{
"Data": [
{
"ProgramGuid": "66666666-6666-4666-8666-666666666666",
"ConsultType": "video_visit",
"InteractionMode": "video_chat",
"UsState": "GA",
"ExternalLinks": [],
"Metadata": {},
"PreferredClinician": null,
"IsScheduled": false
}
],
"ErrorMessage": null,
"IsOK": true
}getProgramLabs(programGuid, options?) — GET
Returns lab tests available for a program. Optional filters: laboratory, labOrderCode, labOrderName, complaintsSnomed, programPopulation.
const response = await steadymdClient.getProgramLabs("66666666-6666-4666-8666-666666666666");Returns Promise<APIResponse<SteadyMDProgramLabTest[]>>.
Clinician Methods
getClinician(clinicianGuid) — GET
Returns one clinician by GUID.
const response = await steadymdClient.getClinician("88888888-8888-4888-8888-888888888888");Returns Promise<APIResponse<SteadyMDClinician>>.
Example response:
{
"Data": {
"Guid": "88888888-8888-4888-8888-888888888888",
"FirstName": "Jane",
"LastName": "Clinician",
"ClinicianSuffixes": "MD",
"Email": "[email protected]",
"Headshot": "https://example.com/headshots/jane.jpg",
"ClinicianType": "Medical Doctor",
"ClinicianTypes": [{ "ClinicianType": "Medical Doctor", "Suffix": "MD" }],
"ClinicianSpecialties": ["Internal Medicine"],
"Supervisor": null,
"Bio": null,
"LanguagesSpoken": [{ "Language": "English", "Hl7Code": "en" }],
"Qualifications": [],
"NpiNumber": "1234567890",
"NpiData": {}
},
"ErrorMessage": null,
"IsOK": true
}Pharmacy Methods
listPharmacies(options?) — GET
Searches pharmacies. Optional filters: name, address, city, state, zipCode, phoneOrFax, specialty1, specialty2.
const response = await steadymdClient.listPharmacies({ city: "Atlanta", state: "GA" });Returns Promise<APIResponse<SteadyMDPharmacyResponse[]>>.
Example response:
{
"Data": [
{
"StoreName": "CVS/pharmacy #4178",
"Address1": "895 Ralph Abernathy Blvd SW",
"Address2": null,
"City": "Atlanta",
"State": "GA",
"ZipCode": "30310",
"PrimaryPhone": "4047551511",
"PrimaryFax": "4047555065",
"PharmacySpecialties": ["Retail", "EPCS"]
}
],
"ErrorMessage": null,
"IsOK": true
}Episode Methods
createEpisode(data) — POST
Creates an episode. All fields are optional.
const response = await steadymdClient.createEpisode({
Pharmacy: {
NcpdpId: "1234567",
NpiNumber: "1234567890",
StoreName: "CVS Pharmacy",
Address1: "123 Main St",
City: "Miami",
State: "FL",
ZipCode: "33101",
PhoneNumber: "+15551234567",
PrimaryFax: "+15557654321",
IsDefault: true,
IsPreferred: true
},
Metadata: { source: "mobile-app" }
});Returns Promise<APIResponse<SteadyMDEpisode>>.
Example response:
{
"Data": {
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"EpisodeUri": "steadymd://episode/22222222-2222-4222-8222-222222222222",
"PatientGuid": "11111111-1111-4111-8111-111111111111",
"ParentsOrGuardians": [],
"Diagnosis": [],
"Prescriptions": [],
"RequestedPharmacy": {
"NcpdpId": "1234567",
"NpiNumber": "1234567890",
"StoreName": "CVS Pharmacy",
"Address1": "123 Main St",
"City": "Miami",
"State": "FL",
"ZipCode": "33101",
"IsDefault": true,
"IsPreferred": true
},
"PrescribedPharmacies": [],
"Notes": "",
"TreatmentPlan": "",
"LabOrders": [],
"Observations": [],
"Metadata": {},
"TransitionCareLocation": ""
},
"ErrorMessage": null,
"IsOK": true
}getEpisode(episodeGuid) — GET
Returns one episode by GUID.
const response = await steadymdClient.getEpisode("22222222-2222-4222-8222-222222222222");Returns Promise<APIResponse<SteadyMDEpisode>>.
updateEpisode(episodeGuid, data) — PUT
Fully updates an episode. Replaces existing fields with whatever is sent.
const response = await steadymdClient.updateEpisode(
"22222222-2222-4222-8222-222222222222",
{ ParentsOrGuardians: [] }
);Returns Promise<APIResponse<SteadyMDEpisode>>.
patchEpisode(episodeGuid, data) — PATCH
Partially updates an episode. Only the fields provided are changed.
const response = await steadymdClient.patchEpisode(
"22222222-2222-4222-8222-222222222222",
{ Metadata: { priority: "standard" } }
);Returns Promise<APIResponse<SteadyMDEpisode>>.
getEpisodeSignedDocuments(episodeGuid, options?) — GET
Returns signed documents for an episode. Optional filters: encounterGuid, labOrderGuid, intakesGuid.
const response = await steadymdClient.getEpisodeSignedDocuments(
"22222222-2222-4222-8222-222222222222"
);Returns Promise<APIResponse<SteadyMDSignedDocument[]>>.
Example response:
{
"Data": [],
"ErrorMessage": null,
"IsOK": true
}createEpisodeLabRequisition(episodeGuid, data) — POST
Creates a lab requisition for an episode.
VENDOR ASYNC — The vendor creates the requisition asynchronously. The response always returns
{"Guid": null}. Do not read the GUID from this response. The documented path is to pollgetIntakeuntilData.LabRequisitionGuidis populated, then use that GUID inupdateIntake— but that link does not reliably populate (see Known Vendor Limitations for acreateLabOrder-based workaround that reliably unblocksupdateIntake).VENDOR SHAPE QUIRK — The SDK type
SteadyMDLabRequisitionCreateRequestdeclaresTests: SteadyMDLabRequisitionShortRequest[](an array of{ LabOrderCode, LabOrderName }, PascalCase) — matching every other non-Consult endpoint's convention, and what the Postman collection shows too. The live dev backend rejects that shape with a 400:{"labOrderCode":["This field is required."],"labOrderName":["This field is required."]}. The error reports those as top-level required fields (not nested underTests), proving the endpoint actually validates a flat, single-test, lowercase-keyed body. Use the shape below — confirmed working against the live dev backend — and cast around the SDK type, since the type itself doesn't (yet) reflect what the vendor accepts. This is a vendor schema/doc mismatch specific to this one endpoint; see Known Vendor Limitations for more detail.
// NOTE: this is the WORKING shape (confirmed live) — not what
// SteadyMDLabRequisitionCreateRequest currently declares. Cast around the
// type until the SDK type is corrected to match the vendor's real schema.
const payload = {
Laboratory: "LABCORP",
labOrderCode: "001453",
labOrderName: "Hemoglobin A1c",
Icd10Codes: ["E11.9"]
} as unknown as SteadyMDLabRequisitionCreateRequest;
const response = await steadymdClient.createEpisodeLabRequisition(
"22222222-2222-4222-8222-222222222222",
payload
);
// response.Data.Guid === null ← expected (vendor links the requisition asynchronously), not an errorReturns Promise<APIResponse<SteadyMDLabRequisition>>.
getEpisodeLabRequisition(episodeGuid, labRequisitionGuid) — GET
Returns one lab requisition by GUID. Use the GUID obtained by polling getIntake, not from createEpisodeLabRequisition.
const response = await steadymdClient.getEpisodeLabRequisition(
"22222222-2222-4222-8222-222222222222",
"33333333-3333-4333-8333-333333333333"
);Returns Promise<APIResponse<SteadyMDLabRequisition>>.
Consult Methods
Casing: All consult request body fields are camelCase (
programGuid,consultType,usState,text,startsAt,status,level). The SteadyMD API is case-sensitive and will reject PascalCase field names on these endpoints.
listConsults(options?) — GET
Lists consults. Optional filters: episodeGuid, programGuid, visitStatus, limit, offset.
VENDOR FILTER BUG —
episodeGuidis accepted but not applied.listConsults({ episodeGuid })can return results belonging to entirely different episodes (theirEmrUrivalues won't match the requestedepisodeGuid). The parameter is echoed correctly in the response'sNextpagination URL — the vendor accepts it but does not filter by it server-side. Do not assumelistConsults({ episodeGuid })returns only that episode's consults; if you need episode-scoped results, filterResultsclient-side byEmrUri/EpisodeGuid. SeesendConsultMessage'sRESOLVED_STATUSblock for related context.
const response = await steadymdClient.listConsults({
episodeGuid: "22222222-2222-4222-8222-222222222222",
limit: 10
});Returns Promise<APIResponse<SteadyMDConsultListResponse>>.
Example response:
{
"Data": {
"Count": 1,
"Next": null,
"Previous": null,
"Results": [
{
"Guid": "55555555-5555-4555-8555-555555555555",
"EmrUri": "steadymd://episode/22222222-2222-4222-8222-222222222222",
"UsState": "GA",
"Clinician": null,
"ClinicianGuid": null,
"ConsultType": "phone_callback",
"ConsultDefinitionGuid": "77777777-7777-4777-8777-777777777777",
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"ProgramName": "Safe Health Sandbox",
"ProgramGuid": "66666666-6666-4666-8666-666666666666",
"VisitStatus": "received",
"CreatedAt": "2026-06-01T23:55:51.022672Z",
"AppointmentTimezone": null,
"AppointmentStartsAt": null,
"AppointmentEndsAt": null,
"AppointmentStartsAtLocalTime": null,
"AppointmentEndsAtLocalTime": null,
"AppointmentScheduledStartsAt": null,
"AppointmentScheduledEndsAt": null,
"IsExternal": false,
"IsPediatric": false,
"IsHighPriority": false,
"IsScheduled": false,
"ExternalLinks": [],
"Reason": null,
"ReasonSlug": null,
"PreferredClinician": null,
"PreferredClinicianGuid": null,
"ReasonForVisit": null,
"VisitStatusSetAt": "2026-06-01T23:56:24.539213Z",
"ProgramDisplayName": null,
"Metadata": {}
}
]
},
"ErrorMessage": null,
"IsOK": true
}createConsult(data) — POST
Creates a consult. programGuid, consultType, and usState are required (camelCase). Use values from getProgramConsultOptions.
SteadyMD allows only one active consult per episode and returns an error if one already exists.
const response = await steadymdClient.createConsult({
programGuid: "66666666-6666-4666-8666-666666666666",
consultType: "phone_callback",
emrUri: "steadymd://episode/22222222-2222-4222-8222-222222222222",
usState: "GA"
});Returns Promise<APIResponse<SteadyMDConsult>>.
getConsult(consultGuid) — GET
Returns one consult by GUID.
const response = await steadymdClient.getConsult("55555555-5555-4555-8555-555555555555");Returns Promise<APIResponse<SteadyMDConsult>>.
getConsultAvailability(consultGuid) — GET
Returns available appointment slots for a consult.
Only valid for schedulable consult types (
IsScheduled: trueANDInteractionMode: "video_chat"fromgetProgramConsultOptions— see that method's note). Returns 400 —{"status": "Cannot get availability for consult that's not in waiting_to_schedule or scheduled status"}— both for non-schedulable consult types and for consults whoseVisitStatushas moved out ofwaiting_to_schedule/scheduled(e.g. canceled/resolved). Check bothgetProgramConsultOptionsand the consult's currentVisitStatus(viagetConsult) before calling this. IfDatais empty or allAvailabilityarrays are empty, show the user "No times available" — do not callscheduleConsultAppointment. This can happen even for a freshly createdscheduled_video_visitconsult when no open slots are configured for the program/clinician. See Known Vendor Limitations.
const response = await steadymdClient.getConsultAvailability("55555555-5555-4555-8555-555555555555");Returns Promise<APIResponse<SteadyMDAvailableAppointment[]>>.
Example response:
{
"Data": [
{
"DurationMinutes": 30,
"Availability": [
"2026-06-10T14:00:00Z",
"2026-06-10T14:30:00Z"
]
}
],
"ErrorMessage": null,
"IsOK": true
}scheduleConsultAppointment(consultGuid, data) — POST
Schedules an appointment for a consult. clinicianGuid and startsAt are required (camelCase).
startsAtmust be an exact slot fromgetConsultAvailability. The vendor rejects arbitrary timestamps. See Known Vendor Limitations.
const { Data: slots } = await steadymdClient.getConsultAvailability(consultGuid);
if (!slots?.[0]?.Availability?.length) {
// Show "No times available"
return;
}
const response = await steadymdClient.scheduleConsultAppointment(
"55555555-5555-4555-8555-555555555555",
{
clinicianGuid: "88888888-8888-4888-8888-888888888888",
startsAt: slots[0].Availability[0]
}
);Returns Promise<APIResponse<SteadyMDConsult>>.
getConsultPatientUI(consultGuid, data) — POST
Creates or retrieves a patient-facing UI link for a consult. Used to embed the patient video/messaging interface.
Only valid for
video_chatconsults. Returns 400 —{"status": "Cannot return video chat url for consult that's not a video chat consult"}— for any consult whoseInteractionModeis not"video_chat". Select agetProgramConsultOptionsoption withInteractionMode: "video_chat"(typicallyscheduled_video_visit) before calling this; for other interaction modes, skip the call instead of treating the 400 as an error. See Known Vendor Limitations.
const response = await steadymdClient.getConsultPatientUI(
"55555555-5555-4555-8555-555555555555",
{
element: "video_visit",
callbackUrl: "https://example.com/consult-complete"
}
);Returns Promise<APIResponse<SteadyMDConsultPatientUI>>.
Example response:
{
"Data": {
"Url": "https://patient.steadymd.com/r/SomeDeepLink"
},
"ErrorMessage": null,
"IsOK": true
}sendConsultMessage(consultGuid, data) — POST
Sends a message within a consult thread. text is required (camelCase).
Blocked patient-wide by historical consult data. Returns 400 ("You cannot create a message consult if the previous consult is not in a RESOLVED_STATUS") whenever any prior consult for the patient — not just the current episode — is not
RESOLVED_STATUS. If the patient has historical consults stuck inrejected, this blocks every new consult. This is a vendor data/scoping issue, not something the client can fix — catch the 400, log the explanation, and continue. See Known Vendor Limitations for the full explanation (including the relatedlistConsultsepisodeGuidfilter bug).
const response = await steadymdClient.sendConsultMessage(
"55555555-5555-4555-8555-555555555555",
{ text: "Hello, doctor.", recipient: "clinician" }
);Returns Promise<APIResponse<SteadyMDMessage>>.
updateConsultStatus(consultGuid, data) — POST
Updates a consult's status. status is required (camelCase). Common values: "canceled".
Intermittent vendor issue for full-integration consults: SteadyMD can return an HTML 500 (surfaced as 502 by our filter) on status changes, or succeed — behavior is inconsistent. Treat it as flaky rather than a hard block: when it throws, fall back to
getConsultand display the current status. See Known Vendor Limitations.
try {
const response = await steadymdClient.updateConsultStatus(
"55555555-5555-4555-8555-555555555555",
{ status: "canceled" }
);
} catch {
const { Data } = await steadymdClient.getConsult("55555555-5555-4555-8555-555555555555");
console.log("Latest consult status:", Data?.VisitStatus);
}Returns Promise<APIResponse<SteadyMDConsult>>.
createConsultIssue(consultGuid, data) — POST
Creates an issue for a consult. level is required (camelCase).
const response = await steadymdClient.createConsultIssue(
"55555555-5555-4555-8555-555555555555",
{
level: "warning",
description: "Patient reports new symptom",
links: []
}
);Returns Promise<APIResponse<SteadyMDConsultIssue>>.
Example response:
{
"Data": {
"Guid": "99999999-9999-4999-8999-999999999999",
"ConsultGuid": "55555555-5555-4555-8555-555555555555",
"ChartAddendumGuid": null,
"Level": "warning",
"Status": "unresolved",
"Description": "Patient reports new symptom",
"Links": [],
"Exception": null
},
"ErrorMessage": null,
"IsOK": true
}Intake Methods
listIntakes(options?) — GET
Lists intakes. Optional filters: episodeGuid, limit, offset.
const response = await steadymdClient.listIntakes({
episodeGuid: "22222222-2222-4222-8222-222222222222"
});Returns Promise<APIResponse<SteadyMDIntakeListResponse>>.
Example response:
{
"Data": {
"Count": 1,
"Next": null,
"Previous": null,
"Results": [
{
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"IntakeGuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"Observations": [
{ "Name": "height", "Value": 70, "Unit": "in" },
{ "Name": "weight", "Value": 175, "Unit": "lb" }
],
"Questionnaire": [],
"Files": [],
"LabRequisitionGuid": null,
"IsDraft": true
}
]
},
"ErrorMessage": null,
"IsOK": true
}createIntake(data) — POST
Creates an intake (typically as a draft). EpisodeGuid is required (PascalCase).
const response = await steadymdClient.createIntake({
EpisodeGuid: "22222222-2222-4222-8222-222222222222",
IsDraft: true,
Observations: [
{ Name: "height", Value: 70, Unit: "in" },
{ Name: "weight", Value: 175, Unit: "lb" }
],
Questionnaire: [
{
Question: "Do you have any allergies?",
Answer: ["None"],
Type: "text",
AnswerType: "valueString",
AnswerOption: []
}
]
});Returns Promise<APIResponse<SteadyMDIntake>>.
getIntake(intakeGuid) — GET
Returns one intake by GUID. The documented flow polls this after createEpisodeLabRequisition until Data.LabRequisitionGuid is non-null, then uses that GUID in updateIntake.
This link does not reliably populate —
LabRequisitionGuidcan remainnullindefinitely. Don't block your flow on it; instead capturelabRequisitionGuidfromcreateLabOrder's response (synchronous, reliable) and pass that toupdateIntake. See Known Vendor Limitations for the full explanation and the working alternative flow. This is also why the Lab Order section should run before Intake — see Order of Execution.
const { Data } = await steadymdClient.getIntake("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa");
console.log("Vendor-linked LabRequisitionGuid:", Data?.LabRequisitionGuid ?? "(not yet linked)");
// Don't poll waiting for this — use the guid captured from createLabOrder instead (see below).Returns Promise<APIResponse<SteadyMDIntake>>.
updateIntake(intakeGuid, data) — PUT
Finalizes an intake. EpisodeGuid is required. LabRequisitionGuid is required when finalizing (IsDraft: false) — the backend returns 400 ("labRequisitionGuid is required") without it.
Don't poll
getIntakefor this guid — the vendor's async link to the intake does not reliably populate. Instead, capturelabRequisitionGuiddirectly fromcreateLabOrder's response (Data.LabRequisitions[0].Guid, populated synchronously) and pass that here. This requires running the Lab Order section before Intake — see Order of Execution and Known Vendor Limitations for the full explanation.
const response = await steadymdClient.updateIntake(
"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
{
EpisodeGuid: "22222222-2222-4222-8222-222222222222",
LabRequisitionGuid: labRequisitionGuid, // captured from createLabOrder, not from polling getIntake
IsDraft: false,
Observations: [],
Questionnaire: []
}
);Returns Promise<APIResponse<SteadyMDIntake>>.
addAllergyIntolerance(intakeGuid, data) — POST
Adds allergy intolerance entries to an intake. At least one entry is required. Pass the array directly — do not wrap in { Data: ... }.
const response = await steadymdClient.addAllergyIntolerance(
"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
[
{
Code: {
Coding: [
{
System: "https://med.steadymd.com/not-specified",
Code: "not_specified",
Display: "Not specified"
}
]
}
}
]
);Returns Promise<APIResponse<{ status: string }>>.
Example response:
{
"Data": { "status": "okay" },
"ErrorMessage": null,
"IsOK": true
}Identity Methods
claimIdentityVerification(data) — POST
Claims an identity verification event on an episode. EpisodeGuid and ClaimType are required (PascalCase). Use ClaimType: "external" for standard external verification.
const response = await steadymdClient.claimIdentityVerification({
EpisodeGuid: "22222222-2222-4222-8222-222222222222",
ClaimType: "external",
ClaimedByName: "John Smith"
});Returns Promise<APIResponse<SteadyMDIdentityClaim>>.
Example response:
{
"Data": {
"ClaimType": "external",
"ClaimedByName": "John Smith",
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"PatientConsentGuid": null,
"Metadata": null
},
"ErrorMessage": null,
"IsOK": true
}Lab Order Methods
listLabOrders(options?) — GET
Lists lab orders. Optional filters: episodeGuid, limit, offset.
const response = await steadymdClient.listLabOrders({
episodeGuid: "22222222-2222-4222-8222-222222222222"
});Returns Promise<APIResponse<SteadyMDLabOrderListResponse>>.
Example response:
{
"Data": {
"Count": 1,
"Next": null,
"Previous": null,
"Results": [
{
"EmrUri": "steadymd://episode/22222222-2222-4222-8222-222222222222/lab/order/bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"Guid": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"PatientGuid": "11111111-1111-4111-8111-111111111111",
"LabOrderId": null,
"Laboratory": "LABCORP",
"PaymentResponsibility": "patient",
"SubmissionMethod": "SELF_SUBMISSION",
"LabAccountId": null,
"LabReferenceId": null,
"LabRequisitions": [
{
"Guid": "33333333-3333-4333-8333-333333333333",
"LabOrderCode": "001453",
"LabOrderName": "Hemoglobin A1c",
"LabResultCodes": []
}
],
"OrderingClinician": null,
"DiagnosticResultId": null,
"LabResults": []
}
]
},
"ErrorMessage": null,
"IsOK": true
}createLabOrder(data) — POST
Creates a lab order. EpisodeGuid and Laboratory are required (PascalCase). Unlike createEpisodeLabRequisition, this endpoint correctly accepts the documented PascalCase LabRequisitions: [{ LabOrderCode, LabOrderName }] array shape.
Useful side effect — a synchronous
labRequisitionGuidsource. The response embeds the newly created requisition atData.LabRequisitions[0].Guid, populated immediately (unlikecreateEpisodeLabRequisition, which always returns{Guid: null}and links asynchronously — a link that does not reliably populate). Capture it here and pass it straight toupdateIntake, skipping the unreliablegetIntakepolling entirely:const labRequisitionGuid = response.Data?.LabRequisitions?.[0]?.Guid;This is why Lab Order should run before Intake — see Order of Execution and Known Vendor Limitations.
const response = await steadymdClient.createLabOrder({
EpisodeGuid: "22222222-2222-4222-8222-222222222222",
Laboratory: "LABCORP",
PaymentResponsibility: "patient",
SubmissionMethod: "SELF_SUBMISSION",
LabRequisitions: [
{ LabOrderCode: "001453", LabOrderName: "Hemoglobin A1c" }
]
});
const labRequisitionGuid = response.Data?.LabRequisitions?.[0]?.Guid;Returns Promise<APIResponse<SteadyMDLabOrder>>.
Example response:
{
"Data": {
"EmrUri": "steadymd://episode/22222222-2222-4222-8222-222222222222/lab/order/bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"Guid": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"PatientGuid": "11111111-1111-4111-8111-111111111111",
"LabOrderId": null,
"Laboratory": "LABCORP",
"PaymentResponsibility": "patient",
"SubmissionMethod": "SELF_SUBMISSION",
"LabAccountId": null,
"LabReferenceId": null,
"LabRequisitions": [
{
"Guid": "33333333-3333-4333-8333-333333333333",
"LabOrderCode": "001453",
"LabOrderName": "Hemoglobin A1c",
"LabResultCodes": []
}
],
"OrderingClinician": null,
"DiagnosticResultId": null,
"LabResults": []
},
"ErrorMessage": null,
"IsOK": true
}getLabOrder(labOrderGuid) — GET
Returns one lab order by GUID.
const response = await steadymdClient.getLabOrder("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb");Returns Promise<APIResponse<SteadyMDLabOrder>>.
getLabOrderPdf(labOrderGuid) — GET
Returns the lab order PDF attachment.
Returns 404 until lab results are received and processed by the vendor. Catch a 404 and display "Pending lab results" instead of surfacing it as an error.
try {
const response = await steadymdClient.getLabOrderPdf("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb");
// response.Data contains { Guid, Kind, File, Checksum, CreatedAt }
} catch (err: any) {
if (err?.statusCode === 404) {
// Show "Pending lab results"
}
}Returns Promise<APIResponse<SteadyMDFileAttachment>>.
listLabOrderResults(labOrderGuid, options?) — GET
Lists results for a lab order. Optional filters: diagnosticResultId, includeReferenceRanges, labOrderId, requestResultId, limit, offset.
const response = await steadymdClient.listLabOrderResults(
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
{ includeReferenceRanges: true }
);Returns Promise<APIResponse<SteadyMDLabResultListResponse>>.
Example response (no results yet):
{
"Data": {
"Count": 0,
"Next": null,
"Previous": null,
"Results": []
},
"ErrorMessage": null,
"IsOK": true
}createLabOrderResult(labOrderGuid, data) — POST
Creates a lab result for a lab order. The combination of ExternalId + Version must be unique per lab order — the vendor returns 400 on duplicates. Use a unique value on each call (e.g. a timestamp or UUID).
const response = await steadymdClient.createLabOrderResult(
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
{
ExternalId: `RESULT_${Date.now()}`,
Version: "1",
Status: "final",
Observations: []
}
);Returns Promise<APIResponse<SteadyMDLabResult>>.
getLabOrderResult(labOrderGuid, labResultGuid) — GET
Returns one lab result by GUID.
const response = await steadymdClient.getLabOrderResult(
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc"
);Returns Promise<APIResponse<SteadyMDLabResult>>.
getLabResultPdf(labOrderGuid, labResultGuid) — GET (raw binary)
Returns the raw PDF bytes for a lab result. Unlike other methods, this returns a raw ArrayBuffer, not an APIResponse.
const buffer = await steadymdClient.getLabResultPdf(
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc"
);
console.log(`Received ${buffer.byteLength} bytes`);Returns Promise<ArrayBuffer>.
Message Methods
These are episode-level messages (standalone, not tied to a consult thread). For consult-level messages, use
sendConsultMessage.
listMessages(options?) — GET
Lists episode messages. Optional filters: episodeGuid, limit, offset.
const response = await steadymdClient.listMessages({
episodeGuid: "22222222-2222-4222-8222-222222222222"
});Returns Promise<APIResponse<SteadyMDMessageListResponse>>.
Example response:
{
"Data": {
"Count": 1,
"Next": null,
"Previous": null,
"Results": [
{
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"IsPleasantry": false,
"Guid": "77777777-7777-4777-8777-777777777777",
"Recipient": "to_clinician",
"Text": "Following up on my visit",
"ClinicianGuid": null,
"SentAt": "2026-06-01T23:56:26.281412Z",
"CreatedBy": 654
}
]
},
"ErrorMessage": null,
"IsOK": true
}createMessage(data) — POST
Creates an episode-level message. EpisodeGuid and Text are required (PascalCase).
const response = await steadymdClient.createMessage({
EpisodeGuid: "22222222-2222-4222-8222-222222222222",
Text: "Following up on my visit",
IsSentDuringVideoChat: false
});Returns Promise<APIResponse<SteadyMDMessage>>.
Example response:
{
"Data": {
"EpisodeGuid": "22222222-2222-4222-8222-222222222222",
"IsPleasantry": false,
"Guid": "77777777-7777-4777-8777-777777777777",
"Recipient": "to_clinician",
"Text": "Following up on my visit",
"ClinicianGuid": null,
"SentAt": "2026-06-01T23:56:26.281412Z",
"CreatedBy": 654
},
"ErrorMessage": null,
"IsOK": true
}getMessage(messageGuid) — GET
Returns one episode message by GUID.
const response = await steadymdClient.getMessage("77777777-7777-4777-8777-777777777777");Returns Promise<APIResponse<SteadyMDMessage>>.
Method Summary
| Area | Method | HTTP | Required Params |
|------|--------|------|-----------------|
| Patient | getMyPatient() | GET | — |
| Program | listPrograms(options?) | GET | — |
| Program | getProgram(programGuid) | GET | programGuid |
| Program | getProgramAppointments(programGuid, consultType, usState, clinicianGuid?) | GET | programGuid, consultType, usState |
| Program | listProgramClinicians(programGuid, options?) | GET | programGuid |
| Program | getProgramConsultOptions(programGuid, usState, consultType?) | GET | programGuid, usState |
| Program | getProgramLabs(programGuid, options?) | GET | programGuid |
| Clinician | getClinician(clinicianGuid) | GET | clinicianGuid |
| Pharmacy | listPharmacies(options?) | GET | — |
| Episode | createEpisode(data) | POST | — |
| Episode | getEpisode(episodeGuid) | GET | episodeGuid |
| Episode | updateEpisode(episodeGuid, data) | PUT | episodeGuid |
| Episode | patchEpisode(episodeGuid, data) | PATCH | episodeGuid |
| Episode | getEpisodeSignedDocuments(episodeGuid, options?) | GET | episodeGuid |
| Episode | createEpisodeLabRequisition(episodeGuid, data) ⚠️ async | POST | episodeGuid |
| Episode | getEpisodeLabRequisition(episodeGuid, labRequisitionGuid) | GET | episodeGuid, labRequisitionGuid |
| Consult | listConsults(options?) | GET | — |
| Consult | createConsult(data) | POST | programGuid, consultType, usState |
| Consult | getConsult(consultGuid) | GET | consultGuid |
| Consult | getConsultAvailability(consultGuid) ⚠️ schedulable only | GET | consultGuid |
| Consult | scheduleConsultAppointment(consultGuid, data) ⚠️ exact slot | POST | consultGuid, clinicianGuid, startsAt |
| Consult | getConsultPatientUI(consultGuid, data) | POST | consultGuid |
| Consult | sendConsultMessage(consultGuid, data) ⚠️ blocked | POST | consultGuid, text |
| Consult | updateConsultStatus(consultGuid, data) ⚠️ 502 | POST | consultGuid, status |
| Consult | createConsultIssue(consultGuid, data) | POST | consultGuid, level |
| Intake | listIntakes(options?) | GET | — |
| Intake | createIntake(data) | POST | EpisodeGuid |
| Intake | getIntake(intakeGuid) | GET | intakeGuid |
| Intake | updateIntake(intakeGuid, data) | PUT | intakeGuid, LabRequisitionGuid |
| Intake | addAllergyIntolerance(intakeGuid, data[]) | POST | intakeGuid |
| Identity | claimIdentityVerification(data) | POST | EpisodeGuid, ClaimType |
| Lab Order | listLabOrders(options?) | GET | — |
| Lab Order | createLabOrder(data) | POST | EpisodeGuid, Laboratory |
| Lab Order | getLabOrder(labOrderGuid) | GET | labOrderGuid |
| Lab Order | getLabOrderPdf(labOrderGuid) ⚠️ 404 until ready | GET | labOrderGuid |
| Lab Order | listLabOrderResults(labOrderGuid, options?) | GET | labOrderGuid |
| Lab Order | createLabOrderResult(labOrderGuid, data) | POST | labOrderGuid |
| Lab Order | getLabOrderResult(labOrderGuid, labResultGuid) | GET | labOrderGuid, labResultGuid |
| Lab Order | getLabResultPdf(labOrderGuid, labResultGuid) | GET raw binary | labOrderGuid, labResultGuid |
| Message | listMessages(options?) | GET | — |
| Message | createMessage(data) | POST | EpisodeGuid, Text |
| Message | getMessage(messageGuid) | GET | messageGuid |
⚠️ = see Known Vendor Limitations before using.
