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

# Changelog

<Update label="v1.6.0" description="2026-06-18">
  ### Added

  * **Meeting mode support (`tortus.meetings.start(...)`)**: Start a meeting recording via the SDK. Two modes are supported:
    * `LIVE_RECORDING` captures audio in the embedded app (matches the standalone meeting flow). Optional `notes` and `title` may be supplied as the meeting starts.
    * `AUDIO_FILE` bypasses the recorder by providing `audio.url` (intended for hosts that already have audio captured or handle audio capturing themselves). Transcription begins immediately on the supplied audio.
  * **`TortusMeeting` object**: Returned by `meetings.start(...)` with `setAudio?(audio)`, `setNotes?(notes)`, and `close()` for mid-flight updates and tear-down.
  * **Meeting lifecycle events** on the SDK client: `meeting:started`, `meeting:resumed`, `meeting:updated`, `meeting:closed`, `meeting:cancelled`, and `meeting:completed`. The `meeting:completed` payload includes the generated meeting note in both Markdown and HTML and the transcription as plain text.
  * **`disableFinishMeetingButton` config option** on `loadTortus({ config })`: when `true`, the embedded meeting view hides the post-generation "Finish meeting" button and exposes the bundled meetings list / "Start new meeting" UI instead. The `meeting:completed` event is not emitted while this flag is set, leaving the host integrator in charge of the meeting's lifecycle UI.

  ### Deprecated

  * **Dictation API**: `client.dictations.start()`, the `TortusDictation` / `DictationOptions` types, and the `dictation:started` / `dictation:closed` events are deprecated. The host application has never implemented the iframe-side handler for these calls; they always reject with `CLIENT_4001: Dictation not yet implemented`. References have been removed from the documentation, and the API surface itself will be removed in a future release. Do not use these in new integrations.
</Update>

<Update label="v1.5.0" description="2026-04-01">
  ### Added

  * **`consultation:resumed` event**: Fired when an existing in-progress consultation is re-opened (e.g., after a client unmount/remount or when the clinician navigates back to the consultation). Provides a `TortusConsultation` object with full consultation data, enabling integrators to track consultation lifecycle across application restarts.
  * **`completedAt` field on `TortusConsultationData`**: ISO 8601 timestamp indicating when the consultation was completed. Present in `consultation:completed` event payloads.
  * **`createdAt` field in `consultation:completed`**: The consultation's original creation timestamp is now reliably included, even when the client was restarted mid-consultation.

  ### Fixed

  * **Reliable consultation data after client restart**: `consultation:completed` now always returns a fully populated `TortusConsultation` object when a consultation is reopened after a client unmount/remount. Previously, restarting the client mid-consultation could result in incomplete consultation data.
</Update>

<Update label="v1.4.0" description="2026-03-03">
  ### Added

  * **Transcription artifacts in `consultation:completed`**: The `result.artifacts` object now includes a `transcriptions` array containing the consultation transcription as plain text (`contentType: 'text/plain'`). This follows the same array pattern as `medicalNotes` and `letters` for future expansion.
</Update>

<Update label="v1.3.0" description="2026-03-03">
  ### Added

  * **`CUSTOM` integration system**: You can now pass `{ system: 'CUSTOM', label: 'Your System' }` as the integration to display a custom label in the "Approve & Save to ..." button. The `label` field is required when `system` is `'CUSTOM'`. The "EHR Connected" badge is not shown for custom integrations.
  * **Optional `label` for known integration systems**: All integration systems (`EMIS`, `SYSTM_ONE`, `MEDICUS`, `CERNER`) now accept an optional `label` field that overrides the "Approve & Save to ..." button text. When omitted, the default system display name is used. The "EHR Connected" badge always shows the system's default name.
  * **Branded error screen on initialisation failure**: When `loadTortus()` fails, the loader is replaced with a user-friendly error screen showing the error code for support, instead of silently failing.
  * **`EMBED_7007` error code**: New error code for client-secrets fetch failures, making it easier to identify integrator-side issues.

  ### Changed

  * **Increased initialisation timeout**: `APP_READY` timeout increased from 30 s to 120 s, with improved diagnostic messages when handshake times out.
