> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corti.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed Corti Assistant in an EHR workflow

> Add Corti Assistant to an existing React EHR workflow and sync reviewed documentation into your clinical form.

Keep the clinician in your electronic health record (EHR) application while [Corti Assistant](/assistant/welcome) handles recording and documentation. This guide follows the `next-ehr-minimal` example: your application supplies the encounter context, controls the embedded experience, and decides how reviewed output updates its own form.

<iframe className="w-full aspect-video rounded-xl" src="https://www.tella.tv/video/vid_cmtvj67yq00mm0agm2ekm679c/embed?b=0&title=1&a=1&loop=0&t=0&muted=0&wt=0&o=1" title="Embedding Corti Assistant: First Working Integration" frameBorder="0" allow="autoplay; fullscreen" allowFullScreen />

The video walks through the completed EHR workflow, from recording an encounter to reviewing documentation and syncing it into the clinical form. The guide below covers the setup and implementation: how to run the example, configure Corti Assistant, and adapt the integration to your own application. For the component's methods and events, see the [Web Component API](/assistant/web-component-api).

## What you'll build

The fictional EHR contains patients, appointments, encounter types and a clinical documentation form. You add Corti Assistant to its **Annual checkup** workflow without replacing the surrounding application.

The clinician opens a consultation with patient context already visible, records the conversation, generates a SOAP document, and reviews it inside Corti Assistant. Only after the clinician chooses to sync do the generated sections populate the EHR's Subjective, Objective, Assessment and Plan fields. The host then collapses Corti Assistant, with a **Show assistant** button to reopen it.

This is a small working integration, not a production EHR. Use synthetic patient data and a test conversation throughout.

***

## Run the example

### Prerequisites

* Git, Node.js 22 LTS and npm. The example uses Next.js 16 and a native SQLite dependency.
* A browser with microphone access and network access to your Corti environment.
* A Corti project with Embedded Assistant access, a user-based OAuth client and a demo Corti user. The steps below explain how to obtain these.
* Familiarity with React and TypeScript to adapt the implementation.

