Skip to main content

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.

The PostMessage API enables secure cross-origin communication between your application and the embedded Corti Assistant. This method is suitable for iframe or WebView integrations requiring fine-grained control over the iframe lifecycle.
Web Component API is recommended. The Web Component API provides the same functionality with a simpler interface. PostMessage API remains fully supported but involves unnecessary complexity. It is not deprecated.
Web Component has full working examples. Complete, runnable examples are available for the Web Component integration method, which is the recommended approach for most integrations. PostMessage API examples demonstrating the lower-level protocol will be added to the repository in the future.

Overview

The PostMessage API uses the browser’s postMessage mechanism to enable secure communication between your application and the embedded Corti Assistant, even when they’re served from different origins. This makes it ideal for embedding Corti Assistant in iframes or WebViews.

Requirements

Before getting started, ensure you have:
  • Access to Corti Assistant: You’ll need credentials and access to one of the available regions
  • HTTPS: The embedded Assistant must be loaded over HTTPS (required for microphone access)
  • Microphone permissions: Your application must request and handle microphone permissions appropriately
  • OAuth2 client: You’ll need an OAuth2 client configured for user-based authentication
  • Modern browser or WebView: For web applications, use a modern browser. For native apps, use a modern WebView

Recommendations

  • Validate message origins to ensure security
  • Use specific target origins instead of '*' when possible
  • Implement proper error handling for all API calls
  • Handle authentication token refresh to maintain user sessions
  • Request microphone permissions before initializing the embedded Assistant

Available regions

Features

  • Secure cross-origin communication
  • Works with any iframe or WebView implementation
  • Fully asynchronous with request/response pattern

Quick start

Step 1: Set up authentication

Before using the PostMessage API, authenticate your users using OAuth2. See the Authentication Guide for complete setup instructions including Authorization Code Flow with PKCE (recommended), obtaining tokens, and handling token refresh.
All Embedded Assistant integrations require user-based OAuth2 authentication. Client credentials and machine-to-machine flows are not supported.
  • Handle token refresh to maintain sessions
  • Never expose client secrets in client-side code

Step 2: Load the Embedded Assistant

Load the Corti Assistant in an iframe or WebView:

Required iframe allow permissions

When you embed Corti Assistant in an iframe, you must delegate the browser permissions that the embedded app needs.
  • microphone is required for recording and dictation
  • display-capture is required if you use virtual recording to capture audio from another tab, window, or screen
  • clipboard-write is recommended so users can copy generated content reliably across browsers
Use the allow attribute on the iframe:
<iframe
  id="corti-iframe"
  src="https://assistant.eu.corti.app/embedded"
  width="100%"
  height="600px"
  allow="microphone; display-capture; clipboard-write"
></iframe>
These examples omit * intentionally. In an iframe allow attribute, each feature defaults to the iframe src origin, which is the safer default for Corti Assistant embeds. Use feature * only if you explicitly want to grant that permission to any origin the iframe might later navigate to.
If you omit allow="microphone" on the iframe, the embedded Assistant cannot access the user’s microphone even if the site itself has microphone permission.
If you support virtual mode, include display-capture so the embedded Assistant can request browser-managed capture of remote audio streams.
<!-- Load the embedded Corti iframe -->
<iframe
  id="corti-iframe"
  src="https://assistant.eu.corti.app/embedded"
  width="100%"
  height="600px"
  allow="microphone; display-capture; clipboard-write"
></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 === 'embedded.ready') {
    isReady = true;
    console.log('Corti embedded app is ready');

    // Authenticate the user (requires OAuth2 tokens)
    await authenticateUser();
  }
});

async function authenticateUser() {
  // Send authentication request with OAuth2 tokens
  iframe.contentWindow.postMessage({
    type: 'CORTI_EMBEDDED',
    version: 'v1',
    action: 'auth',
    requestId: 'auth-1',
    payload: {
      access_token: 'your-access-token', // From OAuth2 flow
      refresh_token: 'your-refresh-token', // From OAuth2 flow
      id_token: "your-id-token", // From OAuth2 flow
      token_type: "Bearer",
    }
  }, '*');
}
</script>

Message format

All messages sent to the embedded app follow this structure:
{
  type: 'CORTI_EMBEDDED',
  version: 'v1',
  action: string,
  requestId?: string,
  payload?: object
}

Message properties

  • type: Always 'CORTI_EMBEDDED'
  • version: API version (currently 'v1')
  • action: The method to invoke (see API Reference for all methods)
  • requestId: Optional unique identifier for tracking responses
  • payload: Optional data specific to the action

Same API as Web Component

The PostMessage API provides access to the same methods documented in the API Reference - auth, configure, createInteraction, etc. - with identical parameters and behavior. Key difference: Instead of direct method calls that return Promises, you communicate through messages:
  1. Send a message with action field matching the method name
  2. Receive the response asynchronously via a separate CORTI_EMBEDDED_RESPONSE message
Example for auth:
// Web Component: Direct call with Promise
const user = await api.auth({
  access_token,
  refresh_token,
  id_token,
  token_type,
});

