The Corti Embedded Assistant API enables seamless integration of Corti Assistant into host applications, such as Electronic Health Record (EHR) systems, web-based clinical portals, or native applications using embedded WebViews. The implementation provides a robust, consistent, and secure interface for parent applications to control and interact with embedded Corti Assistant.
The details outlined below are for you to embed the Corti Assistant “AI scribe solution” natively within your application. To lean more about the full Corti API, please see more
here
Overview
This implementation provides a robust, consistent, and secure interface for parent applications to control and interact with the embedded Corti Assistant. The API supports both asynchronous (postMessage) and synchronous (window object) integration modes.
Integration Modes
1. PostMessage API
This method is recommended for iFrame/WebView integration
Secure cross-origin communication
Works with any iframe or WebView implementation
Fully asynchronous with request/response pattern
<!-- Load the embedded Corti iframe -->
< iframe id = "corti-iframe" src = "/embedded" width = "100%" height = "600px" ></ iframe >
< script >
const iframe = document.getElementById('corti-iframe');
let isReady = false;
// Listen for the ready event
window.addEventListener('message', async (event) => {
if ( event . data ?. type === 'CORTI_EMBEDDED_EVENT' && event . data . event === 'ready' ) {
isReady = true ;
console.log( 'Corti embedded app is ready' );
// Start the integration flow
await authenticateUser();
}
});
async function authenticateUser() {
// Send authentication request
iframe.contentWindow.postMessage({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'auth' ,
requestId: 'auth-1' ,
payload: {
mode: 'stateful' ,
accessToken: 'your-access-token' ,
refreshToken: 'your-refresh-token'
}
}, '*' );
}
</ script >
See all 33 lines
2. Window API
This method is recommended for direct integration
Synchronous typescript API via window.CortiEmbedded
Promise-based methods
Ideal for same-origin integrations
// Wait for the embedded app to be ready
window . addEventListener ( 'message' , async ( event ) => {
if ( event . data ?. type === 'CORTI_EMBEDDED_EVENT' && event . data . event === 'ready' ) {
// Use the window API directly
const api = window . CortiEmbedded . v1 ;
const user = await api . auth ({
mode: 'stateful' ,
accessToken: 'your-access-token' ,
refreshToken: 'your-refresh-token'
});
console . log ( 'Authenticated user:' , user );
}
});
See all 14 lines
Authentication
Authenticate the user session with the embedded app:
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'auth' ,
requestId: 'unique-id' ,
payload: {
mode: 'stateless' | 'stateful' , // we currently do not take this value into account and will always refresh the token internally
access_token: string ,
refresh_token? : string ,
id_token? : string ,
expires_in? : number ,
token_type? : string
}
}, '*' );
See all 14 lines
Create interaction
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'createInteraction' ,
payload: {
assignedUserId: null ,
encounter: {
identifier: `encounter- ${ Date . now () } ` ,
status: "planned" ,
type: "first_consultation" ,
period: {
startedAt: new Date (). toISOString (),
},
title: "Initial Consultation" ,
},
patient: {
identifier: "brief-clinical-note-en" ,
},
}, '*' );
See all 19 lines
Add Facts
Add contextual facts to the current interaction:
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'addFacts' ,
requestId: 'unique-id' ,
payload: {
facts: [
{ text: "Chest pain" , group: "other" },
{ text: "Shortness of breath" , group: "other" },
{ text: "Fatigue" , group: "other" },
{ text: "Dizziness" , group: "other" },
{ text: "Nausea" , group: "other" },
]
}
}, '*' );
See all 15 lines
Set session-level defaults and preferences:
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'configureSession' ,
requestId: 'unique-id' ,
payload: {
defaultLanguage: 'en' ,
defaultOutputLanguage: 'en' ,
defaultTemplateKey: 'soap_note' ,
defaultMode: 'virtual'
}
}, '*' );
See all 12 lines
Navigate
Navigate to a specific path within the embedded app:
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'navigate' ,
requestId: 'unique-id' ,
payload: {
path: '/session/interaction-123'
}
}, '*' );
See all 9 lines
Recording controls
Start and stop recording within the embedded session:
// Start recording
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'startRecording' ,
requestId: 'unique-id'
}, '*' );
// Stop recording
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'stopRecording' ,
requestId: 'unique-id'
}, '*' );
See all 15 lines
Events
The embedded app sends events to notify the parent application of important state changes:
Event Types
ready
Embedded app is loaded and ready loaded
Navigation to a specific path completed recordingStarted
Recording has started recordingStopped
Recording has stopped documentGenerated
A document has been generated documentUpdated
A document has been updated documentSynced
A document has been synced to EHR
Listening for Events
window . addEventListener ( 'message' , ( event ) => {
if ( event . data ?. type === 'CORTI_EMBEDDED_EVENT' ) {
switch ( event . data . event ) {
case 'ready' :
console . log ( 'Embedded app ready' );
break ;
case 'documentGenerated' :
console . log ( 'Document generated:' , event . data . payload . document );
break ;
case 'recordingStarted' :
console . log ( 'Recording started' );
break ;
// ... handle other events
}
}
});
See all 16 lines
Complete Integration Flow
Here’s a complete example showing the recommended integration steps:
Example Embedded Integration
// State management
let iframe = null ;
let isReady = false ;
let currentInteractionId = null ;
let pendingRequests = new Map ();
// Initialize the integration
function initializeCortiEmbeddedIntegration ( iframeElement ) {
iframe = iframeElement ;
isReady = false ;
currentInteractionId = null ;
setupEventListeners ();
}
function setupEventListeners () {
window . addEventListener ( 'message' , ( event ) => {
if ( event . data ?. type === 'CORTI_EMBEDDED_EVENT' ) {
handleEvent ( event . data );
}
});
}
function handleEvent ( eventData ) {
switch ( eventData . event ) {
case 'ready' :
isReady = true ;
startIntegrationFlow ();
break ;
case 'documentGenerated' :
onDocumentGenerated ( eventData . payload . document );
break ;
// ... handle other events
}
}
async function startIntegrationFlow () {
try {
// 1. Authenticate
await authenticate ();
// 2. Configure session
await configureSession ();
// 3. Create interaction
const interaction = await createInteraction ();
// 4. Add relevant facts
await addFacts ();
// 5. Navigate to interaction UI
await navigateToSession ( interaction . id );
console . log ( 'Integration flow completed successfully' );
} catch ( error ) {
console . error ( 'Integration flow failed:' , error );
}
}
async function authenticate () {
return new Promise (( resolve , reject ) => {
const requestId = generateRequestId ();
pendingRequests . set ( requestId , { resolve , reject });
iframe . contentWindow . postMessage ({
type: 'CORTI_EMBEDDED' ,
version: 'v1' ,
action: 'auth' ,
requestId ,
payload: {
mode: 'stateful' ,
accessToken: 'your-accesstoken' ,
refreshToken: 'your-refreshtoken' ,
...
}
}, '*' );
});
}
// Usage example:
const iframeElement = document . getElementById ( 'corti-iframe' );
initializeCortiEmbeddedIntegration ( iframeElement );
See all 83 lines
Error Handling
All API methods can throw errors. Always wrap calls in try-catch blocks:
try {
const api = window . CortiEmbedded . v1 ;
const user = await api . auth ( authPayload );
console . log ( 'Authentication successful:' , user );
} catch ( error ) {
console . error ( 'Authentication failed:' , error . message );
// Handle authentication failure
}
See all 8 lines