Download .md

    CareAtlas Integration Guide

    Overview

    This guide describes how to implement order submission using only the HaaS APIs, with no dependency on the provider-portal UI. It is intended for developers building headless or custom integrations (e.g. external provider portals, scripts, or server-to-server flows) that need to create orders in the same way as this app.

    API contract: HTTP paths below match [public/specs/CareAtlas-Unified-API-oas3-v0.1.json](../public/specs/CareAtlas-Unified-API-oas3-v0.1.json) (CareAtlas Unified API). Combine them with the API base URL (e.g. staging https://qa.api.thecareatlas.com). Hub webhook routes are documented in §8 Webhooks (Hub API). To re-check that guide paths still exist in that spec, run python3 scripts/verify-careatlas-guide-paths.py from the repo root.

    Goal: From a provider/tenant context, get to a successfully submitted order (prescription-based flow.

    1. 1. Getting started

    1.1 High-level flow (registration → screening → consult → prescription → order)

    The app’s provider-portal flow is:

    1. Tenant & auth – Resolve tenant ID and partner app ID (Fetch Tenant ID and Partner App ID); ensure all requests use the same tenant and Bearer token.
    2. Patient – Ensure the patient exists and has account.id (for customer.accountId) and a valid address (required for order import).
    3. Clinic – Ensure the clinic exists (or create/link) and you have clinic details (name, address, email, phone) required for OrderImportRequest.clinic (ClinicInfo).
    4. Practitioner – Ensure the practitioner exists and you have practitionerId for consults, prescriptions, and order context as needed. Note: Practitioner registration requires a valid NPI verifiable from NPPES NPI Registry.
    5. Product / variant – Resolve productVariantId from the catalog if not already on the prescription. Product Variant is the actual medication that will be ordered.
    6. Screening – Complete the questionnaire session and obtain screeningSessionId (§4 Patient Screening).
    7. Consult (when your tenant requires it) – Create and drive a consult tied to that screening session, patient, practitioner, and product (§5 Consult). Skip if you prescribe directly after screening.
    8. Prescription – Create (or find) a prescription with productId and productVariantId via POST /clinical/v1/prescriptions/create, or use GET /clinical/v1/prescriptions/search for an existing record (§6 Step 2).
    9. Order import – Build OrderImportRequest and call POST /commerce/v1/orders/import (§7 Creating Orders).

    For outbound webhooks (register your HTTPS URL, signing secret, test and retry deliveries), see §8 Webhooks (Hub API). For a compact endpoint index across services, see §9 API Reference.

    2. 2. Access & Authentication

    • API base URLStaging: https://qa.api.thecareatlas.com Production: https://api.thecareatlas.com
    • Authentication – Once you receive your App Client credentials from the CareAtlas team, you can request auth token from AWS Cognito: https://qa.app-auth.thecareatlas.com using the credentials. You need a valid Bearer access token with the following scopes per API:
      • Identity (/identity/v1/* on the API base URL) – api://haas.identity/haas.api.read, api://haas.identity/haas.api.write
      • Catalog (/catalog/v1/*) – api://haas.catalog/haas.api.read, api://haas.catalog/haas.api.write
      • Clinical (/clinical/v1/*) – api://haas.clinical/haas.api.read,api://haas.clinical/haas.api.write
      • Commerce (/commerce/v1/*) – api://haas.commerce/haas.api.read,api://haas.commerce/haas.api.write
      • Screening (/screening/v1/*) – api://haas.screening/haas.api.read, api://haas.screening/haas.api.write (as required by each operation in the spec)
      • Consult (/consult/v1/*) – api://haas.consult/haas.api.read, api://haas.consult/haas.api.write (as required by each operation in the spec; see §5 Consult)
      • Hub (/hub/v1/*) – api://haas.hub/haas.api.read, api://haas.hub/haas.api.write for webhook subscriptions, deliveries, and related operations (see §8).
    • Tenant contextX-Tenant-Id header is required on Hub subscription and delivery calls (and most other tenant-scoped routes). You obtain it from GET /identity/v1/tenants/me (see Fetch Tenant ID and Partner App ID). GET /hub/v1/webhooks/event-types/search has no tenant header in the bundled OpenAPI—confirm with your deployment if the gateway differs.

    Fetch Tenant ID and Partner App ID

    Endpoint: GET /identity/v1/tenants/me (getMyTenants)
    Headers: Authorization: Bearer <access_token>

    Response type: MyTenantsResponsepartnerApp may be null when the caller has no linked partner application.

    What to use:

    NeedField
    X-Tenant-Id on tenant-scoped routespartnerApp.tenants[].tenantId for the clinic/tenant your user or app is bound to (often the first row, or match by name/role in multi-tenant apps).
    source.partnerAppId on order importpartnerApp.id
    Partner identitypartnerApp.partner (MyTenantsPartnerResponse) — id, name, role
    Linked pharmacy tenantspartnerApp.tenantProviders — same shape as tenants (MyTenantsTenantResponse); use role (e.g. Pharmacy) and tenantId when resolving pharmacyId for prescriptions or order display.

    Sample response:

    { "partnerApp": { "id": "01933a7e-5f2a-7000-8000-000000000001", "appId": "provider-portal", "name": "Provider Portal", "partner": { "id": "01933a7e-5f2a-7000-8000-000000000002", "name": "Acme Health", "role": "partner" }, "tenants": [ { "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "name": "Acme Clinic", "role": "provider", "attributes": [] } ], "tenantProviders": [ { "tenantId": "0193ace2-7048-7692-9f57-91e59b94b40a", "name": "Example Pharmacy", "role": "Pharmacy", "attributes": [] } ], "attributes": [] } }

    3. 3. Patient Registration

    Prerequisites — registration

    Complete §2 Access & Authentication — Bearer token, Identity read/write scopes, and X-Tenant-Id from Fetch Tenant ID and Partner App ID.

    Register or resolve the patient in Identity so you have a patientId (UUID) for screening (POST /screening/v1/sessions/create), prescriptions, and orders.

    Endpoint: POST /identity/v1/patients/resolve-by-email
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    The API resolves an existing patient by email in the tenant or creates one when none exists. Use patient.id from the response as patientId in later steps.

    Request body: PatientResolveRequest

    FieldTypeNotes
    emailstringPatient email (lookup key).
    firstName, lastNamestringLegal name.
    dateOfBirthstring (date)ISO date, e.g. 1990-05-15.
    genderstring"Male" or "Female" — plain text.
    height, weightobjectHeight and weight payload per API contract (shape may be numeric or structured).
    isOnGlpbooleanWhether the patient is on GLP therapy.
    stateCodestringUS state or region code.
    addressAddressFull AddressaddressLine1, city, state, zipCode, phone; optional label (e.g. Shipping Address).
    partnerPatientKeystringStable external key (often same as email).
    phoneNumberstringContact phone.
    stageIdstring (uuid)Funnel/stage id when your tenant requires it.
    referrerIdstringReferrer id when your tenant requires it.
    externalIdstringExternal/reference identifier from your system (often a generated UUID).

    The sample below sets gender to "Female" (use "Male" for male patients).

    Sample request (POST /identity/v1/patients/resolve-by-email):

    { "email": "jane.doe@example.com", "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "1990-05-15", "gender": "Female", "height": {}, "weight": {}, "isOnGlp": false, "stateCode": "CA", "address": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567", "label": "Shipping Address" }, "partnerPatientKey": "jane.doe@example.com", "phoneNumber": "5551234567", "stageId": "01933a7e-5f2a-7000-8000-000000000020", "referrerId": "01933a7e-5f2a-7000-8000-000000000021", "externalId": "01933a7e-5f2a-7000-8000-000000000022" }

    Response: PatientResolveResponse — the nested patient object is a PatientResponse.

    FieldTypeNotes
    foundbooleantrue if a patient already existed for this email.
    createdbooleantrue if a new patient was created.
    patientPatientResponseFull patient record; use patient.id as patientId.

    Sample response:

    { "found": false, "created": true, "patient": { "id": "01933a7e-7b2c-7456-8000-000000000010", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "accountId": "01933a7e-8c3d-7567-8000-000000000011", "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "1990-05-15", "height": {}, "weight": {}, "isOnGlp": false, "phone": "5551234567", "gender": "Female", "state": "CA", "stateName": "California", "smsVerified": false, "email": "jane.doe@example.com", "emailVerified": true, "phoneNumber": "5551234567", "phoneNumberVerified": false, "etag": "W/\"abc123\"", "address": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" } } }

    Lookup by id or email (GET /identity/v1/patients/search)

    When you need to find or verify a patient by id, email, or accountId (instead of or after resolve-by-email) above, use search.

    Endpoint: GET /identity/v1/patients/search
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Query parameters: Pass the patient’s id (and/or email, accountId, etc. per spec) to retrieve a paged list. When filtering by unique id, use the matching row from data.

    Response: PagedResponseOfPatientResponse — each element in data is a PatientResponse.

    For order import you need:

    • patient.idcustomer.patientId
    • patient.account.idcustomer.accountId (required; resolve from profile/session if not on patient in your flow)
    • patient.address → must be a full Address object with at least:
      • addressLine1, addressLine2, city, state, zipCode, phone

    If the patient has no address or no account.id, create or update the patient via the appropriate Identity APIs before calling order import.

    Sample response (GET /identity/v1/patients/search?id=01933a7e-7b2c-7456-8000-000000000010&limit=1): Example shape for data[0]:

    { "data": [ { "id": "01933a7e-7b2c-7456-8000-000000000010", "account": { "id": "01933a7e-8c3d-7567-8000-000000000011", "username": "jane.doe@example.com", "displayName": "Jane Doe", "etag": "W/\"acct-etag\"" }, "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "1990-05-15", "height": 65, "weight": 140, "isOnGlp": false, "gender": "Female", "state": "CA", "stateName": "California", "smsVerified": false, "email": "jane.doe@example.com", "emailVerified": true, "phoneNumber": "5551234567", "phoneNumberVerified": false, "etag": "W/\"abc123\"", "address": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" } } ], "metadata": { "limit": {}, "nextCursor": "", "hasMore": false } }

    4. 4. Patient Screening

    Before prescribing, many flows require the patient to complete a screening questionnaire tied to a medication (catalog product + variant). A typical headless sequence matches the provider portal: choose the product/variant and questionnaire, then start a screening session. Subsequent calls (answer questions, consent, submit) use the session id returned here.

    Prerequisites — screening

    Complete these before Step 1: Select medication:


    Step 1: Select medication

    A screening session is bound to a catalog product (productId), a product variant (productVariantId), and a questionnaire (questionnaireId). Resolve the product first (to pick a variant), then load active questionnaires and pick questionnaireId for your care path (use the bundle endpoint when you need full question/option payloads for the UI).


    2.1 Search catalogs

    Source: GET /catalog/v1/catalogs/search (searchCatalogs). Lists catalogs available to the tenant (each catalog groups products). Use this when you need catalogId to scope Search products (§2.2) or to show a catalog picker in the UI.

    Endpoint: GET /catalog/v1/catalogs/search
    Headers: Authorization: Bearer <token>; X-Tenant-Id (required — current clinic/tenant UUID); optional If-None-Match

    Query parameters (all optional unless noted)

    NameDescription
    idFilter by catalog UUID.
    nameFilter by catalog name (matching behavior depends on deployment).
    includeCategoriesWhen supported, include category rows on each catalog (string flag per OpenAPI — confirm with your client).
    limit, nextPagination; next is the cursor from metadata on the previous page.
    sortBy, sortOrderSorting.

    (Query parameters are optional; omit If-None-Match on first call.)

    Sample response (200)PagedResponseOfCatalogSearchResponse:

    { "data": [ { "id": "01933a7e-7b2c-7456-8000-000000000040", "name": "Provider catalog", "etag": "W/\"c1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system", "categories": [ { "id": "01933a7e-8c3d-8567-8000-000000000041", "name": "Weight management", "etag": "W/\"cat1\"" } ] } ], "metadata": { "limit": {}, "nextCursor": "", "hasMore": false } }

    Use data[].id as catalogId when calling GET /catalog/v1/products/search. If includeCategories is omitted or unsupported, categories may be an empty array.

    Errors: 401, 403, 404 (per spec). 304 when If-None-Match matches.

    Note: Skip this step if catalogId is already known (config, or from product.catalog.id on a product returned by search).


    2.2 Get product and variant

    Source: GET /catalog/v1/products/search (searchProducts) and optionally GET /catalog/v1/products/{id}/find (findProductById). Prefer search—many deployments only expose /products/search; /find can be absent on the gateway even when it appears in the spec. Catalog calls require X-Tenant-Id on the request headers.

    Search products (recommended)

    Endpoint: GET /catalog/v1/products/search
    Headers: Authorization: Bearer <token> (catalog may use a separate client or token); X-Tenant-Id (tenant UUID); optional If-None-Match

    Query parameters (all optional; combine per your catalog)

    NameDescription
    variantIdFilter by product variant UUID (useful when you already know the variant).
    sku, variantSkus, name, brandProduct / variant text filters.
    catalogId, categoryId, pharmacyScope to catalog or category.
    limit, next, sortBy, sortOrderPagination, sorting.

    Request: No body.

    Response: 200PagedResponseOfProductResponse. Use data[].id as productId. Choose productVariantId from data[].variants[] (match the variant you need).

    Sample request

    GET /catalog/v1/products/search?variantId=01933a7e-7b2c-7456-8000-000000000031&limit=5&catalogId=01933a7e-7b2c-7456-8000-000000000040 HTTP/1.1 Authorization: Bearer <access_token> X-Tenant-Id: 01933a7e-6a1b-7123-8000-000000000003

    (The catalogId query parameter is optional; use it to scope to a catalog from §2.1.)

    Sample response (200) — full page body (example GET /catalog/v1/products/search?variantId=01933a7e-7b2c-7456-8000-000000000031&limit=5):

    { "data": [ { "id": "01933a7e-7b2c-7456-8000-000000000030", "sku": "COMP-GLP-001", "name": "Sample GLP-1 medication", "description": "Example catalog product", "brand": "CareAtlas", "isBundle": false, "effectiveStartUtc": "2024-01-01T00:00:00Z", "effectiveEndUtc": "2099-12-31T23:59:59Z", "catalog": { "id": "01933a7e-7b2c-7456-8000-000000000040", "name": "Provider catalog", "etag": "W/\"c1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system" }, "attributes": [], "variants": [ { "id": "01933a7e-7b2c-7456-8000-000000000031", "variantSku": "V0-30mg", "name": "30 day supply", "uomId": "01933a7e-7b2c-7456-8000-000000000050", "attributes": [], "etag": "W/\"v1\"" } ], "categories": [], "etag": "W/\"p1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system" } ], "metadata": { "limit": {}, "nextCursor": "", "hasMore": false } }
    Get product by id (optional)

    Endpoint: GET /catalog/v1/products/{id}/find — **operationId:** findProductById` in the same OpenAPI file (path key /catalog/v1/products/{id}/find). Headers: Authorization; X-Tenant-Id (required). Returns a single ProductResponse (same inner shape as data[] from search). If this route is not routed by your API gateway, use Search products with variantId or name / sku instead.

    Request: No body.

    Sample request

    GET /catalog/v1/products/{id}/find HTTP/1.1 Authorization: Bearer <access_token> X-Tenant-Id: 01933a7e-6a1b-7123-8000-000000000003

    Sample response (200) — one ProductResponse (not wrapped in data); same fields as a single element of data[] in Search products:

    { "id": "01933a7e-7b2c-7456-8000-000000000030", "sku": "COMP-GLP-001", "name": "Sample GLP-1 medication", "description": "Example catalog product", "brand": "CareAtlas", "isBundle": false, "effectiveStartUtc": "2024-01-01T00:00:00Z", "effectiveEndUtc": "2099-12-31T23:59:59Z", "catalog": { "id": "01933a7e-7b2c-7456-8000-000000000040", "name": "Provider catalog", "etag": "W/\"c1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system" }, "attributes": [], "variants": [ { "id": "01933a7e-7b2c-7456-8000-000000000031", "variantSku": "V0-30mg", "name": "30 day supply", "uomId": "01933a7e-7b2c-7456-8000-000000000050", "attributes": [], "etag": "W/\"v1\"" } ], "categories": [], "etag": "W/\"p1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system" }

    2.3 Fetch Available Questionnaires

    The unified API exposes GET /screening/v1/questionnaires/active (not a separate paged /questionnaires list). Use it to discover questionnaireId. For rendering or validating the flow, load the full bundle with GET /screening/v1/questionnaires/{id}/bundle.

    List active questionnaires

    Endpoint: GET /screening/v1/questionnaires/active
    Headers: Authorization: Bearer <token>; optional If-None-Match

    Query parameters

    NameDescription
    nameFilter by questionnaire name / slug.
    versionQuestionnaire version string.

    Request: No body.

    Response: 200 — JSON array of QuestionnaireResponse. Use [].id as questionnaireId for POST /screening/v1/sessions/create.

    Sample response (GET /screening/v1/questionnaires/active?name=branded):

    [ { "id": "01933a7e-7b2c-7456-8000-000000000060", "name": "branded-medication-screening", "version": "1", "description": "Screening questionnaire for branded medication path", "statusId": "01933a7e-7b2c-7456-8000-000000000061", "treatmentId": "01933a7e-7b2c-7456-8000-000000000062", "effectiveFromUtc": "2024-01-01T00:00:00Z", "effectiveToUtc": "2099-12-31T23:59:59Z", "questions": [], "etag": "W/\"q1\"", "createdAtUtc": "2024-01-01T00:00:00Z", "createdBy": "system", "updatedAtUtc": "2024-01-01T00:00:00Z", "updatedBy": "system" } ]
    Get questionnaire bundle (optional)

    Endpoint: GET /screening/v1/questionnaires/{id}/bundle
    Headers: Authorization: Bearer <token>; optional If-None-Match

    Path parameters

    NameDescription
    idquestionnaireId from the active list.

    Query parameters

    NameDescription
    expandOptional; use per your client (e.g. related entities) when supported.

    Response: 200QuestionnaireBundleResponse (questions, answer options, and related fields per spec—use this to drive the screening UI after you create a session).

    Note: Carry forward productId, productVariantId (from 2.2), and questionnaireId (from 2.3) into Step 3.


    Step 2: Create screening session

    Endpoint: POST /screening/v1/sessions/create (operationId: createSession)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    Body: CreateSessionRequest — all fields are required per the OpenAPI schema:

    FieldDescription
    channelChannel identifier (e.g. web) per your integration contract.
    patientIdFrom §3 Patient Registration; optional lookup via Lookup by id or email.
    questionnaireIdFrom Step 2 above.
    productIdCatalog product UUID.
    productVariantIdCatalog product variant UUID.

    Response: 201 with SessionCreateResponse, including id (session id). Use that value as {id} in Step 3 to post answers and complete the session.

    Notes:

    • 409 may indicate an existing session for the same patient/questionnaire — follow your product rules (resume vs. new session).
    • Confirm with CareAtlas that your client’s Bearer token includes Screening / CRUD write scopes for /screening/v1/* routes (gateway requirements may differ from Identity or Clinical alone).

    Step 3: Submit questionnaire answers and complete the session

    After POST /screening/v1/sessions/create returns a session id, drive the questionnaire with the Screening API: optionally fetch batches of questions, send answers, record consent when your flow requires it, then submit the session so downstream steps (e.g. prescriptions tied to screeningSessionId when your deployment supports that) can proceed.

    Headers (all calls below): Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, and Content-Type: application/json on POST bodies.

    3.1 Get the next question batch (optional)

    Endpoint: GET /screening/v1/sessions/{id}/next
    Path: {id} = session id from Step 3.

    Query parameters: optional limit (string per client), optional If-None-Match.

    Response: 200QuestionnaireNextResponse:

    FieldNotes
    sessionIdSame session id.
    questionsArray of questions for this batch (shape per QuestionnaireNextQuestionResponse).
    totalRemainingServer hint for remaining work (shape per deployment).
    isLastBatchWhen true, no further /next batches are expected for this pass.

    Use this in paged UIs: call /next, render questions, collect answers, then POST /answer (§4.2). Repeat until isLastBatch is true or you have collected every answer your bundle requires.

    Alternative: If you already loaded GET /screening/v1/questionnaires/{id}/bundle (§2.3), you can build the full form without calling /next, then send one or more /answer requests with every linkId the bundle defines.

    3.2 Post answers

    Endpoint: POST /screening/v1/sessions/{id}/answer
    Body: AnswerBundleRequest{ "answers": [ ... ] }

    Each AnswerItem typically includes:

    FieldDescription
    linkIdQuestion link id from the questionnaire bundle or /next payload (stable key for the question).
    answerValue: string, number, boolean, or structured object per question type (single choice, multi-select, text, etc.).
    evidenceRefOptional. For file-upload questions, reference returned after uploading the file to your storage flow (per tenant/API contract).

    Sample request (POST /screening/v1/sessions/{id}/answer):

    { "answers": [ { "linkId": "q-height", "answer": 70 }, { "linkId": "q-current-meds", "answer": "None" }, { "linkId": "q-conditions", "answer": ["condition-a", "condition-b"] } ] }

    Response: 200AnswerBundleResponse (per spec). You may call /answer multiple times (e.g. per batch) before submitting.

    Some tenants require consent before final submit. If your bundle or product rules say consent is needed:

    Endpoint: POST /screening/v1/sessions/{id}/consent
    Body: CreateConsentRequest — e.g. scope, termsVersion, grantedAt / expiresAt (ISO date-times) per OpenAPI.

    Skip this step if your integration does not use session-level consent.

    3.4 Submit the session

    When all required answers are saved, complete the session:

    Endpoint: POST /screening/v1/sessions/{id}/submit
    Body: SessionSubmitRequest

    FieldDescription
    validateOnlyfalse to finalize; true to validate without completing (if supported).

    Sample request:

    { "validateOnly": false }

    Response: 200SubmitSessionResponse — may include status, completedAt, and recommendedProductVariants (used by clinical flows to suggest variants). Use the same sessionId as screeningSessionId on POST /consult/v1/consults/create (§5 Step 2) when your flow includes a consult. For prescribing, pass the consult id as consultId on POST /clinical/v1/prescriptions/create (§6 Step 2).

    Operational notes

    • Order of operations (typical): create session → (/next + /answer)* → optional /consent/submit. Exact branching depends on questionnaire configuration.
    • Idempotency: Re-posting overlapping answers may be rejected or merged per backend rules; prefer one bundle per batch or a single final bundle before submit.
    • Errors: 400 validation (missing required answers), 404 unknown session id — confirm session id and tenant.

    5. 5. Consult

    Many tenant programs run a consult (provider visit or chat thread) after screening and before prescribing. Consult records tie together patient, practitioner, screening session, and catalog product / variant via POST /consult/v1/consults/create (CreateConsultRequest). Skip this section if your flow prescribes directly from screening without a separate consult step.

    Prerequisites — consult

    Step 1: List consults (optional)

    Endpoint: GET /consult/v1/consults/search (operationId: searchConsults)
    Headers: Authorization: Bearer <token>, X-Tenant-Id (required)

    Query (typical): patientId, practitionerId, status, screeningSessionId, selectedProductId, selectedProductVariantId, limit, next, sortBy, sortOrder

    Response: 200PagedResponseOfGetConsultSummaryResponse — use to find or resume consults for a patient or session context.

    Sample response (200) — shape of data[0] when listing:

    { "data": [ { "id": "01933a7e-a001-7c01-8000-000000000040", "status": "active", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "patientId": "01933a7e-7b2c-7456-8000-000000000010", "practitionerId": "01933a7e-ae5f-7789-8000-000000000021", "screeningSessionId": "01933a7e-d182-7a23-8000-000000000030", "selectedProductId": "01933a7e-bf60-7801-8000-000000000022", "selectedProductVariantId": "01933a7e-c071-7912-8000-000000000023", "channel": "web", "startedUtc": "2025-03-04T15:00:00Z" } ], "metadata": { "limit": "10", "nextCursor": "", "hasMore": false } }

    (Metadata keys may match PageMetadata in your client; confirm against the spec.)

    Step 2: Create a consult

    Endpoint: POST /consult/v1/consults/create (createConsult)
    Headers: Authorization: Bearer <token>, X-Tenant-Id, Content-Type: application/json

    Body: CreateConsultRequest — required per OpenAPI: patientId, practitionerId, topic, channel, screeningSessionId, selectedProductId, selectedProductVariantId.

    Sample request (POST /consult/v1/consults/create):

    { "patientId": "01933a7e-7b2c-7456-8000-000000000010", "practitionerId": "01933a7e-ae5f-7789-8000-000000000021", "topic": "weight-loss-intake", "channel": "web", "screeningSessionId": "01933a7e-d182-7a23-8000-000000000030", "selectedProductId": "01933a7e-bf60-7801-8000-000000000022", "selectedProductVariantId": "01933a7e-c071-7912-8000-000000000023" }

    Response: 200CreateConsultResponse — includes id (consult uuid). Use this id on GET/messages routes below.

    Sample response (200):

    { "id": "01933a7e-a001-7c01-8000-000000000040", "providerTenantId": "01933a7e-6a1b-7123-8000-000000000003", "createdAtUtc": "2025-03-04T15:05:00Z", "updatedAtUtc": "2025-03-04T15:05:00Z" }

    Step 3: Get consult detail

    Endpoint: GET /consult/v1/consults/{id}/get (getConsult)
    Headers: Authorization: Bearer <token>, X-Tenant-Id; optional If-None-Match

    Response: 200GetConsultResponsestatus, screeningSessionId, patientId, practitionerId, selected product ids, conversationRef, participants, chats, lifecycle timestamps, etag.

    Sample response (200)GetConsultResponse for path {id} (same consult id as create response):

    { "id": "01933a7e-a001-7c01-8000-000000000040", "status": "active", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "patientId": "01933a7e-7b2c-7456-8000-000000000010", "practitionerId": "01933a7e-ae5f-7789-8000-000000000021", "screeningSessionId": "01933a7e-d182-7a23-8000-000000000030", "selectedProductId": "01933a7e-bf60-7801-8000-000000000022", "selectedProductVariantId": "01933a7e-c071-7912-8000-000000000023", "channel": "web", "startedUtc": "2025-03-04T15:05:00Z", "conversationRef": "", "participants": [], "chats": [], "etag": "W/\"consult-etag\"" }

    Step 4: Messages and integrations

    OperationMethodPathNotes
    Search messagesGET/consult/v1/consults/{id}/messages/searchsearchConsultMessages. Paged ConsultMessageResponse. X-Tenant-Id required.
    Add participantPOST/consult/v1/consults/{id}/participants/addaddConsultParticipant. Body AddParticipantRequest (practitionerId, displayName). 201AddParticipantResponse. Registers a practitioner on the consult chat; patientId on the row is taken from the consult.
    Post messagePOST/consult/v1/consults/{id}/messages/postpostConsultMessage. Body PostMessageRequest (content, optional participantId, isMedia). participantId is the consult participant row id from ConsultParticipantDto, not the identity patient/practitioner uuid.
    Update message deliveryPOST/consult/v1/consults/{id}/messages/{messageId}/update-deliveryupdateConsultMessageDelivery. Body UpdateMessageDeliveryRequest (deliveredUtc, readUtc). 200UpdateMessageDeliveryResponse.
    Post CS messagePOST/consult/v1/consults/{id}/cs-messagespostCsMessage. Body PostCsMessageRequest. Consult write scope.

    Beluga inbound webhooks (POST /consult/v1/consult/message, /consult/v1/consult/cs-message, /consult/v1/consult/close, /consult/v1/consult/cancel) are not in the unified partner OpenAPI; they are server-to-server integration routes on the consult service.

    Step 5: Close or cancel consult (provider / tenant API)

    OperationMethodPathNotes
    ClosePOST/consult/v1/consults/{id}/closecloseConsult. Path id = consult UUID; X-Tenant-Id required. No body. 200CloseConsultResponse.
    CancelPOST/consult/v1/consults/{id}/cancelcancelConsult. Path id = consult UUID; X-Tenant-Id required. No body. 200CancelConsultResponse.

    Close marks the consult ended (e.g. provider portal after prescription create). Cancel records cancellation with canceledAtUtc and canceledBy.

    When your workflow is ready to prescribe, continue to §6 Creating Prescriptions.

    6. 6. Creating Prescriptions

    Prerequisites — prescriptions

    Build on §4 Prerequisites — screening (patient, screening session workflow, Screening scopes). If your program runs a provider consult after screening, complete §5 Prerequisites — consult first. For Identity patient fields used on orders, follow §3 Patient Registration and Lookup by id or email (GET /identity/v1/patients/search) when needed.

    This section adds clinic and practitioner prerequisites not covered above:

    Ensure Clinic exists

    Order import requires clinic (ClinicInfo) on every OrderImportRequest—clinic name, full address, email, and phone. Use the clinic APIs to find an existing clinic or create/link one, then map the result to ClinicInfo for the order.

    Search clinics

    Endpoint: GET /identity/v1/tenants/clinics/search
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Query parameters: name, id, npi, externalId, limit, after (optional). Use these to find a clinic by name, tenant id, NPI, or external id.

    Response: Paged list of tenants (clinics). Each item is a TenantResponse-like object with id, name, partnerId, parentTenantId, role, and attributes. Use the tenant(s) to build or resolve ClinicInfo for the order (name, address, email, phone—from tenant attributes or your own data).

    Sample response (GET /identity/v1/tenants/clinics/search): Returns a paged list; each element in data has id, name, partnerId, parentTenantId, role, etag, and related fields. Map to ClinicInfo using the tenant’s name and attribute/address data as required by your backend.

    Onboard clinic

    Endpoint: POST /identity/v1/tenants/clinics/onboard
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    Body: OnboardClinicRequestpartnerId, parentTenantId, name, and attributes (e.g. name, npi, addressId, email, phone, description). See Object reference for schema details.

    Response: 201 with TenantResponse. Use the returned tenant (and any address resolved from attributes.addressId) to build ClinicInfo for order import.

    Sample request (POST /identity/v1/tenants/clinics/onboard):

    { "partnerId": "01933a7e-5f2a-7000-8000-000000000002", "parentTenantId": "01933a7e-6a1b-7123-8000-000000000003", "name": "Acme Clinic", "attributes": { "name": "Acme Clinic", "npi": "1234567890", "addressId": "01933a7e-ad00-7000-8000-000000000010", "email": "contact@acmeclinic.example.com", "phone": "5559876543", "description": "" } }

    Sample response (POST /identity/v1/tenants/clinics/onboard): Returns the created/linked tenant with id, name, partnerId, parentTenantId, role, etag, and timestamps. Use this tenant and your address data to populate OrderImportRequest.clinic (ClinicInfo).

    What you need for OrderImportRequest:

    • clinicClinicInfo: clinicName, clinicAddressLine1, clinicAddressLine2, clinicCity, clinicState, clinicZip, clinicEmail, clinicPhoneNumber. Populate from the clinic/tenant returned by search or onboard, and from the resolved address when using attributes.addressId.

    Ensure Practitioner exists

    You need practitioner.id as practitionerId in CreatePrescriptionCommandRequest when creating prescriptions (Step 2); it is optional in the OpenAPI schema but typically required for your workflow.

    Fetching existing practitioner

    If you already have a practitioner ID (e.g. from your system or a previous onboard response), call GET /identity/v1/practitioners/search with query id=<practitionerId> (and/or npi, email, etc. per spec).

    Headers: Authorization: Bearer <token>; optional If-None-Match

    Response: PagedResponseOfPractitionerResponse — use the matching PractitionerResponse from data (see PractitionerResponse).

    Sample response (GET /identity/v1/practitioners/search?id=01933a7e-ae5f-7789-8000-000000000021&limit=1): Example shape for data[0]:

    { "data": [ { "id": "01933a7e-ae5f-7789-8000-000000000021", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "accountId": "01933a7e-aa5e-7788-8000-000000000020", "npi": "1234567890", "firstName": "Maria", "middleName": "", "lastName": "Smith", "suffix": "", "displayName": "Maria Smith", "providerTypeId": "provider-type-uuid", "statusId": "active", "inactivated": false, "email": "maria.smith@clinic.example.com", "emailVerified": true, "phoneNumber": "5559876543", "phoneNumberVerified": false, "address": { "addressLine1": "456 Clinic Way", "addressLine2": "", "city": "San Francisco", "state": "CA", "zipCode": "94103", "phone": "5559876543" }, "etag": "W/\"practitioner-etag\"" } ], "metadata": { "limit": {}, "nextCursor": "", "hasMore": false } }
    Creating new practitioner

    If the practitioner does not exist, use POST /identity/v1/practitioners/onboard with PractitionerOnboardRequest (see Object reference for schema). The API returns an existing practitioner when one matches (e.g. by NPI/tenant), or creates one. Use the returned practitioner.id as practitionerId in prescription and order flows.

    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    Body: PractitionerOnboardRequest — see Object reference for schema.

    Sample request (POST /identity/v1/practitioners/onboard):

    { "accountId": "01933a7e-aa5e-7788-8000-000000000020", "npi": "1234567890", "firstName": "Maria", "middleName": "", "lastName": "Smith", "suffix": "", "displayName": "Maria Smith", "providerTypeId": "01933a7e-pt00-7000-8000-000000000001", "statusId": "01933a7e-st00-7000-8000-000000000002", "address": { "addressLine1": "456 Clinic Way", "addressLine2": "", "city": "San Francisco", "state": "CA", "zipCode": "94103", "phone": "5559876543" }, "createIfMissing": true }

    Sample response (POST /identity/v1/practitioners/onboard):

    { "found": false, "created": true, "practitioner": { "id": "01933a7e-ae5f-7789-8000-000000000021", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "accountId": "01933a7e-aa5e-7788-8000-000000000020", "npi": "1234567890", "firstName": "Maria", "middleName": "", "lastName": "Smith", "suffix": "", "displayName": "Maria Smith", "providerTypeId": "01933a7e-pt00-7000-8000-000000000001", "statusId": "01933a7e-st00-7000-8000-000000000002", "inactivated": false, "email": "", "emailVerified": false, "phoneNumber": "5559876543", "phoneNumberVerified": false, "address": { "addressLine1": "456 Clinic Way", "addressLine2": "", "city": "San Francisco", "state": "CA", "zipCode": "94103", "phone": "5559876543" }, "etag": "W/\"practitioner-etag\"" } }

    Step 1: Resolve Product Variant (Medication)

    Endpoint: GET /catalog/v1/products/search (e.g. query variantId from the prescription, or name / sku) — see §4 Step 2.2. Optional: GET /catalog/v1/products/{id}/find when your gateway exposes it (same ProductResponse shape; send X-Tenant-Id).

    Headers: Authorization (catalog may use a different token in some environments); X-Tenant-Id; optional If-None-Match

    Response: ProductResponse (from data[] or from /find) — use the product’s variants to get productVariantId (from prescription or e.g. variants[0].id).

    The Import Order API also requires uomId (unit of measure) on each line. This app does not use UOM for any business logic; it only sends it because the API requires it. The app gets uomId from the variant when present, otherwise uses a fixed default. For headless implementations: send the variant’s uomId if available, or a known default UUID your backend accepts.

    Sample response (single ProductResponse — e.g. one data row from search, or body of /find when available):

    { "id": "01933a7e-bf60-7801-8000-000000000022", "name": "Example Medication", "etag": "W/\"product-etag\"", "variants": [ { "id": "01933a7e-c071-7912-8000-000000000023", "name": "10mg", "variantSku": "MED-10MG", "uomId": "e0b02579-ddbd-4d58-8ed1-8df498178e1d", "product": { "id": "01933a7e-bf60-7801-8000-000000000022", "name": "Example Medication" } } ] }

    (Schema may vary; the important fields for order import are variants[].id (productVariantId) and variants[].uomId.)


    Step 2: Get or create a prescription

    Clinical routes in CareAtlas-Unified-API-oas3-v0.1.json include GET /clinical/v1/prescriptions/search, POST /clinical/v1/prescriptions/create, GET /clinical/v1/prescriptions/{id}/validate, and PATCH /clinical/v1/prescriptions/{id}/update. For provider prescribing after a consult, use create with consultId from §5 Step 2 (and pharmacyId, medsPrescribed, practitioner fields per your workflow).

    Search existing prescriptions

    Endpoint: GET /clinical/v1/prescriptions/search with query id=<prescriptionId> (and/or patientId, patientEmail, etc. per spec).
    Headers: X-Tenant-Id, Authorization

    Response: PagedResponseOfPrescriptionResponse — use the matching PrescriptionResponse from data.

    Create prescriptions (provider flow)

    Endpoint: POST /clinical/v1/prescriptions/create (operationId: createPrescriptionCommand)
    Headers: X-Tenant-Id, Authorization, Content-Type: application/json

    Body: CreatePrescriptionCommandRequest; each element of medsPrescribed is a MedPrescribedInternal. See Object reference for fields.

    Response: 201 Created — JSON array of PrescriptionResponse (one entry per item in medsPrescribed).

    Sample request:

    { "consultId": "01933a7e-a001-7c01-8000-000000000040", "medsPrescribed": [ { "productId": "01933a7e-bf60-7801-8000-000000000022", "productVariantId": "01933a7e-c071-7912-8000-000000000023", "strength": "10mg", "frequency": "once daily", "route": "oral" } ], "pharmacyId": "0193ace2-7048-7692-9f57-91e59b94b40a", "pharmacyNote": "Bill to patient, ship to patient", "practitionerId": "01933a7e-ae5f-7789-8000-000000000021" }

    Sample response (201): Same shape as each element in the search data array below (array of PrescriptionResponse).

    Validate a prescription

    Endpoint: GET /clinical/v1/prescriptions/{id}/validate (operationId: validatePrescription)
    Headers: X-Tenant-Id, Authorization

    Response: 200ValidatePrescriptionResponse (see ValidatePrescriptionResponse): includes isValid (boolean).

    Update a prescription

    Endpoint: PATCH /clinical/v1/prescriptions/{id}/update (operationId: updatePrescriptionCommand)
    Headers: X-Tenant-Id, Authorization, Content-Type: application/json

    Body: UpdatePrescriptionCommandRequest — all properties optional in the bundled schema; use for notes, approval metadata, or payment fields per your process.

    Response: 200PrescriptionResponse.

    Sample response (GET /clinical/v1/prescriptions/search?id=01933a7e-9d4e-7678-8000-000000000020&limit=1): Example shape for data[0]:

    { "data": [ { "id": "01933a7e-9d4e-7678-8000-000000000020", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "patientId": "01933a7e-7b2c-7456-8000-000000000010", "practitionerId": "01933a7e-ae5f-7789-8000-000000000021", "productId": "01933a7e-bf60-7801-8000-000000000022", "productVariantId": "01933a7e-c071-7912-8000-000000000023", "medicationName": "Example Medication 10mg", "quantityAuthorized": { "value": 1 }, "approvedAtUtc": "2025-03-01T14:00:00Z", "pharmacyId": "0193ace2-7048-7692-9f57-91e59b94b40a" } ], "metadata": { "limit": {}, "nextCursor": "", "hasMore": false } }

    Step 3: Map prescription fields for order import

    From the prescription you need for the order:

    • idlines[].matchedPrescriptionId
    • patientIdcustomer.patientId
    • productIdlines[].productId
    • productVariantIdlines[].productVariantId (or resolve from product in Step 1)
    • quantityAuthorizedlines[].qty (e.g. quantityAuthorized.value or default 1)

    7. 7. Creating Orders

    Prerequisites — orders

    Build on §6 Prerequisites — prescriptions (clinic, practitioner, product variant, and prescription). Confirm §2 Access & Authentication grants Commerce scopes for POST /commerce/v1/orders/import (same Bearer token and X-Tenant-Id as earlier steps).

    Complete §6 Step 3 so you have the prescription and patient field mapping before assembling the payload. Full request shape and the import call are in Build OrderImportRequest and call Import Order below.

    Build OrderImportRequest and call Import Order

    Build the request body and call the import endpoint. Body schema: OrderImportRequest — see Object reference for full schema and nested types (CustomerInfo, ClinicInfo, LineInfo, Address, TotalsInfo, PaymentInfo, SourceInfo).

    Mapping from prescription to order: Use the data from earlier steps to fill the payload:

    • prescription.idlines[].matchedPrescriptionId
    • prescription.patientIdcustomer.patientId
    • prescription.productIdlines[].productId
    • prescription.productVariantIdlines[].productVariantId (or from §6 Step 1)
    • prescription.quantityAuthorizedlines[].qty (e.g. .value or default 1)
    • patient.account.idcustomer.accountId (§3 / lookup)
    • patient.addressshippingAddress and billingAddress (full Address objects)
    • clinic§6 Prerequisites — prescriptions (Ensure Clinic exists); source.partnerAppId from Fetch Tenant ID and Partner App ID

    Numeric fields like qty, unitPrice, lineTotal, and totals may be strings in the API; see the sample request below and OrderImportRequest.

    Endpoint: POST /commerce/v1/orders/import Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json. Optional: Idempotency-Key: <key> to avoid duplicate orders on retries.

    Sample request (POST /commerce/v1/orders/import):

    { "externalOrderId": "ORDER-1730123456789", "customer": { "patientId": "01933a7e-7b2c-7456-8000-000000000010", "accountId": "01933a7e-8c3d-7567-8000-000000000011" }, "clinic": { "clinicName": "Acme Clinic", "clinicAddressLine1": "456 Clinic Way", "clinicAddressLine2": "", "clinicCity": "San Francisco", "clinicState": "CA", "clinicZip": "94103", "clinicEmail": "clinic@acme.example.com", "clinicPhoneNumber": "5559876543" }, "currencyISO": "USD", "pricing": { "priceBookVersion": "1.0", "components": [] }, "lines": [ { "externalLineId": "LINE-1730123456789", "productId": "01933a7e-bf60-7801-8000-000000000022", "productVariantId": "01933a7e-c071-7912-8000-000000000023", "uomId": "e0b02579-ddbd-4d58-8ed1-8df498178e1d", "qty": "1", "unitPrice": "29.99", "lineTotal": "29.99", "priceComponents": [], "requiresPrescription": true, "matchedPrescriptionId": "01933a7e-9d4e-7678-8000-000000000020" } ], "promos": [], "totals": { "subtotal": "29.99", "taxTotal": "0", "shippingTotal": "0", "grandTotal": "29.99" }, "shippingAddress": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" }, "billingAddress": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" }, "payment": {}, "validatedAtUtc": "2025-03-04T12:00:00.000Z", "source": { "partnerAppId": "01933a7e-5f2a-7000-8000-000000000001", "channel": "web", "region": "US" }, "notes": "Order for prescription 01933a7e-9d4e-7678-8000-000000000020" }

    Sample response (201 Created):

    { "id": "01933a7e-e293-7b34-8000-000000000040", "orderNumber": "ORD-10042", "tenantId": "01933a7e-6a1b-7123-8000-000000000003", "patientId": "01933a7e-7b2c-7456-8000-000000000010", "status": "Submitted", "currencyISO": "USD", "lines": [ { "id": "01933a7e-f3a4-7c45-8000-000000000041", "productId": "01933a7e-bf60-7801-8000-000000000022", "productVariantId": "01933a7e-c071-7912-8000-000000000023", "sku": "MED-10MG", "uomId": "e0b02579-ddbd-4d58-8ed1-8df498178e1d", "qty": { "value": 1 }, "unitPrice": { "value": 29.99 }, "lineTotal": { "value": 29.99 }, "prescriptionId": "01933a7e-9d4e-7678-8000-000000000020" } ], "subtotal": "29.99", "taxTotal": "0", "shippingTotal": "0", "grandTotal": "29.99", "shippingAddress": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" }, "billingAddress": { "addressLine1": "123 Main St", "addressLine2": "Apt 4", "city": "San Francisco", "state": "CA", "zipCode": "94102", "phone": "5551234567" }, "etag": "W/\"order-etag\"" }

    8. 8. Working with Webhooks

    The Hub service manages outbound webhooks: CareAtlas POSTs event payloads to your HTTPS URL when something happens (per event type). You do not implement CRUD against arbitrary domain tables here—you configure subscriptions, verify delivery to your endpoint, and operate retries and secrets. All Hub webhook routes use the same API base URL as the rest of the unified API; paths published in CareAtlas-Unified-API-oas3-v0.1.json appear in the §9 API Reference table.

    The bundled spec includes subscription create, patch update, disable, plus search, get (…/get), deliveries, test, retry, and rotate-secret.

    OpenAPI: Examples include createSubscriptionCommand, updateSubscriptionCommand, disableSubscriptionCommand, listEventTypesQuery, listSubscriptionsQuery, getSubscriptionQuery, listSubscriptionsForEventType, testWebhook, getDeliveryQuery, retryDelivery, rotateSecret — verify names in the spec.

    Getting started

    Available event types (reference)

    Display name (left) is for readability; the name string (right) matches event-type identifiers. The authoritative list—including payloadSchema—comes from GET /hub/v1/webhooks/event-types/search (List event types).

    Display namename
    Consult Createdconsult.created
    Consult Updatedconsult.updated
    Invoice Createdinvoice.created
    Invoice Updatedinvoice.updated
    Order Createdorder.created
    Order Updatedorder.updated
    Patient Createdpatient.created
    Patient Updatedpatient.updated
    Payment Createdpayment.created
    Payment Updatedpayment.updated
    Practitioner Createdpractitioner.created
    Practitioner Updatedpractitioner.updated
    Prescription Createdprescription.created
    Prescription Updatedprescription.updated
    Screening Response Createdscreening.response.created
    Screening Response Updatedscreening.response.updated
    Screening Session Createdscreening.session.created
    Screening Session Updatedscreening.session.updated

    Your inbound endpoint

    Configure your server to accept HTTPS POST from CareAtlas, respond with 2xx quickly, and verify signatures using the signingSecret from Create subscription (201) or Rotate signing secret. Exact headers and body envelope follow your deployment’s webhook contract (payload shapes are described per EventTypeResponse.payloadSchema where provided).

    Authentication and headers

    • Bearer token must include Hub scopes: api://haas.hub/haas.api.read (event types and subscription reads) and api://haas.hub/haas.api.write (create, update, and disable subscription; test delivery; retry delivery; rotate secret).
    • X-Tenant-Id – Required on routes that declare it (e.g. POST /hub/v1/webhooks/subscriptions/create, GET /hub/v1/webhooks/subscriptions/search, GET /hub/v1/webhooks/subscriptions/{id}/deliveries). GET /hub/v1/webhooks/event-types/search has no tenant header in the bundled OpenAPI.

    List event types

    Endpoint: GET /hub/v1/webhooks/event-types/search (listEventTypesQuery)
    Headers: Authorization: Bearer <token> (Hub read scope).

    Response

    HTTP 200 — JSON array of EventTypeResponse. Fields per item: name, displayName, description, sourceService, payloadSchema. Use each `name` string in the `eventTypes` array when creating or updating a subscription.

    Subscriptions

    Create a subscription

    Endpoint: POST /hub/v1/webhooks/subscriptions/create (createSubscriptionCommand)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    Body: CreateSubscriptionRequest — required: url, eventTypes (array of event name strings from List event types), description, expiresAtUtc. Optional: notificationEmails (comma-separated or deployment-specific format for alert recipients).

    Response: 201 CreatedCreateSubscriptionResponse includes id, url, eventTypes, signingSecret, expiresAtUtc, notificationEmails, etag, isActive, partnerAppId, etc. Store signingSecret securely; it is used to verify inbound webhook requests (also returned only at rotate-secret thereafter).

    Search subscriptions

    Endpoint: GET /hub/v1/webhooks/subscriptions/search (listSubscriptionsQuery)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Query (typical): limit, next, sortBy, sortOrder (per OpenAPI).

    Get one subscription

    Endpoint: GET /hub/v1/webhooks/subscriptions/{id}/get (getSubscriptionQuery)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>; optional If-None-Match

    Search subscriptions for an event type

    Endpoint: GET /hub/v1/webhooks/event-types/{name}/subscriptions/search (listSubscriptionsForEventType)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Path {name} is the event type name (e.g. order.created).

    Update a subscription

    Endpoint: PATCH /hub/v1/webhooks/subscriptions/{id}/update (updateSubscriptionCommand)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>, Content-Type: application/json

    Body: JSON body per the OpenAPI PATCH operation (the bundled file may reference a placeholder schema name; your generated client maps it to the subscription update type). May include notificationEmails when updating alert recipients. 200 returns UpdateSubscriptionResponse (id, url, eventTypes, notificationEmails, expiresAtUtc, etag, etc.—no signingSecret). Responses may include 412 / 409 for concurrency or conflict—follow etag / conditional request rules in the spec for your client.

    Disable a subscription

    Endpoint: POST /hub/v1/webhooks/subscriptions/{id}/disable (disableSubscriptionCommand)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Response: 204 No Content — stops deliveries for that subscription (per API semantics; confirm behavior with your deployment).

    Test delivery

    Endpoint: POST /hub/v1/webhooks/subscriptions/{id}/test
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Triggers a test delivery to the subscription URL. Response: 202 Accepted. Use after creating (or otherwise obtaining) a subscription to confirm connectivity before production traffic.

    Rotate signing secret

    Endpoint: POST /hub/v1/webhooks/subscriptions/{id}/rotate-secret
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Returns a new secret (response shape per RotateSecretResponse in the OpenAPI spec). Update your verifier to accept both old and new secrets during rotation, then retire the old secret.

    Deliveries

    List deliveries for a subscription

    Endpoint: GET /hub/v1/webhooks/subscriptions/{id}/deliveries
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Query (typical): limit, next, status, from, to, sortBy, sortOrder (per OpenAPI).

    Response

    HTTP 200 — paged list of DeliveryResponse (per spec). Use for observability and debugging.

    Get one delivery

    Endpoint: GET /hub/v1/webhooks/deliveries/{id}/get (getDeliveryQuery)
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId> (per spec)

    Use this to inspect payload metadata, status, and errors for a single delivery attempt.

    Retry a failed delivery

    Endpoint: POST /hub/v1/webhooks/deliveries/{id}/retry
    Headers: Authorization: Bearer <token>, X-Tenant-Id: <tenantId>

    Response: 202 Accepted — Hub queues a retry. Combine with the deliveries list to recover from transient 5xx responses on your server.

    9. API Reference

    Subsections follow the service path prefix on the unified API base URL: /identity/v1, /catalog/v1, /screening/v1, /consult/v1, /clinical/v1, /commerce/v1, /hub/v1.

    1. Identity (/identity/v1)

    OperationMethodPathNotes
    Get tenant + partner appGET/identity/v1/tenants/meMyTenantsResponsepartnerApp.id, tenants[], tenantProviders[], partner (MyTenantsPartnerResponse).
    Search clinicsGET/identity/v1/tenants/clinics/searchQuery: name, id, npi, externalId, limit, after. Requires X-Tenant-Id.
    Search practitionersGET/identity/v1/practitioners/searchQuery: id, npi, email, limit, next, etc.
    Onboard clinicPOST/identity/v1/tenants/clinics/onboardBody: OnboardClinicRequest. Creates or links a clinic tenant.
    Search patientsGET/identity/v1/patients/searchQuery: id, email, accountId, limit, next, etc. Requires X-Tenant-Id.
    Resolve patient by emailPOST/identity/v1/patients/resolve-by-emailBody: PatientResolveRequest; returns existing or newly created patient.

    2. Catalog (/catalog/v1)

    OperationMethodPathNotes
    Search catalogsGET/catalog/v1/catalogs/searchQuery: id, name, includeCategories, limit, next, sortBy, sortOrder. Header X-Tenant-Id required. PagedResponseOfCatalogSearchResponse.
    Search productsGET/catalog/v1/products/searchQuery: variantId, sku, name, brand, catalogId, limit, next, etc. Header X-Tenant-Id required. Paged ProductResponse list.
    Get product by id (optional)GET/catalog/v1/products/{id}/findOpenAPI findProductById. Header X-Tenant-Id required. Some gateways omit this route—use Search products if 404. Single ProductResponse.

    3. Screening (/screening/v1)

    OperationMethodPathNotes
    List active questionnairesGET/screening/v1/questionnaires/activeQuery: name, version. Returns array of QuestionnaireResponse.
    Get questionnaire bundleGET/screening/v1/questionnaires/{id}/bundleQuery: expand. Returns QuestionnaireBundleResponse (questions, options, etc.).
    Create screening sessionPOST/screening/v1/sessions/createBody: CreateSessionRequest; headers: X-Tenant-Id. operationId: createSession.
    Next questionnaire batchGET/screening/v1/sessions/{id}/nextPath: session id. Optional query limit. Returns QuestionnaireNextResponse.
    Submit session answersPOST/screening/v1/sessions/{id}/answerBody: AnswerBundleRequest (answers: AnswerItem[]). Headers: X-Tenant-Id.
    Record session consentPOST/screening/v1/sessions/{id}/consentBody: CreateConsentRequest. When tenant flow requires consent before submit.
    Submit screening sessionPOST/screening/v1/sessions/{id}/submitBody: SessionSubmitRequest (validateOnly). Completes session; returns SubmitSessionResponse.
    Update screening sessionPOST/screening/v1/sessions/{id}/updateBody: UpdateSessionRequest (productVariantId, expiresAtUtc). updateSession. Change variant/expiry on in-progress session.
    Record session paymentPOST/screening/v1/sessions/{id}/record-paymentBody: RecordPaymentRequest (paymentIntentId, amountCents). recordPayment. Sets Authorized payment on session.
    Update payment statusPOST/screening/v1/sessions/{id}/update-payment-statusBody: UpdatePaymentStatusRequest (status: Captured, Failed, Refunded). updatePaymentStatus.
    Cancel screening sessionPOST/screening/v1/sessions/{id}/cancelBody: CancelSessionRequest (reason). 200 — SessionResponse. cancelSession.

    4. Consult (/consult/v1)

    OperationMethodPathNotes
    Search consultsGET/consult/v1/consults/searchQuery: patientId, practitionerId, screeningSessionId, status, selectedProductId, selectedProductVariantId, limit, next, etc. X-Tenant-Id required. searchConsults.
    Create consultPOST/consult/v1/consults/createBody: CreateConsultRequest. 200 — CreateConsultResponse. createConsult. Consult write scope.
    Get consultGET/consult/v1/consults/{id}/getGetConsultResponse. getConsult. Optional If-None-Match. X-Tenant-Id required.
    Search consult messagesGET/consult/v1/consults/{id}/messages/searchPaged ConsultMessageResponse. searchConsultMessages.
    Add consult participantPOST/consult/v1/consults/{id}/participants/addBody: AddParticipantRequest (practitionerId, displayName). 201AddParticipantResponse. addConsultParticipant. X-Tenant-Id required.
    Post consult messagePOST/consult/v1/consults/{id}/messages/postBody: PostMessageRequest (content, participantId, isMedia). postConsultMessage. participantId = consult participant row id. X-Tenant-Id required.
    Update consult message deliveryPOST/consult/v1/consults/{id}/messages/{messageId}/update-deliveryBody: UpdateMessageDeliveryRequest (deliveredUtc, readUtc). 200 — UpdateMessageDeliveryResponse. updateConsultMessageDelivery. X-Tenant-Id required.
    Post CS message (consult)POST/consult/v1/consults/{id}/cs-messagesBody: PostCsMessageRequest. postCsMessage. X-Tenant-Id required.
    Close consultPOST/consult/v1/consults/{id}/closePath consult id; no body. 200CloseConsultResponse. closeConsult. Tenant/provider command (not Beluga webhook).
    Cancel consultPOST/consult/v1/consults/{id}/cancelPath consult id; no body. 200CancelConsultResponse. cancelConsult. Tenant/provider command (not Beluga webhook).

    5. Clinical (/clinical/v1)

    OperationMethodPathNotes
    Search prescriptionsGET/clinical/v1/prescriptions/searchQuery: id, patientId, patientEmail, limit, next, etc. Requires X-Tenant-Id.
    Create prescriptionsPOST/clinical/v1/prescriptions/createBody: CreatePrescriptionRequest (consultId, medsPrescribed, pharmacyId, …). 201 — array of PrescriptionResponse. createPrescriptionCommand. Requires clinical write scope.
    Validate prescriptionGET/clinical/v1/prescriptions/{id}/validateReturns ValidatePrescriptionResponse (isValid). validatePrescription.
    Update prescriptionPATCH/clinical/v1/prescriptions/{id}/updateBody: UpdatePrescriptionCommandRequest. 200 — PrescriptionResponse. updatePrescriptionCommand.
    Cancel prescriptionPOST/clinical/v1/prescriptions/{id}/cancelBody: CancelPrescriptionRequest. 200 — PrescriptionResponse. cancelPrescription.

    6. Commerce (/commerce/v1)

    OperationMethodPathNotes
    Submit paymentPOST/commerce/v1/payments/submitBody: SubmitPaymentRequest (entityName, entityId, orderId, provider, intentId, status, amount, currencyISO). 200 — SubmitPaymentResponse. submitPayment.
    Import orderPOST/commerce/v1/orders/importBody: OrderImportRequest; headers: X-Tenant-Id, optional Idempotency-Key.
    Search ordersGET/commerce/v1/orders/searchQuery: patientId, orderNumber, limit, etc.
    Get order by idGET/commerce/v1/orders/{id}/getFull order details. getOrderQuery. Optional If-None-Match. X-Tenant-Id required.
    Link ordersPOST/commerce/v1/orders/linkBody: LinkOrdersRequest (masterOrderId, childOrderIds). 200 — LinkOrdersResponse. linkOrders.
    Update order shippingPOST/commerce/v1/orders/{id}/update-shippingBody: UpdateOrderShippingRequest. 200 — UpdateOrderShippingResponse. updateOrderShipping.
    Cancel orderPOST/commerce/v1/orders/{id}/cancelBody: CancelOrderRequest. 200 — CancelOrderResponse. cancelOrder.

    7. Hub (/hub/v1)

    OperationMethodPathNotes
    List webhook event typesGET/hub/v1/webhooks/event-types/searchHub read scope. listEventTypesQuery. No X-Tenant-Id in bundled spec.
    Create webhook subscriptionPOST/hub/v1/webhooks/subscriptions/createBody: CreateSubscriptionRequest (url, eventTypes, description, expiresAtUtc; optional notificationEmails). 201 — CreateSubscriptionResponse (includes signingSecret, notificationEmails). createSubscriptionCommand.
    Search webhook subscriptionsGET/hub/v1/webhooks/subscriptions/searchQuery: limit, next, sortBy, sortOrder. X-Tenant-Id required. listSubscriptionsQuery.
    Get webhook subscriptionGET/hub/v1/webhooks/subscriptions/{id}/getOptional If-None-Match. X-Tenant-Id required. getSubscriptionQuery.
    Update webhook subscriptionPATCH/hub/v1/webhooks/subscriptions/{id}/updateBody per OpenAPI PATCH. 200 — UpdateSubscriptionResponse. updateSubscriptionCommand.
    Disable webhook subscriptionPOST/hub/v1/webhooks/subscriptions/{id}/disable204. disableSubscriptionCommand. X-Tenant-Id required.
    Search subs by event typeGET/hub/v1/webhooks/event-types/{name}/subscriptions/searchPath name = event type id (e.g. order.created). X-Tenant-Id required. listSubscriptionsForEventType.
    Test webhook subscriptionPOST/hub/v1/webhooks/subscriptions/{id}/testTriggers test delivery (202). X-Tenant-Id required.
    List deliveries (subscription)GET/hub/v1/webhooks/subscriptions/{id}/deliveriesPaged delivery history; query status, from, to, etc.
    Get delivery by idGET/hub/v1/webhooks/deliveries/{id}/getSingle delivery record. getDeliveryQuery.
    Retry deliveryPOST/hub/v1/webhooks/deliveries/{id}/retryQueues retry (202). X-Tenant-Id required.
    Rotate subscription secretPOST/hub/v1/webhooks/subscriptions/{id}/rotate-secretReturns new signing secret. X-Tenant-Id required.

    All non-catalog endpoints require **Authorization: Bearer **** and **X-Tenant-Id unless the operation explicitly omits tenant scope (e.g. GET /hub/v1/webhooks/event-types/search per bundled spec).

    10. Object reference

    Types are grouped by the same service prefixes as §9 API Reference: Shared, Identity (/identity/v1), Catalog (/catalog/v1), Screening (/screening/v1), Consult (/consult/v1), Clinical (/clinical/v1), Commerce (/commerce/v1), Hub (/hub/v1). Shared types are reused across services. For fields omitted below, see CareAtlas-Unified-API-oas3-v0.1.json.

    Shared types

    Address

    Used on commerce OrderImportRequest, practitioner onboard, and (as AddressInfo) on PatientResolveRequest. Patient update uses PatientAddressInfo (same required fields; optional label).

    FieldTypeDescription
    addressLine1stringRequired.
    addressLine2stringRequired (can be empty string).
    citystringRequired.
    statestringRequired.
    zipCodestringRequired.
    phonestringRequired (e.g. 10 digits).
    labelstringOptional on AddressInfo, PatientAddressInfo, and PractitionerAddressInfo (e.g. "Shipping Address" on resolve-by-email).

    Identity (/identity/v1)

    MyTenantsResponse

    200 from GET /identity/v1/tenants/me.

    FieldTypeDescription
    partnerAppMyTenantsPartnerAppResponse | objectPartner application context; may be absent.

    MyTenantsPartnerAppResponse

    FieldTypeDescription
    idstring (UUID)Partner application id — use as source.partnerAppId on order import.
    appIdstringApplication id (e.g. Cognito app client / portal key).
    namestringDisplay name of the partner application.
    partnerMyTenantsPartnerResponseOwning partner.
    tenantsMyTenantsTenantResponse[]Clinic/provider tenants linked to this app.
    tenantProvidersMyTenantsTenantResponse[]Provider/pharmacy tenants (e.g. role Pharmacy) for routing and UI.
    attributesMyTenantsAttributeResponse[]Partner-app-level attributes (see OpenAPI).

    MyTenantsPartnerResponse

    Nested under MyTenantsPartnerAppResponse.partner.

    FieldTypeDescription
    idstring (UUID)Partner id.
    namestringPartner name.
    rolestringPartner role name.

    MyTenantsTenantResponse

    Each element of tenants or tenantProviders.

    FieldTypeDescription
    tenantIdstring (UUID)Use as X-Tenant-Id when this row is selected.
    namestringTenant display name.
    rolestringRole name (e.g. provider, Pharmacy).
    attributesMyTenantsAttributeResponse[]Attributes on the tenant row (see OpenAPI).

    MyTenantsAttributeResponse

    Name/value pair used on MyTenantsTenantResponse and MyTenantsPartnerAppResponse.

    FieldTypeDescription
    namestringAttribute name.
    valuestringAttribute value.

    PatientResponse

    Returned by patient search, resolve, and get-patient flows. Tenant context is X-Tenant-Id on the request, not a field on this object.

    FieldTypeDescription
    idstring (UUID)customer.patientId.
    accountPatientAccountResponseNested account; use account.id as customer.accountId.
    firstNamestring
    lastNamestring
    dateOfBirthstring
    heightnumberHeight in inches (Identity column).
    weightnumberWeight in lbs.
    genderstring"Male" or "Female" (per deployment).
    emailstringOptional for billing.
    phoneNumberstring
    addressAddressRequired for shipping/billing if not from payment.
    etagstringConcurrency token when supported.

    Removed from unified PatientResponse: top-level tenantId and accountId — use account.id instead of accountId.


    OnboardClinicRequest

    Request body for POST /identity/v1/tenants/clinics/onboard:

    FieldTypeDescription
    partnerIdstring (UUID)Partner UUID.
    parentTenantIdstring (UUID)Parent tenant UUID.
    namestringClinic/tenant name.
    attributesOnboardClinicAttributesRequestRequired. See below.

    attributes: name, npi, addressId (UUID), email, phone, description.


    PractitionerOnboardRequest

    Request body for POST /identity/v1/practitioners/onboard (create or find practitioner by NPI):

    FieldTypeDescription
    accountIdstring (UUID)Account UUID for the practitioner (from your identity/tenant context).
    npistringNational Provider Identifier (10 digits).
    firstNamestringRequired.
    middleNamestringRequired; use "" if none.
    lastNamestringRequired.
    suffixstringRequired; use "" if none.
    displayNamestringe.g. "Dr. Maria Smith".
    providerTypeIdstring (UUID)Provider type from tenant config (e.g. physician, NP).
    statusIdstring (UUID)Status from tenant config (e.g. active).
    addressAddressFull address (addressLine1, addressLine2, city, state, zipCode, phone).
    createIfMissingbooleanOptional; default true. If true, creates the practitioner when not found.

    PractitionerResponse

    Returned by GET /identity/v1/practitioners/search (each item in data) and in POST .../practitioners/onboard response:

    FieldTypeDescription
    idstringPractitioner UUID; use as practitionerId in prescriptions.
    tenantIdstringTenant UUID.
    accountIdstringAccount UUID.
    npistringNational Provider Identifier.
    firstNamestring
    middleNamestring
    lastNamestring
    suffixstring
    displayNamestring
    providerTypeIdstring
    statusIdstring
    inactivatedboolean
    emailstring
    emailVerifiedboolean
    phoneNumberstring
    phoneNumberVerifiedboolean
    addressAddressobject
    etagstring

    TenantResponse

    Returned by POST /identity/v1/tenants/clinics/onboard and in clinic search results:

    FieldTypeDescription
    idstringTenant (clinic) UUID.
    partnerIdstringPartner UUID.
    parentTenantIdstringParent tenant UUID.
    namestringClinic/tenant name.
    roleTenantRoleResponseTenant role.
    etagstringFor conditional updates.
    createdAtUtc, updatedAtUtcstringTimestamps.
    attributesarrayTenant role attribute values (e.g. address, contact details).

    Use with address/attribute data to build ClinicInfo for order import.


    Catalog (/catalog/v1)

    Search and product payloads use GetProductResponse (informally called ProductResponse in this guide). Variants carry productVariantId and uomId for prescriptions and order lines.

    GetProductResponse

    Returned from GET /catalog/v1/products/search and GET /catalog/v1/products/{id}/find.

    FieldTypeDescription
    idstring (UUID)productId.
    name, sku, brand, descriptionstringsDisplay and catalog metadata.
    variantsProductVariantInfo[]Use for variant id and uomId.
    catalogobject (ProductCatalogInfo)Nested catalog id/name/supplier.
    etagstringFor conditional requests.

    ProductVariantInfo

    Each variant maps to a prescribe-able SKU and order line.

    FieldTypeDescription
    idstring (UUID)productVariantId for prescriptions and LineInfo.
    uomIdstring (UUID)Required on commerce LineInfo when importing orders.
    namestringe.g. strength label.
    variantSkustringSKU.
    attributesarray (AttributeResponse)Tenant-defined attributes.
    etagstring

    Screening (/screening/v1)

    CreateSessionRequest

    Body for POST /screening/v1/sessions/create.

    FieldTypeDescription
    channelstringe.g. web.
    patientIdstring (UUID)From Identity.
    questionnaireIdstring (UUID)From active questionnaires list.
    productIdstring (UUID)Catalog product.
    productVariantIdstring (UUID)Catalog variant.

    CreateSessionResponse

    201 response from session create; id is the screening session id for /next, /answer, /submit, etc.

    FieldTypeDescription
    idstring (UUID)Session id.
    tenantIdstring (UUID)
    patientIdstring (UUID)
    questionnaireIdstring (UUID)
    productIdstring (UUID)
    productVariantIdstring (UUID)
    startedAtdate-time
    expiresAtUtcdate-time
    etagstring

    ActiveQuestionnaireResponse

    Rows from GET /screening/v1/questionnaires/active (each element describes an available questionnaire).

    FieldTypeDescription
    idstring (UUID)Use as questionnaireId in CreateSessionRequest.
    name, versionstring
    treatmentIdstring (UUID)Care-path binding.
    statusIdstring (UUID)
    effectiveFromUtc, effectiveToUtcdate-timeValidity window.

    SessionSubmitRequest

    Body for POST /screening/v1/sessions/{id}/submit.

    FieldTypeDescription
    validateOnlybooleanOptional dry-run.

    SubmitSessionResponse

    200 body after submit; use recommendedProductVariants when your clinical flow suggests variants.

    FieldTypeDescription
    statusstringSession outcome.
    sessionIdstring (UUID)
    questionnaireIdstring (UUID)
    initiallySelectedProductIdstring (UUID)
    initiallySelectedProductVariantIdstring (UUID)
    completedAtdate-time
    recommendedProductVariantsarrayRecommendedProductVariantInfo per spec.

    AnswerBundleRequest

    Body for POST /screening/v1/sessions/{id}/answer.

    FieldTypeDescription
    answersAnswerItemInfo[]Each item: linkId, answer, optional evidenceRef.

    Consult (/consult/v1)

    CreateConsultRequest

    Body for POST /consult/v1/consults/create (createConsult).

    FieldTypeDescription
    patientIdstring (UUID)From Identity.
    practitionerIdstring (UUID)From Identity practitioner search/onboard.
    topicstringConsult topic label.
    channelstringe.g. web.
    screeningSessionIdstring (UUID)From screening after submit (§4).
    selectedProductIdstring (UUID)Catalog productId.
    selectedProductVariantIdstring (UUID)Catalog productVariantId.

    CreateConsultResponse

    200 from create consult; use id as consult id on GET/messages routes.

    FieldTypeDescription
    idstring (UUID)Consult id.
    providerTenantIdstring (UUID)
    createdAtUtcdate-time
    updatedAtUtcdate-time

    GetConsultResponse

    Returned by GET /consult/v1/consults/{id}/get.

    FieldTypeDescription
    idstring (UUID)
    statusstringWorkflow status.
    tenantIdstring (UUID)
    patientIdstring (UUID)
    practitionerIdstring (UUID)
    screeningSessionIdstring (UUID)
    selectedProductIdstring (UUID)
    selectedProductVariantIdstring (UUID)
    channelstring
    startedUtc, endedUtcdate-timeLifecycle.
    conversationRefstringExternal conversation link when set.
    participantsarrayConsultParticipantDto (see below).
    chatsarrayConsultChatDto per spec.
    etagstring

    ConsultParticipantDto

    Each item in GetConsultResponse.participants (and AddParticipantResponse after POST …/participants/add).

    FieldTypeDescription
    idstring (UUID)Consult participant row id; use as PostMessageRequest.participantId.
    tenantIdstring (UUID)
    patientIdstring (UUID)Identity patient on the consult (from the consult record).
    practitionerIdstring (UUID)Identity practitioner registered on this participant row.
    displayNamestringDisplay label for the participant.
    joinedUtcdate-time
    leftUtcdate-timeOptional. When the participant left the thread.
    etagstring

    The unified partner API does not expose roleId on this type. Role-based participant management (e.g. admin picklists) uses separate admin CRUD routes under /consult/v1/consults/{id}/participants, not participants/add.

    AddParticipantRequest

    Body for POST /consult/v1/consults/{id}/participants/add.

    FieldTypeDescription
    practitionerIdstring (UUID)Required. Practitioner to add to the consult chat.
    displayNamestringRequired. Shown name for this participant.

    The consult’s patientId is assigned on the created row by the API; it is not sent in the request.

    AddParticipantResponse

    201 from POST /consult/v1/consults/{id}/participants/add.

    FieldTypeDescription
    idstring (UUID)New participant row id.
    consultIdstring (UUID)
    patientIdstring (UUID)Consult patient.
    practitionerIdstring (UUID)Practitioner from the request.
    displayNamestring
    joinedUtcdate-time
    createdAtUtcdate-time
    updatedAtUtcdate-time

    CloseConsultResponse

    200 from POST /consult/v1/consults/{id}/close.

    FieldTypeDescription
    idstring (UUID)Consult id.
    endedUtcdate-timeWhen closed.
    createdAtUtcdate-time
    updatedAtUtcdate-time

    CancelConsultResponse

    200 from POST /consult/v1/consults/{id}/cancel.

    FieldTypeDescription
    idstring (UUID)Consult id.
    canceledAtUtcdate-time
    canceledBystringWho canceled.
    createdAtUtcdate-time
    updatedAtUtcdate-time

    PostMessageRequest

    Body for POST /consult/v1/consults/{id}/messages/post.

    FieldTypeDescription
    contentstringRequired. Message text.
    participantIdstring (UUID)Optional. ConsultParticipantDto.id (participant row), not identity patient/practitioner uuid. Omit when no participant row exists; the API still accepts the message.
    isMediabooleanOptional.

    UpdateMessageDeliveryRequest

    Body for POST /consult/v1/consults/{id}/messages/{messageId}/update-delivery.

    FieldTypeDescription
    deliveredUtcdate-timeWhen the message was delivered to the recipient.
    readUtcdate-timeWhen the message was read.

    Path {messageId} is the consult message id (from ConsultMessageResponse / search messages).

    UpdateMessageDeliveryResponse

    200 from POST /consult/v1/consults/{id}/messages/{messageId}/update-delivery.

    FieldTypeDescription
    idstring (UUID)Message id.
    consultIdstring (UUID)
    tenantIdstring (UUID)
    deliveredUtcdate-time
    readUtcdate-time
    etagstring

    Clinical (/clinical/v1)

    ValidatePrescriptionResponse

    Returned by GET /clinical/v1/prescriptions/{id}/validate.

    FieldTypeDescription
    isValidbooleanWhether the prescription passes validation per the API.

    CreatePrescriptionCommandRequest

    Request body for POST /clinical/v1/prescriptions/create (OpenAPI: CreatePrescriptionRequest).

    FieldTypeNotes
    consultIdstring (UUID)Consult id from §5 Step 2. Required for provider prescribing flows.
    medsPrescribedMedPrescribedInternal[]Required. One row per prescribed line.
    pharmacyIdstringRequired. Pharmacy identifier (UUID in typical deployments).
    pharmacyNotestringOptional.
    practitionerIdstring (UUID)Optional in schema; usually set from §6 Prerequisites — prescriptions (Ensure Practitioner exists).
    practitionerFirstNamestringOptional.
    practitionerLastNamestringOptional.
    practitionerNpistringOptional.
    practitionerPhonestringOptional.
    practitionerAddressstringOptional.
    practitionerCitystringOptional.
    practitionerStatestringOptional.
    practitionerZipstringOptional.
    approvedAtUtcstring (date-time)Optional.
    approvedBystringOptional.
    paymentAmountobject (double format per spec)Optional.
    paymentLinkstringOptional.
    paymentLinkSentAtstring (date-time)Optional.
    commentsstringOptional.

    SubmitPaymentRequest

    Body for POST /commerce/v1/payments/submit (submitPayment). Records a payment against an order entity in Commerce.

    FieldTypeDescription
    entityNamestringEntity type label (per your commerce integration).
    entityIdstringEntity UUID.
    orderIdstringOrder UUID.
    providerstringPayment provider (e.g. stripe).
    intentIdstringProvider payment intent id.
    statusstringPayment status string.
    amountnumberAmount (OpenAPI may export as object/double).
    currencyISOstringISO currency code (e.g. USD).

    SubmitPaymentResponse

    200 from submit payment — includes id, tenantId, intentId, status, amount, etag, and related fields mirroring the request.


    MedPrescribedInternal

    One element of medsPrescribed in CreatePrescriptionCommandRequest.

    FieldTypeDescription
    productIdstring (UUID)Required. Product UUID.
    productVariantIdstring (UUID)Required. Variant UUID.
    strengthstringRequired. e.g. "10mg".
    frequencystringRequired. e.g. "once daily".
    routestringRequired. e.g. "oral".

    UpdatePrescriptionCommandRequest

    Request body for PATCH /clinical/v1/prescriptions/{id}/update. All fields are optional in the bundled schema.

    FieldTypeDescription
    approvedAtUtcstring (date-time)Optional.
    approvedBystringOptional.
    pharmacyNotestringOptional.
    commentsstringOptional.
    paymentAmountobject (double format)Optional.
    paymentLinkstringOptional.
    paymentLinkSentAtstring (date-time)Optional.

    PrescriptionResponse

    Relevant fields for building the order:

    FieldTypeDescription
    idstringUsed as matchedPrescriptionId.
    patientIdstringUsed as customer.patientId.
    productIdstringUsed as lines[].productId.
    productVariantIdstringUsed as lines[].productVariantId (or resolve from product).
    quantityAuthorizedobjectUsed for lines[].qty (e.g. .value or default 1).

    Commerce (/commerce/v1)

    ClinicInfo

    Required by the API schema for OrderImportRequest.

    FieldTypeDescription
    clinicNamestring
    clinicAddressLine1string
    clinicAddressLine2string
    clinicCitystring
    clinicStatestring
    clinicZipstring
    clinicEmailstring
    clinicPhoneNumberstring

    If your backend accepts orders without clinic, you may still need to send a minimal object; confirm with the API or backend team.


    CustomerInfo

    FieldTypeDescription
    patientIdstringPatient UUID.
    accountIdstringAccount UUID (from patient or profile/session).

    LineInfo

    FieldTypeDescription
    externalLineIdstringUnique line id (e.g. LINE-<ts> or same as externalOrderId for single line).
    productIdstringProduct UUID.
    productVariantIdstringProduct variant UUID.
    uomIdstringRequired by API. Unit of measure UUID. This app does not use it for logic; it sends the variant's uomId or a default.
    qtyRecord<string, any> or stringQuantity (API may expect string).
    unitPriceRecord<string, any> or stringUnit price.
    lineTotalRecord<string, any> or stringLine total.
    priceComponentsarraye.g. [].
    requiresPrescriptionbooleanTypically true for prescription-based orders.
    matchedPrescriptionIdstringPrescription UUID.

    OrderImportRequest

    Full request body for POST /commerce/v1/orders/import. The API schema marks these as required: externalOrderId, customer, clinic, currencyISO, pricing, lines, promos, totals, shippingAddress, billingAddress, payment, validatedAtUtc, source, notes.

    FieldTypeDescription
    externalOrderIdstringUnique external order id (e.g. ORDER-<ts> or Stripe payment intent id).
    customerCustomerInfoPatient and account identifiers.
    clinicClinicInfoRequired by schema. Clinic name, full address, email, phone.
    currencyISOstringe.g. "USD".
    pricingobject / PricingInfoe.g. { priceBookVersion: "1.0", components: [] }.
    linesLineInfo[]Order lines; each can reference a prescription via matchedPrescriptionId.
    promosstring[]Promo codes; use [] if none.
    totalsTotalsInfosubtotal, taxTotal, shippingTotal, grandTotal.
    shippingAddressAddressFull shipping address.
    billingAddressAddressobject
    paymentPaymentInfoobject
    validatedAtUtcstringISO 8601 date-time.
    sourceSourceInfoobject
    notesstringFree text.

    OrderResponse

    Returned by POST /commerce/v1/orders/import:

    FieldTypeDescription
    idstringOrder UUID.
    orderNumberstringHuman-readable order number.
    statusstringOrder status.
    patientIdstring
    linesOrderLineResponse[]Order lines.
    subtotal, taxTotal, shippingTotal, grandTotalvarious
    paymentobject
    shippingAddress, billingAddressobject

    PaymentInfo

    FieldTypeDescription
    paymentIdstringInternal payment UUID.
    externalReferencestringe.g. Stripe session id.
    statusstringe.g. "paid", "pending".

    Extended payment payload (as used after Stripe) may include intentId, provider (e.g. "Stripe").


    SourceInfo

    FieldTypeDescription
    partnerAppIdstringFrom GET /identity/v1/tenants/mepartnerApp.id.
    channelstringe.g. "web".
    regionstringe.g. "US".

    TotalsInfo

    FieldTypeDescription
    subtotalRecord<string, any> or stringSubtotal amount.
    taxTotalRecord<string, any> or stringTax total.
    shippingTotalRecord<string, any> or stringShipping total.
    grandTotalRecord<string, any> or stringGrand total.

    In this app, totals are often sent as strings (e.g. "0", "12.99") for decimal precision.


    Hub (/hub/v1)

    Webhook subscription and delivery types for §8 Working with Webhooks. Requests use Hub Cognito scopes (api://haas.hub/haas.api.read / …write).

    CreateSubscriptionRequest

    Body for POST /hub/v1/webhooks/subscriptions/create.

    FieldTypeRequiredDescription
    urlstringyesHTTPS endpoint for deliveries.
    eventTypesstring[]yese.g. order.created (per event catalog).
    descriptionstringyesHuman-readable label.
    expiresAtUtcdate-timeyesSubscription expiry (ISO-8601 UTC).
    notificationEmailsstringnoOptional alert recipients for subscription events.

    CreateSubscriptionResponse

    201 — treat signingSecret as sensitive; persist it to verify signatures on inbound webhooks.

    FieldTypeDescription
    idstring (UUID)Subscription id.
    partnerAppIdstring (UUID)
    urlstringCallback URL.
    eventTypesstring[]
    isActiveboolean
    descriptionstring
    expiresAtUtcdate-time
    notificationEmailsstringAlert recipients when configured.
    etagstring
    signingSecretstringHMAC / verification secret.

    UpdateSubscriptionResponse

    200 from PATCH /hub/v1/webhooks/subscriptions/{id}/update — same fields as create response except signingSecret (use rotate-secret to obtain a new secret).

    FieldTypeDescription
    idstring (UUID)
    partnerAppIdstring (UUID)
    urlstring
    eventTypesstring[]
    isActiveboolean
    descriptionstring
    expiresAtUtcdate-time
    notificationEmailsstring
    etagstring

    GetDeliveryResponse

    Returned by GET /hub/v1/webhooks/deliveries/{id}/get for observability and debugging.

    FieldTypeDescription
    idstring (UUID)Delivery attempt id.
    subscriptionIdstring (UUID)
    sourceMessageIdstring (UUID)Hub message id.
    eventTypestring
    statusstringDelivery pipeline status.
    statusCodeintegerHTTP status from your endpoint (if applicable).
    errorstringFailure detail.
    attemptintegerRetry count.
    nextRetryAtUtcdate-timeScheduled retry.
    traceIdstringCorrelate with Hub logs.
    etagstring

    11. Troubleshooting

    • 401 Unauthorized – Check Cognito token and scope (api://haas.commerce/haas.api.write for import).
    • 403 Forbidden – Verify X-Tenant-Id and that the token is allowed for that tenant.
    • 400 Bad Request – Validate OrderImportRequest: required fields (including clinic), address fields (addressLine2 must be present, can be ""), and numeric/string formats for qty, unitPrice, lineTotal, totals.
    • Missing accountId – Ensure patient has accountId or resolve it via your identity/profile API before calling order import.
    • Patient does not have address – Order import requires full shipping and billing addresses; create or update the patient’s address via Identity APIs first.
    • Duplicate orders – Use Idempotency-Key (e.g. prescription id + payment id) on POST /commerce/v1/orders/import when retrying or handling webhooks.

    For payload examples and mapping from prescription to order, see Build OrderImportRequest and call Import Order and the sample request there.