</Update>

<Update label="v1.2.1" description="2026-02-26">
  ### Added

  * **`customFields` support for internal embed client**: Integrator-provided custom fields are now persisted to the encounter record and returned in `consultation:started` and `consultation:completed` events.
  * **Custom fields validation**: Only organisations with pre-configured fields may use `customFields`.
  * **`EMBED_7006` error code**: New "Invalid embed configuration" error for embed-specific configuration issues (e.g. unconfigured custom fields).

  ### Fixed

  * **`MedicalCode` fields now match FHIR conventions**: Medical codes in `consultation:completed` events now use `code` and `display` as primary fields (aligned with FHIR Coding). The previous `id` and `description` fields are still included for backward compatibility but are deprecated; migrate to `code`/`display` at your convenience.
  * **`consultation.close()` reliability**: `consultation:closed` now fires exactly once regardless of whether the close was initiated by the integrator (via `consultation.close()`) or by the clinician within the app. Previously, client-initiated closes could emit the event multiple times.
  * **`consultation:closed` payload**: The event now includes full consultation data (via `toJSON()`) instead of just the reference, matching the shape of other lifecycle events.
  * **`consultation.close()` always available**: `close()` is now a required method on the `TortusConsultation` interface. Previously it was typed as optional and could appear `undefined`.
  * **`consultation:started` event carries live object**: The `consultation:started` event now includes the full `TortusConsultation` instance with `close()` and `toJSON()` methods. Previously, methods were stripped during serialisation.
  * **Type resolution for external consumers**: All type declarations are now self-contained; they no longer reference internal monorepo paths that would resolve as `unknown` for integrators.

  ### Changed

  * **New `TortusConsultationData` type**: Consultation data in terminal event payloads (`consultation:closed`, `consultation:cancelled`, `consultation:completed`) is now typed as `TortusConsultationData` (data-only, serialisation-safe) instead of `TortusConsultation`. Use `toJSON()` on the live consultation object to obtain a `TortusConsultationData` snapshot.
  * **Unused error types removed**: Removed unused configuration error types (`CONFIG_MISSING_FIELD`, `CONFIG_INVALID_VALUE`, `APPLICATION_CONFIG_CONFLICT`) that were declared but never referenced by any error definition.
</Update>

<Update label="v1.2.0" description="2026-02-12">
  ### Added

  * **`text/html` content type**: Artifact `contentType` now supports `'text/markdown' | 'text/html'`, enabling integrators to receive rich HTML directly from the editor alongside markdown.

  ### Fixed

  * **Incorrect content type on medical notes and letters**: Artifacts were labelled as `text/markdown` but actually contained HTML from the editor. Content type now correctly reflects the actual format (`text/html` for HTML content, `text/markdown` for markdown-converted content).
  * **Consultation serialisation**: `consultation` objects in event callbacks (`consultation:started`, `consultation:completed`, etc.) are now plain data; they no longer throw "The object cannot be cloned" when using `structuredClone()` or `postMessage()`.
  * **`finish()` status handling**: `finish({ status: 'failed' })` and `finish({ status: 'success' })` now work correctly. Failed status shows retry UI, success confirms the save (previously ignored and always closed).

  ### Changed

  * **Default event adapter**: The PostMessage adapter is now the default for all consumers. The legacy X-On adapter remains available via explicit opt-in but is no longer used by default.
</Update>

<Update label="v1.1.0" description="2025-12-03">
  ### Added

  * **Cerner EHR Integration**: Added `CERNER` as a supported integration system.
    * Configure with `integration: { system: 'CERNER' }` when starting consultations.
</Update>

<Update label="v1.0.3" description="2025-11-11">
  ### Fixed

  * Medical codes with measurements now properly include `value`, `unit`, and `evidence` in `consultation:completed` events.
</Update>