<Steps>
  <Step title="Clone and install">
    Clone the [examples repository](https://github.com/corticph/corti-examples), install dependencies in `embedded-assistant/react/next-ehr-minimal`, and create the local environment file:

    ```bash title="Terminal" theme={null}
    git clone --branch main https://github.com/corticph/corti-examples.git
    cd corti-examples/embedded-assistant/react/next-ehr-minimal
    npm install
    cp .env.example .env
    ```
  </Step>

  <Step title="Set up Corti">
    Sign in to [Corti Console](https://console.corti.app) and select the project you will use for the demo. If you need a project, [create one](/authentication/creating_clients) in the intended region. The client and user must belong to the same project and tenant/environment combination.

    Under **API clients**, choose **Create API client**. Give it a descriptive name, choose **Embedded Assistant** under **How will this client be used?**, then select **ROPC (Resource Owner Password)** as the **Authentication method**. Create the client and open its details. For an existing client, verify that it uses this authentication method.

    Copy the full **Client ID** into `CORTI_CLIENT_ID`, **Environment ID** into `CORTI_ENVIRONMENT`, and **Tenant name** into `CORTI_TENANT_NAME`. Use the created client's full ID, not just the name or suffix entered in the creation form. The usual public environments are `eu` and `us`, and the usual tenant is `base`; copy your actual values instead of assuming these defaults. See [Environments & Tenants](/authentication/environments_tenants).

    For the demo user, open **Customers**, select the relevant customer, and choose **Add user**. If necessary, create a test customer first. Enter a synthetic name and an email address you control. Enable **Manual Invite** and enter **Set Password** to establish credentials for this local demo. Follow the password requirements shown in the form. Put that user's email in `CORTI_USER_EMAIL` and the password you set in `CORTI_USER_PASSWORD`. Alternatively, use an existing enabled Corti user whose credentials you know.

    User creation requires project developer access or the appropriate administrator access. If you cannot access customer/user management or cannot provision the required user-based client, ask your project administrator or [contact Corti](mailto:help@corti.ai) to provision them for your project. Request the environment, tenant name, ROPC client ID and a demo user with a known password. Do not use your Corti Console login password or try to extract the Console's internal Studio credentials.

    ROPC exchanges a user's email and password for tokens. It therefore needs both a client permitting the password grant (also called **Direct Access Grants**) and an enabled user in that tenant. Selecting ROPC in Console configures the client for this grant; this example does not use a client secret or a machine-to-machine client.
  </Step>

  <Step title="Configure environment variables">
    Edit the `.env` created above. All six values below are read on the server; none needs a `NEXT_PUBLIC_` prefix. The supplied `.env.example` starts with `staging-eu` and `base`: replace these with the environment and tenant of your client, rather than mixing staging and production credentials.

    | Variable              | Value and source                                                                                                         | Sensitivity and browser boundary                                                                        | Illustrative value          |
    | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | --------------------------- |
    | `EHR_SQLITE_PATH`     | Choose a writable local file path; keep the example's default for this walkthrough. Required by the EHR database module. | The path is not a secret, but the database contains clinical records. Keep database access server-side. | `./data/ehr-demo.sqlite`    |
    | `CORTI_ENVIRONMENT`   | Copy **Environment ID** from the API client's details. It selects both authentication and the Assistant host.            | Not a secret. Read server-side; the derived Assistant URL is intentionally returned to the browser.     | `<your-environment>`        |
    | `CORTI_TENANT_NAME`   | Copy **Tenant name** from the same client. This is not the project display name.                                         | Not a credential. Read server-side by the authentication helper.                                        | `<your-tenant-name>`        |
    | `CORTI_CLIENT_ID`     | Copy the full **Client ID** of the ROPC client you created.                                                              | Not a secret by itself. This example reads it only on the server.                                       | `<your-client-id>`          |
    | `CORTI_USER_EMAIL`    | Use the demo Corti user's email from customer/user management.                                                           | User identity data. Keep it server-side in this example.                                                | `<your-demo-user-email>`    |
    | `CORTI_USER_PASSWORD` | Use the password set for that demo user, not a client secret or Console password.                                        | Secret. Must stay server-side and out of source control.                                                | `<your-demo-user-password>` |

    There is no separate Assistant URL variable: `GET /api/config` constructs `https://assistant.${environment}.corti.app`. `GET /api/auth` calls `getCortiRopcToken()` from `lib/corti-server-auth.ts`. That helper creates a `CortiAuth` instance and calls `auth.getRopcFlowToken()`. The route returns the token fields expected by `api.auth()`, with `mode: "stateful"`.

    <Warning>
      Never commit `.env`. The example's `.gitignore` excludes `.env*` except `.env.example`, and also excludes `/data`; preserve these rules and verify `.env` is ignored with `git check-ignore .env`.

      Never expose the demo password or other long-lived secrets through browser code. This example intentionally passes access and refresh tokens to the embedded browser experience, so protect those tokens too. Its local `/api/auth` route has no host-user authentication check: do not deploy it as a public token endpoint.

      A shared password in `.env` is a single-user demo shortcut, not a production clinician-identity design. Use [Authentication for Embedded Users](/assistant/authentication) to choose your production flow.
    </Warning>
  </Step>

  <Step title="Start the EHR">
    Run `npm run dev` in the example directory and open [http://localhost:3000](http://localhost:3000). Next.js serves both the EHR and its `/api` routes; there is no separate Express server. If port 3000 is occupied, use the local URL printed by Next.js.

    The application creates and seeds its SQLite database on first use. Open **Patients**, select a patient, and choose **New consultation**, then **Annual checkup**. An annual-checkup appointment's new consultation screen uses the same integration.

    Confirm that the EHR form loads and the embedded panel reaches **Corti assistant ready**. Allow microphone access, record a synthetic encounter, generate and review a document, then use the document's sync action. The SOAP fields should populate and the panel should collapse. **Save consultation** is a separate EHR action that persists the form.
  </Step>
</Steps>

If initialisation fails, check all five `CORTI_*` values, restart the development server after changing `.env`, and confirm the client permits ROPC and the demo user is enabled. A database startup error usually means `EHR_SQLITE_PATH` is missing or not writable. If the fixed template cannot be resolved, confirm your project can use the standard SOAP template referenced by the example; contact Corti if access needs enabling. Do not substitute a different template without updating the section mapping too.

***

## Integration model

The EHR is the host and the driver of the workflow. Communication crosses the [Web Component API](/assistant/web-component-api) in both directions:

| Owner                   | Responsibility                                                                                                                                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Host application        | Signed-in clinician identity in a real EHR, patient and encounter context, placement and visibility, workflow restrictions, permitted templates/languages/features, form fields, content mapping, preferences and persistence. |
| Corti Assistant         | Embedded clinical UI, microphone lifecycle and audio capture, realtime interaction communication and its recovery, template selection where enabled, document generation, editing/review, and exposed events/state.            |
| Host to Corti Assistant | Authentication, application and interaction configuration, encounter metadata, patient facts, navigation and actions.                                                                                                          |
| Corti Assistant to host | Events, state changes and generated document output. The host decides what to apply to its data model.                                                                                                                         |

React uses a wrapper around the same Web Component that JavaScript, TypeScript, Vue, Angular and web-based wrappers such as Electron can render directly. Native .NET, Swift or Kotlin hosts typically put a small HTML host page and the component in a WebView. This example follows the direct React/web path.

***

## End-to-end flow

The complete round trip is:

<Steps>
  <Step title="Mount and initialise">
    Fetch `/api/config` and `/api/auth`, mount `CortiEmbeddedReact` hidden, and wait for `onReady`. Call `api.auth()`, `api.configureApp()` and `api.setInteractionOptions()`.
  </Step>

  <Step title="Create and open the interaction">
    Call `api.createInteraction()`, then `api.addFacts()` with patient context. Await ``api.navigate({ path: `/session/${interaction.id}` })``, then call `corti.show()`.
  </Step>

  <Step title="Record, generate and review">
    The clinician records in Corti Assistant, reviews the extracted facts as needed, generates the document, and reviews or edits its content. Generation alone does not update the EHR form.
  </Step>

  <Step title="Sync into the EHR">
    The clinician explicitly syncs. The host handles `document.synced`, reads `event.detail.payload.document.sections`, maps known section keys to its form fields, and updates local form state. It calls `corti.hide()` and collapses the panel. The clinician can reopen Corti Assistant or save the consultation in the EHR.
  </Step>
</Steps>

***

## Keep the first workflow small

A predictable output contract makes the first round trip easier to verify. Although the EHR supports several consultation types, this example enables Corti Assistant only for `annual-checkup` and uses:

* One fixed standard SOAP template with known section identifiers.
* A forced template for the first document, with default-template selection controls disabled.
* At most one generated document per interaction.
* English-only spoken-language options and document output languages.
* An explicit sync action and four known destination fields.
* One configured demo user for every local request.

These are this host workflow's choices, not Corti defaults or universal recommendations. Establish the full context-to-document-to-form round trip before adding flexibility.

***

## Project structure

These are the files that matter to the integration; all paths are relative to the [example directory](https://github.com/corticph/corti-examples/tree/main/embedded-assistant/react/next-ehr-minimal).

| File                                                                                              | Role                                                                         |
| ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `app/patients/[id]/new-interaction/page.tsx` and `app/appointments/[id]/new-interaction/page.tsx` | Render the existing form and conditionally enable Corti Assistant.           |
| `app/api/auth/route.ts`, `app/api/config/route.ts`, `lib/corti-server-auth.ts`                    | Server-side credentials, token exchange and Assistant URL.                   |
| `components/annual-checkup-corti-assistant.tsx`                                                   | Derive the encounter identifier, visit reason and patient configuration.     |
| `components/corti-assistant-panel-client.tsx` and `components/corti-assistant-embed.tsx`          | Mount the component, handle readiness/errors/events, and control visibility. |
| `lib/corti-assistant-ehr-integration.ts`                                                          | Initialise the interaction and constrain the SOAP workflow.                  |
| `lib/corti-assistant-visit-config.ts`                                                             | Build patient facts from EHR data.                                           |
| `lib/corti-soap-template.ts` and `lib/corti-assistant-sync.ts`                                    | Define the section mapping and translate synced content into form updates.   |
| `lib/consultation-form-store.ts` and `components/consultation-form.tsx`                           | Store field values and render the editable clinical form.                    |

***

## Enable Corti Assistant for annual checkups

Start with the EHR's existing route. In [the patient consultation page](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/app/patients/%5Bid%5D/new-interaction/page.tsx), one condition adds the integration above the normal form:

```tsx title="app/patients/[id]/new-interaction/page.tsx" theme={null}
{consultationType === "annual-checkup" && (
  <AnnualCheckupCortiAssistant detail={detail} />
)}
```

The appointment route makes the same decision using `appointment.consultationType`. Other workflows keep their existing form without the embed. Corti Assistant does not decide which EHR encounter types should expose it.

***

## Mount Corti Assistant

[CortiAssistantEmbed](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/components/corti-assistant-embed.tsx) renders the React wrapper from `@corti/embedded-web/react`:

```tsx title="components/corti-assistant-embed.tsx" theme={null}
<CortiEmbeddedReact
  key={embedKey}
  ref={ref}
  baseURL={baseUrl}
  visibility="hidden"
  onReady={onReady}
  onError={onError}
  onEvent={onEvent}
  style={{ width: "100%", height: "100%" }}
/>
```

The parent passes a ref used by `useCortiEmbeddedApi(cortiRef)` for Embedded API calls, and by `show()`/`hide()` for visibility. `baseURL` comes from the server configuration. `onReady` starts initialisation, `onError` updates the host's error state, and `onEvent` receives events such as document sync. The component fills the host container, which starts at 500 pixels high; `embedKey` lets the retry action remount it.

Mounting provides a place in the UI. It does not authenticate the user or create the clinical interaction.

***

## Initialise the interaction

The panel's `handleReady()` guards against repeated initialisation and calls [startCortiAssistantSession()](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/lib/corti-assistant-ehr-integration.ts). This excerpt is the helper's call sequence:

```typescript title="lib/corti-assistant-ehr-integration.ts" theme={null}
corti.hide();

await api.auth(authData);
await api.configureApp({ ui: { interactionTitle: false } });
await api.setInteractionOptions(buildSoapInteractionOptions(visitConfig.templateId));
const interaction = await api.createInteraction(interactionData);
await api.addFacts(visitConfig.patientFacts);
await api.navigate({ path: `/session/${interaction.id}` });
corti.show();
```

Authentication establishes the Corti user. `configureApp()` hides the interaction title, while `setInteractionOptions()` constrains the clinical workflow. The helper then creates the interaction, adds context, navigates to it and shows the component. Its name uses "session", but the created Corti resource is an interaction.

The example already includes a readiness timeout, status messages and a retry button. For production timeout and navigation-completion handling, follow [Embedded Reliability, Timeouts, and Recovery](/assistant/reliability-timeouts).

***

## Configure the workflow

`buildSoapInteractionOptions()` in the same helper returns the options passed before interaction creation:

```typescript title="lib/corti-assistant-ehr-integration.ts" expandable theme={null}
function buildSoapInteractionOptions(templateId: string): SetInteractionOptionsPayload {
  return {
    spokenLanguage: {
      options: ["en"],
    },
    templates: {
      defaultTemplate: {
        behaviour: "force-first-document",
        template: {
          source: "standard",
          id: templateId,
        },
        allowUserSelection: false,
      },
    },
    documents: {
      actions: { sync: true },
      maxGenerated: 1,
      allowedLanguages: ["en"],
    },
  };
}
```

The `templateId` comes from `CORTI_SOAP_TEMPLATE_ID` in [lib/corti-soap-template.ts](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/lib/corti-soap-template.ts). It is a concrete standard SOAP template identifier, not a value to create in Console for this walkthrough.

`force-first-document` selects that template for the first document, `allowUserSelection: false` disables default-template selection controls, and `maxGenerated: 1` keeps the workflow to one generated document. `sync: true` exposes the deliberate hand-off to the EHR. Both language restrictions use `en`.

See [Configuration Scenarios](/assistant/configuration-scenarios) for examples, [configureApp()](/assistant/api/configure-app) and [setInteractionOptions()](/assistant/api/set-interaction-options) for the current configuration methods, and [Embedded API Supported Values](/assistant/configuration-values) for lookup values. This example references a fixed template; it does not construct an inline template.

***

## Add patient and encounter context

Avoid asking the clinician to re-enter information the host already knows. [AnnualCheckupCortiAssistant](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/components/annual-checkup-corti-assistant.tsx) derives an identifier from the appointment ID, or from the patient ID plus `annual-checkup`. The panel appends a timestamp when creating the interaction:

```typescript title="components/corti-assistant-panel-client.tsx" theme={null}
const interactionData: CortiAssistantInteractionData = {
  assignedUserId: null,
  encounter: {
    identifier: `${encounterIdentifier}-${Date.now()}`,
    status: "planned",
    type: "first_consultation",
    period: { startedAt: new Date().toISOString() },
  },
};
```

Notice that `annual-checkup` is the host's workflow key; the actual Corti encounter payload uses `type: "first_consultation"`. Do not substitute one for the other. See [createInteraction()](/assistant/api/create-interaction).

[buildCortiAssistantVisitConfig()](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/lib/corti-assistant-visit-config.ts) builds facts for the patient's name, date of birth, age, gender, chronic conditions, allergies and visit reason. Each fact has `group: "other"`; the helper normalises whitespace and truncates each text to 100 characters. These are example-specific choices, so review truncation before adapting this to longer clinical context.

`api.addFacts(visitConfig.patientFacts)` runs after interaction creation. Use [addFacts()](/assistant/api/add-facts) for its input contract. The form's clinician label does not select a Corti user: authentication still uses the one demo identity from `.env`.

***

## Generate and review documentation

Once initialisation completes, the clinician records, generates and reviews within the embedded UI. The host does not build its own microphone lifecycle, realtime transport or document editor for this flow.

Keep the EHR form alongside that experience. At this stage, the generated document belongs to Corti Assistant; the host has not yet applied it to the form.

***

## Handle document sync

Generation and application are separate decisions. In [the panel's event handler](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/components/corti-assistant-panel-client.tsx), only the explicit sync event triggers form updates:

```typescript title="components/corti-assistant-panel-client.tsx" theme={null}
if (event.detail.name !== "document.synced") return;

syncCortiSoapDocumentToEhr(event.detail.payload);

corti.hide();
setIsCollapsedAfterSync(true);
setStatus({ tone: "default", message: "Document synced. Assistant collapsed." });
```

The React wrapper exposes the name as `event.detail.name` and the payload as `event.detail.payload`. The [document.synced reference](/assistant/events/generated/document/synced) distinguishes public metadata from the confidential payload containing the full document. The mapper consumes the latter: `payload.document.sections`, with each section's `key` and `text`. The public metadata alone cannot populate the form.

Treat this payload as clinical data, not telemetry. Do not log document bodies, patient facts, passwords or tokens in application logs.

***

## Populate the EHR form

The fixed SOAP template makes a direct mapping possible. [lib/corti-soap-template.ts](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/lib/corti-soap-template.ts) records the real template and section identifiers used by this example:

```typescript title="lib/corti-soap-template.ts" expandable theme={null}
export const CORTI_SOAP_TEMPLATE_ID = "f901c06a-70db-59f6-8d0a-0a4bef4b8c77";

export const CORTI_SOAP_SECTIONS = [
  {
    id: "30391bb8-2bd5-528c-98d5-808c0bc4a717",
    title: "Subjective",
    formField: "subjective",
  },
  {
    id: "9d06b8c9-6757-52d1-ab7b-791f155fabbc",
    title: "Objective",
    formField: "objective",
  },
  {
    id: "7c1af3f7-6574-50dc-bcd9-efdae057db57",
    title: "Assessment",
    formField: "assessment",
  },
  {
    id: "362ada95-ac25-56b9-b792-000de66e1b35",
    title: "Actions and Plan",
    formField: "plan",
  },
] as const satisfies readonly {
  id: string;
  title: string;
  formField: ConsultationFormFieldName;
}[];
```

These UUIDs are identifiers from the example, not illustrative placeholder IDs. Matching `section.key` against them avoids relying on human-readable headings such as **Actions and Plan**. If you change the template, verify its returned section keys and update the mapping together.

[lib/corti-assistant-sync.ts](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/lib/corti-assistant-sync.ts) translates sections into a partial update, then sends it to the form store:

```typescript title="lib/corti-assistant-sync.ts" theme={null}
return sections.reduce<ConsultationFormFieldUpdates>((fields, section) => {
  const formField = section.key ? getCortiSoapFormField(section.key) : undefined;
  const value = normalizeSectionText(section.text);

  if (formField && value) {
    fields[formField] = value;
  }

  return fields;
}, {});
```

```typescript title="lib/corti-assistant-sync.ts" theme={null}
export function syncCortiSoapDocumentToEhr(payload: unknown) {
  const fields = mapCortiSoapDocumentToEhrFields(payload);
  updateConsultationFormFields(fields);
}
```

The mapper ignores unknown keys, blank text and the exact text `Not recorded`; missing sections leave existing fields unchanged. Known non-empty sections replace their destination values, so syncing again can overwrite manual edits in those fields. Other fields, such as vitals and the clinician, are not populated by this mapping.

`updateConsultationFormFields()` calls the Zustand store's `updateFields()`, which merges the partial update into existing values. [ConsultationForm](https://github.com/corticph/corti-examples/blob/main/embedded-assistant/react/next-ehr-minimal/components/consultation-form.tsx) subscribes to `store.fields` and binds its inputs through `fieldProps()`, so the four SOAP fields immediately display the synced text.

Before sync, only Corti Assistant holds the generated document. After sync, the fields populate and the host hides and collapses the embed. This is the transition illustrated in the introductory walkthrough. It is still a form update, not an EHR save: the clinician reviews the populated fields and chooses **Save consultation** to persist them through the host's server action.

***

## What you have now

You have an EHR-owned workflow that embeds Corti Assistant, supplies patient and encounter context, constrains documentation, and lets the clinician record and review without leaving the screen. An explicit sync returns structured sections, and the host maps known SOAP sections into its own editable form. The integration is useful, but intentionally not production-complete.

***

## Production considerations

* **Multi-user identity and tokens:** Establish which Corti user the signed-in clinician should act as. Do not reuse one `.env` identity for every clinician. Protect the host token route and design renewal, expiry and logout handling using [Authentication for Embedded Users](/assistant/authentication) and [auth()](/assistant/api/auth). Multi-user or brokered authentication is a separate integration step, not implemented here.
* **Loading and recovery:** Build on the demo's loading, error and retry states. Follow the [reliability guide](/assistant/reliability-timeouts) for timeouts, interrupted communication and recovery. Persist interaction IDs where appropriate so retries and returning to an encounter do not unintentionally create new interactions.
* **Permissions and security:** Enforce clinician/patient access in your backend, obtain microphone permissions and use HTTPS outside localhost. Apply appropriate data residency, retention and secret-management controls; a local SQLite demo is not a production storage design.
* **Sync and persistence:** Validate incoming payloads, preserve the active patient/encounter association, define overwrite/conflict behaviour, and distinguish a populated form from a successfully saved record. Handle missing sections, failed saves and navigation away from unsaved work.
* **Telemetry and audit:** Record operational outcomes and audit who accepted and saved documentation without putting clinical payloads or credentials in ordinary logs. Plan workflow-specific failure states and support diagnostics.

***

## Where fixed mapping stops scaling

| Template scope                          | Mapping consequence                                                                                                                                 |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| One fixed template                      | The host knows every section in advance and can maintain a direct mapping, as this example does.                                                    |
| Several predefined templates            | A mapping per supported template is possible, but manual maintenance grows as sections and workflows change.                                        |
| Clinician-created or personal templates | The host cannot predict every section. A generated section may have no predefined destination, so a hard-coded map is no longer a general solution. |

Natural next steps include flexible document/section mapping, personal templates, or choosing a structure from encounter type, patient context and workflow requirements. A host-built dynamic inline template is one possible direction; consult the current [Configuration Scenarios](/assistant/configuration-scenarios) before implementing it. This guide does not define a new payload or solve arbitrary-template mapping.

Extend the proven round trip incrementally, alongside multi-user authentication and production persistence, rather than treating fixed SOAP mapping as the architecture for every EHR.

***

## Related documentation

* [Corti Assistant](/assistant/welcome)
* [Embedding Assistant in React Web App](/assistant/guides/react-integration)
* [Authentication for Embedded Users](/assistant/authentication)
* [Configuration Scenarios](/assistant/configuration-scenarios)
* [configureApp()](/assistant/api/configure-app)
* [setInteractionOptions()](/assistant/api/set-interaction-options)
* [Embedded API Supported Values](/assistant/configuration-values)
* [Web Component API](/assistant/web-component-api)
* [Embedded Reliability, Timeouts, and Recovery](/assistant/reliability-timeouts)
* [Example source](https://github.com/corticph/corti-examples/tree/main/embedded-assistant/react/next-ehr-minimal)