// PostMessage: Send message, listen for response
iframe.contentWindow.postMessage(
  {
    type: "CORTI_EMBEDDED",
    version: "v1",
    action: "auth", // Method name goes here
    requestId: "auth-1",
    payload: { access_token, refresh_token, id_token, token_type },
  },
  "*",
);

// Later, in your message listener:
window.addEventListener("message", (event) => {
  if (
    event.data.type === "CORTI_EMBEDDED_RESPONSE" &&
    event.data.requestId === "auth-1"
  ) {
    const user = event.data.payload; // Same result as Web Component
  }
});
Same functionality, different invocation pattern.

Response handling

Responses from the embedded app are sent via postMessage and can be identified by checking the message type:
window.addEventListener("message", (event) => {
  // Handle responses
  if (event.data?.type === "CORTI_EMBEDDED_RESPONSE") {
    const { requestId, success, payload, error } = event.data;
    // Handle response
  }

  // Handle events
  if (event.data?.type === "CORTI_EMBEDDED_EVENT") {
    const { event: eventType, payload } = event.data;
    // Handle event
  }
});

Events

Corti Assistant dispatches events to notify your application of state changes and important updates. When using the PostMessage API, these events are wrapped in the CORTI_EMBEDDED_EVENT message type.

Event format translation

Core events documented in the Events Reference are wrapped for postMessage delivery: Core Event Structure:
{
  "event": "recording.started",
  "confidential": false,
  "payload": {
    "mode": "dictation",
    "language": "en",
    "interactionId": "int_123"
  }
}
PostMessage wrapper:
{
  "type": "CORTI_EMBEDDED_EVENT",
  "event": "recording.started",
  "confidential": false,
  "payload": {
    "mode": "dictation",
    "language": "en",
    "interactionId": "int_123"
  }
}

Listening for events

Set up a message listener to receive events from the embedded Assistant:
Listening for Events
const ALLOWED_ORIGINS = [
  "https://assistant.eu.corti.app",
  "https://assistantmd.eu.corti.app",
  "https://assistant.us.corti.app",
];

window.addEventListener("message", (event) => {
  // Validate origin for security
  if (!ALLOWED_ORIGINS.includes(event.origin)) {
    return;
  }

  // Check for Corti events
  if (event.data?.type === "CORTI_EMBEDDED_EVENT") {
    const { event: eventName, confidential, payload } = event.data;

    // Handle different event types
    switch (eventName) {
      case "recording.started":
        console.log("Recording started:", payload);
        break;
      case "recording.paused":
        console.log("Recording paused:", payload);
        break;
      case "document.generated":
        console.log("Document generated:", payload);
        handleDocumentGenerated(payload);
        break;
      case "error.triggered":
        console.error("Error occurred:", payload);
        break;
      default:
        console.log("Unknown event:", eventName, payload);
    }
  }
});

function handleDocumentGenerated(payload) {
  const { documentId, documentName, interactionId } = payload;
  // Update your UI, sync to backend, etc.
}

Available events

For a complete list of events and their payload structures, see the Events Overview. Common events include:
  • recording.started - Recording has started
  • recording.paused - Recording has paused
  • document.generated - Document has been generated
  • document.updated - Document has been edited
  • document.synced - Document synced to external system
  • error.triggered - An error occurred

Legacy events

The embedded Assistant also dispatches legacy events using camelCase names (e.g., recordingStarted, documentGenerated). These are deprecated and will be removed in a future version.

Error handling

Always handle errors when making requests:
Error Handling
try {
  const result = await sendMessage("auth", {
    accessToken: "your-access-token",
    refreshToken: "your-refresh-token",
    id_token: "your-id-token",
    token_type: "Bearer",
  });
  console.log("Authentication successful:", result);
} catch (error) {
  console.error("Authentication failed:", error.message);
  // Handle authentication failure
}

Security considerations

When using postMessage, always:
  1. Validate message origin: Check event.origin to ensure messages come from trusted sources
  2. Use specific target origins: Replace '*' with the specific origin when possible
  3. Sanitize data: Never trust data from postMessage without validation
Security Best Practices
const ALLOWED_ORIGINS = [
  "https://assistant.eu.corti.app",
  "https://assistantmd.eu.corti.app",
  "https://assistant.us.corti.app",
];

window.addEventListener("message", (event) => {
  // Validate origin
  if (!ALLOWED_ORIGINS.includes(event.origin)) {
    console.warn("Message from untrusted origin:", event.origin);
    return;
  }

  // Process message
  if (event.data?.type === "CORTI_EMBEDDED_EVENT") {
    // Handle event
  }
});

// Send messages with specific origin
iframe.contentWindow.postMessage(
  {
    type: "CORTI_EMBEDDED",
    version: "v1",
    action: "auth",
    payload: {
      /* ... */
    },
  },
  "https://assistant.eu.corti.app",
); // Specific origin instead of '*'

Next steps

Please contact us for help or questions.