<Update label="v1.0.0" description="2025-11-03">
  <Warning>
    This release removes all deprecated APIs and methods. Applications using deprecated functionality must migrate to the new APIs before upgrading.
  </Warning>

  ### Breaking changes

  **Removed deprecated methods**

  * **`client.launch(options)`**: Use `client.display('home')` instead.
  * **`client.startConsultation(consultation)`**: Use `client.consultations.start(consultation, options)` instead.

  **Removed deprecated types**

  * **`LaunchOptions`** interface: No longer needed, use the `Screen` type with the `display()` method.
  * **`integration.label`** property: Use only the `integration.system` property.
  * **`onConsultationComplete`** callback: Use `client.on('consultation:completed', callback)` instead.
  * **`onError`** callback: Use `client.on('consultation:error', callback)` instead.
  * **`artifacts.transcription`** field: Deprecated field removed from consultation output.
  * **`DictationOutput`** type: Removed from public API (dictation completion not yet supported).
  * **`dictation:completed`** event: Removed from public API (dictation completion not yet supported).

  **Artifacts structure changes**

  * **`artifacts.medicalNotes`** changed from `string` to `MedicalNote[]` (array with `content` and `contentType` for multi-format support).
  * **`artifacts.letter`** changed to `artifacts.letters` as a `Letter[]` array.
  * Currently only `contentType: 'text/markdown'` is supported; the array structure enables future format support (HTML, JSON, etc.).

  **Consultation data structure changes**

  * **Flattened input structure**: the `encounter` object was removed from `StartConsultationInput`.
    * `consultation.encounter.reference` becomes `consultation.reference`
    * `consultation.encounter.metadata` becomes `consultation.metadata`
    * `consultation.encounter.customFields` becomes `consultation.customFields`
  * **Output structure simplification**: metadata removed from `ConsultationOutput`.
    * All consultation metadata (reference, customFields, metadata, integration, patient, mode) is available in the `consultation` object in events.
    * `ConsultationOutput` now contains only `artifacts` (medicalNotes, letters, medicalCodes).
  * **`TortusConsultation` enhanced**:
    * Added an `integration` property to match all data previously in `ConsultationOutput`.
    * Now serves as the single source for all consultation metadata.

  ### Added

  * Enhanced type safety with removal of deprecated optional properties.
  * Cleaner API surface with consistent event-driven architecture.
  * Improved documentation without deprecated method references.
  * Simplified logging; always uses console when debug is enabled (no custom logger needed).

  ### Changed

  * **Event adapters**: Removed deprecated `launch()` method implementations.
  * **Validation**: Streamlined validation schemas without deprecated fields.
  * **Tests**: Updated all test suites to use modern API patterns.
  * **Documentation**: Removed deprecation notices and updated examples.
  * **Error codes**: Consolidated error codes; `CLIENT_4011` (user cancelled) is now `CLIENT_4008` (user cancelled operation).

  ### Removed

  * All `@deprecated` annotations and associated functionality.
  * Legacy callback-based error handling patterns.
  * Unused imports and type definitions related to deprecated functionality.
  * Deprecated test cases and assertions.
  * **Custom logger option**: Removed the `logger` parameter from `LoadTortusConfig` (now always uses console when debug is enabled).

  ### Migration guide

  **Method migrations**

  ```typescript theme={null}
  // Before (deprecated)
  await client.launch({ mode: 'STANDALONE' });
  const consultation = await client.startConsultation({
    mode: 'FACE_TO_FACE',
    onConsultationComplete: (result, finish) => {
      console.log('Completed:', result);
      finish();
    },
    onError: (error) => {
      console.error('Error:', error);
    }
  });

  // After (v1.0.0+)
  await client.display('home');
  const unsubscribe1 = client.on('consultation:completed', ({ result, finish }) => {
    console.log('Completed:', result);
    finish();
  });
  const unsubscribe2 = client.on('consultation:error', ({ error }) => {
    console.error('Error:', error);
  });
  const consultation = await client.consultations.start({
    mode: 'FACE_TO_FACE'
  });
  ```

  **Type migrations**

  ```typescript theme={null}
  // Before (deprecated)
  interface MyConsultation extends StartConsultationInput {
    integration?: {
      system: IntegrationSystem;
      label?: string; // Deprecated
    };
    onConsultationComplete?: (result: ConsultationOutput, finish: () => Promise<void>) => void; // Deprecated
    onError?: (error: TortusError) => void; // Deprecated
  }

  // After (v1.0.0+)
  interface MyConsultation extends StartConsultationInput {
    integration?: {
      system: IntegrationSystem;
    };
  }
  ```

  **Consultation data access**

  ```typescript theme={null}
  // Before (v0.x with encounter nesting)
  const consultation = await client.consultations.start({
    mode: 'FACE_TO_FACE',
    encounter: {
      reference: 'my-ref',
      customFields: { myField: 'value' },
      metadata: { integrationRef: 'ext-123' }
    }
  });
  console.log('Custom field:', consultation.encounter.customFields.myField);
  console.log('Metadata:', consultation.encounter.metadata.integrationRef);

  // After (v1.0.0+ with flattened structure)
  const consultation = await client.consultations.start({
    mode: 'FACE_TO_FACE',
    reference: 'my-ref',
    customFields: { myField: 'value' },
    metadata: { integrationRef: 'ext-123' }
  });
  console.log('Mode confirmed:', consultation.mode); // NEW: confirms what mode was started
  console.log('Custom field:', consultation.customFields.myField);
  console.log('Metadata:', consultation.metadata.integrationRef);
  ```

  **Consultation results access**

  ```typescript theme={null}
  // Before (v0.x with metadata in result)
  client.on('consultation:completed', ({ result }) => {
    console.log('Reference:', result.reference);
    console.log('Mode:', result.mode);
    console.log('Custom fields:', result.customFields);
    console.log('Patient:', result.patient);
    console.log('Integration:', result.integration);
    console.log('Artifacts:', result.artifacts);
  });

  // After (v1.0.0+ with metadata in consultation object)
  client.on('consultation:completed', ({ consultation, result }) => {
    // All metadata is in the consultation object
    console.log('Reference:', consultation.reference);
    console.log('Mode:', consultation.mode);
    console.log('Custom fields:', consultation.customFields);
    console.log('Patient:', consultation.patient);
    console.log('Integration:', consultation.integration);

    // Result now contains only artifacts
    console.log('Artifacts:', result.artifacts);
  });
  ```

  **Artifact handling**

  ```typescript theme={null}
  // Before (deprecated)
  client.on('consultation:completed', ({ result }) => {
    console.log('Transcription:', result.artifacts.transcription); // Always empty string
    console.log('Notes:', result.artifacts.medicalNotes);
  });

  // After (v1.0.0+)
  client.on('consultation:completed', ({ result }) => {
    console.log('Notes:', result.artifacts.medicalNotes);
    console.log('Letter:', result.artifacts.letter);
    console.log('Codes:', result.artifacts.medicalCodes);
  });
  ```

  **Error handling**

  ```typescript theme={null}
  // Before (v0.x)
  try {
    await consultation.close();
  } catch (error) {
    if (error.code === 'CLIENT_4011') { // User cancelled
      console.log('User cancelled the operation');
    }
  }

  // After (v1.0.0+)
  try {
    await consultation.close();
  } catch (error) {
    if (error.code === 'CLIENT_4008') { // User cancelled operation
      console.log('User cancelled the operation');
    }
    // Recommended: Use error type instead of code for better maintainability
    if (error.type === 'application_user_cancelled') {
      console.log('User cancelled the operation');
    }
  }
  ```

  **Logger configuration**

  ```typescript theme={null}
  // Before (v0.x) - Custom logger was supported but undocumented
  const client = await loadTortus({
    publishableKey: 'pk_...',
    container: '#tortus-container',
    debug: true,
    logger: (level, message, data) => {
      // Custom logging logic
      myLogger.log(`[${level}] ${message}`, data);
    }
  });

  // After (v1.0.0+) - Always uses console when debug is enabled
  const client = await loadTortus({
    publishableKey: 'pk_...',
    container: '#tortus-container',
    debug: true // Now always logs to console.log/warn/error
  });
  ```
</Update>
