# Claude Code guidelines for this docs repo Source: https://developer.suki.ai/CLAUDE Claude Code guidelines for this docs repo Use this file when editing Suki developer documentation with Claude Code. For repo layout, navigation IA, release notes, and SDK product boundaries, also read [AGENTS.md](AGENTS.md). For writing rules, follow [STYLE\_GUIDE.md](STYLE_GUIDE.md). ## Audience Primary readers are partner engineers integrating Suki APIs and SDKs into healthcare applications. They know REST, JSON, and OAuth/JWT basics. Prefer task-ready guidance over explaining those primitives unless the page is explicitly introductory. ## Terminology Use published product names and casing from the style guide and Vale: * **Form filling**, **Form filling SDK**, **Form filling API(s)** in body prose; **Form Filling** / **Form Filling SDK** / **Form Filling API(s)** in Card / Tab / nav / frontmatter titles * Mid-sentence **ambient** as a common adjective (`ambient session`); **Ambient** as product list / sentence-start / UI chrome; **Ambient API(s)** as the product name * **Dictation**, **Patient Summary**, **Partner ID**, **Partner Token**, **Suki Token**, **WebSocket** * Keep code identifiers exact: `InitOptions`, `SukiAuthManager`, `PlatformClient`, `DictationClient` Do not invent alternate product names (for example “organization” for partner, or “token” when the docs say Partner Token / Suki Token). ## Content types Identify the page type before editing. Prefer one type per page: | Type | Does | Does not | | --------------------- | ------------------------------------ | -------------------------------- | | Concept / explanation | What and when | Full implementation walkthroughs | | How-to | One job, steps a developer can run | Long conceptual essays | | Tutorial | End-to-end lesson | Exhaustive API surface coverage | | Reference | Contracts, payloads, frames, options | Narrative onboarding | If a how-to needs a concept, link to the concept page instead of restating it. ## Style * Sentence case for H2/H3; no trailing `?` on How/What/Why headings * Oxford comma; no em dashes; active voice; present tense * Sentence case for Next steps and body link text; preserve protected product tokens * Do not restate the title in the first sentence * Do not invent product behavior; ask when ground truth is missing * Do only what was asked; no drive-by refactors ## Documentation access Published docs serve Markdown at the same path with `.md` appended. Prefer those when fetching live pages: Example: `https://developer.suki.ai/documentation/get-started/overview.md` Agent indexes and skills: * `https://developer.suki.ai/llms.txt` (curated page index) * `https://developer.suki.ai/.well-known/agent-skills/index.json` * `https://developer.suki.ai/mcp` ## Git Do not commit or push unless the user explicitly asks. # A Source: https://developer.suki.ai/Glossary/a Glossary terms starting with A

A

| Term | Definition | | :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ABORT** | A WebSocket streaming event that terminates the current audio stream due to interruption while keeping the session active for later resumption. Note generation continues with audio received before interruption. | | **ACO** | Accountable Care Organization. A healthcare group that coordinates care for a defined patient population and shares accountability for cost and quality outcomes. ACOs often care about structured diagnosis and HCC-related data in documentation workflows. | | **AES-256** | Advanced Encryption Standard with 256-bit key length. A symmetric encryption algorithm used by Suki to encrypt data at rest. | | **Allergies** | A clinical note section (LOINC: 48765-2) that lists known allergic reactions and adverse responses that can change treatment decisions. In Suki, pass this LOINC code in ambient session sections when you want allergy content captured in the generated note. | | **Allowlist** | A security mechanism where specific domains, IPs, or URLs are explicitly permitted. Partners must allowlist Suki domains in their firewall or WAF settings for SDK and API connectivity. | | **Ambient API** | The specific set of APIs used to create clinical notes from conversations. | | **ambient session** | A single, time-bound instance of an ambient recording for a specific patient encounter that captures clinical conversations. | | **Auto Onboarding** | A streamlined process where new providers are automatically registered in the Suki platform during their first authentication, without requiring manual setup. | | **API** | Application Programming Interface. A set of rules and tools for building software and applications. | | **ASR** | Automatic Speech Recognition. Technology that converts speech into text. Suki uses ASR to produce clinical transcripts that feed ambient note generation and Dictation experiences. | | **Assessment** | A clinical note section (LOINC: 51848-0) for the clinician's interpretation of the patient's condition. In Suki, pass this LOINC code when you want assessment content in the generated note. For Problem-Based Charting, prefer Assessment and Plan (LOINC: 51847-2) as the PBN section. | | **Assessment and Plan** | A clinical note section (LOINC: 51847-2) that combines the clinician's assessment with the treatment plan. In Suki, this is the default Problem-Based Note (PBN) section when you enable Problem-Based Charting and omit `isPBNSection` while `51847-2` is present. | | **Audio Chunking** | The process of dividing continuous audio streams into smaller segments. Suki requires 100ms audio packets for optimal performance and latency balance. |
# B Source: https://developer.suki.ai/Glossary/b Glossary terms starting with B

B

| Term | Definition | | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Background Processing** | The capability of SDK features to run passively during consultations without disrupting the provider's workflow, such as ambient note generation. | | **BAA** | Business Associate Agreement. A HIPAA-required contract that defines how a vendor like Suki may create, receive, maintain, or transmit protected health information on behalf of a covered entity. | | **Base64 Encoding** | A method of encoding binary data (like audio) into ASCII text format for transmission over text-based protocols like WebSocket. | | **Bearer Token** | An authentication token format where the token holder ("bearer") is granted access to resources. Used in HTTP Authorization headers. | | **Bitrate** | The amount of data processed per unit of time in audio streaming. Suki requires 768kbps bitrate for optimal performance. |
# C Source: https://developer.suki.ai/Glossary/c Glossary terms starting with C

C

| Term | Definition | | :--------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Callback URL** | An endpoint URL registered by a partner to receive webhook event notifications from Suki, such as session completion or note generation events. | | **CANCEL** | A WebSocket streaming event that terminates the current ambient session entirely, discarding all captured audio and preventing note generation. | | **CDN** | Content Delivery Network. A distributed network of servers that delivers web content to users based on geographic proximity, used for hosting SDK assets. | | **Chief Complaint** | A clinical note section (LOINC: 10154-3) for the main reason for the visit, often in the patient's own words. In Suki, pass this LOINC code in ambient session sections when you want chief complaint content in the generated note. | | **Clinic** | An outpatient care location where patients are seen. In partner structures, clinics often sit under a larger organization that integrates Suki for documentation across sites. | | **Client SDK** | An SDK that runs on the end-user device (browser or native app) rather than on your backend server. All Suki SDKs are Client SDKs. Headed or headless describes whether the SDK ships UI, not where it runs. See [Headed SDK](/Glossary/h) and [Headless SDK](/Glossary/h). | | **Clinical Note** | The structured medical documentation produced for a patient encounter. In Suki, ambient note generation organizes content into LOINC-coded sections so partners can review, edit, and submit notes into an EHR-ready workflow. | | **Clinical Workflows** | Repeatable care and documentation processes used in clinics and hospitals, from intake through charting and follow-up. Suki products plug into these workflows so providers can capture visits and produce documentation without leaving their primary application. | | **Clinician** | A care delivery professional who works directly with patients. In Suki docs, clinician is often used interchangeably with provider when describing who captures visits and reviews generated notes. | | **CKG** | Clinical Knowledge Graph. Suki's store for partner-ingested FHIR clinical data used to generate Patient Summaries. Summaries reflect only the data available in CKG at generation time. | | **CKG Data Ingestion** | The Patient Summary workflow that uploads FHIR bundles into CKG: request a pre-signed upload URL, upload the bundle, then poll ingestion status until processing completes. Required before you generate a Patient Summary. | | **Composition ID** | Identifier returned as `composition_id` from ambient session create for the note artifact linked to the session. Use it as `note_id` with note-level Ambient APIs. | | **Context-Aware Processing** | Suki's approach to reading clinical conversation in context and placing content into the right note sections. It uses visit cues and configured LOINC sections so generated documentation follows clinical structure instead of a raw transcript dump. | | **Correlation ID** | Your encounter or appointment ID passed as correlation\_id when starting a Form filling SDK session. Suki returns it in SDK callbacks and partner webhooks so you match structured results to the correct patient record. |
# D Source: https://developer.suki.ai/Glossary/d Glossary terms starting with D

D

| Term | Definition | | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **De-identification** | Removing or obscuring identifiers so data can no longer reasonably identify a person. Suki applies de-identification practices to training-oriented transcripts and related assets while keeping production documentation workflows HIPAA-aware. | | **Diagnosis** | The clinician's determination of a patient's condition or disease. In interoperability workflows, diagnoses are often encoded with ICD10 or SNOMED so EHR, analytics, and billing systems share the same meaning. | | **Diagnosis Context** | Structured diagnosis metadata (code, code type, and description) you pass in ambient session context. Suki uses it to improve problem-oriented note generation and keep generated content aligned with known problems. | | **Dictation** | Speaking content that should become text, typically a clinician monologue. In Suki, Dictation workflows focus on real-time transcription, which is separate from full ambient note generation from multi-party visits. | | **Differential Diagnosis** | A working list of possible conditions that could explain the patient's symptoms while the clinician narrows toward a final diagnosis. It is a clinical reasoning concept that can appear in assessment-style documentation. |
# E Source: https://developer.suki.ai/Glossary/e Glossary terms starting with E

E

| Term | Definition | | :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Early Access** | A phase where new features or APIs are available to select partners before general availability, such as the ambient Clinician Note Generation API. | | **EHR** | Electronic Health Record. The longitudinal digital chart for a patient across care settings. Partners integrate Suki so generated notes and structured clinical data can flow into the EHR clinicians already use. | | **EMR** | Electronic Medical Record. Digitized clinical records maintained in a care setting, often within one organization. Partners commonly map Suki note output into EMR charting fields alongside broader EHR interoperability goals. | | **EMR Encounter ID** | The partner EMR or EHR visit identifier (`emr_encounter_id`) that anchors interoperable ambient notes across modalities. Required for cross-modality ambient workflows. Must be a UUID today. Distinct from the Ambient API `encounter_id` field. | | **Encounter** | One patient visit or appointment with a healthcare provider. In Suki, an encounter can group one or more ambient sessions so related recordings and notes stay tied to the same clinical visit. | | **Encounter Content** | The aggregated clinical note content for a full patient encounter, combining output from one or more ambient sessions under the same encounter ID. | | **Encounter ID** | In ambient session create, `encounter_id` groups re-ambient sessions for one note (up to 255 characters). Reuse the same value for every re-ambient session on that note. Do not confuse it with **EMR Encounter ID** (`emr_encounter_id`). In Web SDK, the encounter identifier maps to `emr_encounter_id`. | | **Encounter Type** | A label for the kind of visit, such as office visit, follow-up, or new patient. In Suki, encounter type is session context that helps guide how notes are generated for that visit pattern. | | **Encryption at Rest** | The protection of stored data by encrypting it when saved on disk or in databases. Suki uses AES-256 encryption for data at rest. | | **Encryption in Transit** | The protection of data while it moves between systems over networks. Suki uses TLS 1.2 for data transmission encryption. | | **EOF** | End of File. A WebSocket streaming event that indicates the closure or completion of an audio stream. | | **ES6** | ECMAScript 2015, a version of JavaScript that includes modern features like arrow functions, classes, and modules. Required for browser compatibility with Suki Web SDK. |
# F Source: https://developer.suki.ai/Glossary/f Glossary terms starting with F

F

| Term | Definition | | :------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Family History** | A clinical note section (LOINC: 10157-6) for relevant conditions among the patient's biological relatives. In Suki, pass this LOINC code when you want family history captured in the generated note. | | **Federated Authentication** | An authentication model where multiple systems trust a single identity provider, allowing users to access multiple services with one set of credentials. | | **FHIR** | Fast Healthcare Interoperability Resources. An HL7 standard for exchanging healthcare data as structured resources (for example Patient or Encounter). Partners use FHIR-oriented patterns when integrating Suki outputs with modern health IT systems, and upload FHIR data into CKG for Patient Summary. | | **FHIR Bundle** | A FHIR resource collection partners upload during **CKG Data Ingestion** so Suki can store encounter, patient, practitioner, and history data for Patient Summary generation. Keep identifiers in the bundle consistent with the IDs you pass when you generate and retrieve summaries. | | **Form filling** | AI-powered workflow that populates Suki Medical form templates from visit conversation. Use **Form filling** for the capability; use **Form filling API** for the REST product. | | **Form filling API** | REST APIs for voice-driven medical form sessions: create and manage sessions, stream audio over the Partner WebSocket, and retrieve structured form output. | | **Form filling SDK** | JavaScript and React library that embeds Form filling in your web app with a hosted iframe. Handles sign-in, the Form filling UI, and SDK callbacks so you do not build the full Form filling API workflow yourself. | | **Form filling Session** | A time-bound visit session for capturing conversation and generating structured medical form output. REST responses return its ID as `ambient_session_id`. That value is not the same as an **ambient session** ID from the Ambient API even though the field name matches. | | **Form filling Session Context** | Patient, provider, encounter, and Medical form template metadata you seed or update for a Form filling session through **Form filling API** context endpoints. | | **FormFillingClient** | Main class in the Form filling SDK. Create it with a configured auth manager, then call start() to open a Form filling session in a container on your page. | | **Full Summary** | The complete Patient Summary object returned after a summary job finishes. Use it for chart review; use **Pre-Visit Summary** when you need only the schedule-preview section. |
# G Source: https://developer.suki.ai/Glossary/g Glossary terms starting with G

G

| Term | Definition | | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | | **GA** | General Availability. The release stage where a feature, API, or SDK version is fully supported, stable, and available to all partners for production use. |
# Suki Developer Platform Glossary Source: https://developer.suki.ai/Glossary/glossary Browse glossary terms by category, letter, and search. Use the category and letter filters to narrow the list

Glossary

Welcome to the Suki Developer Platform Glossary. If you are new here and not sure what a term means? Search and filter below, or open A-Z letter pages under Documentation > Resources > Glossary to learn more about each term.

An **Encounter** is the clinical visit context (patient, provider, appointment). An **ambient session** is one recording instance Suki uses to capture audio and generate a note for that visit. **Session ID (Web SDK)** is the Web SDK **ambient session** identifier (`ambientId` / `activeAmbientId`). **Encounter ID** on the Web SDK **Note Submission** payload is your EHR visit identifier (maps to **EMR Encounter ID**). They are not interchangeable. **Session ID (Ambient APIs)** is `ambient_session_id` from Create ambient session, used for session-scoped Ambient API calls. **Session ID (Web SDK)** is `ambientId` / `activeAmbientId` in the Headed Web SDK. Both identify one ambient recording session in their own product. **Note ID (Ambient APIs)** is the interoperable note identifier: Create ambient session returns `composition_id`, and you pass that value as `note_id` to note-level Ambient APIs. **Note ID (Web SDK)** is `noteId` on Web SDK note submission payloads (`onNoteSubmit` / `note-submission:success`). **Encounter ID** is the Ambient API `encounter_id` field used to group re-ambient sessions for the same note. **EMR Encounter ID** is your EMR or EHR visit identifier (`emr_encounter_id`) that makes notes interoperable across modalities. Do not treat them as the same field. Your identity provider issues the **Partner Token** (JWT). Suki login returns a **Suki Token** access token you use for REST and SDK calls. **Partner ID** identifies your organization in Suki. **Provider ID** identifies the clinician or user within that organization. **Form filling** is the workflow that populates Medical form templates from conversation. The **Form filling API** is the REST product for programmatic Form filling sessions. The **Form filling SDK** embeds Form filling in the browser with a hosted iframe and SDK callbacks. The **Form filling API** is the REST and WebSocket product when you build the full workflow in your own code. Both APIs may return a session ID as `ambient_session_id`, but a **Form filling Session** belongs to the **Form filling API**. An **ambient session** belongs to the Ambient API for clinical note generation. **Form filling Session Context** seeds patient, provider, and **Medical form template** data for a **Form filling Session**. **Session Context** is metadata for an **ambient session** that guides note generation. **Patient Summary** prepares clinicians with chart context before a visit using FHIR data in **CKG**. An **ambient session** captures conversation during the visit to generate a clinical note. A **Full Summary** is the complete Patient Summary object for chart review. A **Pre-Visit Summary** is the schedule-preview section of that same summary for UI display before the appointment. A **Transcription Session** captures speech-to-text for Dictation. An **ambient session** captures conversation for full clinical note generation with LOINC sections. The **Headed SDK** (Web SDK) ships pre-built UI components such as **Note Editor** and **Note Archive**. The **Headless SDK** exposes hooks and types so you build your own UI. **Dictation** is voice-to-text capture, often through the Dictation SDK. An **ambient session** runs the broader ambient workflow that produces structured clinical notes. The **Ambient API** creates clinical notes from conversations. The **Form filling API** fills Suki **Medical form template** schemas with structured form output. A **Clinical Note** is narrative documentation organized into LOINC sections. **Structured Data** is extracted, field-level information (diagnoses, medications, vitals) formatted for EHR integration.
# H Source: https://developer.suki.ai/Glossary/h Glossary terms starting with H

H

| Term | Definition | | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Headed SDK** | An SDK that includes pre-built or hosted User Interface (UI) components. The Web SDK is headed. The Dictation SDK and Form filling SDK use a hosted iframe UI. | | **Headless SDK** | An SDK that does not include pre-built UI components, so you build your own UI. The Headless Web SDK and Mobile SDK are headless. | | **Hosted iframe** | Suki-controlled UI loaded inside your web page. The Form filling SDK and Dictation SDK use a hosted iframe for recording, form selection, and processing while your app supplies layout and callbacks. | | **HCC** | Hierarchical Condition Category. A CMS risk-adjustment grouping derived from ICD10 diagnosis codes and used in value-based care programs. Suki returns HCC in ambient Structured Data output only, not as a note-section LOINC code. | | **HIPAA** | Health Insurance Portability and Accountability Act. U.S. law that sets privacy and security rules for protected health information. Suki healthcare customers operate under HIPAA expectations for how patient data is handled in documentation workflows. | | **HL7** | Health Level Seven International. The organization and family of standards for moving clinical and administrative data between healthcare applications. FHIR is part of the broader HL7 standards landscape partners meet in EHR integration. | | **HMAC** | Hash-based Message Authentication Code. A cryptographic method used to verify the integrity and authenticity of webhook payloads sent from Suki to partner endpoints. | | **Hospital** | An inpatient or acute-care facility with specialized staff and services. Hospital partners use Suki to support documentation across encounters that may span units, specialties, and EHR workflows. | | **HPI** | History of Present Illness. A clinical note section (LOINC: 10164-2) that describes how the patient's current problem developed over time. In Suki, pass this LOINC code when you want HPI content in the generated note. | | **HTTPS** | HyperText Transfer Protocol Secure. An extension of HTTP that uses encryption for secure communication over a network. |
# I Source: https://developer.suki.ai/Glossary/i Glossary terms starting with I

I

| Term | Definition | | :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ICD10** | International Classification of Diseases, 10th Revision. A WHO-maintained coding system for diagnoses, symptoms, and procedures. In Suki ambient Structured Data and related outputs, diagnosis codes often use ICD10 so results map cleanly into EHR problem lists and billing workflows. | | **Idempotency** | A property ensuring that performing the same API operation multiple times produces the same result, preventing duplicate processing of requests. | | **IDP** | Identity Provider. An acronym for a system that manages user identities and authenticates users. Examples include Okta, Auth0, Azure AD, and custom authentication systems. | | **IMO** | Intelligent Medical Objects. A clinical terminology and mapping platform that helps normalize medical concepts across coding vocabularies and EHR workflows. Partners may encounter IMO when aligning Suki diagnosis or problem content with their local terminologies. | | **Interoperability** | The ability of different systems, devices, or software applications to communicate, exchange data, and use that information seamlessly. In Suki ambient workflows, interoperability lets you start, continue, or re-ambient a clinical note across modalities (Ambient APIs, Mobile SDK, Headless Web SDK, and Web SDK) using a shared EMR encounter ID and note artifact. |
# J Source: https://developer.suki.ai/Glossary/j Glossary terms starting with J

J

| Term | Definition | | :------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Job Status (Patient Summary)** | The asynchronous generation state for a Patient Summary request. Poll until a terminal value such as `COMPLETED`, `FAILED`, or `ABORTED`, then retrieve the **Full Summary** or **Pre-Visit Summary**. | | **JWT** | JSON Web Token. A compact, URL-safe means of representing claims to be transferred between two parties, commonly used for authentication and information exchange. | | **JWKS** | JSON Web Key Set. A set of keys containing the public keys used to verify any JWT issued by the authorization server. | | **JWKS Endpoint** | A publicly accessible HTTPS endpoint that hosts cryptographic public keys for JWT token verification. |
# K Source: https://developer.suki.ai/Glossary/k Glossary terms starting with K

K

| Term | Definition | | :------------- | :------------------------------------------------------------------------------------------------------------------------------ | | **Keep Alive** | A WebSocket streaming event sent every 5 seconds during paused states to maintain connection and prevent timeout disconnection. |
# L Source: https://developer.suki.ai/Glossary/l Glossary terms starting with L

L

| Term | Definition | | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Latency** | The delay between sending audio data and receiving a response. Suki requires unloaded latency under 50ms and loaded latency under 150ms for optimal performance. | | **LINEAR16** | An uncompressed audio format with 16-bit depth, used for high-quality audio streaming to Suki's platform at 16KHz sampling rate. | | **LLM** | Large Language Model. Advanced AI models trained on vast amounts of text data to understand and generate human-like text, used by Suki for clinical note generation. | | **LOINC** | Logical Observation Identifiers Names and Codes. An international healthcare coding standard that assigns unique codes to clinical content such as note sections, labs, and observations. In Suki, you pass LOINC codes when you configure ambient note sections so each part of the generated note maps cleanly into your EHR. |
# M Source: https://developer.suki.ai/Glossary/m Glossary terms starting with M

M

| Term | Definition | | :---------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **MCP** | Model Context Protocol. An open standard that enables AI assistants and LLMs to securely connect with external data sources and tools, used by Suki for AI-powered documentation workflows. | | **Medically-tuned Dictation** | Speech recognition tuned for clinical vocabulary, abbreviations, and note-style phrasing. Suki uses medically tuned models so Dictation and ambient transcripts handle healthcare language more reliably than general-purpose ASR. | | **Medical form template** | A Suki-defined form schema identified by form\_template\_id. Enable templates for your partner account, then pass template\_id values in Form filling API sessions or Form filling SDK start() calls. | | **Medications** | A clinical note section (LOINC: 10160-0) for current medications, dosages, and prescription changes discussed in the visit. In Suki, pass this LOINC code when you want medication details in the generated note. Medication orders use a separate LOINC (`52471-0`) in the Web SDK. | | **Mental Status Exam** | A clinical note section (LOINC: 10190-7) for observations about cognition, mood, and related functioning during the encounter. In Suki, pass this LOINC code when you want mental status findings in the generated note. | | **Model Training** | The process of using de-identified and anonymized data to improve AI model performance. Suki uses this data to enhance clinical note generation capabilities. | | **Mono Channel** | Single-channel audio format required for Suki's platform, as opposed to stereo (dual-channel) audio. | | **Monologue** | Single-speaker audio, such as a clinician dictating alone. Dictation sessions are typically monologue-based, while ambient sessions often capture clinician-patient conversation. | | **Multilingual Support** | The ability to process clinical conversation across many spoken languages while producing the clinical note in English. Suki uses this so multilingual visits can still yield consistent English documentation for the chart. |
# N Source: https://developer.suki.ai/Glossary/n Glossary terms starting with N

N

| Term | Definition | | :------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Natural Language Voice Interaction** | Technology that allows users to interact with systems using spoken natural language commands and queries. | | **NLP** | Natural Language Processing. AI technology that helps computers understand, interpret, and generate human language. | | **Note** | In ambient interoperability, the clinical documentation artifact that groups ambient sessions under an EMR encounter. Create Session returns `composition_id`; use that value as `note_id` with note-level Ambient APIs. After finalize and submit to the EMR or EHR, the composition is treated as a finalized note. | | **Note Archive** | A Web SDK component that allows users to view and manage both current and historical clinical notes associated with a patient. | | **Note Editor** | A rich-text editing component in the Web SDK designed specifically for AI-generated clinical content, supporting editing, formatting, and section-level interaction. | | **Note Generation** | Suki's AI process that turns encounter audio and session context into a structured clinical note. Output follows the LOINC sections you configured for the ambient session. | | **Note ID (Ambient APIs)** | Unique identifier for an interoperable ambient note. Create ambient session returns `composition_id`; pass that value as `note_id` to note-level ambient endpoints such as note content, note context, and note structured data. | | **Note ID (Web SDK)** | The unique identifier for the generated note in the Headed Web SDK. It appears in the payload for the `onNoteSubmit` prop (React) and the `note-submission:success` event (React and JavaScript) when you complete **Note Submission**. | | **Note Section** | A labeled part of a clinical note identified by a LOINC code, such as HPI, Physical Exam, or Assessment and Plan. In Suki, you choose which note sections to generate by passing their LOINC codes in ambient session configuration. | | **Note Submission** | The step where a completed clinical note is finalized and handed to the partner application for EHR write-back or downstream storage. In SDKs, this is typically surfaced through note-submission callbacks or events. | | **Non-Generated Values** | **Form filling API** structured-data field (`non_generated_values`) listing `form_template_id` values for which Suki did not generate structured output in that **Form filling Session**. | | **Notification Webhook** | A server-to-server HTTP callback from Suki to a partner's registered endpoint, triggered by events such as note generation completion or session status changes. |
# O Source: https://developer.suki.ai/Glossary/o Glossary terms starting with O

O

| Term | Definition | | :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **OAuth 2.0** | An industry-standard authorization framework that enables secure delegated access to resources without sharing passwords. | | **Offline Mode** | A capability that allows certain SDK features to function without an internet connection, enabling users to work in environments with limited connectivity. | | **Offline Session** | An ambient session recorded while the device has no network connectivity. Audio is stored locally and automatically uploaded when connectivity is restored. | | **OpenAPI** | A specification for describing REST APIs in a machine-readable format, used by Suki to document API endpoints, request/response schemas, and authentication requirements. | | **OpenID Connect** | An authentication layer built on top of OAuth 2.0, providing identity verification and user information access. | | **Organization** | A healthcare entity or health system that partners with Suki. Organizations typically onboard providers, configure integration settings, and roll out Suki documentation capabilities across their sites. |
# P Source: https://developer.suki.ai/Glossary/p Glossary terms starting with P

P

| Term | Definition | | :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Partner** | An organization or company that integrates with Suki's platform to offer AI-powered clinical documentation services to their users. | | **Partner ID** | A unique identifier assigned by Suki during onboarding that links an application to its configuration in the Suki Developer Platform. | | **Partner Token** | A secure, digitally signed JWT issued by a partner's identity provider after user authentication, passed to Suki SDK for user verification. | | **Past Medical History** | A clinical note section (LOINC: 11348-0) for prior conditions, surgeries, hospitalizations, and other significant health events. In Suki, pass this LOINC code when you want past medical history in the generated note. | | **Past Surgical History** | A clinical note section (LOINC: 10167-5) for prior surgical procedures and related outcomes. In Suki, pass this LOINC code when you want surgical history in the generated note. | | **Patient Instructions** | A clinical note section (LOINC: 69730-0) for after-visit guidance, follow-up steps, and patient education. In Suki, pass this LOINC code when you want patient instructions in the generated note. | | **Patient Summary** | A concise overview of a patient's clinical history for pre-visit preparation. Partners ingest FHIR data into **CKG**, start asynchronous generation, then retrieve a **Full Summary** or **Pre-Visit Summary**. Distinct from Ambient note generation during a visit. | | **Patient Summary API** | REST APIs for Patient Summary: CKG data ingestion, summary generation, job status, and summary retrieval. Authenticate generation and retrieval with a Suki Token; CKG ingestion uses an RS256-signed SDP JWT with `sdp_partner_id`. | | **PAUSE** | A WebSocket streaming event that temporarily suspends audio transmission while keeping the session active, allowing resumption later. | | **PBC** | Problem-Based Charting. A documentation style that organizes the note around patient problems, with assessment and plan content tied to each problem. In Suki, enable PBC by marking a PBN LOINC section (commonly Assessment and Plan) with isPBNSection. | | **PBN** | Problem-Based Note. The note structure used with Problem-Based Charting, where content is organized by problems or diagnoses instead of only traditional section order. In Suki, designate one LOINC section as the PBN section when configuring ambient options. | | **PCM** | Pulse-Code Modulation. A method of digitally encoding analog audio signals. Suki uses LINEAR16 PCM format at 16KHz for audio streaming. | | **Personalization** | Provider-level controls for how notes are generated, such as verbosity and section format (narrative or bulleted). In Suki, personalization preferences apply across a provider's future sessions rather than only one visit. | | **PHI** | Protected Health Information. Individually identifiable health information protected under HIPAA when held by covered entities and their business associates. Suki integrations must treat clinical audio, transcripts, and notes as PHI-bearing content. | | **Physical Exam** | A clinical note section (LOINC: 29545-1) for examination findings from the encounter. In Suki, pass this LOINC code when you want physical exam content in the generated note. | | **PII** | Personally Identifiable Information. Data that can identify a person, such as name or contact details. Suki de-identifies PII from transcripts used for model improvement while production clinical workflows still treat patient content as sensitive. | | **Presigned URL** | A time-limited, pre-authenticated URL that grants temporary access to a specific resource (such as an audio recording) without requiring additional authentication. | | **Pre-Visit Summary** | The schedule-preview section of a completed Patient Summary, returned by dedicated pre-visit endpoints for UI display before the appointment. Distinct from the **Full Summary** used for full chart review. | | **Problem List** | A clinical note section (LOINC: 11450-4) for the patient's active diagnoses and ongoing concerns. In Suki, pass this LOINC code when you want problem-list content in the generated note, including Problem-Based Charting workflows. | | **Provider** | A healthcare professional such as a physician, APP, or nurse who documents care. In Suki integrations, provider identity ties sessions, preferences, and generated notes to the correct clinician. | | **Provider ID** | A unique identifier for a specific healthcare provider within a partner organization, used to associate sessions, notes, and preferences with the correct clinician. |
# R Source: https://developer.suki.ai/Glossary/r Glossary terms starting with R

R

| Term | Definition | | :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Rate Limiting** | A mechanism that restricts the number of API requests a client can make within a given time period, used to protect platform stability and ensure fair usage. | | **Re-ambient** | Starting an additional ambient session for an existing note, including from a different modality (Suki product). Pass the same `emr_encounter_id` and `encounter_id`. | | **Real-time** | Processing and response that occurs immediately or with minimal delay, such as live audio transcription and streaming to Suki's platform. | | **Reseller Program** | A business program that allows partners to embed Suki Platform's core technology directly into their own solutions and sell applications powered by Suki's assistive technology. | | **REST API** | Representational State Transfer Application Programming Interface. An architectural style for designing networked applications using standard HTTP methods. | | **RESUME** | A WebSocket streaming event that restarts audio transmission after a pause. | | **Review of Systems (ROS)** | A clinical note section (LOINC: 10187-3) for a system-by-system review of signs and symptoms. In Suki, pass this LOINC code when you want ROS content in the generated note. | | **RS256** | RSA Signature with SHA-256. A digital signature algorithm used for signing and verifying JWT tokens in Suki's authentication flow. | | **RSA** | An asymmetric cryptographic algorithm used for secure data transmission and digital signatures, commonly used in JWT token verification. |
# S Source: https://developer.suki.ai/Glossary/s Glossary terms starting with S

S

| Term | Definition | | :-------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Sampling Rate** | The number of audio samples captured per second, measured in Hertz. Suki requires 16KHz sampling rate for optimal audio quality. | | **SDK** | Software Development Kit. A collection of tools, libraries, and documentation to help developers build applications for a specific platform. | | **Service Contract** | A formal agreement between Suki and healthcare customers that defines service levels, data retention policies, and compliance requirements. | | **Semantic Versioning** | A versioning scheme (MAJOR.MINOR.PATCH) used for SDKs and APIs where major versions indicate breaking changes, minor versions add features, and patches fix bugs. | | **Session** | In Suki docs, session usually means an ambient session: a time-bound recording for one patient encounter. Prefer the specific term ambient session or Transcription Session when the product distinction matters. | | **Session Context** | Metadata provided when creating an ambient session (such as encounter type, patient age, diagnoses) that helps guide note generation and improve output quality. | | **Session ID (Ambient APIs)** | Unique identifier for one ambient recording session in Ambient APIs. Create ambient session returns `ambient_session_id` (you can also pass one on create). Use it for session-scoped operations such as context, streaming, status, and session content. Distinct from **Encounter ID** and **EMR Encounter ID**. | | **Session ID (Web SDK)** | In the Suki Web SDK, the **ambient session** identifier appears as **`ambientId`** on ambient event payloads (`ambient:update`, `ambient:start` through `ambient:submit`) and as **`activeAmbientId`** on `SDKClientInstance` (`string` or `null`). After `startAmbient()`, read `sdkClient.activeAmbientId` or the same value from `useSuki()` in React. It is **not** the same as **`encounterId`** on the **Note Submission** payload or **EMR Encounter ID**. | | **Session Recovery** | The ability to reconnect and resume an interrupted ambient session, allowing continuation of recording and note generation after a network or device disruption. | | **Session Timeouts** | Automatic disconnection that occurs when no audio data is sent for 25 seconds (active state) or 30 minutes during pause with keep-alive events. | | **SNOMED** | Systematized Nomenclature of Medicine (often SNOMED CT). A comprehensive clinical terminology for diagnoses, procedures, findings, and other concepts. Partners use SNOMED where EHR interoperability requires concept-level coding alongside systems like ICD10. | | **SOC 2 Type II** | A security compliance certification that evaluates an organization's controls for data security, availability, processing integrity, confidentiality, and privacy over time. | | **Social History** | A clinical note section (LOINC: 29762-2) for lifestyle and social factors such as tobacco use, alcohol use, occupation, and living situation. In Suki, pass this LOINC code when you want social history in the generated note. | | **SHA-256** | Secure Hash Algorithm 256-bit. A cryptographic hash function used for data integrity verification and digital signatures in security protocols. | | **SOAP Note** | Subjective, Objective, Assessment, Plan. A classic clinical note layout that groups visit information into those four parts. Suki ambient notes more often use LOINC-coded sections, while Problem-Based Charting (PBC) organizes content around problems instead of a strict SOAP skeleton. | | **Speech Recognition** | Converting spoken words into text. In Suki, speech recognition powers clinical Dictation and ambient transcription so providers can document without typing every line. | | **Structured Data** | Machine-readable clinical facts extracted from conversations, such as diagnoses, medications, allergies, vitals, and related codes. In Suki ambient flows, structured data complements the narrative note and supports EHR and analytics integration. | | **Suki Developer Platform (SDP)** | The official name for the entire suite of Suki's developer tools, including all APIs and SDKs. | | **Suki Token** | The access token returned by Suki's authentication API, used to authorize subsequent API requests to the Suki platform. | | **Summary Job** | Asynchronous Patient Summary generation work started by a generate request. Poll **Job Status (Patient Summary)** until the job reaches a terminal state, then retrieve the summary content. |
# T Source: https://developer.suki.ai/Glossary/t Glossary terms starting with T

T

| Term | Definition | | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Telehealth** | Remote care delivery over video or similar technology. Suki's Web SDK can support telehealth documentation by capturing the relevant browser or tab audio from virtual visits. | | **Test Mode** | A development feature in the Web SDK that allows developers to simulate ambient sessions without real audio, useful for testing integration and UI flows. | | **TLS 1.2** | Transport Layer Security version 1.2. A cryptographic protocol used to provide secure communication over networks, required by Suki for data transmission. | | **Transcript** | The text produced from clinical audio by speech recognition. In Suki, transcripts are an intermediate artifact used for note generation, review, and related documentation workflows. | | **Transcription Session** | A session specifically for audio Dictation, where a provider's spoken monologue is transcribed into text in real-time, as opposed to a full ambient note generation session. |
# U Source: https://developer.suki.ai/Glossary/u Glossary terms starting with U

U

| Term | Definition | | :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | | **Upload Speed** | The rate at which data can be transmitted from a client device to Suki's servers. Suki requires minimum 768kbps upload speed for optimal performance. |
# V Source: https://developer.suki.ai/Glossary/v Glossary terms starting with V

V

| Term | Definition | | :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **VARCHAR** | A VARCHAR (Variable Character) data type in SQL accepts variable-length string data, including letters, numbers, and special characters. It is used for storing alphanumeric data where the length of the entries varies significantly, such as names, addresses, or descriptions. | | **varchar(36)** | A **VARCHAR** column with a **36-character** maximum length. Web SDK **`patient.identifier`** and **`encounter.identifier`** must not exceed **36 characters**. For the general **`VARCHAR`** SQL type, see the row above. | | **Verbosity** | A personalization setting for how detailed generated notes should be, typically concise, balanced, or detailed. In Suki, verbosity shapes note length and density without changing which LOINC sections you requested. | | **Visit Type** | A visit classification such as new patient, follow-up, or annual wellness. In Suki, visit type works with encounter type as session context to steer note generation toward the right documentation pattern. | | **Vitals** | A clinical note section (LOINC: 8716-3) for measured vital signs such as blood pressure, heart rate, temperature, and respiratory rate. In Suki, pass this LOINC code when you want vitals captured in the generated note. | | **Voice Commands** | Spoken instructions that trigger product actions hands-free. In Suki experiences, voice commands help clinicians control documentation flows without breaking clinical workflow. |
# W Source: https://developer.suki.ai/Glossary/w Glossary terms starting with W

W

| Term | Definition | | :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **WAF** | Web Application Firewall. A security service that protects web applications by filtering and monitoring HTTP traffic between applications and the internet. | | **Webhook** | A mechanism that allows Suki to send real-time event notifications (like `session_summary_generated`) to your application's server. | | **Webhook Payload** | The JSON data body sent by Suki to a partner's callback URL when a webhook event is triggered, containing event details and relevant session or note data. | | **WebSocket** | A communication protocol that provides full-duplex communication channels over a single TCP connection, used for real-time audio streaming to Suki's platform. | | **WebSocket Secure (WSS)** | The secure version of WebSocket protocol that uses TLS/SSL encryption for protected data transmission during real-time audio streaming. |
# Suki APIs Overview Source: https://developer.suki.ai/api-overview/overview Pick the right Suki APIs for your product: REST, WebSocket, and webhook entry points for Ambient APIs, Form filling APIs, Dictation, and shared auth and security guides

Suki APIs

Suki provides partner REST, WebSocket, and webhook APIs so you can embed Ambient Clinical Intelligence (ACI) into healthcare applications.

Introduction

Suki APIs help you build clinical AI into healthcare software for providers, nurses, and other care staff. Ambient documentation, Form filling, Dictation, and Patient summary are the core workflows you can build from your backend. Your application owns the UI and how results move into the EHR.

Use REST for sessions and results, WebSockets for live audio, and webhooks for completion events. Responses use standard HTTP status codes and JSON.

Explore and test the APIs with the OpenAPI bundle. Access requires partner onboarding.

How it works

Each API follows the same integration pattern:

  1. Authenticate and obtain a Suki access token
  2. Create a clinical session with REST
  3. Stream live audio over WebSocket when the workflow needs capture
  4. End the session and retrieve structured output
  5. Optionally receive webhook events for completion and status

Authentication

API access is available only to approved Suki partners. Complete partner onboarding, then configure authentication for both your application and clinicians. Your application authenticates with a JWT (partner\_token) issued by your identity provider.

After a clinician signs in, Suki issues a Suki access token that authorizes REST API and WebSocket requests on the clinician's behalf. If you need staging access, production credentials, or rollout assistance, contact your Suki partnership representative or Suki Support.

Download OpenAPI description

Languages

```bash theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl -X POST https://sdp.suki.ai/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "partner_id": "your-partner-id", "partner_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_id": "provider-123" }' ```
```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch("https://sdp.suki.ai/api/v1/auth/login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ partner_id: "your-partner-id", partner_token: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", provider_id: "provider-123", // Optional }), }); if (response.ok) { const data = await response.json(); const sukiToken = data.suki_token; console.log(`Authentication successful. Token: ${sukiToken}`); } else { const error = await response.json(); console.error(`Authentication failed: ${response.status}`, error); } ```
```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki.ai/api/v1/auth/login" payload = { "partner_id": "your-partner-id", "partner_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_id": "provider-123" # Optional } response = requests.post(url, json=payload) if response.status_code == 200: data = response.json() suki_token = data["suki_token"] print(f"Authentication successful. Token: {suki_token}") else: print(f"Authentication failed: {response.status_code}") print(response.json()) ```
```ruby theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} require "net/http" require "json" uri = URI("https://sdp.suki.ai/api/v1/auth/login") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true req = Net::HTTP::Post.new(uri) req["Content-Type"] = "application/json" req.body = JSON.generate( "partner_id" => "your-partner-id", "partner_token" => "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_id" => "provider-123" ) res = http.request(req) puts res.body ```
```java theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class LoginExample { public static void main(String[] args) throws Exception { String body = "{" + "\"partner_id\":\"your-partner-id\"," + "\"partner_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\"," + "\"provider_id\":\"provider-123\"" + "}"; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://sdp.suki.ai/api/v1/auth/login")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ```
```php theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} "your-partner-id", "partner_token" => "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_id" => "provider-123", ]) ); $response = curl_exec($ch); curl_close($ch); echo $response; ```

Servers

Production host URL
[https://sdp.suki.ai](https://sdp.suki.ai)
Current API version
[https://sdp.suki.ai/api/v1](https://sdp.suki.ai/api/v1)
Confirm with your Suki partnership team for production URLs, and any host-specific routing before you go live.

Choose your API Workflow

Available APIs

Pick the APIs for your use case and workflow and start building your integration.

REST v1 GA
REST v1 GA
REST v1 GA
REST v1 BETA
Decide Your Workflow

Start building

Ambient API Introduction Learn more about the Ambient API and how to get started. Webhooks Introduction Learn more about the Webhooks to receive notifications from Suki. Ambient API Quickstart Build your first ambient session and stream audio in minutes. WebSocket APIs Stream visit audio over WebSocket for ambient and Form filling sessions. Form Filling API Introduction Learn more about the Form filling API and how to get started. Patient Summary API Introduction Upload FHIR data, trigger summary generation, and retrieve Patient Summaries. Patient Summary API Quickstart Complete the FHIR ingestion → generate → retrieve flow on staging. API Guidelines Learn more about the API guidelines to help you build your integration. Form Filling API Quickstart Build your first Form filling session and retrieve structured data in minutes. Partner Onboarding Learn more about the partner onboarding process to start using the Suki APIs.

Stay updated

Learn about the latest updates to the Ambient, Form filling, Dictation, and Patient Summary APIs.

New endpoints, deprecations, and behavior notes for Ambient and Dictation APIs. New endpoints, deprecations, and behavior notes for Form filling APIs. Patient Summary API reference and documentation: ingestion, generation jobs, and retrieval.
# Suki APIs Quickstarts Source: https://developer.suki.ai/api-overview/quickstarts Quickstarts for Suki APIs Get started with the Suki APIs by following the quickstarts below for your workflow of choice. Build your first ambient session, Stream audio, and Retrieve the note in minutes. Build your first Form filling session and retrieve structured data in minutes. Refer to the Ambient API reference to learn more about the Ambient API. Refer to the Form filling API reference to learn more about the Form filling API. Refer to the Dictation API reference to learn more about the Dictation API. Generate and retrieve Patient Summaries in minutes. # Ambient Content Retrieval APIs Source: https://developer.suki.ai/api-reference/ambient-content-retrieval Poll session status and retrieve transcripts, recordings, note content, and structured clinical data The Ambient Content Retrieval APIs enable partners to check processing status and retrieve transcripts, recordings, generated note text, and structured clinical data after an ambient session runs. Endpoints are scoped by ambient session ID, encounter ID, or note ID and EMR encounter ID for interoperable notes across modalities. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, retrieve content only after the session is ready for your workflow. Do not treat skipped sessions as successful note generation. ## Available endpoints Poll processing status for an ambient session Retrieve the transcript for an ambient session Retrieve recording access for an ambient session Retrieve generated note content for an ambient session Retrieve content when multiple sessions share an encounter Retrieve structured clinical data for an ambient session Retrieve structured data scoped to an encounter List notes associated with an EMR encounter Retrieve note content by note ID for interoperable notes Retrieve note context for an interoperable note Retrieve structured data for an interoperable note ## Related guides Learn how to retrieve note content when capture continues across products Learn how shared encounter IDs keep one Ambient note across modalities Convert medication instructions from ambient encounters into structured Medication order data Learn how to download Ambient recordings for streaming or downloading ## Common use cases Retrieve generated note content and structured data after processing completes, then map sections into your documentation model. Access transcripts or recordings when clinicians, support, or compliance need the source conversation behind a note. Load the latest shared composition after capture continues across Mobile, Web, or APIs for the same EMR encounter. Retrieve structured clinical data when your charting model needs coded sections, problem context, or medication order fields. # Get Ambient Session Content Source: https://developer.suki.ai/api-reference/ambient-content/content GET /api/v1/ambient/session/{ambient_session_id}/content Retrieve generated clinical content from completed Ambient session **Updated:** You can now get the structured data blocks in the response of this API, including Medication orders details. Read more in [Medication orders](/documentation/concepts/ambient-clinical-notes/medication-orders). Use this endpoint to get the summary and structured data associated with the specified ambient session. This endpoint uses the `cumulative` query parameter to get the cumulative summary and structured data for the specified ambient session. If the query parameter is not provided, the default value is `false`. You have two options for the `cumulative` query parameter: Determines whether to retrieve cumulative or snapshot data. Cumulative summary and structured data up to the specified ambient session is retrieved. Snapshot summary and structured data for the specified ambient session is retrieved. **Understanding the SKIPPED Status** If you see a session with a `SKIPPED` status, it means that the clinical note was **not generated** because the conversation transcript was **empty**. This status is an expected outcome if an ambient session is started but contains no audible speech (for example, a silent recording). It does not indicate a system error. Unlike a `FAILED` status, which indicates a processing error, `SKIPPED` is a successful outcome where no action was needed. Typically filter out or ignore sessions with this status in your application's user interface. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/content" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } # Get snapshot content (default, cumulative=false) response = requests.get(url, headers=headers, params={"cumulative": False}) if response.status_code == 200: content = response.json() print("Structured data blocks:") for block in content.get("structured_data", []) or []: print(f"\nBlock title: {block.get('title')}") data = block.get("data") or {} for key, value in data.items(): print(f" {key}: {value}") print("\nGenerated note (summary):") for section in content.get("summary", []) or []: print(f"\nTitle: {section.get('title')}") print(f"LOINC Code: {section.get('loinc_code')}") print(f"Content: {section.get('content')}") else: print(f"Failed to get content: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; // Get snapshot content (default, cumulative=false) const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/content?cumulative=false`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const content = await response.json(); console.log('Structured data blocks:'); (content.structured_data || []).forEach((block: any) => { console.log(`\nBlock title: ${block.title}`); const data = block.data || {}; Object.entries(data).forEach(([key, value]) => { console.log(` ${key}: ${value}`); }); }); console.log('\nGenerated note (summary):'); content.summary?.forEach((section: any) => { console.log(`\nTitle: ${section.title}`); console.log(`LOINC Code: ${section.loinc_code}`); console.log(`Content: ${section.content}`); }); } else { const error = await response.json(); console.error(`Failed to get content: ${response.status}`, error); } ``` ## Related guides Convert medication instructions from ambient encounters into structured Medication order data # Get Ambient Encounter Content Source: https://developer.suki.ai/api-reference/ambient-content/encounter-content GET /api/v1/ambient/encounter/{encounter_id}/content Retrieve generated clinical content from completed encounter **Updated:** You can now get the Medication orders for an encounter from the encounter content response. Read more in [Medication orders](/documentation/concepts/ambient-clinical-notes/medication-orders). Use this endpoint to get the cumulative summary and structured data associated with the specified encounter. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests encounter_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/encounter/{encounter_id}/content" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: content = response.json() print("Encounter Summary:") for section in content.get("summary", []): print(f"\nTitle: {section.get('title')}") print(f"LOINC Code: {section.get('loinc_code')}") print(f"Content: {section.get('content')}") print("\nStructured Data:") for structured_block in content.get("structured_data", []): print(f"\n{structured_block.get('title')}:") # data is a key-value object data = structured_block.get('data', {}) for key, value in data.items(): print(f" {key}: {value}") else: print(f"Failed to get encounter content: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const encounterId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/encounter/${encounterId}/content`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const content = await response.json(); console.log('Encounter Summary:'); content.summary?.forEach((section: any) => { console.log(`\nTitle: ${section.title}`); console.log(`LOINC Code: ${section.loinc_code}`); console.log(`Content: ${section.content}`); }); console.log('\nStructured Data:'); content.structured_data?.forEach((structuredBlock: any) => { console.log(`\n${structuredBlock.title}:`); // data is a key-value object if (structuredBlock.data) { Object.entries(structuredBlock.data).forEach(([key, value]) => { console.log(` ${key}: ${value}`); }); } }); } else { const error = await response.json(); console.error(`Failed to get encounter content: ${response.status}`, error); } ``` ## Related guides Convert medication instructions from ambient encounters into structured Medication order data # Get Ambient Encounter Structured Data Source: https://developer.suki.ai/api-reference/ambient-content/encounter-structured-data GET /api/v1/ambient/encounter/{encounter_id}/structured-data Retrieve structured clinical data from completed encounter **Updated:** * Diagnosis output now includes [HCC codes](https://www.aapc.com/resources/what-is-hierarchical-condition-category?srsltid=AfmBOopcl-dIWrRrQFq58LGS72p58BakTdoWdEHv0P9z89c3XBXuJAOY) alongside ICD10, IMO, and SNOMED. * You now get **Medication orders** in the structured data output for an encounter. Use this endpoint to get the structured data associated with the specified encounter. ## Diagnosis codes in structured data When Problem-Based Charting (PBC) is enabled, each diagnosis in `structured_data.diagnoses.values` can include ICD10, IMO, SNOMED (when available), and HCC codes in the `codes` array. HCC values are derived from the ICD-10-CM code using the CMS-HCC V28 model. The `description` for HCC entries uses the format `CMS-HCC model category `. HCC codes are returned in structured data output only. Do not send them in session context. For a comparison of ICD-10 and HCC codes and how Suki returns them, refer to [Diagnosis codes FAQs](/api-reference/faqs/diagnosis-codes#what-is-the-difference-between-icd-10-and-hcc-codes). ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests encounter_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/encounter/{encounter_id}/structured-data" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: structured_data = response.json() print("Encounter Structured Data:") if "structured_data" in structured_data: diagnoses = structured_data["structured_data"].get("diagnoses", {}) if "values" in diagnoses: for diagnosis in diagnoses["values"]: print(f"Diagnosis Note: {diagnosis.get('diagnosis_note')}") # Additional diagnosis fields if diagnosis.get('laterality_indicator') is not None: print(f"Laterality Indicator: {diagnosis.get('laterality_indicator')}") if diagnosis.get('post_coord_lex_flag') is not None: print(f"Post-coordination Lexical Flag: {diagnosis.get('post_coord_lex_flag')}") # Diagnosis codes (ICD10, IMO, SNOMED, HCC) for code in diagnosis.get("codes", []): print(f" Code: {code.get('code')}") print(f" Description: {code.get('description')}") print(f" Type: {code.get('type')}") hcc_codes = [c for c in diagnosis.get("codes", []) if c.get("type") == "HCC"] if hcc_codes: print(f" HCC categories: {', '.join(c['code'] for c in hcc_codes)}") print("---") orders = structured_data["structured_data"].get("orders", {}) med_orders = orders.get("medication_orders") or {} for order in med_orders.get("values") or []: print(f"Order (submittable): {order.get('drug_name')} - {order.get('status')}") for order in med_orders.get("partial_values") or []: print(f"Order (partial): {order.get('drug_name')} - {order.get('status')}") else: print(f"Failed to get encounter structured data: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const encounterId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/encounter/${encounterId}/structured-data`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const structuredData = await response.json(); console.log('Encounter Structured Data:'); if (structuredData.structured_data) { const diagnoses = structuredData.structured_data.diagnoses || {}; if (diagnoses.values) { diagnoses.values.forEach((diagnosis: any) => { console.log(`Diagnosis Note: ${diagnosis.diagnosis_note}`); // Additional diagnosis fields if (diagnosis.laterality_indicator !== undefined && diagnosis.laterality_indicator !== null) { console.log(`Laterality Indicator: ${diagnosis.laterality_indicator}`); } if (diagnosis.post_coord_lex_flag !== undefined && diagnosis.post_coord_lex_flag !== null) { console.log(`Post-coordination Lexical Flag: ${diagnosis.post_coord_lex_flag}`); } // Diagnosis codes (ICD10, IMO, SNOMED, HCC) diagnosis.codes?.forEach((code: any) => { console.log(` Code: ${code.code}`); console.log(` Description: ${code.description}`); console.log(` Type: ${code.type}`); }); const hccCodes = diagnosis.codes?.filter((code: any) => code.type === 'HCC') ?? []; if (hccCodes.length > 0) { console.log(` HCC categories: ${hccCodes.map((c: any) => c.code).join(', ')}`); } console.log('---'); }); } const orders = structuredData.structured_data.orders || {}; const medOrders = orders.medication_orders || {}; (medOrders.values || []).forEach((order: any) => { console.log(`Order (submittable): ${order.drug_name} - ${order.status}`); }); (medOrders.partial_values || []).forEach((order: any) => { console.log(`Order (partial): ${order.drug_name} - ${order.status}`); }); } } else { const error = await response.json(); console.error(`Failed to get encounter structured data: ${response.status}`, error); } ``` # List Encounter Notes Source: https://developer.suki.ai/api-reference/ambient-content/list-encounter-notes GET /api/v1/ambient/encounter/{emr_encounter_id}/notes List Ambient notes linked to an EMR encounter for cross-modality workflows Use this endpoint to list all finished and unfinished notes tied to an `emr_encounter_id`. Pass the same `emr_encounter_id` you sent when creating interoperable ambient sessions. Use each returned note `id` as `note_id` with the note-level content, context, and structured data endpoints. Cross-modality ambient workflows require `emr_encounter_id` on session create. Without it, notes are not interoperable across modalities. Refer to [Ambient interoperability](/documentation/concepts/ambient-clinical-notes/ambient-interoperability) for more details. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" # Same emr_encounter_id you passed on Create Ambient Session emr_encounter_id = "" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" url = f"{BASE_URL}/api/v1/ambient/encounter/{emr_encounter_id}/notes" headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } response = requests.get(url, headers=headers, timeout=60) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 200: notes = response_body.get("notes") or [] print(f"Notes found: {len(notes)}") for note in notes: note_id = note.get("id") created_at = note.get("created_at") updated_at = note.get("updated_at") print("note_id:", note_id) print("created_at:", created_at) print("updated_at:", updated_at) print( "Use note_id with Get Note Content, Get Note Context, " "and Get Note Structured Data." ) else: print("List Encounter Notes failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; // Same emr_encounter_id you passed on Create Ambient Session const emrEncounterId = ""; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; type EncounterNote = { id?: string; created_at?: string; updated_at?: string; }; type ListEncounterNotesResponse = { notes?: EncounterNote[]; }; type ApiErrorResponse = { code?: number; message?: string; }; const response = await fetch( `${BASE_URL}/api/v1/ambient/encounter/${emrEncounterId}/notes`, { method: "GET", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }, } ); const responseText = await response.text(); let responseBody: ListEncounterNotesResponse | ApiErrorResponse | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("List Encounter Notes returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 200) { const payload = responseBody as ListEncounterNotesResponse; const notes = payload.notes || []; console.log(`Notes found: ${notes.length}`); for (const note of notes) { console.log("note_id:", note.id); console.log("created_at:", note.created_at); console.log("updated_at:", note.updated_at); console.log( "Use note_id with Get Note Content, Get Note Context, and Get Note Structured Data." ); } } else { const error = responseBody as ApiErrorResponse; console.error("List Encounter Notes failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` # Get Note Content Source: https://developer.suki.ai/api-reference/ambient-content/note-content GET /api/v1/ambient/note/{note_id}/content Retrieve accumulated Ambient note section content, including the latest edits Use this endpoint to get accumulated section content across ambient sessions in a note. If clinicians edit sections in a headed product such as the Web SDK, the response returns the **latest edited** section content. Use `composition_id` from [Create ambient session](/api-reference/ambient-sessions/create) as `note_id`. Prefer this endpoint when clinicians edit the note in the other headed products and you need the latest section content in your integration. Session-scoped content endpoints return content for a single ambient session only. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" # Use composition_id from Create Ambient Session as note_id note_id = "" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" url = f"{BASE_URL}/api/v1/ambient/note/{note_id}/content" headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } response = requests.get(url, headers=headers, timeout=60) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 200: summary = response_body.get("summary") or [] print(f"Sections found: {len(summary)}") for section in summary: print("title:", section.get("title")) print("loinc_code:", section.get("loinc_code")) print("content:", section.get("content")) print("source_transcripts:", section.get("source_transcripts")) else: print("Get Note Content failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; // Use composition_id from Create Ambient Session as note_id const noteId = ""; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; type ContentBlock = { title?: string; loinc_code?: string; content?: string; source_transcripts?: string[]; }; type GetNoteContentResponse = { summary?: ContentBlock[]; }; type ApiErrorResponse = { code?: number; message?: string; }; const response = await fetch( `${BASE_URL}/api/v1/ambient/note/${noteId}/content`, { method: "GET", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }, } ); const responseText = await response.text(); let responseBody: GetNoteContentResponse | ApiErrorResponse | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("Get Note Content returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 200) { const payload = responseBody as GetNoteContentResponse; const summary = payload.summary || []; console.log(`Sections found: ${summary.length}`); for (const section of summary) { console.log("title:", section.title); console.log("loinc_code:", section.loinc_code); console.log("content:", section.content); console.log("source_transcripts:", section.source_transcripts); } } else { const error = responseBody as ApiErrorResponse; console.error("Get Note Content failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` # Get Note Context Source: https://developer.suki.ai/api-reference/ambient-content/note-context GET /api/v1/ambient/note/{note_id}/context Retrieve Ambient note context aggregated across Ambient sessions Use this endpoint to get ambient note context aggregated across ambient sessions. The response `context` object can include fields related to the visit context aggregated across sessions in the note. To know the supported visit type, encounter type, and provider role values, refer to the ambient [Info](/api-reference/info/information) endpoint. Use `composition_id` from [Create ambient session](/api-reference/ambient-sessions/create) as `note_id`. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" # Use composition_id from Create Ambient Session as note_id note_id = "" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" url = f"{BASE_URL}/api/v1/ambient/note/{note_id}/context" headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } response = requests.get(url, headers=headers, timeout=60) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 200: context = response_body.get("context") or {} print("visit_type:", context.get("visit_type")) print("encounter_type:", context.get("encounter_type")) print("provider_role:", context.get("provider_role")) print("reason_for_visit:", context.get("reason_for_visit")) print("chief_complaint:", context.get("chief_complaint")) else: print("Get Note Context failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; // Use composition_id from Create Ambient Session as note_id const noteId = ""; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; type NoteContext = { visit_type?: string; encounter_type?: string; provider_role?: string; reason_for_visit?: string; chief_complaint?: string; }; type GetNoteContextResponse = { context?: NoteContext; }; type ApiErrorResponse = { code?: number; message?: string; }; const response = await fetch( `${BASE_URL}/api/v1/ambient/note/${noteId}/context`, { method: "GET", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }, } ); const responseText = await response.text(); let responseBody: GetNoteContextResponse | ApiErrorResponse | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("Get Note Context returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 200) { const payload = responseBody as GetNoteContextResponse; const context = payload.context || {}; console.log("visit_type:", context.visit_type); console.log("encounter_type:", context.encounter_type); console.log("provider_role:", context.provider_role); console.log("reason_for_visit:", context.reason_for_visit); console.log("chief_complaint:", context.chief_complaint); } else { const error = responseBody as ApiErrorResponse; console.error("Get Note Context failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` # Get Note Structured Data Source: https://developer.suki.ai/api-reference/ambient-content/note-structured-data GET /api/v1/ambient/note/{note_id}/structured-data Retrieve accumulated diagnoses and orders across Ambient sessions in a note Use this endpoint to get accumulated structured data (diagnoses and orders) across sessions in a note. Use `composition_id` from [Create ambient session](/api-reference/ambient-sessions/create) as `note_id`. This note-level endpoint accumulates diagnoses and orders across ambient sessions in the note. If you need the latest diagnoses and orders from the most recent session for that encounter ID, use the [Get ambient Encounter Structured Data](/api-reference/ambient-content/encounter-structured-data) endpoint. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" # Use composition_id from Create Ambient Session as note_id note_id = "" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" url = f"{BASE_URL}/api/v1/ambient/note/{note_id}/structured-data" headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } response = requests.get(url, headers=headers, timeout=60) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 200: structured_data = response_body.get("structured_data") or {} diagnoses = (structured_data.get("diagnoses") or {}).get("values") or [] print(f"Diagnoses found: {len(diagnoses)}") for diagnosis in diagnoses: print("diagnosis_note:", diagnosis.get("diagnosis_note")) print("laterality_indicator:", diagnosis.get("laterality_indicator")) print("post_coord_lex_flag:", diagnosis.get("post_coord_lex_flag")) for code in diagnosis.get("codes") or []: print(" code:", code.get("code")) print(" description:", code.get("description")) print(" type:", code.get("type")) print("---") medication_orders = ( (structured_data.get("orders") or {}).get("medication_orders") or {} ) submittable_orders = medication_orders.get("values") or [] partial_orders = medication_orders.get("partial_values") or [] print(f"Submittable medication orders: {len(submittable_orders)}") for order in submittable_orders: medication_code = order.get("medication_code") or {} print("drug_name:", order.get("drug_name")) print("status:", order.get("status")) print("medication_code:", medication_code.get("code")) print("medication_code_type:", medication_code.get("type")) print("---") print(f"Partial medication orders: {len(partial_orders)}") for order in partial_orders: medication_code = order.get("medication_code") or {} print("drug_name:", order.get("drug_name")) print("status:", order.get("status")) print("medication_code:", medication_code.get("code")) print("medication_code_type:", medication_code.get("type")) print("---") else: print("Get Note Structured Data failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; // Use composition_id from Create Ambient Session as note_id const noteId = ""; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; type Code = { code?: string; description?: string; type?: string; }; type Diagnosis = { diagnosis_note?: string; laterality_indicator?: number; post_coord_lex_flag?: number; codes?: Code[]; }; type MedicationCode = { code?: string; type?: string; }; type MedicationOrder = { drug_name?: string; status?: string; medication_code?: MedicationCode; }; type GetNoteStructuredDataResponse = { structured_data?: { diagnoses?: { values?: Diagnosis[]; }; orders?: { medication_orders?: { values?: MedicationOrder[]; partial_values?: MedicationOrder[]; }; }; }; }; type ApiErrorResponse = { code?: number; message?: string; }; const response = await fetch( `${BASE_URL}/api/v1/ambient/note/${noteId}/structured-data`, { method: "GET", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }, } ); const responseText = await response.text(); let responseBody: GetNoteStructuredDataResponse | ApiErrorResponse | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("Get Note Structured Data returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 200) { const payload = responseBody as GetNoteStructuredDataResponse; const structuredData = payload.structured_data || {}; const diagnoses = structuredData.diagnoses?.values || []; console.log(`Diagnoses found: ${diagnoses.length}`); for (const diagnosis of diagnoses) { console.log("diagnosis_note:", diagnosis.diagnosis_note); console.log("laterality_indicator:", diagnosis.laterality_indicator); console.log("post_coord_lex_flag:", diagnosis.post_coord_lex_flag); for (const code of diagnosis.codes || []) { console.log(" code:", code.code); console.log(" description:", code.description); console.log(" type:", code.type); } console.log("---"); } const medicationOrders = structuredData.orders?.medication_orders || {}; const submittableOrders = medicationOrders.values || []; const partialOrders = medicationOrders.partial_values || []; console.log(`Submittable medication orders: ${submittableOrders.length}`); for (const order of submittableOrders) { console.log("drug_name:", order.drug_name); console.log("status:", order.status); console.log("medication_code:", order.medication_code?.code); console.log("medication_code_type:", order.medication_code?.type); console.log("---"); } console.log(`Partial medication orders: ${partialOrders.length}`); for (const order of partialOrders) { console.log("drug_name:", order.drug_name); console.log("status:", order.status); console.log("medication_code:", order.medication_code?.code); console.log("medication_code_type:", order.medication_code?.type); console.log("---"); } } else { const error = responseBody as ApiErrorResponse; console.error("Get Note Structured Data failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` ## Related guides Convert medication instructions from ambient encounters into structured Medication order data # Get Ambient Session Recording Source: https://developer.suki.ai/api-reference/ambient-content/recording GET /api/v1/ambient/session/{ambient_session_id}/recording Get presigned URLs for Ambient session recordings for streaming or download Use this endpoint to get presigned URLs for all recordings for the ambient session. Refer to the [Download Ambient Recordings](/documentation/how-to/audio-streaming/audio-streaming-download) guide for more details. Use the `download` query parameter to control the URL type: * If `download=true`, the URL is for downloading the **full** file. * If `download=false` or omitted, the URL supports streaming with **range** requests. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" # this will be the Ambient session id you get from the create Ambient session API url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/recording" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } # For streaming URLs (default) response = requests.get(url, headers=headers) # For download-only URLs # response = requests.get(url, headers=headers, params={"download": True}) if response.status_code == 200: data = response.json() print(f"Streamable: {data.get('is_streamable')}") for rec in data.get("recordings", []): print(f"Recording ID: {rec.get('recording_id')}") print(f"Presigned URL: {rec.get('presigned_url')}") print(f"Expires at: {rec.get('expires_at')}") print(f"Sequence: {rec.get('sequence_number')}") print("---") else: print(f"Failed to get recording URLs: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; // this will be the Ambient session id you get from the create Ambient session API // For streaming URLs (default) const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/recording`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); // For download-only URLs, append ?download=true // const response = await fetch( // `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/recording?download=true`, // { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } // ); if (response.ok) { const data = await response.json(); console.log('Streamable:', data.is_streamable); data.recordings?.forEach((rec: any) => { console.log('Recording ID:', rec.recording_id); console.log('Presigned URL:', rec.presigned_url); console.log('Expires at:', rec.expires_at); console.log('Sequence:', rec.sequence_number); console.log('---'); }); } else { const error = await response.json(); console.error(`Failed to get recording URLs: ${response.status}`, error); } ``` # Get Ambient Session Status Source: https://developer.suki.ai/api-reference/ambient-content/status GET /api/v1/ambient/session/{ambient_session_id}/status Check current status and processing state of Ambient session Use this endpoint to get the **current status** of an ambient session. Use it to track the session's progress, for example, to see if it is ready to receive audio, still processing, or has completed. ## Session status values Use the following status values to track the session's progress: * **created**: The ambient session has been created but has not yet started. * **ready**: The ambient session has started and is ready for audio streaming. * **running**: The ambient session is actively processing audio and generating content. * **aborted**: The ambient session has been cancelled by the user or client. * **skipped**: The ambient session was skipped because not enough audio was received or the transcript was empty. * **failed**: The ambient session failed due to an error during processing. * **completed**: The ambient session completed successfully and generated the final content. **paused** status is no longer supported. Upon reaching **completed** state, the session is ready to return the content, transcripts, or other structured data. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/status" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: status_data = response.json() status = status_data.get("status") print(f"Session status: {status}") if status == "completed": print("Session completed successfully. Content is ready.") elif status == "failed": print("Session failed during processing.") elif status == "skipped": print("Session was skipped (empty transcript or too short).") else: print(f"Failed to get status: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/status`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const statusData = await response.json(); const status = statusData.status; console.log(`Session status: ${status}`); if (status === 'completed') { console.log('Session completed successfully. Content is ready.'); } else if (status === 'failed') { console.log('Session failed during processing.'); } else if (status === 'skipped') { console.log('Session was skipped (empty transcript or too short).'); } } else { const error = await response.json(); console.error(`Failed to get status: ${response.status}`, error); } ``` # Get Ambient Session Structured Data Source: https://developer.suki.ai/api-reference/ambient-content/structured-data GET /api/v1/ambient/session/{ambient_session_id}/structured-data Retrieve structured clinical data from completed Ambient session **Updated:** * Diagnosis output now includes [HCC codes](https://www.aapc.com/resources/what-is-hierarchical-condition-category?srsltid=AfmBOopcl-dIWrRrQFq58LGS72p58BakTdoWdEHv0P9z89c3XBXuJAOY) alongside ICD10, IMO, and SNOMED. * You now get **Medication orders** in the structured data output for an ambient session. Use this endpoint to get the cumulative structured data associated with the specified ambient session. ## Diagnosis codes in structured data When Problem-Based Charting (PBC) is enabled, each diagnosis in `structured_data.diagnoses.values` can include multiple codes in the `codes` array: | `type` | Description | | -------- | ------------------------------------------------------- | | `ICD10` | ICD-10-CM diagnosis code | | `IMO` | IMO term code | | `SNOMED` | SNOMED CT code (when available) | | `HCC` | CMS-HCC model category derived from the ICD-10-CM code. | HCC entries use `description` in the format `CMS-HCC model category ` (for example, `CMS-HCC model category 65`). HCC codes are returned in structured data output only. **Do not** send them in session context. * If an ICD-10-CM HCC diagnosis code does not map to an HCC model category, Suki looks for general HCC codes that match the diagnosis description. If no match is found, the diagnosis is returned without an HCC code. * For how ICD-10 and HCC codes differ and how Suki returns them, refer to [Diagnosis codes FAQs](/api-reference/faqs/diagnosis-codes#what-is-the-difference-between-icd-10-and-hcc-codes). ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/structured-data" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: structured_data = response.json() print("Structured Data:") if "structured_data" in structured_data: diagnoses = structured_data["structured_data"].get("diagnoses", {}) if "values" in diagnoses: for diagnosis in diagnoses["values"]: print(f"Diagnosis Note: {diagnosis.get('diagnosis_note')}") # Additional diagnosis fields if diagnosis.get('laterality_indicator') is not None: print(f"Laterality Indicator: {diagnosis.get('laterality_indicator')}") if diagnosis.get('post_coord_lex_flag') is not None: print(f"Post-coordination Lexical Flag: {diagnosis.get('post_coord_lex_flag')}") # Diagnosis codes (ICD10, IMO, SNOMED, HCC) for code in diagnosis.get("codes", []): print(f" Code: {code.get('code')}") print(f" Description: {code.get('description')}") print(f" Type: {code.get('type')}") hcc_codes = [c for c in diagnosis.get("codes", []) if c.get("type") == "HCC"] if hcc_codes: print(f" HCC categories: {', '.join(c['code'] for c in hcc_codes)}") print("---") orders = structured_data["structured_data"].get("orders", {}) med_orders = orders.get("medication_orders") or {} for order in med_orders.get("values") or []: med_code = order.get("medication_code") or {} print(f"Order (submittable): {order.get('drug_name')} - {order.get('status')}") print(f" Medication code: {med_code.get('code')} ({med_code.get('type')})") print("---") for order in med_orders.get("partial_values") or []: med_code = order.get("medication_code") or {} print(f"Order (partial): {order.get('drug_name')} - {order.get('status')}") print(f" Medication code: {med_code.get('code')} ({med_code.get('type')})") print("---") else: print(f"Failed to get structured data: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/structured-data`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const structuredData = await response.json(); console.log('Structured Data:'); if (structuredData.structured_data) { const diagnoses = structuredData.structured_data.diagnoses || {}; if (diagnoses.values) { diagnoses.values.forEach((diagnosis: any) => { console.log(`Diagnosis Note: ${diagnosis.diagnosis_note}`); // Additional diagnosis fields if (diagnosis.laterality_indicator !== undefined && diagnosis.laterality_indicator !== null) { console.log(`Laterality Indicator: ${diagnosis.laterality_indicator}`); } if (diagnosis.post_coord_lex_flag !== undefined && diagnosis.post_coord_lex_flag !== null) { console.log(`Post-coordination Lexical Flag: ${diagnosis.post_coord_lex_flag}`); } // Diagnosis codes (ICD10, IMO, SNOMED, HCC) diagnosis.codes?.forEach((code: any) => { console.log(` Code: ${code.code}`); console.log(` Description: ${code.description}`); console.log(` Type: ${code.type}`); }); const hccCodes = diagnosis.codes?.filter((code: any) => code.type === 'HCC') ?? []; if (hccCodes.length > 0) { console.log(` HCC categories: ${hccCodes.map((c: any) => c.code).join(', ')}`); } console.log('---'); }); } const orders = structuredData.structured_data.orders || {}; const medOrders = orders.medication_orders || {}; (medOrders.values || []).forEach((order: any) => { const medCode = order.medication_code || {}; console.log(`Order (submittable): ${order.drug_name} - ${order.status}`); console.log(` Medication code: ${medCode.code} (${medCode.type})`); console.log('---'); }); (medOrders.partial_values || []).forEach((order: any) => { const medCode = order.medication_code || {}; console.log(`Order (partial): ${order.drug_name} - ${order.status}`); console.log(` Medication code: ${medCode.code} (${medCode.type})`); console.log('---'); }); } } else { const error = await response.json(); console.error(`Failed to get structured data: ${response.status}`, error); } ``` # Get Session Transcript Source: https://developer.suki.ai/api-reference/ambient-content/transcript GET /api/v1/ambient/session/{ambient_session_id}/transcript Retrieve conversation transcript from completed Ambient session Use this endpoint to get the full transcript for a specified ambient session after it has completed. **Updated:** The response will now include the new `lang_id` field within the payload. The `lang_id` field indicates the language in which the transcript was sent. For a full list of language codes and their corresponding languages, refer to the [Language code reference](/api-reference/capabilities/multilingual#language-code-reference) section. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/transcript" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: transcript_data = response.json() print("Transcript:") for transcript in transcript_data.get("final_transcript", []): print(f"Transcript ID: {transcript.get('transcript_id')}") print(f"Recording ID: {transcript.get('recording_id')}") print(f"Language: {transcript.get('lang_id')}") print(f"Transcript: {transcript.get('transcript')}") print(f"Start Time: {transcript.get('start_time')}") print(f"End Time: {transcript.get('end_time')}") # Start offset (relative to beginning of audio) start_offset = transcript.get('start_offset', {}) if start_offset: print(f"Start Offset: {start_offset.get('hours')}h {start_offset.get('minutes')}m {start_offset.get('seconds')}s") # End offset (relative to beginning of audio) end_offset = transcript.get('end_offset', {}) if end_offset: print(f"End Offset: {end_offset.get('hours')}h {end_offset.get('minutes')}m {end_offset.get('seconds')}s") print("---") else: print(f"Failed to get transcript: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/transcript`, { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { const transcriptData = await response.json(); console.log('Transcript:'); transcriptData.final_transcript?.forEach((transcript: any) => { console.log(`Transcript ID: ${transcript.transcript_id}`); console.log(`Recording ID: ${transcript.recording_id}`); console.log(`Language: ${transcript.lang_id}`); console.log(`Transcript: ${transcript.transcript}`); console.log(`Start Time: ${transcript.start_time}`); console.log(`End Time: ${transcript.end_time}`); // Start offset (relative to beginning of audio) if (transcript.start_offset) { const { hours, minutes, seconds } = transcript.start_offset; console.log(`Start Offset: ${hours}h ${minutes}m ${seconds}s`); } // End offset (relative to beginning of audio) if (transcript.end_offset) { const { hours, minutes, seconds } = transcript.end_offset; console.log(`End Offset: ${hours}h ${minutes}m ${seconds}s`); } console.log('---'); }); } else { const error = await response.json(); console.error(`Failed to get transcript: ${response.status}`, error); } ``` # Dictation APIs Source: https://developer.suki.ai/api-reference/ambient-dictation Create Dictation sessions, stream audio for transcription, and end sessions The Dictation APIs enable partners to run speech-to-text without the full ambient clinical note flow. You create a transcription session, open a WebSocket to stream audio, then end the session when capture is finished so resources close cleanly. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, Dictation returns transcript text for the session. It does not replace Ambient Session Management when you need a generated clinical note. ## Available endpoints Create a Dictation session and receive a transcription session ID Stream audio over WebSocket and receive transcript frames End the Dictation session when capture is finished ## Related guides Learn how to stream Dictation audio and receive transcript frames Learn how Dictation works and the different modes it supports Review outbound audio message framing for Dictation WebSockets Learn how to parse inbound transcript frames from the Dictation WebSocket ## Common use cases Capture speech-to-text for the focused field or scratchpad without running the full ambient clinical note pipeline. Let clinicians fix wording in a generated note with Dictation, then save the edited content in your existing chart workflow. Own audio capture on a backend or device gateway while your UI renders live transcript results for the clinician. Keep one Dictation session available across multiple speech bursts until the clinician finishes the documentation task. # Ambient Session Management APIs Source: https://developer.suki.ai/api-reference/ambient-session-management Create and manage Ambient sessions, stream audio, attach metadata, and end sessions The Ambient Session Management APIs enable partners to run the ambient session lifecycle for a patient encounter. An encounter is the visit. An ambient session is one recording for that visit. One encounter can include one or more ambient sessions. For each session, you create the session, seed or update visit context, optionally attach metadata, stream visit audio over WebSocket, then end the session when that recording is finished. Ending a session closes that recording so Suki can process it. It does not mean the encounter is closed if another ambient session will follow. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, ending the session is what closes capture cleanly so Suki can finish processing. Streaming alone does not replace the End Ambient Session call. ## Available endpoints Create a new ambient session for a patient encounter Seed patient, provider, and encounter context for the session Update context during an active ambient session Attach or update metadata for an ambient session Stream visit audio over WebSocket to the Suki backend End the ambient session when recording is finished ## Related guides Learn how to stream ambient audio for a live session Learn how the Ambient streaming architecture works Learn how ambient sessions turn conversation into clinical notes ## Common use cases Capture the visit conversation in your product so Suki can draft the clinical note while clinicians stay in your EHR workflow. Provide diagnoses, note sections, specialty, and EMR encounter details so generated notes match the visit your system already knows. Share an EMR encounter ID so clinicians can start capture on one modality and finish review on another without losing the note. End the ambient session when that recording is finished so Suki can process it for review, retrieval, or webhooks. Start another session on the same encounter when the visit needs more capture. # Audio Streaming Source: https://developer.suki.ai/api-reference/ambient-sessions/audio-stream GET /ws/stream WebSocket endpoint for real-time audio streaming during Ambient sessions Use this API to stream audio to the speech service over a WebSocket connection for ambient and Form filling sessions. ## Related guides ## Prerequisites Complete these steps **before** opening the WebSocket. Opening `/ws/stream` before the session and context are ready often leads to handshake failures or a broken stream. * **Authenticate** and obtain `sdp_suki_token`. * **Create an ambient session** with POST [`/api/v1/ambient/session/create`](/api-reference/ambient-sessions/create). A successful create returns **201 Created**; keep the `ambient_session_id` you used or received. * **Seed session context** with POST [`/api/v1/ambient/session/{ambient_session_id}/context`](/api-reference/ambient-sessions/context). Send the JSON body your integration requires (see that endpoint for the full schema). * **Authenticate and open the WebSocket** on `wss://sdp.suki-stage.com/ws/stream`. To stream audio, you must first establish an **authenticated** WebSocket connection. The authentication method you use depends on your client type: browser or non-browser. ## Browser clients When connecting from a browser, include the `Sec-WebSocket-Protocol` header as part of the WebSocket handshake. Set the header value as a single comma-separated string. The order must be: * Subprotocol name. * Token - Your `sdp_suki_token`. * Ambient session ID - Your ambient session ID. Avoid adding spaces between values unless your client library requires it. For example: ```bash theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} Sec-WebSocket-Protocol: SukiAmbientAuth,, ``` The server negotiates this subprotocol to establish the connection. ## Non-browser clients For non-browser clients such as mobile apps, backend services, or testing tools, pass authentication details as separate HTTP headers in the WebSocket upgrade request. Do not use the `Sec-WebSocket-Protocol` header. Include the following headers: * `sdp_suki_token` - Session token from login. * `sdp_provider_id` - Provider identifier. Optional for standard partners; **Required** for Single Auth Token authentication. * `ambient_session_id` - The ID for the current ambient session. If you push non-JSON payloads where the server expects JSON, you can see parse errors (for example invalid character or null byte errors). ## Full code examples For end-to-end ambient and Form filling streaming examples, start with these tutorials: # Seed Ambient Session Context Source: https://developer.suki.ai/api-reference/ambient-sessions/context POST /api/v1/ambient/session/{ambient_session_id}/context Provide clinical context and patient information for Ambient session **Updated:** You can now provide **EMR context** and **Medication orders** details in the Ambient Session Context API. Use this endpoint to provide or update the session context for an ambient session. Providing detailed context helps Suki generate a more accurate and relevant clinical note. For ambient notes that open in Web SDK, seed patient details in this context call: `patient_id`, `name`, `dob`, and `sex`. Web SDK needs these fields to show the patient profile. Refer to [Use ambient across modalities](/documentation/how-to/ambient-clinical-notes/use-ambient-across-modalities) for more details. For example, you can provide: * Provider details (e.g., specialty and role). * Patient and visit information. * A list of LOINC codes for the clinical sections you want to generate. * Existing diagnoses with their associated medical codes. * EMR context, including target EMR, when you need EMR-specific behavior (for example order submission rules). * Orders context (medication orders), including structured medication orders for active medications and related metadata. For more information about the context, refer to the [PBC](/api-reference/capabilities/problem-based-charting) and [Specialty](/documentation/concepts/ambient-clinical-notes/specialties) section. For more information about Medication orders, refer to the [Medication orders](/documentation/concepts/ambient-clinical-notes/medication-orders) guide. Use the `Codes` section to provide additional context for a session, such as **medical codes** for a **diagnosis**. To ensure your requests succeed, follow these validation rules when sending data to the API: ### Field validation and constraints * **Character Limits**: Ensure the **`chief_complaint`** and **`reason_for_visit`** fields do not exceed **255 characters**. * **Enumerated Values**: Use only the predefined string values for **`visit_type`**, **`encounter_type`**, and **`provider_role`**. * **EMR Selection**: You must set **`emr.target_emr`** to one of the following: **`ATHENA`**, **`EPIC`**, or **`CERNER`**. ### Medication order requirements When you send **`orders.medication_orders.values`**, include the following required properties for each object: * **Drug Information**: Provide both the **`drug_name`** and a **`medication_code`**. * **Coding Systems**: For **`medication_code`**, specify the **`code`** and set the **`type`** to **`RXCUI`** or **`NDC`**. * **Order Status**: Set the **`status`** to **`ACTIVE`**, **`DISCONTINUED`**, or **`REFILLED`**. * **Metadata**: Include the **`metadata`** object with a required **`origin`** of **`EMR`** or **`SUKI_AMBIENT`**. If you set **`origin`** to **`EMR`**, you must also set **`metadata.encounter_relation`** to either **`CURRENT_ENCOUNTER`** or **`PRIOR_ENCOUNTER`**. **Diagnosis links**: To link a diagnosis to an order, ensure the codes in **`linked_diagnosis_codes`** match a diagnosis already provided in the **`diagnoses`** section. Use the same coding system for both to allow the service to validate the link. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" # From Create Ambient Session response ambient_session_id = "" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" # Set these from your system patient_id = "" patient_given_name = "" patient_family_name = "" patient_dob = "" # YYYY-MM-DD patient_sex = "" # male | female | other | unknown provider_specialty = "" provider_role = "" chief_complaint = "" reason_for_visit = "" encounter_type = "" visit_type = "" section_loinc_codes = [""] diagnosis_code = "" diagnosis_code_type = "" # for example ICD10 diagnosis_description = "" diagnosis_note = "" target_emr = "" # ATHENA | EPIC | CERNER drug_name = "" medication_code = "" medication_code_type = "" # RXCUI | NDC medication_status = "" # ACTIVE | DISCONTINUED | REFILLED medication_origin = "" # EMR | SUKI_AMBIENT medication_instructions = "" url = f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/context" headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, "Content-Type": "application/json", } payload = { "provider": { "specialty": provider_specialty, "provider_role": provider_role, }, "patient": { "patient_id": patient_id, "name": { "given": [patient_given_name], "family": patient_family_name, }, "dob": patient_dob, "sex": patient_sex, }, "visit": { "chief_complaint": chief_complaint, "encounter_type": encounter_type, "reason_for_visit": reason_for_visit, "visit_type": visit_type, }, "sections": [{"loinc": loinc} for loinc in section_loinc_codes], "diagnoses": { "values": [ { "codes": [ { "code": diagnosis_code, "description": diagnosis_description, "type": diagnosis_code_type, } ], "diagnosis_note": diagnosis_note, } ] }, "emr": { "target_emr": target_emr, }, "orders": { "medication_orders": { "values": [ { "drug_name": drug_name, "medication_code": { "code": medication_code, "type": medication_code_type, }, "linked_diagnosis_codes": [ { "code": diagnosis_code, "type": diagnosis_code_type, } ], "metadata": { "origin": medication_origin, }, "status": medication_status, "instructions": medication_instructions, } ] } }, } response = requests.post(url, headers=headers, json=payload, timeout=60) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 200: print("Context seeded successfully.") else: print("Seed Ambient session context failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; // From Create Ambient Session response const ambientSessionId = ""; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; // Set these from your system const patientId = ""; const patientGivenName = ""; const patientFamilyName = ""; const patientDob = ""; // YYYY-MM-DD const patientSex = ""; // male | female | other | unknown const providerSpecialty = ""; const providerRole = ""; const chiefComplaint = ""; const reasonForVisit = ""; const encounterType = ""; const visitType = ""; const sectionLoincCodes = [""]; const diagnosisCode = ""; const diagnosisCodeType = ""; // for example ICD10 const diagnosisDescription = ""; const diagnosisNote = ""; const targetEmr = ""; // ATHENA | EPIC | CERNER const drugName = ""; const medicationCode = ""; const medicationCodeType = ""; // RXCUI | NDC const medicationStatus = ""; // ACTIVE | DISCONTINUED | REFILLED const medicationOrigin = ""; // EMR | SUKI_AMBIENT const medicationInstructions = ""; type ApiErrorResponse = { code?: number; message?: string; }; const payload = { provider: { specialty: providerSpecialty, provider_role: providerRole, }, patient: { patient_id: patientId, name: { given: [patientGivenName], family: patientFamilyName, }, dob: patientDob, sex: patientSex, }, visit: { chief_complaint: chiefComplaint, encounter_type: encounterType, reason_for_visit: reasonForVisit, visit_type: visitType, }, sections: sectionLoincCodes.map((loinc) => ({ loinc })), diagnoses: { values: [ { codes: [ { code: diagnosisCode, description: diagnosisDescription, type: diagnosisCodeType, }, ], diagnosis_note: diagnosisNote, }, ], }, emr: { target_emr: targetEmr, }, orders: { medication_orders: { values: [ { drug_name: drugName, medication_code: { code: medicationCode, type: medicationCodeType, }, linked_diagnosis_codes: [ { code: diagnosisCode, type: diagnosisCodeType, }, ], metadata: { origin: medicationOrigin, }, status: medicationStatus, instructions: medicationInstructions, }, ], }, }, }; const response = await fetch( `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/context`, { method: "POST", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, "Content-Type": "application/json", }, body: JSON.stringify(payload), } ); const responseText = await response.text(); let responseBody: ApiErrorResponse | Record | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("Seed Ambient session context returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 200) { console.log("Context seeded successfully."); } else { const error = responseBody as ApiErrorResponse; console.error("Seed Ambient session context failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` # Create Ambient Session Source: https://developer.suki.ai/api-reference/ambient-sessions/create POST /api/v1/ambient/session/create Initialize a new Ambient session for patient encounter documentation **Updated** * Pass **`emr_encounter_id`** to enable cross-modality ambient interoperability. * The response now includes **`composition_id`**. Use it as `note_id` with the note-level Ambient APIs. * The `multilingual` parameter is deprecated. Multilingual support is enabled by default for all ambient sessions. Use this endpoint to create an ambient session. An ambient session is one recording for a patient encounter (visit). One encounter can include one or more ambient sessions. Suki returns an `ambient_session_id` and a `composition_id`. Use **`ambient_session_id`** for session-scoped operations such as context, streaming, status, and session content. Store the **`composition_id`** from the response. You will pass this value as the `note_id` when you call the following note-level Ambient APIs: To learn how to use ambient across modalities, refer to the [Ambient interoperability](/documentation/concepts/ambient-clinical-notes/ambient-interoperability) guide. ### Request body fields All fields in the request body are **optional** for a standalone session. Pass `emr_encounter_id` to make the note interoperable. Pass `encounter_id` for a re-ambient workflow, then reuse the same value for every re-ambient session on that note. | Field | Type | Description | | -------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ambient_session_id` | string (UUID) | Session ID (Ambient APIs). If omitted, Suki generates one and returns it in the response. | | `emr_encounter_id` | string (UUID) | EMR Encounter ID. Identifies the patient visit, which can contain multiple notes. Without this field, the note is not interoperable across modalities. | | `encounter_id` | string | Encounter ID. Required for re-ambient workflows. Store and reuse the same value for every re-ambient session on that note. Up to **255** characters. The create response does not include `encounter_id`. | **Important**: * We recommend that recordings are at least **1 minute** long. Short recordings may not contain enough information for note generation. * If the recording is too short, note generation may be **skipped**. * For interoperable workflows, pass a valid UUID for `emr_encounter_id`. * To continue a note on another modality, pass the existing `emr_encounter_id`. * Do not create sessions for the same `emr_encounter_id` at the same time. Wait at least **1 second** between create requests for that encounter. Faster back-to-back creates can return a conflict. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki.ai" CREATE_SESSION_URL = f"{BASE_URL}/api/v1/ambient/session/create" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" # Set these from your system. Omit a field by leaving the value as None. # All request body fields are optional. Suki generates values you omit. # Pass emr_encounter_id for cross-modality Ambient interoperability. ambient_session_id = None # Optional UUID for this Ambient session emr_encounter_id = None # UUID for your EMR encounter encounter_id = None # Required for re-ambient workflows headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, "Content-Type": "application/json", } payload = {} if ambient_session_id: payload["ambient_session_id"] = ambient_session_id if emr_encounter_id: payload["emr_encounter_id"] = emr_encounter_id if encounter_id: payload["encounter_id"] = encounter_id response = requests.post( CREATE_SESSION_URL, headers=headers, json=payload, timeout=60, ) print("HTTP status:", response.status_code) try: response_body = response.json() except ValueError: print("Response was not JSON:") print(response.text) raise SystemExit(1) print("Response body:") print(json.dumps(response_body, indent=2)) if response.status_code == 201: created_ambient_session_id = response_body["ambient_session_id"] composition_id = response_body["composition_id"] print("ambient_session_id:", created_ambient_session_id) print("composition_id:", composition_id) print( "Use ambient_session_id for session APIs " "(context, stream, status, session content)." ) print( "Use composition_id as note_id for note-level Ambient APIs " "(note content, note context, note structured data)." ) else: print("Create Ambient session failed.") if isinstance(response_body, dict): print("code:", response_body.get("code")) print("message:", response_body.get("message")) ``` ```typescript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki.ai"; const CREATE_SESSION_URL = `${BASE_URL}/api/v1/ambient/session/create`; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; // Set these from your system. Omit a field by leaving the value undefined. // All request body fields are optional. Suki generates values you omit. // Pass emr_encounter_id for cross-modality Ambient interoperability. const ambientSessionId: string | undefined = undefined; // Optional UUID for this Ambient session const emrEncounterId: string | undefined = undefined; // UUID for your EMR encounter const encounterId: string | undefined = undefined; // Required for re-ambient workflows type CreateAmbientSessionRequest = { ambient_session_id?: string; emr_encounter_id?: string; encounter_id?: string; }; type CreateAmbientSessionResponse = { ambient_session_id: string; composition_id: string; }; type ApiErrorResponse = { code?: number; message?: string; }; const payload: CreateAmbientSessionRequest = {}; if (ambientSessionId) { payload.ambient_session_id = ambientSessionId; } if (emrEncounterId) { payload.emr_encounter_id = emrEncounterId; } if (encounterId) { payload.encounter_id = encounterId; } const response = await fetch(CREATE_SESSION_URL, { method: "POST", headers: { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, "Content-Type": "application/json", }, body: JSON.stringify(payload), }); const responseText = await response.text(); let responseBody: CreateAmbientSessionResponse | ApiErrorResponse | unknown; try { responseBody = responseText ? JSON.parse(responseText) : {}; } catch { console.error("Response was not JSON:"); console.error(responseText); throw new Error("Create Ambient session returned non-JSON response"); } console.log("HTTP status:", response.status); console.log("Response body:", JSON.stringify(responseBody, null, 2)); if (response.status === 201) { const session = responseBody as CreateAmbientSessionResponse; console.log("ambient_session_id:", session.ambient_session_id); console.log("composition_id:", session.composition_id); console.log( "Use ambient_session_id for session APIs (context, stream, status, session content)." ); console.log( "Use composition_id as note_id for note-level Ambient APIs (note content, note context, note structured data)." ); } else { const error = responseBody as ApiErrorResponse; console.error("Create Ambient session failed."); console.error("code:", error.code); console.error("message:", error.message); } ``` # End Ambient Session Source: https://developer.suki.ai/api-reference/ambient-sessions/end POST /api/v1/ambient/session/{ambient_session_id}/end Complete Ambient session and trigger clinical note generation Use this endpoint to end an ambient session and trigger the clinical note generation process. Ending an ambient session closes that recording so Suki can process it. It does not close the patient encounter. Create another ambient session for the same encounter when the visit needs more capture. If you get a `skipped` status, it means that the note was not generated because the conversation transcript was empty or the session was too short. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests ambient_session_id = "123dfg-456dfg-789dfg-012dfg" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{ambient_session_id}/end" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.post(url, headers=headers) if response.status_code == 200: print("Session ended successfully. Clinical note generation triggered.") else: print(f"Failed to end session: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const ambientSessionId = '123dfg-456dfg-789dfg-012dfg'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${ambientSessionId}/end`, { method: 'POST', headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } } ); if (response.ok) { console.log('Session ended successfully. Clinical note generation triggered.'); } else { const error = await response.json(); console.error(`Failed to end session: ${response.status}`, error); } ``` # Ambient Session Metadata Source: https://developer.suki.ai/api-reference/ambient-sessions/metadata POST /api/v1/ambient/session/{ambient_session_id}/metadata Add metadata to Ambient session (deprecated; use context endpoint instead) This endpoint is `deprecated` We no longer support this endpoint. If you are using it, update your code to use the [Context](/api-reference/ambient-sessions/context) endpoint instead. That endpoint lets you set session context for an ambient session. # Update Ambient Session Context Source: https://developer.suki.ai/api-reference/ambient-sessions/update-context PATCH /api/v1/ambient/session/{ambient_session_id}/context Update existing session context with new clinical information **Updated:** You can now update the ambient session context with new **EMR context** and **Medication orders**. Read more in [Medication orders](/documentation/concepts/ambient-clinical-notes/medication-orders). Use this endpoint to update the session context for an ambient session. The API applies a field mask so you can send only the parts of the context you want to change. This is a **PATCH** operation that allows partial updates to the session context. ## Comparison with POST Context | Feature | POST (Seed) | PATCH (Update) | | :---------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------- | | **Purpose** | Set entire context all at once when available | Incrementally build context as information becomes available | | **Data Approach** | Complete context payload | Partial context updates | | **Timing** | Before EndSession. When you have all context information together. | Before EndSession. As information becomes available progressively | | **Behavior** | Replaces entire context | Updates only specified fields | # API Reference Guidelines Source: https://developer.suki.ai/api-reference/api-guidelines Decode API reference tags ([NEW], [DEPRECATED], [EARLY ACCESS]), parameter markers, example conventions, and versioning before you implement endpoints This guide explains the **tags**, **indicators**, and **standards** we use in our API documentation. Understanding these conventions will help you navigate the reference materials more effectively and build robust integrations. ## API status tags We use the following tags next to endpoint titles to indicate their status and maturity. ### \[NEW] This tag indicates that an API endpoint has been recently added to Suki for partners. * Use this safely in production; it is fully supported and documented. * The API may receive additional non-breaking features in future updates. ### \[UPDATED] This tag indicates that an API endpoint has received significant, backward-compatible enhancements or modifications. * Look for new parameters, response fields, or behavior changes that you can implement. * Your existing integrations should continue to work without modification. ### \[DEPRECATED] This tag indicates that an API endpoint is scheduled for removal in a future version. * You should plan to migrate any existing integrations to the recommended alternatives. * Check the documentation for the specific migration timeline and replacement APIs. Suki provides migration guides to support your transition. You should avoid using this endpoint in new integrations. ### \[EARLY ACCESS] This tag indicates that an API endpoint is available for testing and feedback but may not be fully stable. * The API's behavior may change based on feedback, and breaking changes are possible before it becomes generally available. * Access to this API may require special configuration. We encourage your feedback to help us improve it. Use early access APIs with caution. The ws and webhook indicators in the API documentation indicate that an API endpoint is a WebSocket or a Webhook endpoint. ## Documentation standards ### Parameters Each parameter in an API request is clearly marked to ensure you know what is required. * **Required**: You must include these parameters in all API requests. Requests will fail without them. * **Optional**: Include these parameters to access enhanced functionality. When applicable, the documentation will note the default value used if you don't provide one. ### Examples All API endpoints include comprehensive examples to guide your implementation. * **Response examples**: You will find examples of success responses with realistic data, as well as common error responses. Each field in the response is described. * **Code examples**: You will find practical code snippets, such as `cURL` commands for direct testing and `JSON` payloads to illustrate the request and response structure. ## Using code examples in your integration Code snippets in the API reference (Python, TypeScript, cURL, and similar) show real paths, headers, and JSON shapes. To use them in your own systems, do the following: * **Use real credentials**: Replace placeholders (for example ``, ``, or ``) with values from your partner integration. Complete the [Partner onboarding](/documentation/get-started/partner-onboarding) flow first, then follow [Provider authentication](/api-reference/provider-authentication) for register, login, and how tokens map to API headers. Form filling APIs follow the same authentication model; see [Form filling authentication](/form-filling-api-reference/authentication) for that tab’s layout. * **Use the right base URL**: Examples may use a staging host (for example `https://sdp.suki-stage.com`). Use the base URL Suki gives you for each environment (staging, production, and so on). * **Keep secrets server-side**: Do not put partner tokens, JWTs, or `sdp_suki_token` in untrusted clients, public repos, or browser bundles where they can be extracted. * **Python**: Install any dependency the sample assumes (for example `requests` via `pip install requests`). Run calls from a backend service or trusted script with outbound HTTPS to Suki. * **TypeScript or JavaScript**: Run samples on the **server** using a runtime that provides **`fetch`** (for example **Node.js 18+**, Deno, or Bun). Older Node versions need another HTTP client or a `fetch` polyfill. Calling Suki **directly from a browser** usually hits **CORS** limits unless your integration is explicitly allowed; typical integrations call Suki from **your backend** or **your proxy**. * **cURL**: Use a shell with `curl` installed; pass the same headers and JSON bodies as in the docs, with real tokens and URL. ## Version management ### API versioning Our APIs follow semantic versioning principles to make updates predictable. * **Major versions (`v1`, `v2`)**: Indicate breaking changes that may require you to update your code. * **Minor versions (`v1.1`, `v1.2`)**: Introduce new features in a backward-compatible way. * **Patch versions (`v1.1.1`, `v1.1.2`)**: Include backward-compatible bug fixes and minor improvements. The following table shows which features are available in each version: | Feature | v1 | | ------------------------------- | -- | | Authentication (Login/Register) | ✓ | | Ambient session management | ✓ | | Audio streaming (WebSocket) | ✓ | | Content retrieval | ✓ | | Audio transcription | ✓ | | Multilingual support | ✓ | | Personalization | ✓ | | Problem-Based Charting (PBC) | ✓ | | Webhooks | ✓ | | User preferences | ✓ | | Form filling | ✓ | | Dictation | ✓ | | Patient summaries | ✓ | ### Backward compatibility We are committed to making platform updates as smooth as possible. * We communicate breaking changes well in advance and provide migration guidance. * When we add new optional parameters, your existing integrations will not break. * Changes to the format of API responses are additive, meaning we may add new fields, but we will not remove or alter existing ones in a breaking way. ## Best practices ### Choosing the right API * **For production use**: You should use APIs that are unmarked or are tagged as `[NEW]` or `[UPDATED]`. These are stable, fully supported, and have long-term compatibility guarantees. * **For development and testing**: Consider using `[EARLY ACCESS]` APIs to preview upcoming features and provide feedback. This can help you plan for future integrations. ### Migration strategy When an API you are using is marked as `[DEPRECATED]`, we recommend the following process: 1. **Assess impact**: Review your current usage of the deprecated endpoint. 2. **Plan timeline**: Check the deprecation timeline in the documentation and plan your migration. 3. **Test alternatives**: Implement and test the recommended replacement API. 4. **Migrate**: Update your integration in phases to minimize disruption. ### Getting help For questions about API status, migration timelines, or implementation guidance, please contact our **customer success team**. Read the [API changelog](/api-reference/product-updates/changelog) section for the latest updates and changes to the APIs. For a searchable list of deprecated endpoints, parameters, and SDK properties, refer to the [Deprecation list](/updates/deprecations). ## Next steps Use the following APIs to get started with the Suki Platform: **[Ambient API](/api-reference/overview)** - Learn about the Ambient API. **[Form filling API](/form-filling-api-reference/overview)** - Learn about the Form filling API. **[Dictation API](/api-reference/ambient-dictation)** - Learn about the Dictation API. # Asynchronous Notifications Source: https://developer.suki.ai/api-reference/asynchronous/webhook POST /webhooks/notification Webhook endpoint for receiving asynchronous notifications from Suki platform * **Notification Webhooks are available through the Partner APIs.** Sessions created with the Web SDK, Mobile SDK, or Headless Web SDK use the same platform Webhook callbacks. * **Webhooks are available for ambient session and CKG data ingestion events.**. Use this endpoint to implement an HTTP endpoint in your application that receives Webhook requests from Suki. During [Partner onboarding](/documentation/get-started/partner-onboarding), provide the endpoint URL to Suki to receive notifications for ambient session and CKG data ingestion events. Learn more about how Webhooks work and how to implement your own HTTP endpoint to receive notifications in the [Webhook overview](/documentation/webhook/overview) documentation. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/webhooks/notification', methods=['POST']) def handle_webhook(): """ Webhook endpoint to receive notifications from Suki platform. This endpoint should be hosted by your application. """ # The payload is received in the request body from Suki data = request.get_json() # This is the payload sent by Suki if not data: return jsonify({"error": "Invalid request"}), 400 status = data.get("status") if status == "success": # Handle success notification session_id = data.get("session_id") encounter_id = data.get("encounter_id") sessions = data.get("sessions", []) additional_info = data.get("additional_info") print(f"Session {session_id} completed successfully") print(f"Encounter ID: {encounter_id}") print(f"Total sessions: {len(sessions)}") if additional_info: print(f"Additional info: {additional_info}") # Access links to retrieve content if "_links" in data: links = data["_links"] print("Available links:") # contents is an array of Link objects if "contents" in links: print(" Session contents:") for link in links["contents"]: print(f" {link.get('method')} {link.get('href')} - {link.get('name')}") # encounter_content is an array of Link objects if "encounter_content" in links: print(" Encounter content:") for link in links["encounter_content"]: print(f" {link.get('method')} {link.get('href')} - {link.get('name')}") # transcripts is an array of Link objects if "transcripts" in links: print(" Transcripts:") for link in links["transcripts"]: print(f" {link.get('method')} {link.get('href')} - {link.get('name')}") # status is an array of Link objects if "status" in links: print(" Status:") for link in links["status"]: print(f" {link.get('method')} {link.get('href')} - {link.get('name')}") return jsonify({"message": "Notification received"}), 200 elif status == "failure": # Handle failure notification session_id = data.get("session_id") encounter_id = data.get("encounter_id") error_code = data.get("error_code") error_detail = data.get("error_detail") print(f"Session {session_id} failed") print(f"Encounter ID: {encounter_id}") print(f"Error Code: {error_code}") print(f"Error Detail: {error_detail}") return jsonify({"message": "Failure notification received"}), 200 else: return jsonify({"error": "Unknown status"}), 400 if __name__ == '__main__': app.run(port=3000) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import express from 'express'; const app = express(); app.use(express.json()); app.post('/webhooks/notification', (req, res) => { /** * Webhook endpoint to receive notifications from Suki platform. * This endpoint should be hosted by your application. */ // The payload is received in the request body from Suki const data = req.body; // This is the payload sent by Suki if (!data) { return res.status(400).json({ error: 'Invalid request' }); } const status = data.status; if (status === 'success') { // Handle success notification const sessionId = data.session_id; const encounterId = data.encounter_id; const sessions = data.sessions || []; const additionalInfo = data.additional_info; console.log(`Session ${sessionId} completed successfully`); console.log(`Encounter ID: ${encounterId}`); console.log(`Total sessions: ${sessions.length}`); if (additionalInfo) { console.log(`Additional info:`, additionalInfo); } // Access links to retrieve content if (data._links) { const links = data._links; console.log('Available links:'); // contents is an array of Link objects if (links.contents) { console.log(' Session contents:'); links.contents.forEach((link: any) => { console.log(` ${link.method} ${link.href} - ${link.name}`); }); } // encounter_content is an array of Link objects if (links.encounter_content) { console.log(' Encounter content:'); links.encounter_content.forEach((link: any) => { console.log(` ${link.method} ${link.href} - ${link.name}`); }); } // transcripts is an array of Link objects if (links.transcripts) { console.log(' Transcripts:'); links.transcripts.forEach((link: any) => { console.log(` ${link.method} ${link.href} - ${link.name}`); }); } // status is an array of Link objects if (links.status) { console.log(' Status:'); links.status.forEach((link: any) => { console.log(` ${link.method} ${link.href} - ${link.name}`); }); } } return res.status(200).json({ message: 'Notification received' }); } else if (status === 'failure') { // Handle failure notification const sessionId = data.session_id; const encounterId = data.encounter_id; const errorCode = data.error_code; const errorDetail = data.error_detail; console.log(`Session ${sessionId} failed`); console.log(`Encounter ID: ${encounterId}`); console.log(`Error Code: ${errorCode}`); console.log(`Error Detail: ${errorDetail}`); return res.status(200).json({ message: 'Failure notification received' }); } else { return res.status(400).json({ error: 'Unknown status' }); } }); app.listen(3000, () => { console.log('Webhook server listening on port 3000'); }); ``` # Create Dictation Session Source: https://developer.suki.ai/api-reference/audio-transcription/create-session POST /api/v1/transcription/session/create Create a Dictation session to transcribe spoken audio into text in real time Use this endpoint to create a Dictation session to transcribe spoken audio into text. Refer to the [Audio Dictation guide](/documentation/concepts/dictation/dictation) for more information. Returns a `201 Created` status with the `transcription_session_id` that is used to identify the session for transcribing audio and ending the session. # End Dictation Session Source: https://developer.suki.ai/api-reference/audio-transcription/end-session POST /api/v1/transcription/session/{transcription_session_id}/end End a Dictation session and retrieve the final transcription results Use this endpoint to end an active Dictation session and retrieve the final transcription results. This endpoint stops the audio streaming and returns the complete transcript along with session metadata. Returns a `200 OK` status with a success message. # Dictation Session Streaming Source: https://developer.suki.ai/api-reference/audio-transcription/stream-transcription GET /ws/transcribe Stream audio to an active Dictation session for real-time transcription Use this WebSocket endpoint to stream audio to an active Dictation session for **real-time transcription**. ## Related guides ## Prerequisites Complete these steps **before** opening the WebSocket. Opening `/ws/transcribe` before the Dictation session is **`READY`** or **`IDLE`** often leads to handshake failures. If the session is **`RUNNING`**, **`COMPLETED`**, or in another state, the WebSocket handshake fails with **`FailedPrecondition`** (for example **transcript session is not accepting new speech sessions**). * **Authenticate** and obtain `sdp_suki_token`. * **Create a Dictation session** with POST [`/api/v1/transcription/session/create`](/api-reference/audio-transcription/create-session). A successful create returns **201 Created**; keep the `transcription_session_id` from the response. * **Authenticate and open the WebSocket** on `wss://sdp.suki-stage.com/ws/transcribe`. To stream audio, you must first establish an **authenticated** WebSocket connection. The authentication method you use depends on your client type: browser or non-browser. - Stream audio in **chunks** for the best latency and throughput. - For partial and final inbound transcript frames, **`EOF`**, and session state rules, refer to [Dictation transcript frames](/documentation/how-to/audio-streaming/dictation-streaming-transcripts). ## Inbound transcript messages The server sends **JSON text frames** that include `transcript`, `is_final`, and `transcript_id`. Use `is_final` to identify whether the transcript is a partial result or a final result. After the audio stream ends, the server sends `{ "transcript": { "transcript": "EOF" } }` and then closes the WebSocket connection. Refer to [Read Dictation transcript frames](/documentation/how-to/audio-streaming/dictation-streaming-transcripts) for frame examples, **`words`** and speaker IDs on finals, and client-side filtering rules. ## Authentication Authentication is applied during the WebSocket handshake. The method depends on your client type. Use the `Sec-WebSocket-Protocol` header for browser clients, and `sdp_suki_token` and `transcription_session_id` headers for non-browser clients. ### Browser clients If you are connecting from a browser, you must use the `Sec-WebSocket-Protocol` header during the WebSocket handshake. The header must specify the `SukiAmbientAuth` protocol, followed by the **token** and the **transcription session ID** in the following format. ```bash theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} Sec-WebSocket-Protocol: SukiAmbientAuth,, ``` ### Non-browser clients If you are connecting from a non-browser client, such as a mobile or server-side application, you must provide the **token** and **session ID** as separate HTTP headers in the initial WebSocket upgrade request. * `sdp_suki_token`: Session token from login. * `sdp_provider_id`: Provider identifier. Optional for standard partners; **Required** for Single Auth Token authentication. * `transcription_session_id`: The ID for the current session. Important: * All messages must be sent as **JSON text** frames over the WebSocket connection. * Do not send raw binary data or use HTTP endpoints for streaming audio. ## Full code examples For end-to-end Dictation streaming examples, start with these tutorials: # Authentication APIs Source: https://developer.suki.ai/api-reference/authentication Register providers, exchange Partner Tokens for Suki Tokens, and fetch JWKS keys for Register, Login, and token verification on the Suki platform The Authentication APIs enable partners to register healthcare providers with Suki and exchange a Partner Token for a Suki access token. Providers typically sign in to your application through your identity provider. Your identity provider issues a Partner Token (JWT), and your servers send that token to Suki on Register and Login. Suki does not store provider passwords or host provider sign-in screens. Register is a one-time call that creates a provider in Suki or links an existing provider to your partner organization. Login returns a Suki Token (`sdp_suki_token`) that authorizes subsequent REST and WebSocket API calls for that provider. Critically, a Partner Token alone is not enough to call session, streaming, or content APIs. You must exchange it for a Suki Token first. Register and Login are called from your servers and authenticated with your `partner_id` and Partner Token. Suki Tokens are valid for **1 hour**. Call Login again with a valid Partner Token to refresh. The JWKS endpoint is public and returns Suki's public keys so you can verify Suki-issued tokens such as the Suki Token. ## Available endpoints Register a new provider or link an existing provider to your partner organization Exchange your Partner Token for a Suki Token Return the current JSON Web Key Set for verifying Suki-issued tokens ## Related guides Learn how to authenticate standard partners using the Suki Token Learn how to authenticate Single Auth Token partners using the Suki Token and send provider identity on every request Learn how to authenticate Bearer partners using the Suki Token and send provider identity on Login and Register ## Common use cases Use your own authentication flow while Suki securely authenticates clinicians in the background. No separate Suki sign-in is required. Renew authentication before Suki Tokens expire so ambient capture, dictation, and other workflows continue without interruption. Validate Suki Tokens using the JWKS endpoint before creating sessions, processing webhooks, or authorizing API requests. Use a shared organization-level Partner Token while identifying each clinician with `provider_id` during authentication. # JWKS URL Source: https://developer.suki.ai/api-reference/authentication/jwks GET /api/auth/.well-known/jwks-pub.json Public key endpoint for JWT token verification and signature validation Use this public endpoint to get the JWKS (JSON Web Key Set) containing Suki's public keys. Use these keys to verify the signature of any JWT issued by Suki, such as the `suki_token`. This endpoint follows the **RFC 7517** standard. **Authentication** This is a public endpoint and does not require authentication. ## Common integration patterns and use cases * **Verify issued tokens:** Fetch the JWKS and use the matching public key to verify the signature of a `suki_token` before trusting its claims. * **Handle key rotation:** Resolve signing keys by key ID and refresh the JWKS when a token references a key that is not in your cache. * **Cache public keys:** Cache the JWKS according to your token-verification library or service policy, and refresh it when key resolution fails. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki.ai/api/auth/.well-known/jwks-pub.json" response = requests.get(url) if response.status_code == 200: jwks = response.json() print("Public keys retrieved successfully") print(f"Keys: {jwks}") else: print(f"Failed to retrieve JWKS: {response.status_code}") ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki.ai/api/auth/.well-known/jwks-pub.json'); if (response.ok) { const jwks = await response.json(); console.log('Public keys retrieved successfully'); console.log('Keys:', jwks); } else { console.error(`Failed to retrieve JWKS: ${response.status}`); } ``` # Login Source: https://developer.suki.ai/api-reference/authentication/login POST /api/v1/auth/login Authenticate healthcare provider and obtain access token for API usage Use this endpoint to authenticate a provider. On a successful request, this endpoint returns a Suki Token (`suki_token`/`sdp_suki_token`) that you must use to authorize all subsequent API calls for that user. The `suki_token` is a JWT that is valid for **one hour**. If you are using the JWT Bearer/Assertion authentication method, the response may also include an additional `jwt_bearer` field. ## Guides ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript, C++. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki.ai/api/v1/auth/login" payload = { "partner_id": "your-partner-id", "partner_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_id": "provider-123" # Required for Bearer and Single Auth Token partners; omit for Standard } response = requests.post(url, json=payload) if response.status_code == 200: data = response.json() suki_token = data["suki_token"] print(f"Authentication successful. Token: {suki_token}") else: print(f"Authentication failed: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki.ai/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ partner_id: 'your-partner-id', partner_token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', provider_id: 'provider-123' // Required for Bearer and Single Auth Token partners; omit for Standard }) }); if (response.ok) { const data = await response.json(); const sukiToken = data.suki_token; console.log(`Authentication successful. Token: ${sukiToken}`); } else { const error = await response.json(); console.error(`Authentication failed: ${response.status}`, error); } ``` ```cpp theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} // deps: libcurl, nlohmann/json #include #include #include #include using json = nlohmann::json; static size_t write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) { static_cast(userdata)->append(ptr, size * nmemb); return size * nmemb; } int main() { curl_global_init(CURL_GLOBAL_DEFAULT); const std::string url = "https://sdp.suki.ai/api/v1/auth/login"; json payload = { {"partner_id", "your-partner-id"}, {"partner_token", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}, {"provider_id", "provider-123"} // Required for Bearer and Single Auth Token partners; omit for Standard }; std::string body = payload.dump(); std::string response; CURL* curl = curl_easy_init(); struct curl_slist* headers = curl_slist_append(nullptr, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_perform(curl); long status = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status); curl_slist_free_all(headers); curl_easy_cleanup(curl); if (status == 200) { std::string suki_token = json::parse(response).at("suki_token").get(); std::cout << "Authentication successful. Token: " << suki_token << "\n"; } else { std::cerr << "Authentication failed: " << status << "\n" << response << "\n"; } curl_global_cleanup(); return 0; } ``` # Register Source: https://developer.suki.ai/api-reference/authentication/register POST /api/v1/auth/register Register new healthcare provider or link existing provider to partner organization Use this endpoint to register a **new healthcare provider** in the Suki platform or to link an **existing provider** to a new **Partner**-organization relationship. This is a **one-time** setup call for each provider within an organization. ## Registration scenarios This endpoint handles **three** different scenarios depending on the user's status in the Suki system. | Scenario | Condition | Actions Taken | Response | | --------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------ | | **New User** | The provider does not exist in Suki. | • Creates a new organization
• Links your partner account to the organization
• Creates a new user with the provided details | 201 Created | | **Existing User, New Link** | The provider exists but is not yet linked to your partner account. | • Verifies the user and organization details
• Links your partner account to the existing organization | 201 Created | | **Existing User, Already Linked** | The provider and organization are already linked to your partner account. | • Detects the existing link | 409 Conflict | ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki.ai/api/v1/auth/register" payload = { "partner_id": "your-partner-id", "partner_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "provider_name": "Dr. John Smith", "provider_org_id": "org-123", "provider_id": "provider-123", # Optional "provider_specialty": "CARDIOLOGY" # Optional, defaults to FAMILY_MEDICINE } response = requests.post(url, json=payload) if response.status_code == 201: print("Provider registered successfully") elif response.status_code == 409: print("Provider already linked to this partner") else: print(f"Registration failed: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki.ai/api/v1/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ partner_id: 'your-partner-id', partner_token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', provider_name: 'Dr. John Smith', provider_org_id: 'org-123', provider_id: 'provider-123', // Optional provider_specialty: 'CARDIOLOGY' // Optional, defaults to FAMILY_MEDICINE }) }); if (response.status === 201) { console.log('Provider registered successfully'); } else if (response.status === 409) { console.log('Provider already linked to this partner'); } else { const error = await response.json(); console.error(`Registration failed: ${response.status}`, error); } ``` # Bearer Partner Type Authentication Source: https://developer.suki.ai/api-reference/bearer-partner-authentication Learn how Bearer partner authentication works, when to pass provider_id, and how to integrate with REST APIs Some partners cannot include clinician identity in the OAuth 2.0 token they send to Suki. During onboarding, Suki configures these organizations as **Bearer partners**. Bearer partners authenticate the same way as other server-to-server integrations by sending `partner_token` in the request body of the [Login](/api-reference/authentication/login) and [Register](/api-reference/authentication/register) APIs. Because `partner_token` does not identify the clinician, Bearer partners must also include `provider_id` in every Login and Register request. Suki uses `provider_id` to identify the clinician and validates it against the expression configured during onboarding. **Important** * Bearer authentication **is not the same as** Single Auth Token authentication. * A partner cannot use both Bearer authentication and Single Auth Token authentication. * Suki assigns your authentication type during onboarding. If you are unsure whether your organization is configured as a Bearer partner, contact your Suki partnership team. ## Prerequisites Before you implement Bearer partner authentication, confirm the following: * **Bearer partner configuration** - Your Suki partner contact confirms that your organization is configured as a Bearer partner. * **Provider ID format** - You and Suki agree on a stable provider identifier format, such as an email address or external user ID. Use the same format on every login and register call. * **HTTPS required** - Send [Login](/api-reference/authentication/login) and [Register](/api-reference/authentication/register) requests as HTTPS POST requests with a JSON body. Do not send credentials in query parameters. ## Common integration patterns and use cases Use Bearer partner authentication only when Suki configured this partner type during onboarding. In each pattern, your backend supplies the active provider identity separately from the shared token. Reuse the shared `partner_token` across providers, and send the active provider's stable `provider_id` on every [Login](/api-reference/authentication/login) and [Register](/api-reference/authentication/register) request. Read the signed-in provider from your application session or identity store, then map that identity to the agreed `provider_id` format in the authentication request body. Keep your existing shared-token model when your identity provider cannot issue a Suki-compatible per-user token. Use `provider_id` as the separate provider identity. Diagram: Tenant A, Tenant B, and Tenant C connect through shared partner tokens, then to the Suki platform. Diagram: Tenant A, Tenant B, and Tenant C connect through shared partner tokens, then to the Suki platform. ## How Bearer authentication differs Bearer partners authenticate the same way as other partners, but clinician identity is provided through `provider_id` instead of being derived from `partner_token`. | Topic | Standard authentication | Bearer authentication | | :---------------------------------- | :------------------------------------- | :---------------------------------------------------------- | | Clinician identity | Derived from `partner_token` | Passed as `provider_id` in the request body | | `partner_token` | Per-user ID token or user-scoped token | Typically one shared `partner_token` for multiple providers | | `provider_id` on Login and Register | Optional and ignored | **Required** | | `provider_id` validation | Not applicable | Must match the expression configured during onboarding | ### Bearer authentication behavior * Login and Register identify the clinician using `provider_id` instead of per-user claims in `partner_token`. * Clients, including the Web SDK, pass `provider_id` for Bearer partners. Other clients can do the same. * `provider_id` is **required** and must follow the format agreed during onboarding. * Bearer partners cannot have the `READONLY` partner access level. In Bearer partner authentication, the partner application provides the provider identity on behalf of the signed-in user. This is different from the HTTP `Authorization: Bearer` header format. You still send `partner_token` in the JSON request body for login and register requests. **Security considerations for Bearer partners** Accepting end-user identifiers as API metadata has security implications: * **Encryption:** Send `provider_id` in the JSON body of HTTPS POST requests over TLS. Do not put credentials in query parameters. * **Impersonation:** Restrict Login and Register to trusted systems so impostors cannot assert another clinician's `provider_id`. * **Shared token risk:** Unlike signed OAuth tokens, user metadata in the API body can be misused if someone obtains your shared service account `partner_token`. Monitor for abuse and rotate tokens when your identity provider allows it. ## Authentication workflow For Bearer partners, Suki validates `partner_id` and `provider_id` on [Login](/api-reference/authentication/login). If the provider is not registered, call [Register](/api-reference/authentication/register), then call Login again. The flow matches standard partners after registration. Learn more about registration scenarios in [Provider authentication](/api-reference/provider-authentication#registration-scenarios). ## Login and Register request fields Bearer partners use the same login and register endpoints as standard partners. You must include `provider_id` on every login and register call. ### Login **Endpoint:** [Login](/api-reference/authentication/login) **Method:** POST | Field | Bearer partners | | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------ | | `partner_id` | Required. Partner ID from Suki. | | `partner_token` | Required. Shared `partner_token` your integration uses for authentication. | | `provider_id` | Required. Stable identifier for the provider in your system. Must match the format agreed with Suki during onboarding. | #### Example request ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl -X POST https://sdp.suki-stage.com/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "partner_id": "your-partner-id", "partner_token": "your-shared-partner-token", "provider_id": "provider-123" }' ``` On success, the API returns `suki_token`. Use it as the `sdp_suki_token` header on later Ambient API calls. The token is valid for **1 hour**. To refresh it, call Login again with a valid `partner_token`. ### Register Register a provider once before their first login. Refer to [Provider authentication](/api-reference/provider-authentication#registration-scenarios) for new user, existing user, and conflict responses. **Endpoint:** [Register](/api-reference/authentication/register) **Method:** POST | Field | Bearer partners | | :------------------- | :--------------------------------------------------------------------------------------------------------------------------- | | `partner_id` | Required. Partner ID from Suki. | | `partner_token` | Required. Shared `partner_token` your integration uses for authentication. | | `provider_id` | Required. Stable identifier for the provider in your system. Use this as the user identifier at registration. | | `provider_name` | Required. Display name for the provider. | | `provider_org_id` | Required. Organization the provider belongs to. | | `provider_specialty` | Optional. Defaults to `FAMILY_MEDICINE` if omitted. | #### Example request ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl -X POST https://sdp.suki-stage.com/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "partner_id": "your-partner-id", "partner_token": "your-shared-partner-token", "provider_id": "provider-123", "provider_name": "Dr. Jane Smith", "provider_org_id": "org-123" }' ``` For all Register fields and response codes, refer to the [Register API reference](/api-reference/authentication/register). # Multilingual Support Source: https://developer.suki.ai/api-reference/capabilities/multilingual Multi-language support for Ambient sessions and clinical documentation
Quick summary
Multilingual support lets patients and providers speak in their preferred language during clinical conversations, while Suki automatically generates the final clinical note in English.
Last updated: August 2026
**Multilingual support is supported by:** Ambient APIs, Mobile SDK, Web SDK (v2.1.1+) Multilingual support lets patients and providers speak in their preferred language during clinical conversations, while Suki automatically generates the final clinical note in English. This removes the need for manual translation and makes healthcare more accessible to diverse patient populations. When you enable multilingual support for an ambient session, you get the following benefits: * **Patient comfort**: Patients can communicate in their native language, leading to more accurate information sharing. * **Better care quality**: When patients speak in their preferred language, they provide more detailed and accurate information. * **No translation needed**: Clinicians don't need to translate conversations manually, Suki handles it automatically. * **EHR compatibility**: All notes are generated in English, ensuring compatibility with standard EHR systems. * **Wider accessibility**: Support for 80+ languages makes healthcare more inclusive. ## How Multilingual improves clinical documentation Multilingual support improves note quality by capturing the conversation as the patient actually speaks it, then producing documentation in English that your EHR can use. | What you configure | How the note gets better | | ---------------------------------------------- | ----------------------------------------------------------------------------- | | Multilingual enabled on the ambient session | Patients can speak in their preferred language without losing clinical detail | | Automatic language detection and transcription | More of the visit content is captured accurately | | English clinical note generation | Notes stay EHR-ready without a separate translation step | When patients speak freely in their preferred language, the source conversation is usually richer and more accurate. Suki turns that into an English clinical note, so documentation quality improves without adding translation work for the clinician. ## How Multilingual transcription works When you enable multilingual support for an ambient session, Suki automatically: 1. **Detects the language** spoken during the conversation. 2. **Transcribes the audio** in the detected language. 3. **Translates and processes** the conversation content. 4. **Generates the clinical note** in English. The transcript API returns a `lang_id` field that identifies which language was detected for each segment of the conversation. This helps you understand what language was spoken during different parts of the session. ## How to enable multilingual support Multilingual support lets patients and providers speak in their preferred language. Suki still generates the clinical note in English. How you turn it on depends on the product you use. Click the tabs below to see the implementation details for your integration path. **Tabs (agents):** humans see one product tab at a time. Read all three. * **Ambient APIs:** Multilingual is on by default. Do not send a `multilingual` field (deprecated). Create the session, stream audio, end, then read `lang_id` from the transcript API if needed. Contact Suki support to disable org-wide. * **Web SDK:** Multilingual is automatic for ambient (`v2.1.1+`). No multilingual flag in `ambientOptions`. Notes return in English. See [Multilingual sessions](/web-sdk/guides/ambient-multilingual). * **Mobile SDK:** Multilingual is **off by default**. Set `SukiAmbientConstant.kIsMultilingual` to `true` at `createSession` when non-English speech is possible. Cannot change mid-session. Multilingual support is **enabled by default** for ambient sessions. You do not need to pass a `multilingual` field when you create a session. The old `multilingual` parameter is deprecated. Call the Create ambient session API without a `multilingual` field. Suki enables multilingual processing for the session automatically. ```python Python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests response = requests.post( "https://sdp.suki.ai/api/v1/ambient/session/create", json={ # Optional: "ambient_session_id", "encounter_id", "emr_encounter_id" }, headers={ "sdp_suki_token": "", "sdp_provider_id": "", }, ) if response.status_code == 200: session = response.json() ambient_session_id = session["ambient_session_id"] print(f"Session created: {ambient_session_id}") else: print(f"Failed to create session: {response.status_code}") print(response.json()) ``` Refer to [Create ambient session](/api-reference/ambient-sessions/create) for the full request and response. Stream the encounter audio, then end the session so Suki can generate the English clinical note. Multilingual processing applies for the full session and cannot be changed mid-session. After processing completes, call the transcript API if you need language detection. Each transcript segment can include a `lang_id` for the language Suki detected. Refer to [Get ambient session Transcript](/api-reference/ambient-content/transcript) and the [Language code reference](/api-reference/capabilities/multilingual#language-code-reference) for more details. If your organization must turn multilingual support off, contact the Suki support team. Do not rely on the deprecated `multilingual` request field. Refer to [Deprecations](/updates/deprecations) for the deprecation notice. The Web SDK enables Multilingual support automatically for ambient sessions. You do not configure a multilingual flag in `ambientOptions`. Requires Web SDK `v2.1.1+`. Initialize authentication and mount the ambient experience as usual. Multilingual processing is already on for the session. Refer to [Ambient implementation](/web-sdk/guides/ambient-implementation) for mount options and [Multilingual sessions](/web-sdk/guides/ambient-multilingual) for Web SDK behavior. Providers and patients can speak in their preferred language during the ambient session. You do not need to select a language in the SDK. After submit, the Web SDK returns the generated note in English. Handle `onNoteSubmit` (React) or `note-submission:success` (JavaScript and React) as usual. Refer to [Note management](/web-sdk/guides/note-management) for more details. On Mobile SDK, Multilingual support is **off by default**. Set `SukiAmbientConstant.kIsMultilingual` to `true` when you create the session if the conversation may include languages other than English. Once set, you cannot change it for that session. Pass `kIsMultilingual: true` in the session info dictionary when you call `createSession`. Store the returned `sessionId` for recording and session-level content retrieval. ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} let sessionInfo: [String: AnyHashable] = [ SukiAmbientConstant.kSessionId: encounterId, // Ambient API encounter_id for re-ambient SukiAmbientConstant.kIsMultilingual: true ] SukiAmbientCoreManager.shared.createSession( with: sessionInfo, onCompletion: { result in switch result { case .success(let sessionResponse): let sessionId = sessionResponse.sessionId // Store sessionId for recording and content retrieval print("Session created successfully: \(sessionId)") case .failure(let error): print("Error creating session: \(error)") } } ) ``` Refer to [Create session](/mobile-sdk/ambient-guides/create-session) for session info parameters. Call `setSessionContext(with:)` as needed, then start recording. Capture the visit in the patient's preferred language. End the session when capture is complete so note generation can run. After processing completes, retrieve content with `content(for:)`. The generated clinical note is in English even when the conversation was in another language. Refer to [Session status and content retrieval](/mobile-sdk/ambient-guides/session-status-and-content-retrieval) for more details. For Ambient APIs and Web SDK, multilingual support is on by default. For Mobile SDK, set `kIsMultilingual` to `true` when you create the session. In all products, the setting applies to the entire session and cannot be changed mid-session. ## Supported languages for Multilingual support Suki supports over **80 languages** for Multilingual ambient sessions. Refer to the table below to see the languages currently supported: | | | | | | | ------------------- | ------------------ | ----------- | ------------- | --------- | | Spanish | Norwegian | Macedonian | Kazakh | Yoruba | | Italian | Finnish | Hungarian | Icelandic | Telugu | | English | Vietnamese | Tamil | Marathi | Khmer | | Portuguese | Thai | Hindi | Maori | Malayalam | | German | Slovak | Estonian | Swahili | Lao | | Japanese | Greek | Urdu | Armenian | Punjabi | | Polish | Czech | Latvian | Belarusian | Gujarati | | Russian | Croatian | Slovenian | Nepali | Somali | | Dutch | Danish | Azerbaijani | Occitan | Bengali | | Indonesian | Tagalog | Hebrew | Lingala | Georgian | | Catalan | Korean | Lithuanian | Maltese | Assamese | | French | Romanian | Persian | Tajik | Mongolian | | Turkish | Bulgarian | Welsh | Luxembourgish | Myanmar | | Swedish | Galician | Serbian | Hausa | Shona | | Ukrainian | Bosnian | Afrikaans | Uzbek | Amharic | | Malay | Arabic | Kannada | Pashto | Sindhi | | Chinese (Cantonese) | Chinese (Mandarin) | | | | ## Language code reference Pick a **Letter** below to show languages starting with that letter, then use the table to map each `lang_id` to its corresponding language. This helps you interpret the language codes returned by the Transcript API. We regularly update this list as we add support for new languages. If a language is not included in this table, it is not yet supported.
**A** | Language | Language ID (`lang_id`) | | ----------- | ----------------------- | | afrikaans | af | | amharic | am | | arabic | ar | | armenian | hy | | assamese | as | | azerbaijani | az |
**B** | Language | Language ID (`lang_id`) | | ---------- | ----------------------- | | belarusian | be | | bengali | bn | | bosnian | bs | | bulgarian | bg |
**C** | Language | Language ID (`lang_id`) | | ------------------ | ----------------------- | | catalan | ca | | chinese | zh | | chinese\_cantonese | yue | | chinese\_mandarin | cmn | | croatian | hr | | czech | cs |
**D** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | danish | da | | dutch | nl |
**E** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | english | en | | estonian | et |
**F** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | finnish | fi | | french | fr |
**G** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | galician | gl | | georgian | ka | | german | de | | greek | el | | gujarati | gu |
**H** | Language | Language ID (`lang_id`) | | --------- | ----------------------- | | hausa | ha | | hebrew | he | | hindi | hi | | hungarian | hu |
**I** | Language | Language ID (`lang_id`) | | ---------- | ----------------------- | | icelandic | is | | indonesian | id | | italian | it |
**J** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | japanese | ja |
**K** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | kannada | kn | | kazakh | kk | | khmer | km | | korean | ko |
**L** | Language | Language ID (`lang_id`) | | ------------- | ----------------------- | | lao | lo | | latvian | lv | | lingala | ln | | lithuanian | lt | | luxembourgish | lb |
**M** | Language | Language ID (`lang_id`) | | ---------- | ----------------------- | | macedonian | mk | | malay | ms | | malayalam | ml | | maltese | mt | | maori | mi | | marathi | mr | | mongolian | mn | | myanmar | my |
**N** | Language | Language ID (`lang_id`) | | --------- | ----------------------- | | nepali | ne | | norwegian | no |
**O** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | occitan | oc |
**P** | Language | Language ID (`lang_id`) | | ---------- | ----------------------- | | pashto | ps | | persian | fa | | polish | pl | | portuguese | pt | | punjabi | pa |
**R** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | romanian | ro | | russian | ru |
**S** | Language | Language ID (`lang_id`) | | --------- | ----------------------- | | serbian | sr | | shona | sn | | sindhi | sd | | slovak | sk | | slovenian | sl | | somali | so | | spanish | es | | swahili | sw | | swedish | sv |
**T** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | tagalog | tl | | tajik | tg | | tamil | ta | | telugu | te | | thai | th | | turkish | tr |
**U** | Language | Language ID (`lang_id`) | | --------- | ----------------------- | | ukrainian | uk | | urdu | ur | | uzbek | uz |
**V** | Language | Language ID (`lang_id`) | | ---------- | ----------------------- | | vietnamese | vi |
**W** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | welsh | cy |
**Y** | Language | Language ID (`lang_id`) | | -------- | ----------------------- | | yoruba | yo |
## Best practices * **Enable when needed**: Only enable multilingual support when you expect conversations in multiple languages. This optimizes performance. * **Set patient language preference**: If you know the patient's preferred language, you can display this information in your UI to help providers prepare. * **Monitor language detection**: Use the `lang_id` from transcripts to understand language usage patterns in your application. * **Test with your languages**: Verify multilingual support works correctly with the languages your patients commonly use. * **Note language in UI**: Consider displaying the detected language in your UI so providers know what language was spoken. ## Related APIs Use these APIs to work with multilingual support: Retrieve transcripts with language detection information (`lang_id`) Create ambient sessions. Multilingual support is enabled by default # Personalization Source: https://developer.suki.ai/api-reference/capabilities/personalization Customize clinical note generation based on provider preferences and specialty
Quick summary
Personalization allows you to customize how Suki generates clinical notes based on each provider's preferences. Control how much detail (short and concise, balanced, or very detailed) and how it's formatted (continuous paragraphs or bullet points).
Last updated: August 2026
**Personalization is supported by:** APIs, Web SDK, Mobile SDK Personalization allows you to help providers customize how Suki generates their clinical notes. Every provider has different preferences, some want short bullet points, others want detailed paragraphs. Personalization ensures each provider gets notes that match their style. When you use personalization, you can customize two aspects of note generation: * **How much detail**: Short and concise, balanced, or very detailed notes. * **How it's formatted**: Continuous paragraphs (narrative) or bullet points. Once you set a provider's preferences, Suki automatically applies them to all future notes for that provider. You set it once, and Suki remembers, no need to send preferences with every request. Using personalization, you get the following benefits: * **Provider satisfaction**: Notes match each provider's preferred style and level of detail. * **Consistent documentation**: Once set, preferences apply automatically to all future notes. * **Efficiency**: Providers don't need to manually adjust notes; they're generated according to their preferences. * **Flexibility**: Different providers can have different preferences based on their specialty and workflow. * **Better adoption**: When notes match provider preferences, they're more likely to use and trust the system. ## How Personalization improves clinical documentation Personalization reduces post-generation editing by aligning note style with how each provider already documents. This helps clinicians trust the generated notes and reduces the need for manual edits before signing. | What you configure | How the note gets better | | ------------------------------------------------ | ---------------------------------------------------------------------- | | Verbosity (`CONCISE`, `BALANCED`, or `DETAILED`) | Notes have the right amount of detail for that provider | | Section format (`NARRATIVE` or `BULLETED`) | Sections match the reading style the provider expects | | Persistent provider preferences | Future notes stay consistent without sending settings on every session | When notes match provider preference, clinicians usually make fewer style edits before sign. That improves trust and adoption, and it shortens the path from generated note to final documentation. ## How Personalization works Settings are saved at the user level (not per session) and applied to all future note generation for that provider. **The process:** 1. **Set preferences**: Use the Mobile SDK `setPersonalizationPreferences` method or the User Preferences API to configure a provider's preferences. 2. **Automatic application**: Suki applies these settings to all future notes for that provider. 3. **Update anytime**: Update preferences at any time; the most recent settings always take effect. Settings are **persistent** and **user-specific**. You don't need to send preferences with every session request. ## How to set Personalization preferences Personalization is saved for the provider, not for one ambient session. Set preferences before the visit starts. Suki uses the latest saved values for that provider's future notes. Click the tabs below to see the implementation details for your integration path. **Tabs (agents):** humans see one product tab at a time. Read all three. * **Ambient APIs:** `PATCH /api/v1/user/preferences` with `personalization_preference` (verbosity `CONCISE` | `BALANCED` | `DETAILED`; optional section\_format per LOINC). Preferences are per `sdp_provider_id`. * **Mobile SDK:** Set personalization through Mobile SDK provider preference APIs (see this tab). * **Web SDK:** Configure personalization in the Web SDK ambient / preferences flow (see this tab). Preferences apply to future notes for that provider. Save preferences with the [User Preferences API](/api-reference/user-preferences/preferences). Send a `PATCH` to `/api/v1/user/preferences` and set `sdp_provider_id` to the provider whose note style you want to change. Use that provider's Suki token and provider ID. Preferences are user-specific, so use the correct `sdp_provider_id` for each clinician. Set verbosity to `CONCISE`, `BALANCED`, or `DETAILED`. Optionally set section format to `NARRATIVE` or `BULLETED` for supported LOINC sections: History of Present Illness (`10164-2`), Assessment and Plan (`51847-2`), Assessment (`51848-0`), and Plan (`18776-5`). This is a `PATCH` request, so send only the fields you want to change. You can update verbosity, section format, or both. ```python Python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests response = requests.patch( "https://sdp.suki.ai/api/v1/user/preferences", headers={ "sdp_suki_token": "", "sdp_provider_id": "", "Content-Type": "application/json", }, json={ "personalization_preference": { "verbosity": "CONCISE", "section_format": [ { "loinc": "10164-2", "style": "NARRATIVE", } ], } }, ) if response.status_code == 200: print("Preferences updated successfully") print(response.json()) else: print(f"Failed to update preferences: {response.status_code}") print(response.json()) ``` Refer to [User Preferences](/api-reference/user-preferences/preferences) for the full request and response schema. After the update succeeds, create ambient sessions as usual for the same provider. You do not send personalization fields in session context. Suki applies the saved preferences when it generates the note. When a provider changes their preferred style, call the same `PATCH` endpoint again before the next visit. The most recent values apply to future notes. Call `setPersonalizationPreferences` after you initialize the Mobile SDK. Preferences are saved for the signed-in provider and apply to future notes. Requires Mobile SDK `v2.3.0+`. Initialize and authenticate the Mobile SDK for the provider whose preferences you want to update. Include `verbosity`, `section_format`, or both. For each section format entry, pass a supported LOINC code and either `NARRATIVE` or `BULLETED`. ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} let preferences: [String: AnyHashable] = [ "verbosity": "CONCISE", "section_format": [ [ "loinc": "10164-2", "style": "NARRATIVE" ], [ "loinc": "51847-2", "style": "BULLETED" ] ] ] ``` Call `setPersonalizationPreferences` and wait for the completion handler before you start recording. ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} SukiAmbientCoreManager.shared.setPersonalizationPreferences(preferences) { result in switch result { case .success: print("Preferences updated successfully") case .failure(let error): print("Error updating preferences: \(error)") } } ``` Do not pass a nil or empty preferences dictionary. The SDK returns `invalidPreferences` for that input. Create the session, set clinical context, record, and end the session as usual. Do not add personalization fields to `setSessionContext(with:)`. The SDK uses the saved preferences for future note generation. Call `setPersonalizationPreferences` again when the provider changes verbosity or section style. The most recently saved values apply to future notes. The Web SDK does not take personalization fields in `ambientOptions`. Save preferences from your backend with the User Preferences API for the same provider, then run the Web SDK ambient workflow as usual. Use the same provider identity that authenticates the Web SDK. Your backend must update preferences for that provider. Call `PATCH /api/v1/user/preferences` from your backend with the provider's Suki token and `sdp_provider_id`. Keep API credentials on the server, not in browser code. ```typescript TypeScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch( "https://sdp.suki.ai/api/v1/user/preferences", { method: "PATCH", headers: { "Content-Type": "application/json", "sdp_suki_token": "", "sdp_provider_id": "", }, body: JSON.stringify({ personalization_preference: { verbosity: "CONCISE", section_format: [ { loinc: "10164-2", style: "NARRATIVE", }, ], }, }), }, ); if (response.ok) { const data = await response.json(); console.log("Preferences updated successfully", data); } else { const error = await response.json(); console.error(`Failed to update preferences: ${response.status}`, error); } ``` Refer to [User Preferences](/api-reference/user-preferences/preferences) for the full request and response schema. After preferences are saved, initialize and mount the Web SDK for that provider. Configure note sections in `ambientOptions.sections` as usual. Do not add verbosity or section-format fields to `ambientOptions`. Refer to [Ambient implementation](/web-sdk/guides/ambient-implementation) and [AmbientOptions](/web-sdk/api-reference/types/ambient-options) for more details. Providers capture and submit the session in the Web SDK. Suki applies the latest saved preferences when it generates the note. When a provider changes their preferred style in your app, call the User Preferences API again from your backend before the next visit. ## Personalization options With Personalization, you can customize two aspects of note generation: verbosity and section style. ### Verbosity Verbosity controls how much detail is included in the generated note. This setting applies to **all note sections**. **Applies to:** All note sections Generates shorter, to-the-point notes with essential information only. Provides a moderate level of detail: comprehensive but not excessive. Generates comprehensive notes with extensive detail and context. ### Section style Section style lets you control the formatting style for specific clinical sections. Set different styles for different sections as needed. **Applies to:** * History of Present Illness **(10164-2)**. * Assessment and Plan **(51847-2)**. * Assessment **(51848-0)**. * Plan **(18776-5)**. Generates notes in a continuous, story-like format that flows naturally. Generates notes using bullet points for easy scanning and quick reference. **Example:** ```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} "section_format": [ { "loinc": "10164-2", "style": "NARRATIVE" }, { "loinc": "51848-0", "style": "BULLETED" } ] ``` ## Best practices * **Set defaults early**: Configure preferences when providers are first registered in your system. * **Offer a UI**: Let providers choose their preferences through your application's settings page. * **Explain options**: Help providers understand the difference between verbosity levels and style options. * **Update when requested**: Make it easy for providers to change their preferences as their needs evolve. * **Test with real notes**: Verify that preferences produce notes that match provider expectations. ## Related APIs Set and update personalization preferences for providers # Problem-Based Charting Source: https://developer.suki.ai/api-reference/capabilities/problem-based-charting Problem-based clinical documentation approach with diagnosis context integration **Updated** * Structured data output now includes **HCC** codes alongside ICD10, IMO, and SNOMED for each suggested diagnosis. * For how the system reconciles those diagnoses with the conversation (API flow), refer to [Reconciliation](/api-reference/capabilities/problem-based-charting#reconciliation). For Web SDK implementation details, refer to [Existing patient diagnoses](/web-sdk/guides/ambient-problem-based-charting#existing-patient-diagnoses).
Quick summary
Problem-Based Charting (PBC) is a clinical documentation approach that organizes notes by patient problems instead of traditional note sections, and suggests diagnoses for each problem.
Last updated: August 2026
**Problem-Based Charting is supported by:** Ambient APIs, Web SDK, Mobile SDK Problem-Based Charting (PBC) organizes clinical notes by patient problems instead of traditional note sections. When you use PBC, Suki generates two things: 1. **Clinical note**: Organized by each problem or diagnosis. 2. **Structured artifacts**: Suggested diagnoses with ICD10, IMO, SNOMED, and HCC codes. PBC notes are different from traditional notes. In traditional notes, information is organized by sections like "History," "Assessment," and "Plan." In PBC notes, information is organized by each problem, grouping all related information together. When you enable PBC, providers get a note that has the following benefits: * **Easier to read**: See everything about each problem in one place. * **Better continuity**: Includes existing problems from previous visits automatically. * **Complete picture**: Captures both old and new problems discussed during the visit. * **Structured data**: Generates standardized codes (ICD10, IMO, SNOMED, and HCC) for EHR integration. ## How Problem-Based Charting improves clinical documentation Problem-Based Charting improves documentation by organizing the note around clinical problems and returning coded diagnoses that your application can use to send to the EHR. | What you configure | How the note gets better | | ----------------------------------------------- | -------------------------------------------------------------------------------- | | One PBN section (for example Assessment & Plan) | Related history, assessment, and plan content groups under each problem | | Existing patient diagnoses in session context | Continuity of care is reflected instead of treating every visit as a blank slate | | Structured diagnosis output after generation | Suggested ICD10, IMO, SNOMED, and HCC codes support coding and EHR workflows | Traditional section-based notes can scatter details about one problem across the note. PBC keeps problem-specific content together and adds structured diagnosis artifacts, so review, coding, and EHR submission are closer to how clinicians manage care. ## How to use PBC for APIs and SDKs You enable PBC by doing three things: * Define which note sections to generate and which one is the PBN. * Pass the patient's existing diagnoses into session context. * Read structured diagnosis output after the session finishes. **Workflow tabs (agents):** (1) Configure sections for PBC / mark one PBN section, (2) Provide existing diagnoses in context, (3) Retrieve diagnosis results after processing. Details differ by Web SDK, Ambient APIs, and Mobile SDK. * **Web SDK:** In `ambientOptions.sections`, set `isPBNSection: true` on **exactly one** section. Rules for defaults, overrides, and errors are in [Configuration rules](/api-reference/capabilities/problem-based-charting#configuration-rules-for-pbc). * **Ambient APIs:** Send the LOINC `sections` array in the [Context API](/api-reference/ambient-sessions/context) body so the Suki backend knows which note sections to generate. PBN defaults (for example, when Assessment & Plan, LOINC `51847-2`, is treated as the PBN) follow the same rules as in [Configuration rules](/api-reference/capabilities/problem-based-charting#configuration-rules-for-pbc). * **Mobile SDK (iOS):** Pass LOINC sections in `kSections` via `setSessionContext`. See the Mobile SDK [Create session](/mobile-sdk/ambient-guides/provide-clinical-context) guide for field names and examples. * **Ambient APIs:** Include diagnoses when you POST (and, if needed, PATCH) session context. * **Web SDK:** Use `ambientOptions.diagnoses`. Refer to the [AmbientOptions type](/web-sdk/api-reference/types/ambient-options) for more details. * **Mobile SDK (iOS):** Use `SukiAmbientConstant.kDiagnosisInfo` in `setSessionContext`. Refer to the Mobile SDK [Create session](/mobile-sdk/ambient-guides/provide-clinical-context) guide for more details. * **Ambient APIs:** After the session has finished processing, use the [Structured Data](/api-reference/ambient-content/structured-data) or [Encounter Structured Data](/api-reference/ambient-content/encounter-structured-data) APIs and related endpoints to read suggested diagnoses. * **Mobile SDK (iOS):** After the session completes, call `getStructuredData(for:)`. See [Session status and content retrieval](/mobile-sdk/ambient-guides/session-status-and-content-retrieval#get-structured-data). * **Web SDK:** After the user submits the ambient session and note generation succeeds, read results from the **`onNoteSubmit`** callback (React) or the **`note-submission:success`** event (JavaScript and React). Refer to [Receiving note content](/web-sdk/guides/note-management#receiving-note-content), [Response structure](/web-sdk/guides/note-management#response-structure), [NoteContent](/web-sdk/api-reference/types/note-content), and [Diagnosis](/web-sdk/api-reference/types/diagnosis) for more details. ## Implementation examples **Implementation example tabs (agents):** Web SDK (`ambientOptions.diagnoses` / `isPBNSection`), Mobile SDK iOS (`kDiagnosisInfo` / `getStructuredData`), and Ambient APIs (Context API + structured data endpoints). Use the tab that matches your integration. Use the `diagnoses` block in `ambientOptions` to provide existing patient diagnoses when starting a session. **Code example:** ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} sdkClient.mount({ rootElement: document.getElementById("suki-root"), encounter: encounterDetails, ambientOptions: { sections: [ { loinc: "51847-2", isPBNSection: true }, // Assessment and Plan as PBN { loinc: "11450-4" }, // Problem List { loinc: "29545-1" }, // Physical Exam ], diagnoses: { // [!code ++:14] New in v2.1.2 values: [ { codes: [ { code: "I10", description: "Essential hypertension", type: "ICD10", }, ], diagnosisNote: "Hypertension", }, ], }, }, }); ``` Use `setSessionContext` to pass LOINC sections and structured diagnosis information. After the session ends, call `getStructuredData(for:)` to retrieve diagnoses and other structured output. Refer to the Mobile SDK [Create session](/mobile-sdk/ambient-guides/provide-clinical-context) guide for more details. **Code example:** ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} let context = SukiAmbientContext( sections: [ SukiAmbientSection(loinc: "51847-2", isPBNSection: true), // Assessment and Plan as PBN SukiAmbientSection(loinc: "11450-4"), // Problem List SukiAmbientSection(loinc: "29545-1"), // Physical Exam ], diagnosisInfo: [ SukiAmbientDiagnosisInfo( codes: [ SukiAmbientCode(code: "I10", description: "Essential hypertension", type: .icd10), ], diagnosisNote: "Hypertension", ), ], ) ``` Use the [Context API](/api-reference/ambient-sessions/context) to provide existing patient diagnoses when starting a session. **Code example:** ```python Python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} payload = { "diagnoses": { "values": [ { "codes": [ { "code": "I10", "description": "Essential hypertension", "type": "ICD10", }, ], "diagnosis_note": "Hypertension", }, ], }, } ``` **APIs to use:** Provide initial diagnoses when starting a session Update or add diagnoses during a session ## Configuration rules for PBC When configuring PBC, follow these rules: Only one section can have `isPBNSection: true`. If multiple sections are marked as PBN, the ambient session will fail to start. If no section includes the `isPBNSection` flag and the Assessment & Plan section (51847-2) is present, that section automatically becomes the PBN. Explicitly set `isPBNSection: false` to prevent automatic PBN assignment. For a given ambient session, **only one section** can have `isPBNSection: true`. If more than one section is marked as PBN, the ambient session will fail to start. ## Core principles Understanding these principles helps you use PBC effectively: The ICD10 code is treated as the **primary identifier** for all clinical problems during processing. **System uses ICD10 for:** * Diagnosis identification and matching. * Clinical problem categorization. * Cross-session diagnosis continuity. * Normalization of other code types (IMO, SNOMED). Non-ICD10 codes are automatically converted to ICD10 equivalents when possible. All diagnosis generation is done on a **best-effort** basis. The system prioritizes returning partial, useful information over failing an entire request due to an issue with a single data point. In reambient scenarios, diagnoses from previous sessions are **not automatically carried forward**. You must provide the full context for each new session. **Your Responsibility**: Include all relevant diagnoses (previous + new + modified) in each session context. ## How PBC works PBC processes diagnoses in three steps: You provide existing diagnoses when starting the session using the Context APIs. Suki's AI analyzes the conversation and identifies new problems or updates to existing diagnoses. Suki generates a clinical note organized by problem and structured artifacts with standardized codes. ```mermaid actions={false} theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#FFE148','primaryTextColor':'#111827','primaryBorderColor':'#FFE148','lineColor':'#FFE148','secondaryColor':'#FFF394','tertiaryColor':'#FFFADE','mainBkg':'#FFF394','secondBkg':'#FFFADE','tertiaryBorderColor':'#FFE148','border1':'#FFE148','border2':'#FFE148','arrowheadColor':'#FFE148','fontFamily':'Inter, system-ui, sans-serif','fontSize':'14px','nodeBorder':'#FFE148','edgeLabelBackground':'#FFE148','clusterBkg':'#FFFADE','clusterBorder':'#FFE148','defaultLinkColor':'#FFE148','titleColor':'#111827','nodeTextColor':'#111827'}}}%% flowchart TD A[Session audio/transcript] --> B[ML processing] B --> C[Suki Backend] C --> D{Valid ICD10?} D -->|Yes| E[Case 1: Enrich with IMO
Add description,
laterality, IMO code] D -->|No| F[Case 2: Enrich with IMO
Add ICD10, description,
laterality, IMO code] E --> G[Final Output
Problems with Code,
Description, Diagnosis Note] F --> G style A fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style B fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style C fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style D fill:#FFE148,stroke:#FFE148,stroke-width:2px,color:#111827 style E fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style F fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style G fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 ``` Suki backend includes the ML-suggested problem name and returns standardized ICD10 code, description, and IMO equivalent in the final output. ### Validation rules Each diagnosis in your request must follow these rules: * **One code per diagnosis**: Each diagnosis must have exactly one code (ICD10 or IMO). * **No mixed codes**: A single diagnosis cannot contain multiple code types. * **Code required**: Every diagnosis must include a code. ### Input processing Suki processes diagnoses through normalization and deduplication: Normalization does not preserve the original input code. If a code cannot map to an ICD10 equivalent, **Suki skips the entire diagnosis object** and continues processing the remaining input. ### Reconciliation flow for APIs and SDKs When you send existing diagnoses at session start, Suki reconciles them with what is discussed during the visit. Matching problems are merged into one entry, so the structured output stays clean and free of duplicates. For Ambient APIs, send diagnoses through the Context API, then retrieve results from the Structured Data API. For Web SDK, pass diagnoses in `ambientOptions.diagnoses`. Refer to [Existing patient diagnoses](/web-sdk/guides/ambient-problem-based-charting#existing-patient-diagnoses) for the Web SDK flow. **What happens to each diagnosis you send:** * **Discussed in the session**: The diagnosis is updated and returned in the structured data output. * **Not discussed in the session**: The diagnosis is not included in the final output. * **Matches something discussed**: Your diagnosis and the one discussed are merged into a single entry (no duplicate). The Structured Data API returns only diagnoses that were updated or newly generated. ### How diagnoses are generated During the session, Suki's AI analyzes the conversation and takes one of three actions on the diagnoses you provided: 1. **Update existing diagnosis**: Modify the content if it was discussed. 2. **Generate new diagnosis**: Create a new diagnosis if a new problem was discussed. 3. **Keep unchanged**: Leave a diagnosis untouched if it wasn't significantly discussed. Only diagnoses that were **updated or newly generated** are returned in the final output. Untouched diagnoses are not returned. If a diagnosis wasn't discussed, it won't appear in the output. ### Output enrichment For any diagnosis that was updated or newly generated, Suki enriches it with: * **ICD10 code**: Standard diagnosis code. * **IMO code**: Intelligent Medical Objects code. * **SNOMED code**: SNOMED CT code (when available). * **HCC code**: CMS-HCC model category derived from the ICD-10-CM code. The description uses the format `CMS-HCC model category `. * **Laterality**: Left/right/bilateral information when applicable. * **Post coordination flag**: Indicates if the diagnosis requires additional modifiers. The IMO code returned in the output may be different from any IMO code that was sent in the input payload. This is normal: Suki uses the most accurate code based on the conversation content. If enrichment fails, Suki still returns the diagnosis with available information to ensure you don't lose generated content. ### Retrieving generated diagnoses Refer to the [How to use PBC for APIs and SDKs](/api-reference/capabilities/problem-based-charting#how-to-use-pbc-for-apis-and-sdks) section for more details. ## Handling re-Ambient scenarios In reambient scenarios, where a single patient encounter involves multiple recording sessions, understanding how context is managed is critical. Sessions do not **automatically inherit diagnoses** from previous sessions. Each session starts fresh. You must provide all relevant diagnoses for each new session. **What this means:** * When you use APIs in your implementation, only diagnoses passed via the Context APIs for the current session are considered. * Diagnoses from previous sessions are **not automatically carried forward**. * You must provide the complete and current list of all relevant diagnoses for each new session. **Your responsibilities:** Because sessions don't inherit context, you must provide the complete list of all relevant diagnoses for each new session. This includes: * **Modified diagnoses**: Any diagnoses that were changed by the provider in previous sessions. * **New diagnoses**: Any newly added diagnoses from previous sessions. * **Existing diagnoses**: Diagnoses from previous sessions that should be retained. **Recommended workflow:** ```mermaid actions={false} theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#FFE148','primaryTextColor':'#1a1a1a','primaryBorderColor':'#FFE148','lineColor':'#FFE148','secondaryColor':'#FFF394','tertiaryColor':'#FFFADE','mainBkg':'#FFF394','secondBkg':'#FFFADE','border1':'#FFE148','border2':'#FFE148','arrowheadColor':'#FFE148','fontFamily':'Inter, system-ui, sans-serif','fontSize':'14px','nodeBorder':'#FFE148','clusterBkg':'#FFFADE','clusterBorder':'#FFE148','defaultLinkColor':'#FFE148','titleColor':'#1a1a1a','edgeLabelBackground':'#FFE148','nodeTextColor':'#1a1a1a'}}}%% graph TD A[Start session] --> B[Context with
existing diagnoses
] B --> C[Conduct encounter] C --> D[End session] D --> E[Get generated
diagnoses
] E --> F{Reambient session?} F -->|Yes| G[Include all
relevant diagnoses
] F -->|No| H[Complete] G --> B style A fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style B fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style C fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style D fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style E fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style F fill:#FFE148,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style G fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a style H fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#1a1a1a ``` After each session, retrieve the generated diagnoses using the Structured Data API, then include all relevant diagnoses (including any modifications) when starting the next session. ## Best practices * **Provide complete context**: Always include all relevant existing diagnoses when starting a session. * **Use ICD10 when possible**: ICD10 codes are preferred and processed most reliably. * **Handle reambient carefully**: Retrieve diagnoses after each session and include them in the next session. * **Validate codes**: Ensure diagnosis codes are valid before sending them. * **Monitor output**: Check which diagnoses were updated or generated to understand what was discussed. * **Update after user edits**: If providers modify diagnoses, include those modifications in subsequent sessions. ## FAQs In reambient scenarios, the system does not automatically carry forward diagnoses from previous sessions. You must provide the complete and current list of all relevant diagnoses for each new session. The system uses [IMO APIs](https://www.imohealth.com/) to find the best possible ICD10 code equivalent for non-ICD10 codes. If a code cannot be mapped, that diagnosis is skipped. The system normalizes all codes to ICD10 before processing. ICD10 is used as the source of truth for all diagnosis operations. The system deduplicates diagnoses based on the ICD10 code. Diagnoses with the same ICD10 code are merged, and their notes are combined. Only diagnoses that were updated or newly generated are returned. Diagnoses that weren't discussed during the session are not included in the output. # Ambient & Dictation Error Messages Source: https://developer.suki.ai/api-reference/error-messages Look up Ambient and Dictation API error ids, HTTP mappings, and category filters to debug failed REST calls in your integration This page lists the error messages returned by the Suki APIs. All error messages are returned in JSON format as shown in the example below. ```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "code": 16, "message": "invalid sdp token", "details": [] } ``` The `code` field in the JSON body is a numeric status code. Suki maps it to the HTTP status on the response. See [Status code to HTTP mapping](#status-code-to-http-mapping) for the full mapping. Each table row lists an **error id**: a stable name you can use in client code. In responses, that value appears in the `message` field, either as the full string or as a prefix (for example `invalid_sdp_token` or `invalid_sdp_token: …`). Match on the id exactly or by prefix when you handle errors in your integration.

No error messages match this filter or search. Choose another category or clear the search box.

## Common errors These are some common errors that can occur across all Suki REST APIs. | Error id | Code | Description | | :------------------------------- | :--- | :-------------------------------------------------------------- | | `invalid_sdp_token` | 401 | Missing, expired, or invalid `sdp_suki_token` | | `permission_denied` | 403 | General authorization failure | | `insufficient_scope` | 403 | `method not allowed due to insufficient scope. Need: sdp.write` | | `sbac_denied` | 403 | Organization not accessible to partner (SBAC) | | `provider_not_registered` | 401 | Clinician not registered via `/auth/register` | | `provider_user_inactive` | 412 | Provider user is not ACTIVATED/LICENSE\_PENDING | | `missing_sdp_provider_id_header` | 400 | `sdp_provider_id` header required (single\_auth) | | `invalid_sdp_provider_id` | 400 | `sdp_provider_id` fails partner regex | | `request_cancelled` | 499 | Request cancelled by client | | `request_timeout` | 504 | Request timed out | | `internal_server_error` | 500 | Unexpected server error |
## Ambient These are some common errors that can occur while implementing the ambient workflow using the REST APIs. | Error id | Code | Description | | :--------------------------------------------- | :--- | :------------------------------------------------------------------- | | `invalid_ambient_id_format` | 400 | `ambient_session_id` is not a valid UUID on create | | `invalid_request` | 400 | Request body failed validation | | `invalid_end_session_request` | 400 | End session request failed validation | | `invalid_cancel_session_request` | 400 | Cancel session request failed validation | | `invalid_context_request` | 400 | Context body failed validation (specialty, role, visit type, etc.) | | `invalid_encryption_hash` | 400 | Encryption hash must be exactly 64 characters | | `ambient_session_id_required` | 400 | `ambient_session_id` is required (recording) | | `invalid_ambient_session_id` | 404 | Ambient session ID not found | | `ambient_session_not_found` | 404 | Ambient session not found on end | | `session_wrong_state` | 412 | Session is not in CREATED state (includes current status) | | `session_job_type_unsupported` | 412 | Session job type does not support EndSession | | `session_in_progress` | 409 | Concurrent session conflict (for example session in progress on WEB) | | `transcripts_retention_exceeded` | 404 | Transcripts older than 7 days are not available | | `content_retention_exceeded` | 404 | Content for session older than 7 days is not available | | `encounter_content_retention_exceeded` | 404 | Content for encounter older than 7 days is not available | | `structured_data_retention_exceeded` | 404 | Structured data for session older than 7 days is not available | | `encounter_structured_data_retention_exceeded` | 404 | Structured data for encounter older than 7 days is not available | | `invalid_encounter_id` | 404 | Encounter ID not found | | `no_appointment_found` | 404 | No appointment found for `emr_encounter_id` | | `missing_emr_encounter_id` | 400 | `emr_encounter_id` is required (list encounter notes) | | `missing_user_id` | 400 | `user_id` missing from token (list encounter notes) | | `missing_organization_id` | 400 | `organization_id` missing from token (list encounter notes) | | `error_creating_session` | 500 | Error creating ambient session | | `error_ending_session` | 500 | Internal error ending session | | `error_streaming_audio` | 500 | Internal error during `/ws/stream` | | `client_disconnected` | 499 | WebSocket client disconnected during stream | | `unknown_request_type` | 400 | Unknown message type on `/ws/stream` | | `error_extracting_ambient_session_id` | 400 | Ambient session ID missing from WebSocket/metadata | | `error_adding_context` | 500 | Internal error adding/updating session context | | `error_processing_context` | 500 | Internal error processing context payload | | `error_generating_presigned_url` | 500 | Internal error generating offline audio upload URL | | `error_fetching_recording` | 500 | Internal error fetching session recording | | `client_metrics_log_failed` | 500 | Client metrics could not be logged | | `error_resolving_encounter` | 500 | Internal error resolving encounter (list notes) | | `error_fetching_encounter_notes` | 500 | Internal error fetching encounter notes |
## Dictation These are some common errors that can occur while implementing the Dictation workflow using the REST APIs. | Error id | Code | Description | | :------------------------------------------ | :--- | :------------------------------------------------------------ | | `invalid_transcription_session_id_format` | 400 | `transcription_session_id` is not a valid UUID | | `invalid_request` | 400 | Transcription request failed validation | | `error_extracting_transcription_session_id` | 400 | Transcription session ID missing from WebSocket/metadata | | `invalid_transcription_session_id` | 404 | Transcription session ID not found | | `transcription_session_not_found` | 500 | No transcription session found for given ID | | `session_job_type_unsupported` | 412 | Session job type does not support EndTranscriptionSession | | `transcription_session_completed` | 412 | Transcription session is already completed | | `transcription_session_not_accepting` | 412 | Transcription session is not accepting new speech sessions | | `error_creating_transcription_session` | 500 | Error creating transcription session | | `error_ending_transcription_session` | 500 | Internal error ending transcription session | | `error_creating_transcription_stream` | 500 | Internal error creating `/ws/transcribe` stream | | `error_receiving_audio` | 500 | Internal error receiving audio on transcription stream | | `error_sending_audio` | 500 | Internal error sending audio on transcription stream | | `error_ending_transcription` | 500 | Internal error ending transcription stream | | `error_reading_transcripts` | 500 | Internal error reading transcripts from transcription service | | `client_disconnected` | 499 | WebSocket client disconnected during transcribe | | `unknown_request_type` | 400 | Unknown message type on `/ws/transcribe` |
## Feedback These are some common errors that can occur while implementing the Feedback workflow using the REST APIs. ### Ambient feedback | Error id | Code | Description | | :---------------------------- | :--- | :------------------------------------------------------ | | `invalid_request` | 400 | Feedback request failed validation | | `ambient_session_id_required` | 400 | `ambient_session_id` is required | | `invalid_uuid_format` | 400 | `ambient_session_id` is not a valid UUID | | `feedback_required` | 400 | `feedback` object is required | | `rating_feedback_required` | 400 | `ratingFeedback` is required | | `invalid_entity` | 400 | Only `CONTENT` entity is supported for ambient feedback | | `invalid_rating_range` | 400 | `minRating` must be less than `maxRating` | | `rating_below_min` | 400 | `rating` must be >= `minRating` | | `rating_above_max` | 400 | `rating` must be \<= `maxRating` | | `negative_min_rating` | 400 | `minRating` must be >= 0 | | `comments_too_long` | 400 | `qualitativeComments` exceeds 2000 characters | | `failed_get_session` | 500 | Failed to get ambient session for feedback | | `failed_submit_feedback` | 500 | Failed to submit feedback to feedback service |
## Notification These are some common errors that can occur while implementing the Notification workflow using the REST APIs. ### Success payload | Field | Description | | :------------- | :------------------------------------------------------------- | | `status` | `"success"` | | `session_id` | Session that completed | | `encounter_id` | Parent encounter ID | | `sessions` | Ordered list of session IDs in encounter | | `_links` | HATEOAS links to status, transcripts, content, structured-data | ### Failure payload | Error id | Code | Description | | :------------------------------------------- | :--- | :------------------------------------------------ | | `ERROR_CODE_UNSPECIFIED` | — | Failure reason unknown or not classified | | `ERROR_CODE_NOTIFICATION_GENERATION_FAILURE` | — | Notification payload generation failed | | `ERROR_CODE_TRANSCRIPTION` | — | **Swagger example only**, not in proto enum today | | Field | Description | | :------------- | :--------------------------------------------- | | `status` | `"failure"` | | `session_id` | Session that failed | | `encounter_id` | Parent encounter ID | | `error_code` | Machine-readable error code (see table above) | | `error_detail` | Human-readable failure details from job output |
## Preferences These are some common errors that can occur while implementing the Preferences workflow using the REST APIs. | Error id | Code | Description | | :------------------------------------- | :--- | :--------------------------------------------------------------- | | `invalid_request` | 400 | Preferences request failed validation | | `update_paths_required` | 400 | `update_paths` field mask is required | | `preference_required` | 400 | `preference` object is required | | `personalization_preference_required` | 400 | `personalization_preference` is required | | `verbosity_or_section_format_required` | 400 | At least one of `verbosity` or `section_format` must be provided | | `invalid_preferences_format` | 400 | Preferences could not be converted to internal format | | `invalid_verbosity` | 400 | Invalid verbosity enum value | | `invalid_section_format` | 400 | Invalid section format enum value | | `error_updating_preferences` | 500 | Internal error updating user preferences via ms-preferences |
## Status code to HTTP mapping This table maps the status names returned by the Suki APIs to the corresponding HTTP status codes. | Status name | HTTP | | :------------------- | :--- | | `InvalidArgument` | 400 | | `Unauthenticated` | 401 | | `PermissionDenied` | 403 | | `NotFound` | 404 | | `AlreadyExists` | 409 | | `Aborted` | 409 | | `FailedPrecondition` | 412 | | `Unimplemented` | 501 | | `Unavailable` | 503 | | `Internal` | 500 | | `Canceled` | 499 | | `DeadlineExceeded` | 504 |
# Audio Capture & Streaming Source: https://developer.suki.ai/api-reference/faqs/audio-capture-streaming Questions about audio capture, streaming, and WebSocket implementation LINEAR16 (16KHz sampling rate) over the mono channel. Audio should be chunked into 100ms packets for optimal performance. We only support 100ms audio chunks to achieve the right balance between quality, latency, and efficiency. Network connection speed and consistency are important for Suki to perform well. **Suki requires:** * **Upload speed**: 1Mbps. * **Bitrate**: 768kbps. * **Ping time**: 150ms. * **Unloaded latency**: \<50ms. * **Loaded latency**: \<150ms. Client should set up a WebSocket Secure (wss\://) request with the Suki endpoint. Refer to the [Audio stream API](/api-reference/ambient-sessions/audio-stream) for implementation details. For **ambient** WebSocket **`/ws/stream`** message format, send **LINEAR16**, **16 kHz**, **mono** audio, in about **100 ms** chunks (see the [Audio streaming](/api-reference/ambient-sessions/audio-stream) reference and [WebSocket streaming wire format](/documentation/how-to/audio-streaming/websocket-streaming-wire-format-ambient#audio-format-and-chunking)). ### How messages are sent Each outbound message from the client must be: * **One WebSocket text frame** (UTF-8) with **one JSON object** inside. * **One logical send** per frame (do not pack multiple JSON objects in one frame). On **`/ws/stream`**, do **not** send PCM as **binary** WebSocket frames. Do **not** stream raw audio over HTTP with `Content-Type: application/json`. **Field names (proto-style JSON)** * **`START_TIME`** and **`AUDIO`**: use **`type`** and **`data`**. * **`data`**: standard Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648)) of the **raw bytes** you mean to send (same idea as Go `encoding/json` for `[]byte`). Do not use hex, URL-safe Base64, or raw binary inside the JSON string. * **`EVENT`**: use **`type`**: `"EVENT"` and the **`event`** field. Do **not** put the action name in **`data`**. ### Message order (each stream segment) 1. Send **`START_TIME`** once: **`data`** is Base64 of a UTF-8 **RFC 3339** timestamp (for example `2026-04-25T12:34:56Z`). 2. Send one or more **`AUDIO`** messages: **`data`** is Base64 of each **raw PCM** chunk. 3. Send a final **`AUDIO`** to end audio: **`data`** is **`RU9G`** (Base64 of ASCII **`EOF`**, bytes `0x45`, `0x4F`, `0x46`). Do not use a separate `end_of_stream` type unless your integration team tells you otherwise. `EVENT` messages can go **anywhere** in the stream when you need control (pause, resume, keep-alive, cancel, abort). ### EVENT values you can send Use **`{"type":"EVENT","event":""}`** with one of: | Value | What it does | | :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | | **PAUSE** | Pause the stream | | **RESUME** | Resume the stream | | **CANCEL** | User cancels the stream | | **ABORT** | Stream is aborted (interruption) | | **KEEP\_ALIVE** | Keep the connection alive during inactivity. While **paused**, send at least once every **five seconds** so the server does not close the connection. | ### Message examples ```json START_TIME theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "START_TIME", "data": "" } ``` ```json AUDIO (PCM chunk) theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "AUDIO", "data": "Base64EncodedPcmBytes" } ``` ```json AUDIO (stream end marker) theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "AUDIO", "data": "RU9G" } ``` ```json PAUSE Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "EVENT", "event": "PAUSE" } ``` ```json RESUME Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "EVENT", "event": "RESUME" } ``` ```json CANCEL Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "EVENT", "event": "CANCEL" } ``` ```json KEEP_ALIVE Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "EVENT", "event": "KEEP_ALIVE" } ``` ```json ABORT Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "type": "EVENT", "event": "ABORT" } ``` The stream end marker is an **`AUDIO`** message whose **`data`** is Base64 of the raw bytes **`EOF`**, not a bare JSON string `"EOF"` and not an **`EVENT`** named EOF, unless your stack documentation says otherwise. # Authentication Source: https://developer.suki.ai/api-reference/faqs/authentication Authentication and authorization questions for API access We support * OAuth 2.0 ID token for public clients such as browsers, mobile devices etc. * Access token for confidential clients such as backend systems. We support [HMAC (Hash-based message authentication code)](https://www.okta.com/identity-101/hmac/) for webhook authentication (Details can be shared) Client systems cannot authenticate with Suki's platform via APIs when a JWT token fails. It's handled with standard HTTPS error codes; refer API reference # Diagnosis codes Source: https://developer.suki.ai/api-reference/faqs/diagnosis-codes FAQ on diagnosis code types in Ambient API structured data, including ICD-10 and HCC ICD-10 and HCC codes serve different purposes in clinical documentation: **ICD-10 (International Classification of Diseases, 10th Revision)** * A standardized system of codes used to classify and record diagnoses, symptoms, and procedures. * Used for billing, clinical documentation, and interoperability across healthcare systems. * Example: `I10` = Essential hypertension. * ICD-10 is the **primary identifier** Suki uses internally to match, deduplicate, and process diagnoses. **HCC (Hierarchical Condition Category)** * A risk-adjustment coding model used primarily in value-based care and Medicare Advantage programs. * HCC codes are derived from ICD-10 codes: CMS groups related ICD-10 codes into HCC categories to estimate a patient's expected healthcare costs. * Not every ICD-10 code maps to an HCC category: only those that significantly affect patient risk scores do. * Example: ICD-10 `I10` (Essential hypertension) maps to HCC 136. **How they relate in Suki structured data:** * Suki processes and stores diagnoses using ICD-10 as the source of truth. * In API structured data, HCC categories appear in the diagnosis `codes` array with `type: "HCC"`. * In the Web SDK, the `hccCode` field in the [Diagnosis type](/web-sdk/api-reference/types/diagnosis) surfaces the HCC category that corresponds to the ICD-10 code, when one exists. * You can use HCC output to support risk-adjustment workflows or value-based care reporting in your integration. | | ICD-10 | HCC | | ----------- | ------------------------- | ------------------------------------ | | **Purpose** | Clinical diagnosis coding | Risk adjustment and cost prediction | | **Scope** | All diagnoses | Subset of high-impact diagnoses | | **Used by** | All payers, EHRs | Medicare Advantage, value-based care | | **In Suki** | Primary identifier | Supplemental output field | See [Ambient session structured data](/api-reference/ambient-content/structured-data) and [Supported Diagnosis Codes](/api-reference/info/diagnosis) for endpoint details. No. HCC codes are returned in structured data output only. Send ICD10 or IMO codes in session context. Suki derives HCC categories from the ICD-10-CM code when you retrieve structured data. See [Ambient session structured data](/api-reference/ambient-content/structured-data#diagnosis-codes-in-structured-data). # Miscellaneous Source: https://developer.suki.ai/api-reference/faqs/miscellaneous General API questions and miscellaneous topics To handle different doctor roles/specialties dynamically, clients use our context API to seed session context with the provider role (e.g. SPECIALTY). Yes. For an **ambient** session, ending the session and receiving a successful webhook means note generation completed. Suki still runs the Ambient documentation pipeline in the background, including clinical note and encounter content, even if your application only follows the transcript link afterward. The success webhook payload identifies the session and encounter and includes `_links` for session content, encounter content, structured data, status, and transcripts. Using only [Get Session Transcript](/api-reference/ambient-content/transcript) does not skip note generation. Session status **`completed`** means the session finished and final content was generated. See [Webhook event types](/documentation/webhook/event-types) and [Webhook payload](/documentation/webhook/payload-and-response). There is no ambient option today that returns only the conversation transcript without generating the clinical note and related encounter documentation. # Patient Summary Source: https://developer.suki.ai/api-reference/faqs/patient-summary FAQs about the Patient Summary APIs Use your partner organization ID from your external registration with Suki. Do not use an internal Suki organization ID. Suki maps your partner organization ID to the correct internal organization and Clinical Knowledge Graph (CKG). Authenticate requests with your Suki Developer Platform (SDP) token. No separate login or token exchange is required. The pre-signed Google Cloud Storage (GCS) upload URL expires after 15 minutes. If the URL expires before you upload, request a new upload URL. Each FHIR bundle can be up to 500 MB. Upload a raw JSON file containing a FHIR Bundle of type `searchset`. The bundle must follow the FHIR specification and include only supported resource types. No. All resources in a bundle must belong to the same organization. No. Suki does not enforce referential integrity during ingestion. Ingestion can succeed even if a resource references another resource that has not been ingested yet. Set the correlation ID to the original tracking identifier when uploading updates for a previous ingestion. This ensures Suki processes related updates in order and helps avoid conflicting changes. No. A successful `PUT` confirms the file was stored. Suki processes the file asynchronously after upload completes. Poll the ingestion status endpoint or configure webhooks to learn when processing finishes. # Technical Constraints & Risks Source: https://developer.suki.ai/api-reference/faqs/technical-constraints-risks Technical limitations, constraints, and risk considerations for API integration No, we don't have pre-approved domains. To register for our webhook, share your callback URL so we can notify you there. This step is currently manual; we plan to upgrade this system in the future. N/A, we can share the IP of our system which calls callback URL if need be A POST call will be made to the webhook hosted by the Partner using the HTTPS protocol. Yes, the Webhook URL should be configured at the Partner level during [partner onboarding](/documentation/get-started/partner-onboarding). We currently do not support session-based webhook callbacks or similar configurations; webhook support is only for APIs and not for Web SDK. The client is responsible for creating and managing the `encounter_id`. We support combining sessions and generating the note based on the provided `encounter_id`. An encounter can include multiple ambient sessions. 1. Obtain a developer platform test license (POC: Commercials team).
. 2. Complete partner onboarding:
. * Share required details for partner creation in our system → you will receive a Partner ID (`partner_id`).
. * Let us know the unique identifier you will use in the OAuth 2.0 JWT token to identify the user (provider).
. Example: user\_id, email\_id, sid, pid, etc. (need not be actual id from your system, can be hash value as well)
* Provide your JWKS endpoint for accessing your public key.
. * Test authentication with Suki.
.
Here's a minimal flow for your reference: `/login → /session/create → /context (optional) → /stream → /end` This flow automatically triggers note generation. Either: 1. Use `/status` to poll the note generation status, then call /content to retrieve the note. 2. Receive a notification through our webhook. As long as the stream is active, there is no upper limit on call duration. The system allows a maximum pause of 30 minutes during the streaming. If you get disconnected and then rejoin, or lose the WebSocket connection, Suki stitches the sessions together using the same session ID. Although there is no strict lower limit, Suki needs a minimum amount of data to generate recommendations. For calls **shorter than 1 minute**, Suki may not have enough meaningful data/information to provide accurate recommendations and returns empty content. The session will be marked as **skipped**. # Ambient Session User Feedback Source: https://developer.suki.ai/api-reference/feedback/feedback POST /api/v1/ambient/session/{session_id}/{entity}/feedback Submit user feedback on generated clinical content for continuous improvement Use the **Feedback API** to collect quantitative (ratings) and qualitative (comments) feedback. Capturing feedback helps drive AI model improvement and increases client confidence. The API supports the following actions: * **Quantitative Feedback**: Rate content using a scale with configurable minimum and maximum values. * **Qualitative Feedback**: Provide optional, free-form comments for detailed insights. * **Entity-Level Tracking**: Tie feedback to specific entities within sessions. ## Supported entity types Provide feedback on the following entity types: | Entity type | Description | | ----------- | -------------------------- | | `content` | Generated clinical content | Within a single ambient session (session\_id), you can provide feedback for each `entity type` only **once**. If you provide feedback for the same `entity type` multiple times, the feedback will not be valid. Also, a single `session_id` can contain **multiple feedbacks**, provided each entry corresponds to a **different** entity type. ## Rating system The `ratingFeedback` object provides quantitative feedback. It includes the following fields: * `min_rating`: The minimum rating value (e.g., 0). * `max_rating`: The maximum rating value. * `rating`: The actual rating you provide within the min-max range. Configure the rating scale by setting the `min_rating` and `max_rating` values. The range is **inclusive**, so both the `min_rating` and `max_rating` values are valid ratings. For example: * To create a rating scale of 0 to 5, set `min_rating` to 0 and `max_rating` to 5. A user can provide any integer rating from 0 to 5. * To create a binary scale, set `min_rating` to 0 and `max_rating` to 1. A user can provide a rating of either 0 or 1. * Suki suggests using a scale of 1 to 5 for the rating. ## Character limits * `qualitative_comments`: Maximum **2000** characters. Your feedback helps Suki to improve the AI-generated content. All feedback is reviewed and used to enhance quality. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests session_id = "session_abc_123" entity = "content" url = f"https://sdp.suki-stage.com/api/v1/ambient/session/{session_id}/{entity}/feedback" headers = { "sdp_suki_token": "", "sdp_provider_id": "", "Content-Type": "application/json" } payload = { "ratingFeedback": { "min_rating": 0, "max_rating": 5, "rating": 4 }, "qualitative_comments": "The generated content was accurate and helpful. Great job!" # Optional, max 2000 chars } response = requests.post(url, json=payload, headers=headers) if response.status_code == 201: data = response.json() feedback_id = data.get("feedback_id") print(f"Feedback submitted successfully. Feedback ID: {feedback_id}") else: print(f"Failed to submit feedback: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const sessionId = 'session_abc_123'; const entity = 'content'; const response = await fetch( `https://sdp.suki-stage.com/api/v1/ambient/session/${sessionId}/${entity}/feedback`, { method: 'POST', headers: { 'sdp_suki_token': '', 'sdp_provider_id': '', 'Content-Type': 'application/json' }, body: JSON.stringify({ ratingFeedback: { min_rating: 0, max_rating: 5, rating: 4 }, qualitative_comments: 'The generated content was accurate and helpful. Great job!' // Optional, max 2000 chars }) } ); if (response.status === 201) { const data = await response.json(); const feedbackId = data.feedback_id; console.log(`Feedback submitted successfully. Feedback ID: ${feedbackId}`); } else { const error = await response.json(); console.error(`Failed to submit feedback: ${response.status}`, error); } ``` # HTTPS Guidelines Source: https://developer.suki.ai/api-reference/https-guidelines Map Suki HTTP status codes (2xx, 4xx, 5xx) to request outcomes, including auth failures, validation errors, and server errors Suki uses **standard HTTP status codes** to indicate the outcome of an API request. * **`2xx` codes** indicate success. * **`4xx` codes** indicate a client-side error (e.g., you omitted a required parameter or provided an invalid configuration). * **`5xx` codes** indicate a server-side error on Suki's end. These are rare. The following table lists the most common HTTP status codes you may receive. | Code | Title | Description | | :----------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------- | | **`200`** | OK | The request was successful. | | **`201`** | Created | The resource was created successfully. The URL for the new resource is in the `Location` header. | | **`204`** | No Content | The request was successful, and there is no content to return. | | **`400`** | Bad Request | The request was unacceptable, often due to malformed syntax or a missing parameter. | | **`401`** | Unauthorized | The request was not authenticated. This could be due to missing, invalid, or insufficient credentials. | | **`402`** | Over Quota | The request was valid, but you have exceeded your plan's quota or rate limits. | | **`403`** | Forbidden | The request was not authenticated. This could be due to missing, invalid, or insufficient credentials. | | **`404`** | Not Found | The requested resource does not exist. | | **`409`** | Conflict | The request conflicts with the current state of the resource (e.g., the resource already exists, or the request was based on stale data). | | **`422`** | Validation Failed | The request was parsed correctly but failed a validation rule. | | **`429`** | Too Many Requests | You have sent too many requests in a short period. We recommend using an exponential backoff strategy for your requests. | | **`500, 502, 503, 504`** | Server Errors | An unexpected error occurred on Suki's servers. | # Info APIs Source: https://developer.suki.ai/api-reference/info Reference data for specialties, diagnoses, encounter types, visit types, LOINC codes, and provider roles The Info APIs enable partners to retrieve the specialties, encounter types, visit types, provider roles, LOINC codes, and diagnosis types Suki accepts when you register providers or create ambient sessions. Partners typically call these endpoints from their backend to populate pickers in their product and validate payloads before session or context requests. You can fetch a combined catalog from System Information or request each category through its dedicated Info endpoint. Critically, Info endpoints return supported values only. They do not create ambient sessions or generate clinical notes. Info APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Response bodies are stable reference data you can cache on a release schedule that fits your product. ## Available endpoints Retrieve platform system information for your integration Retrieve supported LOINC codes for note sections and related fields Retrieve diagnosis code reference data for ambient requests Retrieve supported medical specialties for provider registration and sessions Retrieve supported encounter types for ambient sessions Retrieve supported visit types for ambient sessions Retrieve supported provider roles for ambient context ## Related guides Learn how ambient sessions use encounter and specialty context See how LOINC-coded sections map into generated notes Review specialty support for clinical notes ## Common use cases Use supported catalogs so registration and session forms only offer values Suki accepts. Check note sections and diagnosis payloads against supported codes before you seed ambient context. Refresh Info catalogs on your release cycle so specialty, encounter, and role pickers stay aligned with Suki. Apply supported provider roles when building ambient session context for the encounter. # Supported Diagnosis Codes Source: https://developer.suki.ai/api-reference/info/diagnosis GET /api/v1/info/diagnosis Get list of supported diagnosis codes and medical conditions **Updated:** * **HCC** is now included as a supported diagnosis code type for ambient structured data output. * Send **ICD10** or **IMO** codes in session context. Do not send [HCC](https://www.aapc.com/resources/what-is-hierarchical-condition-category?srsltid=AfmBOopcl-dIWrRrQFq58LGS72p58BakTdoWdEHv0P9z89c3XBXuJAOY) codes as input. * HCC categories are returned from the [Ambient session structured data API](/api-reference/ambient-content/structured-data) when an ICD-10-CM diagnosis maps to a CMS-HCC model category. For how ICD-10 and HCC differ, refer to [Diagnosis codes FAQs](/api-reference/faqs/diagnosis-codes#what-is-the-difference-between-icd-10-and-hcc-codes). Use this endpoint to get the list of supported diagnosis code types, including **HCC** for ambient structured data output. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/diagnosis" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: diagnosis_data = response.json() print("Supported Diagnosis Code Types:") for code_type in diagnosis_data.get("diagnosis_code_types", []): print(f" {code_type.get('code_type')}") else: print(f"Failed to get diagnosis codes: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/diagnosis', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const diagnosisData = await response.json(); console.log('Supported Diagnosis Code Types:'); diagnosisData.diagnosis_code_types?.forEach((codeType: any) => { console.log(` ${codeType.code_type}`); }); } else { const error = await response.json(); console.error(`Failed to get diagnosis codes: ${response.status}`, error); } ``` # Encounter Types Source: https://developer.suki.ai/api-reference/info/encounter-types GET /api/v1/info/encounter-types Get list of supported clinical encounter types Use this endpoint to get the list of supported encounter types. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/encounter-types" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: encounter_types_data = response.json() print("Supported Encounter Types:") for encounter_type in encounter_types_data.get("encounter_types", []): print(f" {encounter_type.get('code')}") else: print(f"Failed to get encounter types: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/encounter-types', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const encounterTypesData = await response.json(); console.log('Supported Encounter Types:'); encounterTypesData.encounter_types?.forEach((encounterType: any) => { console.log(` ${encounterType.code}`); }); } else { const error = await response.json(); console.error(`Failed to get encounter types: ${response.status}`, error); } ``` # System Information Source: https://developer.suki.ai/api-reference/info/information GET /api/v1/info Get system information and supported configuration values Use this endpoint to get the list of supported LOINC codes, specialties, encounter types, visit types, provider roles, diagnosis code types, and medication order metadata (coding systems, dosage units, frequency types, timings, order statuses, encounter relations, and origins). You can also fetch each category with dedicated `GET /api/v1/info/...` routes listed under **Info** in the API reference. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: info = response.json() print("System Information:") print(f"LOINCs: {len(info.get('loincs', []))} codes") print(f"Specialties: {len(info.get('specialties', []))} specialties") print(f"Encounter Types: {len(info.get('encounter_types', []))} types") print(f"Visit Types: {len(info.get('visit_types', []))} types") print(f"Provider Roles: {len(info.get('provider_roles', []))} roles") print(f"Diagnosis Code Types: {len(info.get('diagnosis_code_types', []))} types") print(f"Medication coding systems: {len(info.get('medication_coding_systems', []))}") print(f"Medication dosage units: {len(info.get('medication_dosage_units', []))}") print(f"Medication frequency types: {len(info.get('medication_frequency_types', []))}") print(f"Medication timings: {len(info.get('medication_timings', []))}") print(f"Medication order statuses: {len(info.get('medication_order_statuses', []))}") print(f"Order encounter relations: {len(info.get('order_encounter_relations', []))}") print(f"Order origins: {len(info.get('order_origins', []))}") else: print(f"Failed to get system information: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const info = await response.json(); console.log('System Information:'); console.log(`LOINCs: ${info.loincs?.length || 0} codes`); console.log(`Specialties: ${info.specialties?.length || 0} specialties`); console.log(`Encounter Types: ${info.encounter_types?.length || 0} types`); console.log(`Visit Types: ${info.visit_types?.length || 0} types`); console.log(`Provider Roles: ${info.provider_roles?.length || 0} roles`); console.log(`Diagnosis Code Types: ${info.diagnosis_code_types?.length || 0} types`); console.log(`Medication coding systems: ${info.medication_coding_systems?.length ?? 0}`); console.log(`Medication dosage units: ${info.medication_dosage_units?.length ?? 0}`); console.log(`Medication frequency types: ${info.medication_frequency_types?.length ?? 0}`); console.log(`Medication timings: ${info.medication_timings?.length ?? 0}`); console.log(`Medication order statuses: ${info.medication_order_statuses?.length ?? 0}`); console.log(`Order encounter relations: ${info.order_encounter_relations?.length ?? 0}`); console.log(`Order origins: ${info.order_origins?.length ?? 0}`); } else { const error = await response.json(); console.error(`Failed to get system information: ${response.status}`, error); } ``` # Supported LOINCs Source: https://developer.suki.ai/api-reference/info/loincs GET /api/v1/info/loincs Get list of supported LOINC codes for clinical note sections Use this endpoint to get the list of supported LOINC codes. For more information about the LOINC codes, refer to the [Note sections](/documentation/concepts/ambient-clinical-notes/note-sections). ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/loincs" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: loincs_data = response.json() print("Supported LOINC Codes:") for loinc in loincs_data.get("loincs", []): print(f" {loinc.get('code')}: {loinc.get('common_name')}") else: print(f"Failed to get LOINC codes: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/loincs', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const loincsData = await response.json(); console.log('Supported LOINC Codes:'); loincsData.loincs?.forEach((loinc: any) => { console.log(` ${loinc.code}: ${loinc.common_name}`); }); } else { const error = await response.json(); console.error(`Failed to get LOINC codes: ${response.status}`, error); } ``` # Medication Order Metadata Source: https://developer.suki.ai/api-reference/info/orders GET /api/v1/info/orders Get all supported medication order metadata in one response Use this endpoint to get supported metadata for medication orders in one response, including coding systems, dosage units, frequency types, timings, statuses, origins, and encounter relations. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: order_info = response.json() print("Medication order metadata:") print(f" Coding systems: {len(order_info.get('coding_systems', []))}") print(f" Dosage units: {len(order_info.get('dosage_units', []))}") print(f" Encounter relations: {len(order_info.get('encounter_relations', []))}") print(f" Frequency types: {len(order_info.get('frequency_types', []))}") print(f" Origins: {len(order_info.get('origins', []))}") print(f" Statuses: {len(order_info.get('statuses', []))}") print(f" Timings: {len(order_info.get('timings', []))}") else: print(f"Failed to get medication order metadata: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const orderInfo = await response.json(); console.log('Medication order metadata:'); console.log(` Coding systems: ${orderInfo.coding_systems?.length ?? 0}`); console.log(` Dosage units: ${orderInfo.dosage_units?.length ?? 0}`); console.log(` Encounter relations: ${orderInfo.encounter_relations?.length ?? 0}`); console.log(` Frequency types: ${orderInfo.frequency_types?.length ?? 0}`); console.log(` Origins: ${orderInfo.origins?.length ?? 0}`); console.log(` Statuses: ${orderInfo.statuses?.length ?? 0}`); console.log(` Timings: ${orderInfo.timings?.length ?? 0}`); } else { const error = await response.json(); console.error(`Failed to get medication order metadata: ${response.status}`, error); } ``` # Medication Coding Systems Source: https://developer.suki.ai/api-reference/info/orders-coding-systems GET /api/v1/info/orders/coding-systems Get supported medication coding systems Use this endpoint to get the list of supported medication coding systems. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/coding-systems" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: coding_systems_data = response.json() print("Supported Medication Coding Systems:") for item in coding_systems_data.get("coding_systems", []): print(f" {item.get('code')}") else: print(f"Failed to get medication coding systems: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/coding-systems', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const codingSystemsData = await response.json(); console.log('Supported Medication Coding Systems:'); codingSystemsData.coding_systems?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get medication coding systems: ${response.status}`, error); } ``` # Medication Dosage Units Source: https://developer.suki.ai/api-reference/info/orders-dosage-units GET /api/v1/info/orders/dosage-units Get supported medication dosage units Use this endpoint to get the list of supported medication dosage units. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/dosage-units" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: dosage_units_data = response.json() print("Supported Medication Dosage Units:") for item in dosage_units_data.get("dosage_units", []): print(f" {item.get('code')}") else: print(f"Failed to get medication dosage units: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/dosage-units', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const dosageUnitsData = await response.json(); console.log('Supported Medication Dosage Units:'); dosageUnitsData.dosage_units?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get medication dosage units: ${response.status}`, error); } ``` # Order Encounter Relations Source: https://developer.suki.ai/api-reference/info/orders-encounter-relations GET /api/v1/info/orders/encounter-relations Get supported order encounter relations Use this endpoint to get the list of supported order encounter relations. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/encounter-relations" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: encounter_relations_data = response.json() print("Supported Order Encounter Relations:") for item in encounter_relations_data.get("encounter_relations", []): print(f" {item.get('code')}") else: print(f"Failed to get order encounter relations: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/encounter-relations', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const encounterRelationsData = await response.json(); console.log('Supported Order Encounter Relations:'); encounterRelationsData.encounter_relations?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get order encounter relations: ${response.status}`, error); } ``` # Medication Frequency Types Source: https://developer.suki.ai/api-reference/info/orders-frequencies GET /api/v1/info/orders/frequencies Get supported medication frequency types Use this endpoint to get the list of supported medication frequency types. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/frequencies" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: frequency_types_data = response.json() print("Supported Medication Frequency Types:") for item in frequency_types_data.get("frequency_types", []): print(f" {item.get('code')}") else: print(f"Failed to get medication frequency types: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/frequencies', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const frequencyTypesData = await response.json(); console.log('Supported Medication Frequency Types:'); frequencyTypesData.frequency_types?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get medication frequency types: ${response.status}`, error); } ``` # Medication Timings Source: https://developer.suki.ai/api-reference/info/orders-medication-timings GET /api/v1/info/orders/medication-timings Get supported medication timings Use this endpoint to get the list of supported medication timings. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/medication-timings" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: timings_data = response.json() print("Supported Medication Timings:") for item in timings_data.get("timings", []): print(f" {item.get('code')}") else: print(f"Failed to get medication timings: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/medication-timings', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const timingsData = await response.json(); console.log('Supported Medication Timings:'); timingsData.timings?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get medication timings: ${response.status}`, error); } ``` # Order Origins Source: https://developer.suki.ai/api-reference/info/orders-origins GET /api/v1/info/orders/origins Get supported order origins Use this endpoint to get the list of supported order origins. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/origins" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: origins_data = response.json() print("Supported Order Origins:") for item in origins_data.get("origins", []): print(f" {item.get('code')}") else: print(f"Failed to get order origins: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/origins', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const originsData = await response.json(); console.log('Supported Order Origins:'); originsData.origins?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get order origins: ${response.status}`, error); } ``` # Medication Order Statuses Source: https://developer.suki.ai/api-reference/info/orders-statuses GET /api/v1/info/orders/statuses Get supported medication order statuses Use this endpoint to get the list of supported medication order statuses. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/orders/statuses" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: statuses_data = response.json() print("Supported Medication Order Statuses:") for item in statuses_data.get("statuses", []): print(f" {item.get('code')}") else: print(f"Failed to get medication order statuses: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/orders/statuses', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const statusesData = await response.json(); console.log('Supported Medication Order Statuses:'); statusesData.statuses?.forEach((item: any) => { console.log(` ${item.code}`); }); } else { const error = await response.json(); console.error(`Failed to get medication order statuses: ${response.status}`, error); } ``` # Provider Roles Source: https://developer.suki.ai/api-reference/info/provider-roles GET /api/v1/info/provider-roles Get list of supported healthcare provider roles Use this endpoint to get the list of supported provider roles. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/provider-roles" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: provider_roles_data = response.json() print("Supported Provider Roles:") for provider_role in provider_roles_data.get("provider_roles", []): print(f" {provider_role.get('code')}") else: print(f"Failed to get provider roles: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/provider-roles', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const providerRolesData = await response.json(); console.log('Supported Provider Roles:'); providerRolesData.provider_roles?.forEach((providerRole: any) => { console.log(` ${providerRole.code}`); }); } else { const error = await response.json(); console.error(`Failed to get provider roles: ${response.status}`, error); } ``` # Supported Medical Specialties Source: https://developer.suki.ai/api-reference/info/specialties GET /api/v1/info/specialties Get list of supported medical specialties and their identifiers Use this endpoint to get the list of supported medical specialties. This list is used to validate the specialty field in the session context when creating or updating an ambient session. For more information about the specialties, refer to the [Medical specialties section](/documentation/concepts/ambient-clinical-notes/specialties). ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/specialties" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: specialties_data = response.json() print("Supported Medical Specialties:") for specialty in specialties_data.get("specialties", []): print(f" {specialty.get('code')}") else: print(f"Failed to get specialties: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/specialties', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const specialtiesData = await response.json(); console.log('Supported Medical Specialties:'); specialtiesData.specialties?.forEach((specialty: any) => { console.log(` ${specialty.code}`); }); } else { const error = await response.json(); console.error(`Failed to get specialties: ${response.status}`, error); } ``` # Visit Types Source: https://developer.suki.ai/api-reference/info/visit-types GET /api/v1/info/visit-types Get list of supported clinical visit types Use this endpoint to get the list of supported visit types. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/info/visit-types" headers = { "sdp_suki_token": "", "sdp_provider_id": "" } response = requests.get(url, headers=headers) if response.status_code == 200: visit_types_data = response.json() print("Supported Visit Types:") for visit_type in visit_types_data.get("visit_types", []): print(f" {visit_type.get('code')}") else: print(f"Failed to get visit types: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/info/visit-types', { headers: { 'sdp_suki_token': '', 'sdp_provider_id': '' } }); if (response.ok) { const visitTypesData = await response.json(); console.log('Supported Visit Types:'); visitTypesData.visit_types?.forEach((visitType: any) => { console.log(` ${visitType.code}`); }); } else { const error = await response.json(); console.error(`Failed to get visit types: ${response.status}`, error); } ``` # Medication Orders Info APIs Source: https://developer.suki.ai/api-reference/medication-orders-info Get supported medication order metadata in one response The Medication Orders Info APIs enable partners to retrieve supported metadata for medication orders, including coding systems, dosage units, frequency types, timings, statuses, origins, and encounter relations. Use these catalogs when you build order-related request fields or validate clinician selections. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, these endpoints return reference metadata. They do not place medication orders in an EHR. ## Available endpoints Retrieve supported medication order metadata in one response Retrieve supported coding systems for medication orders Retrieve supported dosage units for medication orders Retrieve supported encounter relations for medication orders Retrieve supported frequency values for medication orders Retrieve supported medication timing values Retrieve supported origin values for medication orders Retrieve supported status values for medication orders ## Related guides Learn how to convert medication instructions from ambient encounters into structured Medication order data See how Medication orders fit into the ambient clinical note workflow ## Common use cases Use supported order metadata so clinicians select units, frequency, timing, and status values that pass EHR validation. Refresh Medication Orders Info on your release cycle so coding systems and timings stay aligned with Suki. Check ambient-suggested medication orders against supported catalogs before you persist them in the chart. Use the same order metadata when clinicians review medication suggestions after capture continues across products. # Ambient & Dictation APIs Overview Source: https://developer.suki.ai/api-reference/overview Plan an Ambient or Dictation integration with REST session APIs, Partner WebSocket audio, webhooks, and endpoints for notes, preferences, feedback, and structured clinical output **New** The Ambient APIs are now interoperable with other Suki products that support Ambient workflows. Pass `emr_encounter_id` when you create an ambient session so clinicians can continue the same clinical note across Ambient APIs, Mobile SDK, and Web SDK. Refer to [Ambient interoperability](/documentation/concepts/ambient-clinical-notes/ambient-interoperability) for more information. **Are you a Suki partner?** To use any Suki API or SDK, you must be a Suki partner. Contact the partnership team to begin the onboarding process. They help you set up your authentication system and get started with the Suki APIs and SDKs. Suki Ambient APIs let you integrate **Ambient clinical documentation** into your application. You can create and manage **ambient sessions**, stream visit audio, and retrieve AI-generated **clinical notes** while maintaining full control over your application's workflows and user experience. An encounter is the patient visit. An ambient session is one recording for that visit. One encounter can include one or more ambient sessions. During an ambient session, providers and patients have a real-time conversation while Suki processes the streamed audio and generates a clinical note. Most operations use REST APIs and return standard [HTTP status codes](/api-reference/https-guidelines). Audio is streamed over the Partner WebSocket (`GET /ws/stream`) using the ambient session ID. When note generation is complete, Suki sends a webhook notification to your application, so you don't need to continuously poll for results. The same APIs also support **Dictation** when you need transcription without the full clinical note workflow. You create a Dictation session, stream audio, and retrieve the transcript in real time. To learn more, refer to [Audio Dictation](/documentation/concepts/dictation/dictation). ## Available APIs The following set of APIs are available for the Ambient and Dictation workflows. View each card below to learn more about the endpoints that are available and how to use them. Endpoints for authentication and authorization. Endpoints for ambient session management. Endpoints for Dictation. Endpoints for content retrieval after the session is completed. Endpoints for managing the user preferences. Endpoints for managing user feedback. Endpoints for managing notifications to your service. Endpoints for retrieving information about the encounter type, visit type, and provider role. Endpoints for retrieving information about the medication orders. ## Authentication For an overview of Suki's supported authentication mechanisms refer to [Authentication mechanisms](/documentation/how-to/partner-authentication). We recommend using OAuth 2.0 with JWT tokens for your authentication system. If you know what your authentication model is, refer to the following guides to get started: All Suki API requests must include the following headers: | Header | Value | Required | | :-------------- | :----------------------------------- | :---------- | | `Authorization` | `Bearer ` | Yes | | `partner_token` | JWT issued by your identity provider | Yes | | `Content-Type` | `application/json` | Yes | | `Accept` | `application/json` | Recommended | If you're using a Suki SDK, the SDK manages authentication and sends the required headers automatically after authentication is configured. ## Key capabilities The Ambient APIs provide the following capabilities, so you can control audio capture, note quality, and how generated outputs reach your product and downstream systems. Create ambient sessions, stream visit audio over the Partner WebSocket, and pause, resume, or end each session when that recording is finished. Turn provider-patient conversations into structured clinical notes and full transcripts, then retrieve draft content and metadata after processing finishes. Let patients speak in 80+ languages while Suki generates English notes and transcripts that fit standard EHR workflows. Set provider-level verbosity and section formats through the User Preferences API so generated notes match how each clinician documents care. Organize documentation by patient problems, merge existing diagnoses from context, and retrieve ICD10, IMO, SNOMED, and HCC structured output for EHR integration. Convert medication instructions from ambient encounters into structured Medication order data for APIs, Mobile SDK, and Web SDK. Extract diagnoses, medications, and other encounter-level artifacts from the conversation for charting, orders, and analytics in your application. Configure which LOINC-based sections appear in generated notes so output aligns with your specialty templates and compliance requirements. Run speech-to-text sessions when you need transcription without the full ambient clinical note workflow. Receive webhook callbacks when processing completes, and submit feedback on transcripts or generated content to track quality over time. ## Requirements Before you can use the Ambient and Dictation APIs, meet these requirements: * You must be a Suki partner. Learn more about how to become a Suki partner in the [Partner onboarding](/documentation/get-started/partner-onboarding) documentation. * A standards-based authentication system (for example OAuth 2.0 or OpenID Connect with JWTs). * JWT tokens with consistent user identifiers (for example `sub`, `email`, or `userId`). * A publicly accessible JWKS endpoint for token verification. ## Common integration patterns and use cases The Ambient APIs provide REST and WebSocket endpoints to create ambient sessions, stream audio, complete sessions, and retrieve clinical outputs. Your application owns the capture UI, session orchestration, and how notes are reviewed or persisted. The following examples show common ways to integrate the Ambient APIs into your application. Create the session through REST, stream visit audio over the Partner WebSocket, and expose recording controls in your own interface. End the session, receive a completion webhook or poll status, then retrieve the generated clinical note and related outputs when processing completes. Map LOINC-based note sections, transcripts, and available structured data into your review and EHR persistence workflow after the session completes. Use Dictation APIs when your application needs real-time transcription without running the ambient note-generation workflow. ## API versioning All endpoints use the `/api/v1/` prefix. **v1** is the stable version. Non-breaking changes may ship without a major version jump. For policies and migration, refer to [API guidelines](/api-reference/api-guidelines#version-management). These APIs may include Early Access features. If you are unsure what is enabled for your account, contact your Suki representative. ## Suki Ambient APIs workflow To integrate with the Suki Ambient API, you follow a session-based workflow. ```mermaid actions={false} theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} flowchart TD Start([Start Session]) --> Auth[Authentication] Auth --> Check{User registered?} Check -->|No| Register[Register new user] Register --> Auth Check -->|Yes| Token[Get sdp_suki_token] Token --> Create[Create session] Create --> SessionID[Get ambient_session_id] SessionID --> Context{Seed Context?} Context -->|Yes| AddContext[Add additional context] Context -->|No| Stream AddContext --> Stream[Stream audio chunks] Stream --> Control[PAUSE/RESUME
/KEEP_ALIVE] Control --> Done{Session Complete?} Done -->|No| Stream Done -->|Yes| End[Generate note] End --> Wait[AI processing] Wait --> Notify{Webhook configured?} Notify -->|Yes| Hook[Receive notification] Notify -->|No| Poll[Poll status] Hook --> Retrieve Poll --> Retrieve[Retrieve note] Retrieve --> Complete([Session Complete]) classDef authStyle fill:#FFE148,stroke:#D4A017,stroke-width:2px,color:#000000 classDef registerStyle fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#000000 classDef highlightStyle fill:#FFD700,stroke:#D4A017,stroke-width:3px,color:#000000 class Auth,Create,Stream,End authStyle class Register registerStyle class Retrieve highlightStyle ``` ### Developer workflow Authenticate with Suki to get a Suki authentication token, also called `suki_token`. Create an ambient session for the patient visit. One encounter can include more than one session. Stream visit audio over WebSocket to the Suki backend. End the ambient session when that recording is finished. Ending a session is not the same as closing the encounter. Retrieve generated outputs through REST endpoints. If webhooks are enabled for your partner account, your application will receive automatic completion notifications instead of relying only on polling. **Best practices** * Store **partner\_id**, **partner\_token**, and issued tokens securely; rotate credentials per your security policy. * Send API traffic over HTTPS and validate webhook signatures when your integration receives callbacks. * Read HTTP status and error bodies from REST responses; handle auth expiry by refreshing **suki\_token** as documented. ## Next steps Refer to the [Ambient APIs quickstart](/api-reference/quickstart) to get started. # Ambient & Dictation APIs Changelog Source: https://developer.suki.ai/api-reference/product-updates/changelog API product updates and announcements for the Ambient and Dictation APIs Suki's API versioning policy is based on the semantic versioning standard. For example, in version 1.2.3, 1 is the major version, 2 is the minor version, and 3 is the patch version. When we release a new API version for new features or bug fixes, we increment one of these three version components depending on the type of change introduced. **API version numbering policy** All Suki REST APIs are currently in `v1` version. **Release version** The release version in this changelog page represents the incremental progress. It is not the API version. It tracks new optional fields, performance improvements, new endpoints, and other changes.

No changelog entries match this filter. Choose All or another scope.

### New endpoints * **Note-level ambient endpoints**: You can now retrieve accumulated content, context, and structured data for a note across ambient sessions while using the interoperability feature. Use `composition_id` from [Create ambient session](/api-reference/ambient-sessions/create) as `note_id`. * GET [/api/v1/ambient/note//content](/api-reference/ambient-content/note-content). * GET [/api/v1/ambient/note//context](/api-reference/ambient-content/note-context). * GET [/api/v1/ambient/note//structured-data](/api-reference/ambient-content/note-structured-data). * **List encounter notes**: You can now list all notes linked to an EMR encounter for cross-modality ambient workflows. * GET [/api/v1/ambient/encounter//notes](/api-reference/ambient-content/list-encounter-notes). ### Enhancements * **Create ambient session**: You can now pass `emr_encounter_id` to enable cross-modality ambient interoperability. The response now includes `composition_id`, which you use as `note_id` with the note-level ambient endpoints. The `multilingual` parameter is deprecated. Multilingual support is enabled by default for all ambient sessions. * POST [/api/v1/ambient/session/create](/api-reference/ambient-sessions/create). Learn more in the [How to use ambient across modalities](/documentation/how-to/ambient-clinical-notes/use-ambient-across-modalities) documentation. ### Enhancements * **HCC codes**: You now get [HCC codes](https://www.aapc.com/resources/what-is-hierarchical-condition-category?srsltid=AfmBOopcl-dIWrRrQFq58LGS72p58BakTdoWdEHv0P9z89c3XBXuJAOY) in the **Structured data API** and **Encounter structured data API** output for an ambient session and encounter. * GET [/api/v1/ambient/session//structured-data](/api-reference/ambient-content/structured-data). * GET [/api/v1/ambient/encounter//structured-data](/api-reference/ambient-content/encounter-structured-data). * Use HCC codes in the structured data output to validate the diagnosis codes in the EMR context. ```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "structured_data": { "diagnoses": { "values": [ { "codes": [ { "code": "A00.0", "description": "Acute myocardial infarction", "type": "ICD10" }, { "code": "R05.2", "description": "Hypertension, unspecified", "type": "ICD10" }, { "code": "65", "description": "CMS-HCC model category 65", // HCC code in the format `CMS-HCC model category ` "type": "HCC" } ] } ] } } } ``` If an ICD-10-CM HCC diagnosis code does not map to an HCC model category, Suki looks for general HCC codes that match the diagnosis description. If no match is found, the diagnosis is returned without an HCC code. ### Enhancements * Suki now supports **Single Auth Token authentication**: your backend can use one shared `partner_token` for all clinicians instead of a per-user token. The shared token proves your organization is authorized, but it does not identify who is signed in. If you use this model, you **must** send `sdp_provider_id` on every API call so Suki can route each call to the correct clinician. Learn more in the [Provider authentication](/api-reference/provider-authentication) documentation. ```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "sdp_suki_token": "your-suki-token", // sdp_suki_token required for all API calls // Required with Single Auth Token auth: send sdp_provider_id on Register, Login, and every API call "sdp_provider_id": "doc1234567890" } ``` ### New endpoints * **Info endpoints**: Added new endpoints to get the list of supported medication coding systems, dosage units, encounter relations, frequencies, medication timings, origins, and statuses. * GET [/api/v1/info/orders/coding-systems](/api-reference/info/orders-coding-systems). * GET [/api/v1/info/orders/dosage-units](/api-reference/info/orders-dosage-units). * GET [/api/v1/info/orders/encounter-relations](/api-reference/info/orders-encounter-relations). * GET [/api/v1/info/orders/frequencies](/api-reference/info/orders-frequencies). * GET [/api/v1/info/orders/medication-timings](/api-reference/info/orders-medication-timings). * GET [/api/v1/info/orders/origins](/api-reference/info/orders-origins). * GET [/api/v1/info/orders/statuses](/api-reference/info/orders-statuses). ### Enhancements * **Medication orders**: You can now send and retrieve medication orders for an ambient session and encounter using the following endpoints. **Structured data endpoints**: These endpoints return the structured data for an ambient session and encounter. * GET [/api/v1/ambient/session//structured-data](/api-reference/ambient-content/structured-data). * GET [/api/v1/ambient/session//encounter-structured-data](/api-reference/ambient-content/encounter-structured-data). **Context API**: This endpoint allows you to update the ambient session context with new EMR context and medication orders. * POST [/api/v1/ambient/session//context](/api-reference/ambient-sessions/update-context). **Content API**: This endpoint returns the content for an ambient session and encounter. * GET [/api/v1/ambient/session//content](/api-reference/ambient-content/content). * GET [/api/v1/ambient/session//encounter-content](/api-reference/ambient-content/encounter-content). **Payload structure**: ```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { "structured_data": { "orders": { "medication_orders": { "values": [ { "drug_name": "Drug Name", "status": "Status", "medication_code": "Medication Code", "medication_code_type": "Medication Code Type" } ] } } } } ``` When you send medication orders to the context API, the medication orders are validated against the EMR context. If the medication orders are not valid, the context API will return an error. Learn more in the [Medication orders](/documentation/concepts/ambient-clinical-notes/medication-orders) documentation.
### New endpoints * **Audio streaming and download**: We've added a new endpoint for audio streaming and download from ambient sessions. Stream or download the audio recording from an ambient session. * GET [/api/v1/ambient/session//recording](/api-reference/ambient-content/recording). Learn more in the [Audio streaming and download](/documentation/how-to/audio-streaming/audio-streaming-download) documentation.
### Deprecated * **Multilingual support**: The `multilingual` parameter is deprecated in the `Create Ambient Session` endpoint. When you call create ambient session API, the multilingual support is now **set to true by default**.
### New endpoints * **Audio Dictation API**: Added support for real-time audio transcription. Create transcription sessions, stream transcription data, and end sessions to get final transcripts. This enables use cases like Dictation, real-time captioning, and transcript generation. * POST [/api/v1/transcription/session/create](/api-reference/audio-transcription/create-session). * POST [/api/v1/transcription/session//end](/api-reference/audio-transcription/end-session). * GET [/ws/transcribe](/api-reference/audio-transcription/stream-transcription).
### Enhancements * **Code examples**: Added code examples in Python and TypeScript for all APIs, making it easier to integrate with the platform regardless of your preferred programming language.
### New endpoints * **Info endpoints**: Introduced three new info endpoints to provide supported enum values, helping you validate context data before submission and ensuring data consistency. * GET [/api/v1/info/encounter-types](/api-reference/info/encounter-types). * GET [/api/v1/info/visit-types](/api-reference/info/visit-types). * GET [/api/v1/info/provider-roles](/api-reference/info/provider-roles). * **API reference guidelines**: Added a new [API reference guidelines](/api-reference/api-guidelines) page to help you understand API status tags, versioning, and documentation standards. ### Enhancements * **Enhanced API documentation**: Significantly restructured and enhanced API reference documentation for better developer experience, clearer organization, and improved discoverability. * **Problem-based charting guide**: Completely rewritten the Problem-Based Charting (PBC) guide with a clearer structure and more detailed explanations of the processing pipeline. * **Audio streaming authentication**: Added detailed authentication guidance for both browser and non-browser clients in the Audio streaming API reference documentation. * **Enhanced context support**: Updated the [Ambient session context APIs](/api-reference/ambient-sessions/context) to support a new `VisitContext` schema, including fields like `chief_complaint` and `visit_type`. The provider context has also been enhanced to support `provider_role`. ### Removed support * **SNOMED codes**: SNOMED codes are no longer supported for the diagnosis context. * **Paused state**: Paused state is no longer supported for ambient sessions.
# Provider Authentication Source: https://developer.suki.ai/api-reference/provider-authentication Run Register and Login to obtain Suki access token, choose Standard, Single Auth Token, or Bearer partner authentication models, and refresh tokens for Ambient API calls **Not a Suki Partner yet?** To use the Suki APIs, you must first register your organization as a partner. To begin, follow the [Partner onboarding](/documentation/get-started/partner-onboarding) guide to learn more or schedule a call with Suki using the **Ask AI** chat assistant. After you register, you use a Partner Token (`partner_token`) to authenticate your API requests. The `partner_token` is a JWT that **you** provide, and it is a **required parameter** when registering a provider. Find more details on how to get a `partner_token` in the [Partner authentication](/documentation/how-to/partner-authentication) guide. All Suki REST and WebSocket APIs require partner authentication. Call the [Register](/api-reference/authentication/register) and [Login](/api-reference/authentication/login) APIs with your Partner Token (`partner_token`) to authenticate clinicians with Suki and receive a Suki access token (`sdp_suki_token` / `suki_token`). Suki access tokens are valid for **1 hour**. This guide explains the **two main endpoints** for the authentication workflow: * **Register user**: A **one-time** call to register a **new provider** in the Suki system. * **Authenticate user**: Call this endpoint to get a **suki\_token** (`sdp_suki_token`) for a registered provider. ## Choose your authentication model Before integrating with Suki, determine which authentication model your organization uses. Your authentication model defines how clinician identity is sent to Suki and which fields are required during authentication and subsequent API requests. Suki supports the following authentication models and defines your model during the [Partner onboarding](/documentation/get-started/partner-onboarding) process. This guide is for Standard partner authentication only. For Single Auth Token authentication and Bearer partner authentication, refer to the [Single Auth Token authentication](/api-reference/single-auth-token-authentication) and [Bearer partner authentication](/api-reference/bearer-partner-authentication) guides respectively. ### 1. Standard partner authentication Each clinician authenticates with their own `partner_token`. Suki derives provider identity from that token, so you do not need to send `provider_id` on Register or Login. **Best for** * Enterprise deployments where each clinician has their own account in your identity provider. * Integrations where your IdP issues a per-user ID token or user-scoped JWT as `partner_token`. * Flows where the token already identifies the signed-in provider without a separate `provider_id`. ### 2. Single Auth Token authentication Your backend uses **one shared** `partner_token` for multiple clinicians. The token proves your organization is authorized, but it does not identify who is signed in. With Single Auth Token authentication, you send **provider identity on every** request: `provider_id` on Register and Login, and `sdp_provider_id` on every subsequent REST and WebSocket call. **Best for** * Server backends that authenticate to Suki with one organization-level token for many clinicians. * Integrations that supply a stable `provider_id` for each clinician (from any source your system chooses). * Identity setups that cannot include per-user claims in the `partner_token`. If you plan to use Single Auth Token authentication, see [Single Auth Token authentication](/api-reference/single-auth-token-authentication) for more details. ### 3. Bearer partner authentication **Bearer** is a separate partner type that Suki configures during onboarding. A Bearer partner validates the end-user identity with `provider_id` during **Login** and **Register**, instead of relying on per-user claims in the token. **Best for** * Partners whose shared `partner_token` cannot carry per-user identity. * Integrations where Suki must validate `provider_id` against an agreed expression during authentication. * Web SDK and other clients that pass `provider_id` for a Bearer partner configuration. For Login and Register fields, validation rules, and security guidance, refer to the [Bearer partner authentication](/api-reference/bearer-partner-authentication) guide. * Single Auth Token partners cannot be a Bearer partner. * To refresh a Suki access token, send another **POST** request to [Login](/api-reference/authentication/login) with a valid `partner_token`. ## Register provider/user account Use the below endpoint to **register** a new **provider/user** in the Suki platform. You only need to do this **once** for each new provider. **Endpoint**: [Register](/api-reference/authentication/register) **Method:** POST ### Registration scenarios Flowchart: POST register leads to User Exists; if No, New User Registration, Create User and Link, then Response 201; if Yes, Linked to this Partner; if No, Existing User New Partner Link, Link User to Partner, then Response 201; if Yes, Existing User Already Linked, then Response 409 Conflict. Flowchart: POST register leads to User Exists; if No, New User Registration, Create User and Link, then Response 201; if Yes, Linked to this Partner; if No, Existing User New Partner Link, Link User to Partner, then Response 201; if Yes, Existing User Already Linked, then Response 409 Conflict. The `Register` endpoint handles three main scenarios: * **New user registration**: If the provider **does not exist** in the Suki system, this call **creates a new user** and links them to your partner account and organization. * **Existing user, new partner link**: If the provider **already exists** but is not linked to your partner account, this call **links them to your partner** and their existing organization. * **Existing user, already linked**: If the provider is already registered and linked to your partner account, the API returns a `409` Conflict error. ## Authenticate provider/user session After a provider is registered, call the [Login](/api-reference/authentication/login) endpoint to get a Suki access token (`sdp_suki_token`). If you are a **Bearer partner**, send `provider_id` on every [Login](/api-reference/authentication/login) and [Register](/api-reference/authentication/register) request. Refer to [Bearer partner authentication](/api-reference/bearer-partner-authentication). If you use **Single Auth Token authentication**, also send `sdp_provider_id` on every API call after Login. Refer to [Single Auth Token authentication](/api-reference/single-auth-token-authentication). ### JWKS endpoint Suki provides a public **JWKS (JSON Web Key Set)** endpoint that you can use to verify the signature of the `sdp_suki_token` that our API returns. **Endpoint:** [JWKS URL](/api-reference/authentication/jwks) **Method:** GET **Authentication:** None (Public) ### Use cases Diagram: Fetch Public Keys leads to JWKS Endpoint; from JWKS, three branches to Token Verification, Signature Validation, and Key Rotation. Diagram: Fetch Public Keys leads to JWKS Endpoint; from JWKS, three branches to Token Verification, Signature Validation, and Key Rotation. * **Token verification**: Fetch public keys to verify JWTs issued by Suki. * **Signature validation**: Validate the signature of the `sdp_suki_token`. * **Key rotation**: Automatically discover new public keys when Suki rotates our signing keys. # Ambient API Quickstart Source: https://developer.suki.ai/api-reference/quickstart Authenticate, create an Ambient session, stream audio, end the session, and retrieve the clinical note on staging This quickstart walks you through one successful Ambient API session on staging: authenticate, create a session, stream visit audio, end the session, and retrieve the clinical note. Rely on a webhook when processing finishes to handle notifications. Your application owns session controls, audio streaming, status handling, note review, and EHR handoff. For product context and when to choose Ambient APIs versus ambient SDKs, refer to [Ambient clinical documentation](/documentation/concepts/ambient-clinical-notes/ambient-documentation). **What you will do** 1. **Authenticate** to get an `sdp_suki_token` (and **register** the user if needed). 2. **Create** an ambient session and optionally **seed context** for better notes. An ambient session is one recording for a patient visit (encounter). One encounter can include more than one session. 3. **Stream audio** over the WebSocket, send control events, and **end** the ambient session when that recording is finished. 4. **Retrieve** the clinical note and transcript, or rely on a **webhook** when processing finishes. **Prefer one paste-ready file?** Use the [Complete staging script](#complete-staging-script) in the preferred language below, then follow the numbered steps for the same flow with full explanations. Building in **C++**? See the C++ sample on [Login](/api-reference/authentication/login). For Ambient, Dictation, and Form filling flows, use the TypeScript or Python complete staging scripts below. **Using an AI coding tool?** Copy the prompt below to point your agent at the Ambient skill and [Documentation MCP](/documentation/references/mcp). For every task skill, refer to [AI coding tools](/documentation/references/ai-coding-tools). Build ambient clinical documentation with Suki for Partners. Fetch the Ambient build skill: [https://developer.suki.ai/.well-known/agent-skills/suki-ambient/SKILL.md](https://developer.suki.ai/.well-known/agent-skills/suki-ambient/SKILL.md) Connect the documentation MCP for page search: [https://developer.suki.ai/documentation/references/mcp](https://developer.suki.ai/documentation/references/mcp) ## Access and credentials You need partner credentials to use the Suki Ambient APIs. Contact our [Partnership team](https://www.suki.ai/suki-partners/) to get your credentials. They will guide you through the [Onboarding process](/documentation/get-started/partner-onboarding) and provide what you need to get started. ### Prerequisites To use the Suki Ambient APIs, you must have the following: * An OAuth-compliant authentication system. * JWT tokens with consistent user identifiers. * A publicly accessible JWKS endpoint (or Okta authorization server) for token validation. ### Environments to use for development and testing This guide uses **`https://sdp.suki-stage.com`** and **`wss://sdp.suki-stage.com`** for API and WebSocket examples (staging). **Important**: * The production environment is **`https://sdp.suki.ai`** and **`wss://sdp.suki.ai`**. * The staging environment is **`https://sdp.suki-stage.com`** and **`wss://sdp.suki-stage.com`**. * Your partnership team will confirm which environment, base URL, and credentials apply for your integration. ## Complete staging script Replace the credential placeholders, put a 16 kHz mono LINEAR16 WAV (or raw PCM) at `audio.wav`, then run. For detailed explanations of each step, refer to the numbered steps below. * **Python:** `pip install requests websocket-client` then `python ambient_staging.py`. * **TypeScript (Node):** `npm install ws` then `npx tsx ambient_staging.ts` (Node 18+). Ambient sessions must be **at least 1 minute** of audio for note generation. Shorter sessions can return status `skipped` with no note. Use a WAV or raw LINEAR16 PCM file that is long enough when you test. ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} # ambient_staging.py # Flow: login (register once if needed) → create → context → stream → end → poll content # pip install requests websocket-client import base64 import json import time from datetime import datetime, timezone from typing import Any, Optional import requests import websocket BASE_URL = "https://sdp.suki-stage.com" WS_URL = "wss://sdp.suki-stage.com/ws/stream" CHUNK_BYTES = 3200 # ~100 ms of 16 kHz mono 16-bit PCM WAV_HEADER_BYTES = 44 # Replace these with your partner credentials PARTNER_ID = "your-partner-id" PARTNER_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." # Keep on your backend only PROVIDER_ID = "provider-123" # Optional; required for Bearer / Single Auth Token partners SDP_PROVIDER_ID = "" # Leave empty unless your partnership requires sdp_provider_id AUDIO_PATH = "audio.wav" # 16 kHz mono LINEAR16 WAV or raw PCM def b64(data: bytes) -> str: return base64.b64encode(data).decode("ascii") def rest_headers(suki_token: str) -> dict[str, str]: headers = { "sdp_suki_token": suki_token, "Content-Type": "application/json", } if SDP_PROVIDER_ID: headers["sdp_provider_id"] = SDP_PROVIDER_ID return headers def expect_status(response: requests.Response, url: str, want: int) -> None: if response.status_code == want: return detail = (response.text or "")[:500] try: body = response.json() if isinstance(body, dict) and body.get("message"): detail = str(body["message"]) except ValueError: pass raise RuntimeError(f"HTTP {response.status_code} {url}: {detail}") def login(partner_id: str, partner_token: str, provider_id: Optional[str] = None) -> str: url = f"{BASE_URL}/api/v1/auth/login" payload: dict[str, Any] = {"partner_id": partner_id, "partner_token": partner_token} if provider_id: payload["provider_id"] = provider_id r = requests.post(url, json=payload, timeout=60) expect_status(r, url, 200) token = r.json().get("suki_token") if not token: raise RuntimeError("login response missing suki_token") return token def register_provider( partner_id: str, partner_token: str, provider_name: str, provider_org_id: str, provider_id: Optional[str] = None, ) -> None: url = f"{BASE_URL}/api/v1/auth/register" payload: dict[str, Any] = { "partner_id": partner_id, "partner_token": partner_token, "provider_name": provider_name, "provider_org_id": provider_org_id, } if provider_id: payload["provider_id"] = provider_id r = requests.post(url, json=payload, timeout=60) # New link: 201. Already linked: 409. Both are success for this flow. if r.status_code not in (201, 409): expect_status(r, url, 201) def login_with_register_fallback( partner_id: str, partner_token: str, provider_id: Optional[str], provider_name: str, provider_org_id: str, ) -> str: try: return login(partner_id, partner_token, provider_id) except RuntimeError as err: if "provider_not_registered" not in str(err): raise register_provider( partner_id, partner_token, provider_name, provider_org_id, provider_id ) return login(partner_id, partner_token, provider_id) def create_ambient_session(suki_token: str, body: Optional[dict[str, str]] = None) -> dict[str, str]: url = f"{BASE_URL}/api/v1/ambient/session/create" r = requests.post(url, headers=rest_headers(suki_token), json=body or {}, timeout=60) expect_status(r, url, 201) data = r.json() sid = data.get("ambient_session_id") composition_id = data.get("composition_id") if not sid: raise RuntimeError("create response missing ambient_session_id") return { "ambient_session_id": sid, "composition_id": composition_id or "", } def seed_context(suki_token: str, ambient_session_id: str) -> None: url = f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/context" payload = { "provider": {"specialty": "CARDIOLOGY", "provider_role": "ATTENDING"}, "patient": {"dob": "2000-01-01", "sex": "male"}, "visit": { "chief_complaint": "Headache", "encounter_type": "AMBULATORY", "reason_for_visit": "Follow-up for migraines", "visit_type": "ESTABLISHED_PATIENT", }, "sections": [{"loinc": "10164-2"}, {"loinc": "48765-2"}], "diagnoses": { "values": [ { "codes": [ { "code": "I10", "description": "Essential hypertension", "type": "ICD10", } ], "diagnosis_note": "Hypertension", } ] }, "emr": {"target_emr": "EPIC"}, } r = requests.post(url, headers=rest_headers(suki_token), json=payload, timeout=60) expect_status(r, url, 200) def strip_wav_header(raw: bytes) -> bytes: if len(raw) >= 12 and raw[:4] == b"RIFF" and raw[8:12] == b"WAVE": return raw[WAV_HEADER_BYTES:] return raw def stream_pcm_file(suki_token: str, ambient_session_id: str, path: str) -> None: header = [ f"sdp_suki_token: {suki_token}", f"ambient_session_id: {ambient_session_id}", ] if SDP_PROVIDER_ID: header.append(f"sdp_provider_id: {SDP_PROVIDER_ID}") ws = websocket.create_connection(WS_URL, header=header, timeout=60) try: rfc3339 = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") ws.send(json.dumps({"type": "START_TIME", "data": b64(rfc3339.encode("utf-8"))})) with open(path, "rb") as f: pcm = strip_wav_header(f.read()) for i in range(0, len(pcm), CHUNK_BYTES): ws.send(json.dumps({"type": "AUDIO", "data": b64(pcm[i : i + CHUNK_BYTES])})) # End marker: Base64 of ASCII bytes EOF (literal RU9G) ws.send(json.dumps({"type": "AUDIO", "data": "RU9G"})) finally: ws.close() def end_ambient_session(suki_token: str, ambient_session_id: str) -> None: url = f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/end" r = requests.post(url, headers=rest_headers(suki_token), timeout=60) expect_status(r, url, 200) def get_status(suki_token: str, ambient_session_id: str) -> str: url = f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/status" r = requests.get(url, headers=rest_headers(suki_token), timeout=60) expect_status(r, url, 200) return r.json()["status"] def get_content(suki_token: str, ambient_session_id: str) -> Any: url = f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/content" r = requests.get( url, headers=rest_headers(suki_token), params={"cumulative": "false"}, timeout=60, ) expect_status(r, url, 200) return r.json() def wait_for_content(suki_token: str, ambient_session_id: str, poll_sec: float = 2.0) -> dict[str, Any]: while True: status = get_status(suki_token, ambient_session_id) print("status:", status) if status == "completed": return {"status": status, "content": get_content(suki_token, ambient_session_id)} if status in ("failed", "skipped", "aborted"): return {"status": status, "content": None} time.sleep(poll_sec) if __name__ == "__main__": suki_token = login_with_register_fallback( PARTNER_ID, PARTNER_TOKEN, PROVIDER_ID, provider_name="Dr. John Smith", provider_org_id="org-123", ) print("Authenticated") created = create_ambient_session(suki_token, {}) ambient_session_id = created["ambient_session_id"] print("ambient_session_id:", ambient_session_id) print("composition_id:", created["composition_id"]) seed_context(suki_token, ambient_session_id) print("Context seeded") stream_pcm_file(suki_token, ambient_session_id, AUDIO_PATH) print("Stream finished") end_ambient_session(suki_token, ambient_session_id) print("Session ended") result = wait_for_content(suki_token, ambient_session_id) print(json.dumps(result, indent=2)) ``` ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} // ambient_staging.ts // Flow: login (register once if needed) → create → context → stream → end → poll content // Node 18+: npm install ws && npx tsx ambient_staging.ts import fs from "node:fs"; import WebSocket from "ws"; const BASE_URL = "https://sdp.suki-stage.com"; const WS_URL = "wss://sdp.suki-stage.com/ws/stream"; const CHUNK_BYTES = 3200; // ~100 ms of 16 kHz mono 16-bit PCM const WAV_HEADER_BYTES = 44; // Replace these with your partner credentials const PARTNER_ID = "your-partner-id"; const PARTNER_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."; // Keep on your backend only const PROVIDER_ID = "provider-123"; // Optional; required for Bearer / Single Auth Token partners const SDP_PROVIDER_ID = ""; // Leave empty unless your partnership requires sdp_provider_id const AUDIO_PATH = "audio.wav"; // 16 kHz mono LINEAR16 WAV or raw PCM function restHeaders(sukiToken: string): Record { const headers: Record = { sdp_suki_token: sukiToken, "Content-Type": "application/json", }; if (SDP_PROVIDER_ID) headers.sdp_provider_id = SDP_PROVIDER_ID; return headers; } async function expectStatus(response: Response, url: string, want: number): Promise { if (response.status === want) return; const raw = await response.text(); let detail = raw.slice(0, 500); try { const body = JSON.parse(raw); if (body?.message) detail = String(body.message); } catch { // keep raw text } throw new Error(`HTTP ${response.status} ${url}: ${detail}`); } async function login( partnerId: string, partnerToken: string, providerId?: string, ): Promise { const url = `${BASE_URL}/api/v1/auth/login`; const body: Record = { partner_id: partnerId, partner_token: partnerToken, }; if (providerId) body.provider_id = providerId; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); await expectStatus(response, url, 200); const data = (await response.json()) as { suki_token?: string }; if (!data.suki_token) throw new Error("login response missing suki_token"); return data.suki_token; } async function registerProvider(input: { partnerId: string; partnerToken: string; providerName: string; providerOrgId: string; providerId?: string; }): Promise { const url = `${BASE_URL}/api/v1/auth/register`; const body: Record = { partner_id: input.partnerId, partner_token: input.partnerToken, provider_name: input.providerName, provider_org_id: input.providerOrgId, }; if (input.providerId) body.provider_id = input.providerId; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); // New link: 201. Already linked: 409. Both are success for this flow. if (response.status !== 201 && response.status !== 409) { await expectStatus(response, url, 201); } } async function loginWithRegisterFallback( partnerId: string, partnerToken: string, providerId: string | undefined, providerName: string, providerOrgId: string, ): Promise { try { return await login(partnerId, partnerToken, providerId); } catch (err) { if (!String(err).includes("provider_not_registered")) throw err; await registerProvider({ partnerId, partnerToken, providerName, providerOrgId, providerId, }); return login(partnerId, partnerToken, providerId); } } async function createAmbientSession( sukiToken: string, ): Promise<{ ambientSessionId: string; compositionId: string }> { const url = `${BASE_URL}/api/v1/ambient/session/create`; const response = await fetch(url, { method: "POST", headers: restHeaders(sukiToken), body: JSON.stringify({}), }); await expectStatus(response, url, 201); const data = (await response.json()) as { ambient_session_id?: string; composition_id?: string; }; if (!data.ambient_session_id) { throw new Error("create response missing ambient_session_id"); } return { ambientSessionId: data.ambient_session_id, compositionId: data.composition_id ?? "", }; } async function seedContext(sukiToken: string, ambientSessionId: string): Promise { const url = `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/context`; const response = await fetch(url, { method: "POST", headers: restHeaders(sukiToken), body: JSON.stringify({ provider: { specialty: "CARDIOLOGY", provider_role: "ATTENDING" }, patient: { dob: "2000-01-01", sex: "male" }, visit: { chief_complaint: "Headache", encounter_type: "AMBULATORY", reason_for_visit: "Follow-up for migraines", visit_type: "ESTABLISHED_PATIENT", }, sections: [{ loinc: "10164-2" }, { loinc: "48765-2" }], diagnoses: { values: [ { codes: [ { code: "I10", description: "Essential hypertension", type: "ICD10", }, ], diagnosis_note: "Hypertension", }, ], }, emr: { target_emr: "EPIC" }, }), }); await expectStatus(response, url, 200); } function stripWavHeader(buf: Buffer): Buffer { if ( buf.length >= 12 && buf.subarray(0, 4).toString("ascii") === "RIFF" && buf.subarray(8, 12).toString("ascii") === "WAVE" ) { return buf.subarray(WAV_HEADER_BYTES); } return buf; } function streamPcmFile( sukiToken: string, ambientSessionId: string, path: string, ): Promise { return new Promise((resolve, reject) => { const headers: Record = { sdp_suki_token: sukiToken, ambient_session_id: ambientSessionId, }; if (SDP_PROVIDER_ID) headers.sdp_provider_id = SDP_PROVIDER_ID; const ws = new WebSocket(WS_URL, { headers }); ws.on("open", () => { try { const rfc3339 = new Date().toISOString().replace(/\.\d{3}Z$/, "Z"); ws.send( JSON.stringify({ type: "START_TIME", data: Buffer.from(rfc3339, "utf8").toString("base64"), }), ); const pcm = stripWavHeader(fs.readFileSync(path)); for (let i = 0; i < pcm.length; i += CHUNK_BYTES) { ws.send( JSON.stringify({ type: "AUDIO", data: pcm.subarray(i, i + CHUNK_BYTES).toString("base64"), }), ); } // End marker: Base64 of ASCII bytes EOF ws.send(JSON.stringify({ type: "AUDIO", data: "RU9G" })); ws.close(); } catch (err) { reject(err); } }); ws.on("message", (data) => console.log("ws message:", data.toString())); ws.on("error", reject); ws.on("close", () => resolve()); }); } async function endAmbientSession(sukiToken: string, ambientSessionId: string): Promise { const url = `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/end`; const response = await fetch(url, { method: "POST", headers: restHeaders(sukiToken), }); await expectStatus(response, url, 200); } async function getStatus(sukiToken: string, ambientSessionId: string): Promise { const url = `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/status`; const response = await fetch(url, { headers: restHeaders(sukiToken) }); await expectStatus(response, url, 200); const data = (await response.json()) as { status: string }; return data.status; } async function getContent(sukiToken: string, ambientSessionId: string): Promise { const url = `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/content?cumulative=false`; const response = await fetch(url, { headers: restHeaders(sukiToken) }); await expectStatus(response, url, 200); return response.json(); } async function waitForContent( sukiToken: string, ambientSessionId: string, pollMs = 2000, ): Promise<{ status: string; content: unknown }> { for (;;) { const status = await getStatus(sukiToken, ambientSessionId); console.log("status:", status); if (status === "completed") { return { status, content: await getContent(sukiToken, ambientSessionId) }; } if (status === "failed" || status === "skipped" || status === "aborted") { return { status, content: null }; } await new Promise((r) => setTimeout(r, pollMs)); } } async function main() { const sukiToken = await loginWithRegisterFallback( PARTNER_ID, PARTNER_TOKEN, PROVIDER_ID, "Dr. John Smith", "org-123", ); console.log("Authenticated"); const created = await createAmbientSession(sukiToken); console.log("ambient_session_id:", created.ambientSessionId); console.log("composition_id:", created.compositionId); await seedContext(sukiToken, created.ambientSessionId); console.log("Context seeded"); await streamPcmFile(sukiToken, created.ambientSessionId, AUDIO_PATH); console.log("Stream finished"); await endAmbientSession(sukiToken, created.ambientSessionId); console.log("Session ended"); const result = await waitForContent(sukiToken, created.ambientSessionId); console.log(JSON.stringify(result, null, 2)); } main().catch((err) => { console.error(err); process.exit(1); }); ``` ## Create your first Ambient session Send a **POST** request to the [Login API](/api-reference/authentication/login) endpoint with the following parameters in the request body: * **partner\_id**: Your unique Partner ID, which we provide to you securely offline. * **partner\_token**: The user's OAuth 2.0 ID token (Partner Token) from your identity provider. * **provider\_id** (Optional for standard partners; required for some auth flows): Unique identifier for the provider. On success the API returns a Suki Token (`suki_token`). Include it as the `sdp_suki_token` header for subsequent API calls. If the user is not registered, call the [Register API](/api-reference/authentication/register) first, then retry `/login`. You only need to register a user once. Each sample below is self-contained (TypeScript, Python, and cURL). Expect HTTP **200**. ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki-stage.com"; const response = await fetch(`${BASE_URL}/api/v1/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ partner_id: "your-partner-id", partner_token: "your-jwt-token", provider_id: "provider-123", // Required for Bearer / Single Auth; omit for Standard }), }); const data = await response.json(); if (response.status !== 200) { throw new Error(`Login failed: ${response.status} ${JSON.stringify(data)}`); } if (!data.suki_token) throw new Error("login response missing suki_token"); const sukiToken = data.suki_token as string; console.log("suki_token:", sukiToken); ``` ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests BASE_URL = "https://sdp.suki-stage.com" response = requests.post( f"{BASE_URL}/api/v1/auth/login", headers={"Content-Type": "application/json"}, json={ "partner_id": "your-partner-id", "partner_token": "your-jwt-token", "provider_id": "provider-123", # Required for Bearer / Single Auth; omit for Standard }, timeout=60, ) if response.status_code != 200: raise RuntimeError(f"Login failed: {response.status_code} {response.text}") data = response.json() suki_token = data.get("suki_token") if not suki_token: raise RuntimeError("login response missing suki_token") print("suki_token:", suki_token) ``` ```bash cURL expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl --request POST \ --url https://sdp.suki-stage.com/api/v1/auth/login \ --header 'Content-Type: application/json' \ --data '{ "partner_id": "your-partner-id", "partner_token": "your-jwt-token", "provider_id": "provider-123" }' ``` Save the `suki_token` as it is valid for **1 hour**. Request a new token before it expires. Send a **POST** request to [Create Ambient Session API](/api-reference/ambient-sessions/create). The body can be empty for a first staging session. Optional body fields: * **emr\_encounter\_id** (UUID): EMR or EHR visit ID for cross-modality Ambient interoperability. * **encounter\_id**: Required for re-ambient workflows. Alphanumeric string up to **255** characters to group sessions for the same note. * **ambient\_session\_id**: Optional UUID v4 to identify the session; Suki generates one if omitted. Expect HTTP **201** and a response with `ambient_session_id` and `composition_id`. ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki-stage.com"; const CREATE_SESSION_URL = `${BASE_URL}/api/v1/ambient/session/create`; // Get sdp_suki_token from Login: POST /api/v1/auth/login const sdpSukiToken = ""; // Required for single_auth partners const sdpProviderId = ""; // Set these from your system. Omit a field by leaving the value undefined. // All request body fields are optional. Suki generates values you omit. // Pass emr_encounter_id for cross-modality Ambient interoperability. const ambientSessionId: string | undefined = undefined; // Optional UUID for this Ambient session const emrEncounterId: string | undefined = undefined; // UUID for your EMR encounter const encounterId: string | undefined = undefined; // Required for re-ambient workflows type CreateAmbientSessionRequest = { ambient_session_id?: string; emr_encounter_id?: string; encounter_id?: string; }; type CreateAmbientSessionResponse = { ambient_session_id: string; composition_id: string; }; const payload: CreateAmbientSessionRequest = {}; if (ambientSessionId) payload.ambient_session_id = ambientSessionId; if (emrEncounterId) payload.emr_encounter_id = emrEncounterId; if (encounterId) payload.encounter_id = encounterId; const headers: Record = { "Content-Type": "application/json", sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }; const createResponse = await fetch(CREATE_SESSION_URL, { method: "POST", headers, body: JSON.stringify(payload), }); const created = (await createResponse.json()) as CreateAmbientSessionResponse; if (createResponse.status !== 201) { throw new Error( `Create failed: ${createResponse.status} ${JSON.stringify(created)}`, ); } console.log("ambient_session_id:", created.ambient_session_id); console.log("composition_id:", created.composition_id); ``` ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki-stage.com" CREATE_SESSION_URL = f"{BASE_URL}/api/v1/ambient/session/create" # Get sdp_suki_token from Login: POST /api/v1/auth/login sdp_suki_token = "" # Required for single_auth partners sdp_provider_id = "" # Set these from your system. Omit a field by leaving the value as None. # All request body fields are optional. Suki generates values you omit. # Pass emr_encounter_id for cross-modality Ambient interoperability. ambient_session_id = None # Optional UUID for this Ambient session emr_encounter_id = None # UUID for your EMR encounter encounter_id = None # Required for re-ambient workflows headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, "Content-Type": "application/json", } payload = {} if ambient_session_id: payload["ambient_session_id"] = ambient_session_id if emr_encounter_id: payload["emr_encounter_id"] = emr_encounter_id if encounter_id: payload["encounter_id"] = encounter_id response = requests.post( CREATE_SESSION_URL, headers=headers, json=payload, timeout=60, ) if response.status_code != 201: raise RuntimeError( f"Create failed: {response.status_code} {response.text}" ) created = response.json() print(json.dumps(created, indent=2)) print("ambient_session_id:", created["ambient_session_id"]) print("composition_id:", created["composition_id"]) ``` ```bash cURL expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl --request POST \ --url https://sdp.suki-stage.com/api/v1/ambient/session/create \ --header 'Content-Type: application/json' \ --header 'sdp_suki_token: ' \ --header 'sdp_provider_id: ' \ --data '{ "ambient_session_id": "", "emr_encounter_id": "", "encounter_id": "" }' ``` Save `ambient_session_id` and `composition_id`. Use the session ID for streaming and content calls; use `composition_id` as `note_id` for note-level APIs. POST to [Seed Context API](/api-reference/ambient-sessions/context) after session creation to provide metadata that improves note quality. Include fields such as `provider`, `patient`, `visit`, `sections`, `diagnoses`, and `emr`. ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki-stage.com"; const sdpSukiToken = ""; const ambientSessionId = ""; const sdpProviderId = ""; // Required for single_auth partners const headers: Record = { "Content-Type": "application/json", sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }; const contextResponse = await fetch( `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/context`, { method: "POST", headers, body: JSON.stringify({ provider: { specialty: "CARDIOLOGY", provider_role: "ATTENDING" }, patient: { dob: "2000-01-01", sex: "male" }, visit: { chief_complaint: "Headache", encounter_type: "AMBULATORY", reason_for_visit: "Follow-up for migraines", visit_type: "ESTABLISHED_PATIENT", }, sections: [{ loinc: "10164-2" }, { loinc: "48765-2" }], diagnoses: { values: [ { codes: [ { code: "I10", description: "Essential hypertension", type: "ICD10", }, ], diagnosis_note: "Hypertension", }, ], }, emr: { target_emr: "EPIC" }, }), }, ); if (contextResponse.status !== 200) { const err = await contextResponse.text(); throw new Error(`Context failed: ${contextResponse.status} ${err}`); } console.log("Context seeded"); ``` ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests BASE_URL = "https://sdp.suki-stage.com" sdp_suki_token = "" ambient_session_id = "" sdp_provider_id = "" # Required for single_auth partners headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, "Content-Type": "application/json", } payload = { "provider": {"specialty": "CARDIOLOGY", "provider_role": "ATTENDING"}, "patient": {"dob": "2000-01-01", "sex": "male"}, "visit": { "chief_complaint": "Headache", "encounter_type": "AMBULATORY", "reason_for_visit": "Follow-up for migraines", "visit_type": "ESTABLISHED_PATIENT", }, "sections": [{"loinc": "10164-2"}, {"loinc": "48765-2"}], "diagnoses": { "values": [ { "codes": [ { "code": "I10", "description": "Essential hypertension", "type": "ICD10", } ], "diagnosis_note": "Hypertension", } ] }, "emr": {"target_emr": "EPIC"}, } response = requests.post( f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/context", headers=headers, json=payload, timeout=60, ) if response.status_code != 200: raise RuntimeError(f"Context failed: {response.status_code} {response.text}") print("Context seeded") ``` ```bash cURL expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl --request POST \ --url https://sdp.suki-stage.com/api/v1/ambient/session//context \ --header 'Content-Type: application/json' \ --header 'sdp_suki_token: ' \ --header 'sdp_provider_id: ' \ --data '{ "provider": { "specialty": "CARDIOLOGY", "provider_role": "ATTENDING" }, "patient": { "dob": "2000-01-01", "sex": "male" }, "visit": { "chief_complaint": "Headache", "encounter_type": "AMBULATORY", "reason_for_visit": "Follow-up for migraines", "visit_type": "ESTABLISHED_PATIENT" }, "sections": [ { "loinc": "10164-2" }, { "loinc": "48765-2" } ], "diagnoses": { "values": [ { "codes": [ { "code": "I10", "description": "Essential hypertension", "type": "ICD10" } ], "diagnosis_note": "Hypertension" } ] }, "emr": { "target_emr": "EPIC" } }' ``` Open a WebSocket to `wss://sdp.suki-stage.com/ws/stream` after session creation and context. Authenticate using `Sec-WebSocket-Protocol` (`SukiAmbientAuth,,`) for browsers or headers for non-browser clients. Audio requirements: * encoding: LINEAR16. * sample\_rate: 16KHz. * channel: Mono. Strip WAV headers (44 bytes) before chunking. Send 100ms PCM chunks Base64-encoded in `AUDIO` messages. Required send order: `START_TIME`, one or more `AUDIO` messages, then an `AUDIO` end marker with Base64 of ASCII `EOF` (`RU9G`). Supported `EVENT` values: `PAUSE`, `RESUME`, `CANCEL`, `ABORT` (deprecated), `KEEP_ALIVE`. Close the socket when finished, then call the end session endpoint and poll status/content. Use the [Complete staging script](#complete-staging-script) for a full streaming client. When capture finishes, close the WebSocket, then call **end session**. POST to [End Session API](/api-reference/ambient-sessions/end) to end the session. ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki-stage.com"; const sdpSukiToken = ""; const ambientSessionId = ""; const sdpProviderId = ""; // Required for single_auth partners const headers: Record = { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }; const endResponse = await fetch( `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/end`, { method: "POST", headers }, ); if (endResponse.status !== 200) { const err = await endResponse.text(); throw new Error(`End failed: ${endResponse.status} ${err}`); } console.log("Session ended"); ``` ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests BASE_URL = "https://sdp.suki-stage.com" sdp_suki_token = "" ambient_session_id = "" sdp_provider_id = "" # Required for single_auth partners headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } response = requests.post( f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/end", headers=headers, timeout=60, ) if response.status_code != 200: raise RuntimeError(f"End failed: {response.status_code} {response.text}") print("Session ended") ``` ```bash cURL expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl --request POST \ --url https://sdp.suki-stage.com/api/v1/ambient/session//end \ --header 'sdp_suki_token: ' \ --header 'sdp_provider_id: ' ``` Suki notifies your webhook with `session_summary_generated` when the note is ready. Alternatively, poll these endpoints: * [Get Status API](/api-reference/ambient-content/status). * [Get Content API](/api-reference/ambient-content/content). * [Get Transcript API](/api-reference/ambient-content/transcript). ```typescript TypeScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const BASE_URL = "https://sdp.suki-stage.com"; const sdpSukiToken = ""; const ambientSessionId = ""; const sdpProviderId = ""; // Required for single_auth partners const headers: Record = { sdp_suki_token: sdpSukiToken, sdp_provider_id: sdpProviderId, }; const statusResponse = await fetch( `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/status`, { headers }, ); const statusBody = await statusResponse.json(); if (statusResponse.status !== 200) { throw new Error( `Status failed: ${statusResponse.status} ${JSON.stringify(statusBody)}`, ); } console.log("status:", statusBody.status); const contentResponse = await fetch( `${BASE_URL}/api/v1/ambient/session/${ambientSessionId}/content?cumulative=false`, { headers }, ); const content = await contentResponse.json(); if (contentResponse.status !== 200) { throw new Error( `Content failed: ${contentResponse.status} ${JSON.stringify(content)}`, ); } console.log(JSON.stringify(content, null, 2)); ``` ```python Python expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import json import requests BASE_URL = "https://sdp.suki-stage.com" sdp_suki_token = "" ambient_session_id = "" sdp_provider_id = "" # Required for single_auth partners headers = { "sdp_suki_token": sdp_suki_token, "sdp_provider_id": sdp_provider_id, } status_response = requests.get( f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/status", headers=headers, timeout=60, ) if status_response.status_code != 200: raise RuntimeError( f"Status failed: {status_response.status_code} {status_response.text}" ) print("status:", status_response.json()["status"]) content_response = requests.get( f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/content", headers=headers, params={"cumulative": "false"}, timeout=60, ) if content_response.status_code != 200: raise RuntimeError( f"Content failed: {content_response.status_code} {content_response.text}" ) print(json.dumps(content_response.json(), indent=2)) ``` ```bash cURL expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl --request GET \ --url https://sdp.suki-stage.com/api/v1/ambient/session//status \ --header 'sdp_suki_token: ' \ --header 'sdp_provider_id: ' curl --request GET \ --url 'https://sdp.suki-stage.com/api/v1/ambient/session//content?cumulative=false' \ --header 'sdp_suki_token: ' \ --header 'sdp_provider_id: ' ``` ### Verify your integration Before you design the full production workflow, confirm that your staging integration can complete this path: * Authenticate successfully and use the returned `sdp_suki_token` in follow-up requests. * Create an ambient session and store the returned `ambient_session_id` (and `composition_id` when you need note-level APIs). * Stream visit audio on **`/ws/stream`** with the required PCM format and message order. * End the session and confirm that Suki starts processing. * Retrieve note content (and optionally the transcript), or confirm your webhook receives `session_summary_generated`. After this path works end to end on staging, continue with context quality, interoperability fields, and production rollout. ## Available cookbooks
Ambient API

End Ambient After Streaming

Send RU9G, then end session.

5 min
Ambient API

Authenticate Browser WebSocket Handshake

Auth browser WebSocket with protocols.

5 min
## Available tutorials
Ambient

Build an Ambient Streaming Client

Authenticate, create a session, stream PCM audio over WebSocket, and retrieve clinical note results.

20 min Intermediate
## Next steps After you complete your first Ambient API session: [Authentication API](/api-reference/authentication/login) - Login, register, and JWKS configuration. [Context API](/api-reference/ambient-sessions/context) - Seed specialty, sections, and patient info for better note accuracy. [Audio streaming API](/api-reference/ambient-sessions/audio-stream) - WebSocket connection details and message formats. [Webhook](/api-reference/asynchronous/webhook) - Configure webhooks to receive notifications when notes are ready. # Security & Best Practices Source: https://developer.suki.ai/api-reference/security-best-practices Secure Suki integrations with HTTPS, token storage, JWT validation, webhook HMAC verification, HIPAA-aware data handling, and safe error logging This section provides best practices for securing your Suki APIs and SDKs. ## Security best practices All API requests must use **HTTPS** (TLS 1.2 or higher) to ensure data encryption in transit. Never send requests over unencrypted HTTP connections. ### Token management Following are the best practices for token management: Never expose `sdp_suki_token` in client-side code, logs, or version control. Store tokens securely on your backend server. Implement token refresh logic to automatically obtain a new `sdp_suki_token` when the current one expires. Call the `/login` endpoint with a valid partner token to refresh. When receiving `sdp_suki_token` from Suki, verify its signature using the public keys from the JWKS endpoint ([Authentication JWKS](/api-reference/authentication/jwks)) (`/api/auth/.well-known/jwks-pub.json`). Your partner token must be a standards-compliant JWT signed with RS256 (RSA Signature with SHA-256) algorithm. Ensure your JWKS endpoint is publicly accessible and properly configured. ### Webhook security Following are the best practices for webhook security: Suki signs webhook POSTs with **HMAC-SHA-256**. A **secret key** on your **partner record** is provided by Suki. Each request sends **`generated-at`** (Unix ms) and **`X-API-Key`** (hex HMAC of `generated-at`, a colon, and the raw JSON body). Verify before you process the body. For the exact steps, refer to [Notification webhook for Partners](/documentation/webhook/signature-verification) for more details. Your webhook callback URL must use HTTPS protocol. Never use HTTP endpoints for webhooks. Always validate the webhook payload structure and verify the HMAC signature before processing notifications. ### Data protection Following are the best practices for data protection: All data transmitted to and from Suki is encrypted using TLS 1.2. Ensure your application maintains encryption standards for data at rest. Ensure your integration complies with HIPAA requirements. Obtain patient consent before sending personal data to the platform. Only send the minimum required data for each API call. Avoid including unnecessary patient or provider information. ### Error handling Following are the best practices for error handling: If you receive a `401 Unauthorized` or `403 Forbidden` response, verify your `sdp_suki_token` is valid and not expired. Re-authenticate if necessary. For transient errors (5xx status codes), implement exponential backoff retry logic. Do not retry on 4xx client errors. When logging API errors, never include tokens, passwords, or sensitive patient data in logs. For more details on security and compliance, see the [Security FAQs](/documentation/references/faqs/security). # Send Notifications API Source: https://developer.suki.ai/api-reference/send-notifications Receive asynchronous notifications from Suki using your notification endpoint The Notifications API enable partners to receive asynchronous webhook notifications when ambient session processing completes or fails. You expose an HTTPS URL that accepts inbound requests. Suki calls that URL with a signed payload so your backend can pull results or update job state without relying only on polling. Critically, your notification endpoint is called by Suki. Register and configure the webhook in your partner setup, then verify signatures before you trust the payload. ## Available endpoints Review the webhook contract for ambient session notifications ## Related guides Learn how Partner webhooks deliver asynchronous session updates Verify webhook signatures before you process the payload Configure your notification URL and partner webhook settings ## Common use cases Receive webhook notifications when ambient processing finishes so your backend can retrieve content and update job state without polling. React to failure and timeout notifications so clinicians and operations see accurate visit status. Verify webhook signatures before trusting payloads that change session or job state in your system. Use payload links to retrieve status or clinical content for the ambient session that just completed. # Single Auth Token Authentication Source: https://developer.suki.ai/api-reference/single-auth-token-authentication Learn how Single Auth Token authentication works, when to send provider_id and sdp_provider_id, and how to call Login, Register, and Partner APIs Some partners use a single shared `partner_token` for all clinicians instead of generating a unique token for each user through their identity provider. Suki refers to this authentication model as **Single Auth Token authentication**. In this model, your backend authenticates every request using the same `partner_token`. Because the token identifies your organization rather than an individual clinician, you **must provide the clinician's identity separately**. With Single Auth Token authentication, include the clinician identifier on every request: * Pass `provider_id` in the request body when calling [Register](/api-reference/authentication/register) and [Login](/api-reference/authentication/login). * Pass `sdp_provider_id` as an HTTP header on every subsequent REST API request and WebSocket connection. **Important** * Single Auth Token authentication **is different** from Bearer partner authentication. * A partner can use either Bearer partner authentication or Single Auth Token authentication, but not both. * Suki assigns your authentication model during onboarding. If you are unsure which authentication model your organization uses, contact your Suki partnership team. ## Prerequisites Before you implement Single Auth Token authentication, confirm the following: * **Single Auth Token configuration:** Your Suki partnership team confirms that your organization uses Single Auth Token authentication. * **Stable clinician identifiers:** Choose a stable `provider_id` for each clinician and use the same value on every Register, Login, and later API request. * **HTTPS required:** Send [Login](/api-reference/authentication/login) and [Register](/api-reference/authentication/register) as HTTPS POST requests with a JSON body. Do not send credentials in query parameters. ## How this authentication model differs Single Auth Token partners authenticate the same way as other partners by sending `partner_token`, but clinician identity is not derived from that token. You provide the clinician identity separately through `provider_id` and `sdp_provider_id`. | Topic | Standard authentication | Single Auth Token authentication | | :----------------------------------- | :------------------------------------- | :----------------------------------------------------------------------------------------- | | Clinician identity | Derived from `partner_token` | Passed as `provider_id` on Register and Login, and as `sdp_provider_id` on later API calls | | `partner_token` | Per-user ID token or user-scoped token | One shared `partner_token` for multiple clinicians | | `provider_id` on Register and Login | Optional and ignored | **Required** | | `sdp_provider_id` on later API calls | Not required for standard partners | **Required** on every REST API request and WebSocket connection | ### Single Auth Token authentication behavior * Register and Login identify the clinician using `provider_id` because the shared `partner_token` identifies your organization, not the clinician. * After Login, send `sdp_provider_id` on every subsequent REST API request and WebSocket connection. The token authorizes your organization. `sdp_provider_id` tells Suki which clinician is acting. * Use the same stable `provider_id` for a clinician on Register, Login, and later `sdp_provider_id` headers. * A partner can use either Bearer partner authentication or Single Auth Token authentication, but not both. ## Typical flow **Register** each clinician once with [Register](/api-reference/authentication/register). Use a stable **`provider_id`** for that person. **Login** with [Login](/api-reference/authentication/login). Send your `partner_id`, shared `partner_token`, and the active clinician's **`provider_id`**. **Call Suki APIs** with the **`sdp_suki_token`** returned from Login. Include the **`sdp_provider_id`** header on every REST and WebSocket request. **Refresh** the token before it expires (**1 hour**). Call Login again with the same `partner_token` and `provider_id`. ## Send sdp\_provider\_id with all API requests When you use Single Auth Token authentication, include the `sdp_provider_id` header on **every** Suki API request after Login. * **Register and Login:** Send the clinician's `provider_id` in the request body so Suki can register or authenticate them. * **All other APIs:** After Login, send `sdp_provider_id` on every REST and WebSocket request along with `sdp_suki_token`. Suki uses it to route the request to the correct clinician. Register each provider with a stable `provider_id` before their first Login. If Login fails because the provider is not registered, call Register, then call Login again. ## Login and Register request fields Single Auth Token partners use the same Login and Register endpoints as standard partners. You must include `provider_id` on every Login and Register call. ### Login **Endpoint:** [Login](/api-reference/authentication/login) **Method:** POST | Field | Single Auth Token partners | | :-------------- | :---------------------------------------------------------------------------------------- | | `partner_id` | Required. Partner ID from Suki. | | `partner_token` | Required. Shared `partner_token` your integration uses for authentication. | | `provider_id` | Required. Stable identifier for the provider in your system. | #### Example request ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl -X POST https://sdp.suki-stage.com/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "partner_id": "your-partner-id", "partner_token": "your-shared-partner-token", "provider_id": "provider-123" }' ``` On success, the API returns `suki_token`. Use it as the `sdp_suki_token` header on later API calls. Also send `sdp_provider_id` with the same clinician identifier on every request. The token is valid for **1 hour**. To refresh it, call Login again with the same `partner_token` and `provider_id`. ### Register Register a provider once before their first Login. Refer to [Provider authentication](/api-reference/provider-authentication#registration-scenarios) for new user, existing user, and conflict responses. **Endpoint:** [Register](/api-reference/authentication/register) **Method:** POST | Field | Single Auth Token partners | | :------------------- | :--------------------------------------------------------------------------------------------------------------------------- | | `partner_id` | Required. Partner ID from Suki. | | `partner_token` | Required. Shared `partner_token` your integration uses for authentication. | | `provider_id` | Required. Stable identifier for the provider in your system. Use this as the user identifier at registration. | | `provider_name` | Required. Display name for the provider. | | `provider_org_id` | Required. Organization the provider belongs to. | | `provider_specialty` | Optional. Defaults to `FAMILY_MEDICINE` if omitted. | #### Example request ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} curl -X POST https://sdp.suki-stage.com/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "partner_id": "your-partner-id", "partner_token": "your-shared-partner-token", "provider_id": "provider-123", "provider_name": "Dr. Jane Smith", "provider_org_id": "org-123" }' ``` For all Register fields and response codes, refer to the [Register API reference](/api-reference/authentication/register). # User Feedback API Source: https://developer.suki.ai/api-reference/user-feedback Submit feedback on Ambient session entities such as transcripts or generated content The User Feedback API enable partners to submit structured feedback tied to an ambient session and a specific entity, such as a transcript or generated content. Suki uses that feedback to track quality issues, regressions, or clinician-reported problems against concrete artifacts. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, feedback must reference a valid ambient session entity. It is separate from Form filling feedback endpoints. ## Available endpoints Submit feedback for an ambient session entity ## Common use cases Capture clinician feedback against the specific ambient session artifact when generated content is wrong or incomplete. Send thumbs-down or issue reports from your review screen so support can investigate the right transcript or note section. # User Preferences API Source: https://developer.suki.ai/api-reference/user-preferences Read and update end-user preferences for the Suki platform The User Preferences APIs enable partners to read and update preferences for the authenticated provider so your client stays aligned with Suki user-scoped settings. Typical preferences include language, layout, or other defaults exposed by the API for that user. These APIs are called from your servers and authenticated with a Suki Token (`sdp_suki_token`). Critically, preferences are scoped to the authenticated provider. They do not replace organization-level Partner configuration. ## Available endpoints Read or update preferences for the authenticated provider ## Related guides Set up Partner Tokens before you call authenticated Partner APIs See how authenticated ambient workflows fit into clinical documentation ## Common use cases Save verbosity and section format preferences so future ambient notes match how each clinician documents. Let clinicians change documentation preferences in your UI so later ambient sessions pick up those settings automatically. # User Preferences Source: https://developer.suki.ai/api-reference/user-preferences/preferences PATCH /api/v1/user/preferences Update user personalization preferences for clinical note generation Use this endpoint to update and save a user's personalization preferences. These settings are saved at the user level, not per session, and will be applied to all of the user's future interactions. For details, see [Personalization](/api-reference/capabilities/personalization). Section format preferences use LOINC codes to identify note sections. This is a `PATCH` request, you only need to send the fields you want to change. For the best results, we recommend that you call this endpoint before the **main interaction begins** (for example, before audio streaming starts or before you call the `/end` endpoint). This ensures the user's preferences are applied before content is generated. However, you can call this endpoint at any time to update the settings. ## Code examples **Language tabs (agents):** Equivalent code samples are available in: Python, TypeScript. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import requests url = "https://sdp.suki-stage.com/api/v1/user/preferences" headers = { "sdp_suki_token": "", "sdp_provider_id": "", "Content-Type": "application/json" } payload = { "personalization_preference": { "verbosity": "CONCISE", # Options: CONCISE, BALANCED, DETAILED "section_format": [ { "loinc": "10164-2", "style": "NARRATIVE" # Options: NARRATIVE, BULLETED } ] } } response = requests.patch(url, json=payload, headers=headers) if response.status_code == 200: data = response.json() print("Preferences updated successfully") print(f"Updated preferences: {data}") else: print(f"Failed to update preferences: {response.status_code}") print(response.json()) ``` ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} const response = await fetch('https://sdp.suki-stage.com/api/v1/user/preferences', { method: 'PATCH', headers: { 'sdp_suki_token': '', 'sdp_provider_id': '', 'Content-Type': 'application/json' }, body: JSON.stringify({ personalization_preference: { verbosity: 'CONCISE', // Options: CONCISE, BALANCED, DETAILED section_format: [ { loinc: '10164-2', style: 'NARRATIVE' // Options: NARRATIVE, BULLETED } ] } }) }); if (response.ok) { const data = await response.json(); console.log('Preferences updated successfully'); console.log('Updated preferences:', data); } else { const error = await response.json(); console.error(`Failed to update preferences: ${response.status}`, error); } ``` # Dictation SDK Changelog Source: https://developer.suki.ai/dictation-sdk/changelog Dictation SDK product updates and announcements Suki's Dictation SDK versioning policy is based on the semantic versioning standard. For example, in version 1.2.3, 1 is the major version, 2 is the minor version, and 3 is the patch version. When we release a new Dictation SDK version for new features or bug fixes, we increment one of these three version components depending on the type of change introduced. ### New features * **Initial beta release**: First release of the Suki Dictation SDK. Build custom speech-to-text integrations with complete control over your user interface. Currently in **beta** stage for you to try out and provide feedback. # General Source: https://developer.suki.ai/dictation-sdk/faqs/general General questions about the Suki Dictation SDK The Suki Dictation SDK is a JavaScript and React library for Dictation in the browser. It lets you add speech-to-text to your web application using Suki's hosted Dictation experience, authentication helpers, and callbacks. Read the [Dictation SDK Overview](/dictation-sdk/introduction) for supported packages, In-field and Scratchpad modes, and how a typical session flows. You can build Dictation in two ways: * **In-field:** Dictation overlays a target field. This pattern fits notes, forms, and similar workflows. * **Scratchpad:** Dictation uses a floating panel that is not tied to a single input. Read [In-field mode](/dictation-sdk/guides/in-field-mode) and [Scratchpad mode](/dictation-sdk/guides/scratchpad-mode). The [Introduction](/dictation-sdk/introduction) page also summarizes both. **Dictation SDK:** Your app embeds Dictation in the browser. The SDK handles platform authentication with **`SukiAuthManager`**, the iframe lifecycle, and callbacks such as **`onSubmit`**. **Dictation APIs:** You call Suki's REST and WebSocket Dictation APIs from your own code without using this iframe SDK. That path is documented under [Audio Dictation](/documentation/concepts/dictation/dictation) and the [Dictation API](/api-reference/ambient-dictation) reference. The [Introduction](/dictation-sdk/introduction) page includes a short note that compares the two approaches. Every setup uses **`@suki-sdk/core`** for **`SukiAuthManager`**. You then add one Dictation package: * **JavaScript (vanilla or non-React frameworks):** **`@suki-sdk/dictation`** plus **`@suki-sdk/core`**. * **React:** **`@suki-sdk/dictation-react`** plus **`@suki-sdk/core`**. You still import **`DictationClient`** from **`@suki-sdk/dictation`** in examples when you construct the client in code. Copy-paste install commands are in [Installation](/dictation-sdk/installation). Package names also appear on the [Introduction](/dictation-sdk/introduction) page. No. The product is meant for **browser** embedding. Your page needs a real **`HTMLIFrameElement`**, **`postMessage`**, and layout so the hosted UI can mount and size correctly. **Not supported:** Using Node.js as the runtime that hosts **`DictationClient`** or the Dictation iframe, or relying on **SSR alone** to render Dictation instead of initializing on the client after the DOM (and your container, when you use one) exists. Read the runtime section in [Error handling](/dictation-sdk/guides/error-handling) and [Prerequisites](/dictation-sdk/prerequisites). # Integration Source: https://developer.suki.ai/dictation-sdk/faqs/integration Integration questions about the Suki Dictation SDK **JavaScript:** Use **`DictationClient`** from **`@suki-sdk/dictation`** and call **`await dictationClient.show({ ... })`** when the user should dictate. Walk through [Dictation SDK JavaScript integration](/dictation-sdk/javaScript-integration/javaScript). **React:** Use **`DictationProvider`** and **`Dictation`** from **`@suki-sdk/dictation-react`**, with the same **`DictationClient`** instance passed into the provider. Walk through [Dictation SDK React integration](/dictation-sdk/react-integration/react). Pick the guide that matches your stack. The [Quickstart](/dictation-sdk/quickstart) shows both patterns in one place if you want a shorter comparison. The documentation treats **`SukiAuthManager`** and **`DictationClient`** as **long-lived** for a page or session. If you create a new **`DictationClient`** on every render or for every textarea, the iframe and session tend to tear down and start again, which feels unstable. That guidance is spelled out in the [Quickstart](/dictation-sdk/quickstart) (recommended integration pattern) and in the best-practices sections of the [JavaScript](/dictation-sdk/javaScript-integration/javaScript) and [React](/dictation-sdk/react-integration/react) integration guides. Call **`show()`** again with the next field's options. A new **`show()`** call **replaces** the active session. You do **not** need to call **`hide()`** manually just to move from one field to another for that pattern. See [JavaScript integration](/dictation-sdk/javaScript-integration/javaScript) and [Configuration](/dictation-sdk/guides/configuration) for examples and option details. Keep a **single** **`client`** and **`DictationProvider`**. Use state (for example **`activeFieldId`** or a boolean) so **only one** **`Dictation`** is mounted at a time, or change **`fieldId`** / **`initialText`** when you remount. You do **not** need to call **`hide()`** yourself for that kind of switch. Full pattern: [React integration](/dictation-sdk/react-integration/react). When **`Dictation`** unmounts, the SDK **automatically** calls **`hide()`**. For normal React flows you do **not** call **`hide()`** yourself. Details: [React integration](/dictation-sdk/react-integration/react). # Technical Source: https://developer.suki.ai/dictation-sdk/faqs/technical Technical questions about the Suki Dictation SDK **Required** * **`partnerId`**. * **`partnerToken`**. **Optional** (when your integration needs them) * **`environment`** (for example **`"staging"`** or **`"production"`**). * **`autoRegister`**. * **`loginOnInitialize`**. Field descriptions and **AuthConfig** details are in [Configuration](/dictation-sdk/guides/configuration) and [Authentication](/dictation-sdk/guides/authentication). Invalid **`partnerId`** or **`partnerToken`** block iframe initialization, as noted on those pages and in [Prerequisites](/dictation-sdk/prerequisites). **`fieldId`** is a **stable, unique** string that names one Dictation session. Every callback returns it together with **`text`** so you know which field the result belongs to. It does **not** have to match a DOM **`id`**, but using the same string as your input's **`id`** is a simple pattern. Naming examples and guidance: [Configuration](/dictation-sdk/guides/configuration) (Field IDs in practice) and [Callbacks](/dictation-sdk/guides/callbacks). **`onSubmit`** runs when the user **commits** the transcript. If you omit it, Dictation often **closes immediately** after the user acts, so production integrations should always implement it. Read [Configuration](/dictation-sdk/guides/configuration) and [Callbacks](/dictation-sdk/guides/callbacks) for the full callback contract. **`rootElement`** is the **DOM node** where the SDK mounts the Dictation iframe. The iframe **sizes to that container**, so the node should have real width and height. **Layout:** Wrapper markup and CSS patterns are described under **Wrapper layout** on the [Configuration](/dictation-sdk/guides/configuration) page. [In-field mode](/dictation-sdk/guides/in-field-mode) and [Error handling](/dictation-sdk/guides/error-handling) cover related layout issues. **React:** Some examples omit **`rootElement`**; the [React integration](/dictation-sdk/react-integration/react) guide explains when the minimal pattern skips it and when to pass it (including refs in real apps). [Configuration examples](/dictation-sdk/guides/examples/configuration-examples) includes sample wiring. Work through checks in this order: 1. **Runtime:** Browser-only use, correct timing (call after the DOM and container exist and have size). 2. **Layout:** **`rootElement`** (when used), height, and CSS. 3. **Auth and CSP:** Valid partner credentials and any CSP rules that affect iframes. 4. **Configuration and callbacks:** **AuthConfig**, **ShowOptions**, and a working **`onSubmit`**. That order is documented on [Error handling](/dictation-sdk/guides/error-handling). Use [Configuration](/dictation-sdk/guides/configuration) for every option field. # Dictation SDK Architecture Source: https://developer.suki.ai/dictation-sdk/guides/architecture Learn how your application, the Dictation SDK, sign-in, and Suki-hosted Dictation fit together
Quick summary
Learn about the architecture of the Suki Dictation SDK and how your application, the Dictation SDK, sign-in, and Suki-hosted Dictation fit together.
Last updated: August 2026
This guide explains the responsibilities for embedding Dictation in your application. You maintain control of your user interface and determine when you turn Dictation on or off. The Suki Dictation SDK hosts the microphone experience and transcription to ensure a consistent look and behavior across every integration. ## Architecture of the Suki Dictation SDK The Suki Dictation SDK has four main components: * Your application. * The Suki Auth Manager. * The Dictation SDK. * The Suki hosted Dictation iframe. The following diagram illustrates the architecture of the Suki Dictation SDK and how each component fits together: Diagram: your web application contains application code, Dictation SDK, and layout with callbacks; Suki provides sign-in and hosted Dictation; arrows show authenticate and tokens, hosted Dictation session, and transcript back to your app. Diagram: your web application contains application code, Dictation SDK, and layout with callbacks; Suki provides sign-in and hosted Dictation; arrows show authenticate and tokens, hosted Dictation session, and transcript back to your app. Your app never has to build the Dictation screen itself. The SDK opens that experience in the place you choose and passes results back to your code. ### What each layer does | Layer | What it does | | :------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Your application** | You decide when Dictation should appear, where it mounts on the page, and what to do with text when the user is done (and optional live updates if you use them). | | **Dictation SDK** | The client you install talks to Suki, shows or hides the hosted Dictation experience, and wires your callbacks so you receive transcripts. | | **Sign-in** | You configure this once with your partner details. It checks your setup, signs in with Suki, refreshes access when needed, and gives the hosted experience what it needs to run securely. | | **Hosted Dictation** | The Dictation UI users speak into lives on Suki's side. It stays separate from your page's styles and layout so the experience stays consistent.

The iframe is isolated from host CSS and DOM to ensure consistent rendering across integrations. | If you need step-by-step setup, start with [Authentication](./authentication), then the [Quickstart](../quickstart). ## Lifecycle of a Dictation session Diagram: four steps from configure SukiAuthManager, create DictationClient, open Dictation, to close Dictation. Diagram: four steps from configure SukiAuthManager, create DictationClient, open Dictation, to close Dictation. Create and configure [SukiAuthManager](/dictation-sdk/guides/authentication#use-sukiauthmanager-for-authentication) with your partner credentials. Sign-in may run when you initialize, depending on your settings. Create [DictationClient](/dictation-sdk/javaScript-integration/javaScript), or use the React provider and component, tied to that auth. When the user should dictate, **open** Dictation (in-field or scratchpad). A session is active while they work. When they finish or you no longer need Dictation, **close** it. In React, unmounting the Dictation UI usually closes the session for you. For full implementation details for these APIs, refer to [JavaScript integration](../javaScript-integration/javaScript) for JavaScript, and [React integration](../react-integration/react) for React. ## Next steps Refer to the [Callbacks guide](/dictation-sdk/guides/callbacks) for more details on how to use the callbacks. # Dictation SDK Authentication Source: https://developer.suki.ai/dictation-sdk/guides/authentication Sign in to Suki before Dictation opens: use SukiAuthManager with the Partner ID and Partner Token Suki gives you The Dictation SDK uses a helper called **`SukiAuthManager`** from the **`@suki-sdk/core`** package. You give it the **`partnerId`** and **`partnerToken`** Suki assigned to your app. You create this helper **once**, then hand it to **`DictationClient`** in JavaScript or to **`DictationProvider`** in React. After sign-in works, Suki can show the Dictation experience (the screen users talk to) inside your page. The helper also renews access when it expires. If the ID or token is wrong, or sign-in never finishes, that Dictation screen will not appear. ## Prerequisites Before you set up **`SukiAuthManager`**, you must have: * **Partner ID** (the **`partnerId`** value): Suki gives you this when you complete [Partner onboarding](/documentation/get-started/partner-onboarding). * **Partner Token** (the **`partnerToken`** value): The access value your program uses for this SDK. Your Suki contact explains how you get it and what it looks like. ## Use SukiAuthManager for authentication Create the helper when your app already knows **`partnerId`** and **`partnerToken`** by running the following code: ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // required partnerToken: "YOUR_PARTNER_TOKEN", // required environment: "staging", // optional: "staging" or "production" (default "production") loginOnInitialize: true, // optional (default false) autoRegister: false, // optional (default false); when true, provider fields below are often required providerId: "YOUR_PROVIDER_ID", // optional; provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional; full name, often required if autoRegister is true providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional; org in your system, often required if autoRegister is true providerSpecialty: "FAMILY_MEDICINE", // optional; often required if autoRegister is true }); ``` For values you can pass as **`providerSpecialty`**, see [Specialties](/documentation/concepts/ambient-clinical-notes/specialties). ## What SukiAuthManager does * **Checks** your settings before Dictation tries to open. * **Signs in** to Suki's platform with your partner details. * **Renews access** when the SDK needs a fresh session. * **Lets** Suki's hosted Dictation UI run with the right permissions. A bad **`partnerId`** or **`partnerToken`** stops Dictation from loading. Users will not see the Dictation UI until sign-in succeeds. Refer to [AuthConfig](/dictation-sdk/guides/configuration#authconfig) section in [Configuration](/dictation-sdk/guides/configuration) guide for more details on the available options and how to use them. If **`autoRegister`** is on, you may need extra **provider metadata**. Check your package README or ask your Suki contact. ## Sign in later instead of on create You can create **`SukiAuthManager`** first and call **`login()`** when your app is ready, instead of **`loginOnInitialize: true`**. Use whatever pattern your installed SDK version supports. ## Next steps Refer to [Quickstart](/dictation-sdk/quickstart) guide to get started with the Dictation SDK. # Callbacks Source: https://developer.suki.ai/dictation-sdk/guides/callbacks Wire `onSubmit`, `onCancel`, and `onDraft` callbacks in JavaScript or React, including payload shape, `fieldId` routing, and when each handler fires
Quick summary
The Suki Dictation SDK supports three callbacks: `onSubmit`, `onCancel`, and `onDraft`. These callbacks are called when the user commits, cancels, or drafts the Dictation respectively. You can use these callbacks to handle the Dictation result, cancel the session, or receive intermediate updates while the user is dictating.
Last updated: August 2026
**Callbacks** allow your application to run your own code when the user commits, cancels, or moves on without committing during Dictation. You supply functions; the Suki Dictation SDK calls them when those events occur. You do **not** poll on a timer or in a loop for new text. **Registering callbacks** When you start a session, register them in **JavaScript** as properties on the object you pass to `DictationClient.show()`, or in **React** as props on ``. **Callback execution** It calls **`onSubmit`** after the user commits, and **`onCancel`** if they leave without committing. If you supply **`onDraft`**, the SDK may call it when the user does **not** submit and switches to another field (or otherwise moves on without committing). **`onDraft`** is **not** invoked on every live transcript change while Dictation stays on one field. The SDK does **not** persist draft text to your systems; only your **`onDraft`** handler decides whether to store or send it to your partner backend. **Payload** Every callback receives the same argument: one object, `{ fieldId, text }`. The `fieldId` value is whatever you passed into `show()` or ``. A common pattern is to set it to the **same value as the target control's `id`**, so `onSubmit` can use `document.getElementById(fieldId)` and write `text` into that element. ## Supported callbacks Dictation SDK supports the following callbacks: Runs when the user commits the Dictation result. **Optional**: Runs when the user discards the session without committing. **Optional**. May run when the user leaves Dictation **without** submitting and switches context (for example, to another field). Use it if you want to capture unstaged transcript text; the SDK does not save or forward it unless you do. **Mode** controls how Dictation is shown. Set it to **`in-field`** when the UI is tied to a container on your page, or **`scratchpad`** for a standalone Dictation UI. Refer to [In-field mode](/dictation-sdk/guides/in-field-mode) and [Scratchpad mode](/dictation-sdk/guides/scratchpad-mode) guides for behavior and layout. For every other option you pass to `DictationClient.show()` or to `` as props, including **`rootElement`**, **`initialText`**, and these callbacks, use the [Configuration](/dictation-sdk/guides/configuration) reference. ## Callback contract payload shape All callbacks receive a **single** argument: an object with these fields: This is the string you invent to name this Dictation session. The SDK includes it in every callback so you know which field the `text` is for. Using the same text as your input’s `id` (for example `clinical-notes`) is a simple way to tie them together. The transcript string for this callback (committed result, state at cancel, or interim draft, depending on which handler ran). **Example:** ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} // After the user commits, your onSubmit might receive: { fieldId: "clinical-notes", text: "The user said hello.", } ``` For structured notes, use **stable**, **unique** ids per section, for example **`soap.subjective`**, **`soap.objective`**, **`soap.assessment`**, **`soap.plan`**, or **`scratchpad`** for a floating session. See [Field IDs](/dictation-sdk/guides/configuration#field-ids-in-practice). If **`onSubmit`** is missing, Dictation often **closes immediately** after the user acts. Always implement `onSubmit`. ## Code examples Use callbacks as properties on the object you pass to **`await dictationClient.show({ ... })`**. They sit alongside `mode`, `fieldId`, `rootElement`, `initialText`, and other options from [Configuration](/dictation-sdk/guides/configuration). The iframe **resizes to the container** you pass as `rootElement` when you use `in-field` mode. ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; import { DictationClient } from "@suki-sdk/dictation"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // Required partnerToken: "YOUR_PARTNER_TOKEN", // Required environment: "staging", // Optional loginOnInitialize: true, autoRegister: false, // Optional - default is false providerId: "YOUR_PROVIDER_ID", // Optional - required if autoRegister is true providerName: "YOUR_PROVIDER_NAME", // Optional - required if autoRegister is true providerOrgId: "YOUR_PROVIDER_ORG_ID", // Optional - required if autoRegister is true providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // Optional - required if autoRegister is true }); const dictationClient = new DictationClient({ authManager }); // Example markup for in-field: //
// await dictationClient.show({ mode: "in-field", fieldId: "clinical-notes", // same string as id="clinical-notes" on your textarea rootElement: document.getElementById("clinical-notes-dictation-root"), initialText: document.getElementById("clinical-notes")?.value ?? "", onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId, text }) => { // Optional: user cancelled without committing }, onDraft: ({ fieldId, text }) => { // Optional: e.g. user switched fields without submit; persist draft in your app if needed }, }); ``` Calling **`show()`** again **replaces** the active session; you do not need to call **`hide()`** between fields for that pattern. Wrap `show()` in `try` / `catch` if you want to log configuration or auth failures. Refer to the [Error handling](/dictation-sdk/guides/error-handling) guide for more details. For more on imperative `show()` and one client per page scope, refer to the [JavaScript integration](/dictation-sdk/javaScript-integration/javaScript) guide for more details.
Pass the same three handlers as **props** on **``**. Build **`DictationClient`** once (with `SukiAuthManager`), wrap your tree with **``**, then render `Dictation` where Dictation should be active. When `Dictation` **unmounts**, the SDK calls **`hide()`** for you. ```jsx React theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { useMemo, useState } from "react"; import { SukiAuthManager } from "@suki-sdk/core"; import { DictationClient } from "@suki-sdk/dictation"; import { DictationProvider, Dictation } from "@suki-sdk/dictation-react"; function NotesApp() { const client = useMemo(() => { const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // Required partnerToken: "YOUR_PARTNER_TOKEN", // Required environment: "staging", // Optional loginOnInitialize: true, autoRegister: false, // Optional - default is false providerId: "YOUR_PROVIDER_ID", // Optional - required if autoRegister is true providerName: "YOUR_PROVIDER_NAME", // Optional - required if autoRegister is true providerOrgId: "YOUR_PROVIDER_ORG_ID", // Optional - required if autoRegister is true providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // Optional - required if autoRegister is true }); return new DictationClient({ authManager }); }, []); const [notes, setNotes] = useState(""); // Drive from your UI: e.g. setActiveField("clinical-notes") when this field owns dictation. const [activeField, setActiveField] = useState(null); const handleSubmit = ({ fieldId, text }) => { // fieldId matches id="clinical-notes" below if you use that pattern setNotes(text); }; const handleCancel = ({ fieldId, text }) => { // Optional }; const handleDraft = ({ fieldId, text }) => { // Optional: e.g. save unstaged text when user leaves without submit }; return (
``` ```css theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} .wrapper { position: relative; height: 100%; } ``` For mode usage, you should use the `in-field` mode when Dictation is tied to a specific text field or editor, and the `scratchpad` mode when Dictation is not tied to a specific text field or editor. ```javascript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} mode: "in-field", ``` ```javascript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} mode: "scratchpad", ``` ## Next steps Refer to the [Error handling](/dictation-sdk/guides/error-handling) guide for more details on common issues and how to troubleshoot them. # Dictation SDK Error Handling Source: https://developer.suki.ai/dictation-sdk/guides/error-handling Learn to fix common Dictation SDK issues: auth, CSP, layout, missing callbacks, and client-only runtime requirements The Dictation SDK does not always return a single error code for every failure. A successful integration depends on several components working together, including **authentication**, the **hosted iframe**, the **`rootElement`** you provide, and your **application callbacks**. When one of these components is misconfigured, you may see symptoms such as **the UI not rendering**, the **dictation window closing immediately**, or **layout issues** instead of a specific error. To troubleshoot efficiently, work through this guide in the following order: 1. **Runtime** (browser compatibility and initialization timing). 2. **Layout** (**`rootElement`** and CSS). 3. **Authentication and Content Security Policy (CSP)**. 4. **Configuration and callbacks**. This sequence helps isolate the most common integration issues first. For detailed information about every **`AuthConfig`** and **`ShowOptions`** property, see [Configuration](/dictation-sdk/guides/configuration). The **wrapper** pattern for **`rootElement`** (stable height, **`position: relative`**) is documented on [Configuration guide wrapper layout](/dictation-sdk/guides/configuration#wrapper-layout). Refer to that page if you are not sure how to structure your DOM. ## Runtime requirements The Dictation SDK is built for **in-browser** embedding. It is **not** a Node-only or server-rendered iframe product. Browser environments where you can create an `HTMLIFrameElement`, use `postMessage`, and measure a DOM container Using Node.js as the environment that hosts `DictationClient` or the Dictation iframe Relying on **SSR** alone to render Dictation; initialize and call `show()` on the client after the document (and your `rootElement`) exist * A real `HTMLIFrameElement` (the SDK creates and manages it inside your container). * `postMessage` between your page and the hosted UI. * Layout information so the iframe can size to `rootElement`. Dictation runs in the **browser** only. The iframe is not created during **SSR** or on the server. Call **`show()`** only after **`rootElement`** points at an element that **already exists** in the DOM and has been laid out (so it has a real size). If you call too early, **`rootElement`** may be **`null`** or zero height. * [React integration](/dictation-sdk/react-integration/react) for **`DictationProvider`** and **`Dictation`**. * [Configuration examples](/dictation-sdk/guides/examples/configuration-examples) for sample **`rootElement`** wiring. ## Layout and root element related issues The iframe **fills the layout box** of the element you pass as **`rootElement`**. Common mistakes are as follows: * A **zero-height** parent. * A flex or grid child that **shrinks to zero**. * **`overflow: hidden`** on a parent that clips the overlay. ### Recommended approach * Use a dedicated **wrapper** around the Dictation region, not the raw **` ``` The wrapper and textarea can be structured however your layout needs; the important part is that **`rootElement`** points at the **element that should host the iframe**, not at the textarea node. | Do this | So that | | :------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------- | | Give the host element a **visible height and width** | The iframe fills its parent. A parent with no height often produces a blank area where Dictation should be. | | Set **`position: relative`** on the host when you use overlays or stacking | The Dictation layer stays aligned with the field region in typical layouts. | Refer to [Configuration](/dictation-sdk/guides/configuration) for every `ShowOptions` field and matching React props. ### Field ID `fieldId` is a **string you invent** to name this Dictation session. Every callback sends it back with `text`, so you know **which field** the result belongs to if you have several on the page. It does not have to match a DOM `id`, but using the same value as your input's `id` is a simple pattern. Each open Dictation instance should use a **stable**, **unique** `fieldId`. Examples for SOAP-style sections: **`soap.subjective`**, **`soap.objective`**, **`soap.assessment`**, **`soap.plan`**. Refer to [Callback contract payload shape](/dictation-sdk/guides/callbacks#callback-contract-payload-shape) for more details. ## How to use in-field mode **You** build how users **start** Dictation: a **Dictation** button, a link, an icon, or any control that calls `show()` or mounts ``. After they start, **Suki** draws the Dictation UI inside the iframe: **microphone**, **submit**, **cancel**, and the rest. You do not rebuild those controls yourself. You receive text and events through **`onSubmit`**, **`onCancel`**, and optionally **`onDraft`**. ## Quick reference | Item | In-field behavior | | :--------------- | :------------------------------------------------------------------------ | | **Layout** | Dictation sits over the **input container** you target with `rootElement` | | **Mode** | `"in-field"` | | **Root element** | Recommended: element that wraps the field | ## Available cookbooks
## Available tutorials
## Next steps Refer to [Scratchpad mode](/dictation-sdk/guides/scratchpad-mode) for floating Dictation off a single field. # Scratchpad Mode Source: https://developer.suki.ai/dictation-sdk/guides/scratchpad-mode Run Dictation in a floating scratchpad panel instead of a single field: when to choose it, `mode` setup, layout, and callback handling
Quick summary
Scratchpad mode opens Dictation in a floating UI that is not tied to a single text field. You choose how users open it, and you still receive committed (and optional draft) text through callbacks.
Last updated: August 2026
**Scratchpad mode** allows you to run the Suki Dictation SDK in a standalone area of your web application. Dictation does not attach to one specific input the way [In-field mode](/dictation-sdk/guides/in-field-mode) does. **Launching Dictation** The entry point is entirely part of your UI. You can use a toolbar action, header button, floating launcher, menu item, keyboard shortcut, or any pattern you prefer. To launch scratchpad Dictation, your code must call `show()` with **mode: "scratchpad"** in **JavaScript** or mount the **Dictation** component in **React** with **mode: "scratchpad"**. **Managing the Dictation interface** Once the session is open, the Suki Dictation SDK provides the Dictation UI. This includes the **microphone**, **Close**, **copy-to-clipboard**, and related controls. The interface appears as a hosted iframe in the layout you configure. Keep the following requirements in mind to ensure the interface displays correctly: * **Layout**: You control where the scratchpad appears (for example, a floating panel anchored to a launcher). * **Mode**: You must pass **scratchpad** in `show()` or on `` so the SDK uses the floating UI. * **Data handling**: You receive transcript text through defined callbacks. The diagram below is a **clinical-style form** (for example, SOAP note sections) with a **floating Open dictation** launcher in the corner. After the user opens it, the **scratchpad** appears **above** that launcher as a tall panel on the right, with the transcript area and **Mic**, **Close**, and **Copy**. You can place the launcher anywhere in your application that fits your design. Your real layout might use a portal, column, or different spacing. These screens are only examples.
New SOAP Note interface with Subjective, Objective, and Assessment sections and a patient sidebar; floating Suki Dictate button in the bottom-right corner with an arrow and label reading Floating Scratchpad for Dictation.
## When to choose scratchpad mode Use **scratchpad mode** when: * Dictation should live in its **own** area (side panel, overlay region, or similar), not overlaid on one field’s container. * Users need to **capture speech first** and then paste or apply text elsewhere, or you want **quick dictation** without binding the session to a single `textarea`. When Dictation should stay tied to **one** text field and your **Dictate** control sits with that field, use [In-field mode](/dictation-sdk/guides/in-field-mode) instead. ## How to configure scratchpad mode For scratchpad Dictation you set **`mode`**, **`fieldId`**, and usually consider **`rootElement`** (and other [`ShowOptions`](/dictation-sdk/guides/configuration)) so the SDK knows **which layout to use**, **where the iframe mounts**, and **how to label the session** in callbacks. ### Mode Set `mode` to the string **`"scratchpad"`** so the SDK uses the **floating standalone** Dictation UI instead of in-field overlay. * **JavaScript:** include `mode: "scratchpad"` in the object you pass to `DictationClient.show()`. * **React:** set `mode="scratchpad"` on ``. ```javascript Mode configuration theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} mode: "scratchpad", ``` ### Root element For scratchpad, **`rootElement`** is still the DOM node where the SDK **mounts** the Dictation iframe. It is usually a **dedicated region** of your layout (panel, column, or modal body), **not** a wrapper around a single clinical line item. The hosted UI still **measures the same layout box** as in-field mode: **`rootElement`** should be an element with **real width and height** so the floating UI has room to render. If the host **collapses** (for example **zero height** in a flex or grid row, a hidden parent, or no **`min-height`**), you will usually see a **blank** or **clipped** area even though scratchpad is “floating.” When the scratchpad region **sits on top of** or **beside** other UI, set **`position: relative`** on that host (unless you already have another positioning context) so stacking and alignment stay predictable. For wrapper sizing patterns and CSS, refer to [Wrapper layout best practices](/dictation-sdk/guides/configuration#wrapper-layout) on [Configuration](/dictation-sdk/guides/configuration). ### Field ID **`fieldId`** is a **string you invent** to name this scratchpad session. Every callback sends it back with `text`, which helps if you run **multiple** scratchpads or mix scratchpad with in-field flows. It does not have to match a DOM `id`. Use a **stable**, **unique** id per scratchpad instance; a common choice is **`scratchpad`**, or a namespaced value such as **`scratchpad.draft`** if you run more than one. ## How to use scratchpad mode **You** build how users **open** scratchpad Dictation. After they start, **Suki** draws the Dictation UI in the iframe: **microphone**, **close**, **copy**, and the rest. You do not recreate those controls yourself. You receive text and events through **`onSubmit`**, **`onCancel`**, and optionally **`onDraft`**. ## Quick reference | Item | Scratchpad behavior | | :--------------- | :-------------------------------------------------------------------- | | **Layout** | **Floating** standalone Dictation UI, not tied to one input container | | **Mode** | `"scratchpad"` | | **Root element** | Host region for the iframe | ## Next steps Refer to [In-field mode](/dictation-sdk/guides/in-field-mode) when Dictation should attach to a specific field. Read [Callbacks](/dictation-sdk/guides/callbacks) for handlers and payload shape, and the [Configuration](/dictation-sdk/guides/configuration) reference for all options. # Suki Dictation SDK Source: https://developer.suki.ai/dictation-sdk/index Add In-field or Scratchpad Dictation to your web app with Suki's hosted iframe UI for JavaScript and React The Suki Dictation SDK is a JavaScript and React library that lets you add Dictation to your web application using Suki's hosted iframe UI. Instead of building the Dictation experience yourself, you embed the SDK and integrate it with your application's fields and workflows. Your application initializes the SDK, authenticates with `SukiAuthManager`, and handles transcript callbacks. The SDK provides the hosted Dictation UI, while your application controls how final transcripts update chart fields or other UI. **Are you a Suki partner?** To use any Suki API or SDK, you must be a Suki partner. Contact the partnership team to begin the onboarding process. They help you set up your authentication system and get started with the Suki APIs and SDKs. If your integration uses Suki's Web SDK, Dictation is **already included** in the Web SDK. Install the standalone Dictation packages only when you want Dictation without the rest of the Web SDK. ## Get started Confirm requirements, install the SDK, authenticate, and run your first Dictation session.

Learn how the Dictation SDK works and when to use it in your application

Confirm Partner credentials and setup requirements before you install

Install the JavaScript or React Dictation packages

Learn how `SukiAuthManager` authenticates Dictation SDK sessions

Initialize, authenticate, and start a Dictation session end to end

## Choose a Dictation mode Pick the hosted Dictation experience that fits your UI. Use In-field mode for a target input. Use Scratchpad mode for a floating Dictation panel.

Dictate directly into a target field in notes or forms

Use a floating Dictation panel that is not tied to one input

## Integrate Dictation Embed the SDK in JavaScript or React, then wire architecture, callbacks, and configuration for how transcripts return to your application.

Embed Dictation in vanilla JavaScript applications

Embed Dictation in React applications

Learn how your application, the SDK, sign-in, and hosted Dictation fit together

Handle transcripts and session events from the Dictation SDK

Configure Dictation SDK options for your application

## Resources Use these pages when you need examples, tutorials, error handling, release notes, or partner support.

Browse Dictation SDK configuration examples for common setups

Build Dictation into a chart field with the Dictation SDK

Handle Dictation SDK errors during authentication and recording

Find answers to general, integration, and technical questions

Track Dictation SDK releases, enhancements, and breaking changes

Contact Suki for partner documentation and SDK support

# Dictation SDK Installation Source: https://developer.suki.ai/dictation-sdk/installation Install Suki Dictation SDK in your JavaScript or React application We have modularized the Suki Dictation SDK into **framework-specific packages** plus shared **`@suki-sdk/core`** for **`SukiAuthManager`**, so you install **`core`** in every setup and add either **`@suki-sdk/dictation`** or **`@suki-sdk/dictation-react`** depending on your environment. The Dictation SDK is built for browser applications and requires **`HTMLIFrameElement`** and **`postMessage`** (refer to [Prerequisites](/dictation-sdk/prerequisites) guide for more details). **Already using `@suki-sdk/js` or `@suki-sdk/react`?** These packages already include the **Dictation** client. You do not need to install `@suki-sdk/dictation` or `@suki-sdk/dictation-react` separately. Import Dictation from the Web SDK package instead of installing them separately: ```javascript @suki-sdk/js theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { DictationClient } from "@suki-sdk/js"; ``` ```tsx @suki-sdk/react theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { Dictation, DictationClient, DictationProvider, useDictation } from "@suki-sdk/react"; ``` * Install a standalone Dictation package only if you want Dictation without the rest of the Web SDK. * Refer to [Web SDK installation](/web-sdk/installation) for details. ## Prerequisites For the rest of this documentation, we will assume you have completed the [Partner onboarding](/documentation/get-started/partner-onboarding) process. Refer to the [Prerequisites](/dictation-sdk/prerequisites) guide for more information. ## Install the package ### For vanilla JavaScript Use **`@suki-sdk/dictation`** with **`@suki-sdk/core`** for plain JavaScript or frameworks other than React. To install the packages, run one of the following commands: ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/core @suki-sdk/dictation ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/core @suki-sdk/dictation ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/core @suki-sdk/dictation ``` ### For React For React applications, use **`@suki-sdk/dictation-react`** with **`@suki-sdk/core`**. It includes **`DictationProvider`** and **`Dictation`** so you can wire Dictation declaratively. To install the packages, run one of the following commands: ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/core @suki-sdk/dictation-react @suki-sdk/dictation ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/core @suki-sdk/dictation-react @suki-sdk/dictation ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/core @suki-sdk/dictation-react @suki-sdk/dictation ``` ## Next steps Read the [Authentication](/dictation-sdk/guides/authentication) guide to learn how to authenticate yourself to use the Dictation SDK. # Dictation SDK Introduction Source: https://developer.suki.ai/dictation-sdk/introduction Add browser Dictation with Suki's hosted iframe via JavaScript or React packages, in-field and scratchpad modes, and `SukiAuthManager` authentication The Suki Dictation SDK is a JavaScript and React library that lets you add Dictation to your web application using Suki's hosted iframe UI. After you initialize the SDK, you can start Dictation in either **In-field** mode for direct text entry or **Scratchpad** mode for free-form dictation. If you use the **Headed Web SDK** `v3.X.X+`, Dictation capabilities are available out of the box. Refer to the [Web SDK for Audio Dictation](/web-sdk/dictation-overview) guide for more information. The Suki Dictation SDK supports two Dictation modes: **In-field** and **Scratchpad**. Use this mode for Dictation over a target field. Commonly used for notes and forms. Use this mode for a floating Dictation panel, not tied to one input. Commonly used for Dictation in a separate area of the page. When the user starts the Dictation session: 1. Recording begins automatically. 2. Transcription appears inside the text field and the scratchpad UI. 3. When the user finishes Dictation and confirms, the SDK calls the handler functions you registered and passes the final transcript into your app so you can update fields, save data, or run your own logic. The Dictation SDK is different from integrating directly with the [Dictation APIs](/api-reference/audio-transcription/create-session). The SDK manages authentication through `SukiAuthManager`, iframe lifecycle, and transcript callbacks for you. If you need a custom or server-side integration without the hosted iframe experience, use the APIs described in [Dictation basic usage](/documentation/how-to/dictation/dictation-basic-usage). ## Supported packages The Dictation SDK is available in the following packages: Use `@suki-sdk/dictation-react` for React web applications. Install the Dictation SDK for React:
Use `@suki-sdk/dictation` for vanilla JavaScript applications. Install the Dictation SDK for JavaScript:
Both require shared authentication through **`@suki-sdk/core`** (Refer to the [Dictation SDK Quickstart](/dictation-sdk/quickstart) for more information). ## When to use Dictation SDK Choose the Dictation SDK when: * You want **real-time speech-to-text** in the browser with Suki's hosted iframe experience. * You need **in-field** overlays on inputs or a **scratchpad** workflow for Dictation mechanics. * You prefer **callback-driven** commit of the transcription result over owning REST and WebSocket Dictation calls yourself. ## Common use cases The Dictation SDK provides a hosted browser experience for real-time speech-to-text, including in-field overlays and scratchpad mode. Your application owns field targeting, commit handling, and how transcripts are used in your workflow. The following examples show common ways to integrate the Dictation SDK into your web application. Use in-field mode over a note, form, or charting input, then commit the transcript when the clinician confirms. Open scratchpad mode for a floating draft area, then place the final text into your app state or target fields. Reuse one **`DictationClient`** on the page, activate it for the focused field, and handle each commit in your callbacks. Handle **`onSubmit`** and optional draft callbacks to update state, save drafts, or write text into your EHR model without owning REST and WebSocket Dictation yourself. Add the Dictation SDK on screens where clinicians need speech-to-text for targeted fields, not a full ambient note session. Mount the same in-field or scratchpad experience on virtual visit pages so remote clinicians can dictate into documentation fields. ## Recommended integration pattern Follow the below pattern to integrate the Dictation SDK into your application: ```mermaid actions={false} theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#FFE148','primaryTextColor':'#111827','lineColor':'#6B7280','fontSize':'14px','edgeLabelBackground':'#FFFFFF','tertiaryColor':'#F9FAFB','tertiaryTextColor':'#111827','tertiaryBorderColor':'#D1D5DB'}}}%% graph TB SM["SukiAuthManager
@suki-sdk/core
Once, after partner token is available"] DC["DictationClient
new DictationClient({ authManager })
One instance per page · reuse for every target"] DP["DictationProvider
@suki-sdk/dictation-react
React only · wrap your tree"] F1["In-field · field A
show() or Dictation when this field is active"] F2["In-field · field B
Same pattern · switch active field"] SP["Scratchpad
mode: scratchpad · still one client"] SM -->|auth| DC DC -.->|optional · pass same client| DP DC --> F1 DC --> F2 DC --> SP ``` ## How the Dictation SDK works The following diagram illustrates the Dictation SDK architecture and workflow: ```mermaid actions={false} theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#FFE148','primaryTextColor':'#111827','lineColor':'#6B7280','fontSize':'14px','edgeLabelBackground':'#FFFFFF','tertiaryColor':'#F9FAFB','tertiaryTextColor':'#111827','tertiaryBorderColor':'#D1D5DB'}}}%% graph TB subgraph client["Your web application"] direction TB A["Application code
React / JavaScript / Other frameworks"] B["Dictation SDK
@suki-sdk/dictation or dictation-react + core"] C["Your layout + callbacks
Container • onSubmit • optional onDraft"] A --> B B --> C end subgraph platform["Suki"] direction TB D["Authentication
SukiAuthManager"] E["Dictation iframe
Speech UI + transcription"] end B -->|Authenticate / tokens| D B -->|Hosted dictation session| E E -->|Transcript / draft to your app| C style client fill:#FFFADE,stroke:#D1D5DB,stroke-width:2px,color:#111827 style platform fill:#FFF394,stroke:#FFE148,stroke-width:2px,color:#111827 style A fill:#ffffff,stroke:#9CA3AF,stroke-width:2px,color:#111827 style B fill:#FFE148,stroke:#111827,stroke-width:3px,color:#111827 style C fill:#ffffff,stroke:#9CA3AF,stroke-width:2px,color:#111827 style D fill:#ffffff,stroke:#9CA3AF,stroke-width:2px,color:#111827 style E fill:#ffffff,stroke:#9CA3AF,stroke-width:2px,color:#111827 ``` ### Architecture workflow * **You** choose when Dictation should open and where it should appear on the page (for example over one input, or as a separate floating area). * **Your code** starts Dictation and listens for results from the SDK. When the user finishes, you receive the final text. * **Your UI** decides what to do with that text (fill a field, save a draft, discard, and so on). * **Sign-in:** Suki checks your configuration, signs in with the partner account details you provide, keeps access fresh, and hands the hosted Dictation experience what it needs to run securely. * **Hosted Dictation:** The microphone experience and transcription run in an embedded view that Suki hosts. That way the Dictation screen looks and behaves the same in every app, and it does not inherit your site’s fonts, colors, or layout. 1. Set up sign-in once using the partner details Suki gives you. 2. Add the Dictation SDK to your app and connect it to that sign-in. 3. When the user asks to dictate, open Dictation in the place you picked (over a field or as a scratchpad-style area). 4. The user speaks and confirms. Your app receives the text so you can put it where it belongs in your workflow. 5. When Dictation should stop, close it from your app so the session ends. Refer to the [Architecture guide](/dictation-sdk/guides/architecture) for more details. ## Next steps Get started by following these steps: Refer to the [Installation guide](/dictation-sdk/installation) to add the packages to your project Refer to the [Prerequisites](/dictation-sdk/prerequisites) guide to confirm browser, CSP, and layout requirements Refer to the [Quickstart](/dictation-sdk/quickstart) for JavaScript and React examples through your first `show()` call # Dictation SDK JavaScript Integration Source: https://developer.suki.ai/dictation-sdk/javaScript-integration/javaScript Integrate `@suki-sdk/dictation` in vanilla JavaScript: install packages, create `SukiAuthManager` and `DictationClient`, and open in-field or scratchpad sessions This guide shows how to integrate the Suki Dictation SDK into browser-based web applications using the JavaScript package. You'll initialize the `DictationClient`, connect it to your application's input field or editor, and start Dictation sessions from your own code. Use this approach if you're building with vanilla JavaScript, Vue, Angular, or another non-React framework, or if you need full control over when and where the Dictation interface is displayed. Let's get started! ## Prerequisites Before you begin, you must have the following requirements met: * **Packages:** Install `@suki-sdk/dictation` and `@suki-sdk/core` packages. * **Partner credentials:** Obtain `partnerId` and `partnerToken` from Suki after [Partner onboarding](/documentation/get-started/partner-onboarding). * **Browser and layout:** Your app runs in a **browser**, with a real DOM and a Dictation **container** that has height. Refer to [Prerequisites](/dictation-sdk/prerequisites) guide for more details. ## Install the packages Add both packages to the same project you load in the browser: ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/core @suki-sdk/dictation ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/core @suki-sdk/dictation ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/core @suki-sdk/dictation ``` After you install, pull the SDK into your files with **`import`**, the same way as in the examples below. Use whatever approach your project already uses for other npm libraries. ## Step 1: Add container and field HTML For this example we will assume you are using **`in-field`** mode as your preferred mode. In **`in-field`** mode you need **two** nodes in the page: a **`div`** (or similar) that you pass as **`rootElement`**, where the Dictation controls show up, and a **textarea** (or input) that **`onSubmit`** will update when the user finishes. The Dictation layer **matches the size of** **`rootElement`**, so that node should have a **height** you control. Refer to [Wrapper layout](/dictation-sdk/guides/configuration#wrapper-layout) guide for recommended markup and CSS. ```html HTML theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
``` ## Step 2: Create auth manager Now you need to create the **Auth Manager** for your application. To create the Auth Manager, you must have the `partnerId` and `partnerToken` credentials from Suki. Refer to [Partner onboarding](/documentation/get-started/partner-onboarding) guide to learn how to get these credentials. Once you have all the required credentials, create **one** auth manager for the page (or app shell). **Code example for creating auth manager** ```js JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); ``` ## Step 3: Create Dictation client After you have created the auth manager, you can create the **Dictation client** for your application. The Dictation Client is the object that will be used to start the Dictation session. Create **one** Dictation client and reuse it for every **`show()`** call on that page. **Code example for creating Dictation client** ```js JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { DictationClient } from "@suki-sdk/dictation"; const dictationClient = new DictationClient({ authManager }); ``` ## Step 4: Call show() to start Dictation Now you can start the Dictation session by calling the **`show()`** method on the Dictation client. Call **`await dictationClient.show({ ... })`** from a click handler (or similar) when the DOM is ready. Pass **`mode`**, **`fieldId`**, **`rootElement`**, **`onSubmit`**, and any optional fields you need. Refer to [Configuration](/dictation-sdk/guides/configuration) guide for more details on the available options and how to use them. **Code example for starting Dictation** ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} async function startDictation() { const root = document.getElementById("dictation-root"); const notes = document.getElementById("clinical-notes"); if (!root || !notes) { console.error("Missing dictation-root or clinical-notes in the DOM"); return; } try { await dictationClient.show({ mode: "in-field", // replace with your preferred mode - required fieldId: "clinical-notes", // often the same string as the textarea id rootElement: root, // replace with the DOM element where the dictation controls will be shown - required initialText: notes.value ?? "", // replace with the initial text for the dictation session - optional onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Dictation cancelled", fieldId); }, onDraft: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; // optional live preview while dictating }, }); } catch (err) { console.error("Dictation show() failed", err); } } document.getElementById("start-dictation")?.addEventListener("click", () => { void startDictation(); }); ``` **`onSubmit`** is required for a good user experience. If you omit it, Dictation often **closes immediately** after the user acts. ## Callbacks Every callback receives the same shape as shown in the code example below: ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { fieldId: string, text: string } ``` Refer to [Callbacks](/dictation-sdk/guides/callbacks) guide for more details on the available callbacks and how to use them. ## Switching fields Calling **`show()`** again **replaces** the active session. You do **not** need to call **`hide()`** manually just to move from one field to another: ```js JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} await dictationClient.show({ /* field A options */ }); await dictationClient.show({ /* field B options */ }); ``` ## Complete code example Below is a complete code example in JavaScript for in-field mode with a single field. ```js JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; import { DictationClient } from "@suki-sdk/dictation"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); const dictationClient = new DictationClient({ authManager }); async function startClinicalNotesDictation() { const root = document.getElementById("dictation-root"); const notes = document.getElementById("clinical-notes"); if (!root || !notes) return; try { await dictationClient.show({ mode: "in-field", fieldId: "clinical-notes", rootElement: root, initialText: notes.value ?? "", onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Cancelled", fieldId); }, }); } catch (e) { console.error(e); } } document.addEventListener("DOMContentLoaded", () => { document .getElementById("start-dictation") ?.addEventListener("click", () => void startClinicalNotesDictation()); }); ``` This page focuses on **`in-field`** Dictation next to a specific input. If you want a **floating Dictation panel** instead, set **`mode`** to **`"scratchpad"`** and follow [Scratchpad mode](/dictation-sdk/guides/scratchpad-mode) guide. ## Best practices * **Reuse one Dictation client.** Build a single **DictationClient** for the page or shell and call it again for each Dictation session. Creating a new client on every click or for every field often resets the hosted UI and feels flaky. * **Reuse one auth manager.** Create **SukiAuthManager** once and pass that same instance into the client, the same pattern as in the steps above. * **Handle when the user commits.** You must supply a submit handler so the SDK can deliver the final text. Without it, Dictation often closes right after the user tries to finish. * **Pick a clear field label.** Each session needs a stable, unique **fieldId** in callbacks. Using the same value as the target input's **id** is a simple way to know which element to update. Refer to [Field IDs](/dictation-sdk/guides/configuration#field-ids-in-practice) guide for more details. * **Open Dictation only when the host is ready.** The DOM node you use as the Dictation host should exist and have real height before you open. Otherwise the Dictation area can look blank. Refer to [Error handling](/dictation-sdk/guides/error-handling) and [In-field mode](/dictation-sdk/guides/in-field-mode) guides for more details. * **Catch failures when opening Dictation.** Wrap the open call so auth or setup errors show up in your logs instead of disappearing. * **Move to another field by opening again.** A new open call replaces the active session. You usually do not need a separate hide step when you are only switching which field is dictating. ## Next steps Refer to the following guides for more information. [Configuration](/dictation-sdk/guides/configuration) to learn about the available options and how to use them. [React integration](/dictation-sdk/react-integration/react) to learn how to integrate the Dictation SDK with React. # Dictation SDK Prerequisites Source: https://developer.suki.ai/dictation-sdk/prerequisites Browser, layout, authentication, and partner setup required before you integrate the Suki Dictation SDK This guide outlines technical requirements you need to meet before you integrate the Dictation SDK. ## Technical requirements The following is required before you integrate the Dictation SDK: ### Browser and runtime * Your app runs in a **browser**. Dictation SDK does not support **Node.js** or **SSR** for iframe rendering. * The hosted Dictation iframe is not something **SSR** alone covers; you still need **`HTMLIFrameElement`**, **`postMessage`**, and **DOM layout** on the client so the SDK can mount and size the iframe. ### Layout * Give Dictation a **container** (**`rootElement`**) with **real height** and a stable layout box. ### Authentication requirements * The Dictation SDK needs `partnerId` and `partnerToken`. Refer to [Partner onboarding](/documentation/get-started/partner-onboarding) guide to learn how to get these credentials. Invalid credentials **block iframe initialization**. ## Information you will receive from Suki After you complete [Partner onboarding](/documentation/get-started/partner-onboarding), your Suki contact will provide you with `partnerId` and `partnerToken`. ## Next steps Refer to [Quickstart](/dictation-sdk/quickstart) guide to get started with the Dictation SDK. # Dictation SDK Quickstart Source: https://developer.suki.ai/dictation-sdk/quickstart Install Dictation SDK packages, create a reusable `SukiAuthManager` and `DictationClient`, and mount your first in-field or scratchpad session This guide walks you through the steps to integrate the Dictation SDK into your application. **What will you do** 1. Install the Dictation SDK package for your framework (JavaScript or React). 2. Create a `SukiAuthManager` from `@suki-sdk/core` with your `partnerToken` and provider fields. 3. Create a `DictationClient` from `@suki-sdk/dictation` with your auth manager. 4. Mount the Dictation UI into your application using the `encounter` object. **Using an AI coding tool?** Copy the prompt below to point your agent at the Dictation skill and [Documentation MCP](/documentation/references/mcp). For every task skill, refer to [AI coding tools](/documentation/references/ai-coding-tools). Build clinical dictation with the Suki Dictation SDK. Fetch the Dictation build skill: [https://developer.suki.ai/.well-known/agent-skills/suki-dictation/SKILL.md](https://developer.suki.ai/.well-known/agent-skills/suki-dictation/SKILL.md) Connect the documentation MCP for page search: [https://developer.suki.ai/documentation/references/mcp](https://developer.suki.ai/documentation/references/mcp) ## Prerequisites Before you start, ensure you have the following: * You have received your **`partnerId`** and **`partnerToken`** from Suki. * Your app meets **browser**, **CSP**, and host requirements for the Dictation iframe. Refer to [Prerequisites](/dictation-sdk/prerequisites) for more details. ## Recommended integration pattern The Dictation SDK works best when you treat authentication and the Dictation client as **long-lived objects** for a page or session. You should only change the specific field or container receiving the Dictation. This approach ensures that token refreshes and iframe setups remain predictable while avoiding duplicate overlays. A common mistake is to build a new **`DictationClient`** on every React render (for example, in the component body without **`useMemo`**) or to use a separate client for each text field. The SDK assumes **one client per page scope**. If you do not follow this pattern, the session and iframe will frequently tear down and restart. This creates an unstable experience for the user. Initialize **once per session** and reuse: Create **`SukiAuthManager`** from **`@suki-sdk/core`** after the **partner token** is available. Create **`DictationClient`** with that **`authManager`**. **Reuse** this client **across** Dictation fields. In React, wrap components with **`DictationProvider`** from **`@suki-sdk/dictation-react`**. Show the Dictation UI **per field** or **scratchpad**. Avoid recreating **`DictationClient`** on every render or **per field**. The **JavaScript** and **React** tabs in **Create Your First Dictation Session** below mirror this pattern: one auth manager, one client, then **`show()`** or **``** for the active target only. ## Field IDs Each Dictation instance needs a **stable**, **unique** **`fieldId`**. The SDK sends it back on every callback with **`text`**, so you can route results to the right control. A common pattern is to match the target input's HTML **`id`**. Refer to [Field IDs](/dictation-sdk/guides/configuration#field-ids-in-practice) section in [Configuration](/dictation-sdk/guides/configuration) guide for more details. ## Create your first Dictation session Install the Dictation package for your framework, plus `@suki-sdk/core` for authentication. **Language tabs (agents):** Equivalent code samples are available in: JavaScript, React. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/dictation @suki-sdk/core ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/dictation @suki-sdk/core ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/dictation @suki-sdk/core ``` More detail: [Installation](/dictation-sdk/installation). ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/dictation-react @suki-sdk/core ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/dictation-react @suki-sdk/core ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/dictation-react @suki-sdk/core ``` More detail: [Installation](/dictation-sdk/installation). For **JavaScript**, give Dictation a **container** (**`rootElement`**) with real height. Example markup: ```html theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
``` In React, mount **``** next to the target field. The component manages the hosted UI container for you.
Apply **Recommended integration pattern** above: build **`SukiAuthManager`** and **`DictationClient`** once, then open Dictation only for the target that should be active. **Language tabs (agents):** Equivalent code samples are available in: JavaScript, React. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs. Create the auth manager and client **once**, then call **`show()`** when the user should dictate (for example after a button click). Use **`try`** / **`catch`** so configuration or auth errors surface in your logs. ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; // Step 1: Create the auth manager import { DictationClient } from "@suki-sdk/dictation"; // Step 2: Create the client const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional - default is "production" loginOnInitialize: true, // optional - default is false providerName: "John doe", // optional - default is empty providerOrgId: "1234", // optional - default is empty providerId: "1234567890", // optional - default is empty providerSpecialty: "FAMILY_MEDICINE", // optional - default is empty }); const client = new DictationClient({ authManager }); // Step 3: Create the client async function startDictation() { try { await client.show({ mode: "in-field", // required - you must set this as per your use case fieldId: "clinical-notes", // required - you must set this to the ID of the textarea you want to dictate rootElement: document.getElementById("dictation-root"), // required - you must set this to the ID of the div you want to contain the dictation iframe initialText: document.getElementById("clinical-notes")?.value ?? "", // optional - you can set this to the initial text of the textarea onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Cancelled", fieldId); }, }); } catch (err) { console.error(err); } } // Call startDictation() from your UI when ready. ``` Your integration is working when the Dictation UI appears inside **`dictation-root`**, you can dictate, and text you commit is written to the textarea in **`onSubmit`**. For optional settings and callbacks (**`onDraft`**, **`initialText`**, scratchpad **`mode`**, and more), refer to [Configuration](/dictation-sdk/guides/configuration). For iframe or layout problems, refer to [Error handling](/dictation-sdk/guides/error-handling) guide for more details. Create **`DictationClient`** once (**`useMemo`**), wrap the tree with **`DictationProvider`**, and render **``** only when that field should own the session. Unmounting **``** calls **`hide()`** for you. ```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { useMemo, useState } from "react"; import { SukiAuthManager } from "@suki-sdk/core"; // Step 1: Create the auth manager import { DictationClient } from "@suki-sdk/dictation"; // Step 2: Create the client import { DictationProvider, Dictation } from "@suki-sdk/dictation-react"; // Step 3: Wrap the tree with DictationProvider export function NotesWithDictation() { const client = useMemo(() => { const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional - default is "production" loginOnInitialize: true, // optional - default is false providerName: "John doe", // optional - default is empty providerOrgId: "1234", // optional - default is empty providerId: "1234567890", // optional - default is empty providerSpecialty: "FAMILY_MEDICINE", // optional - default is empty }); return new DictationClient({ authManager }); // Step 4: Create the client }, []); // Step 5: Create the client once and reuse it across fields const [notes, setNotes] = useState(""); const [dictationActive, setDictationActive] = useState(false); return ( ``` ## Step 2: Create auth manager Now you need to create the **Auth Manager** for your application. To create the Auth Manager, you must have the `partnerId` and `partnerToken` credentials from Suki. Refer to [Partner onboarding](/documentation/get-started/partner-onboarding) guide to learn how to get these credentials. Once you have all the required credentials, create **one** auth manager for the page (or app shell). **Code example for creating auth manager** ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); ``` ## Step 3: Create Dictation client After you have created the auth manager, you can create the **Dictation client** for your application. The Dictation Client is the object that will be used to start the Dictation session. Create **one** Dictation client and reuse it for every **`show()`** call on that page. **Code example for creating Dictation client** ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { DictationClient } from "@suki-sdk/js"; const dictationClient = new DictationClient({ authManager }); ``` ## Step 4: Call show() to start Dictation Now you can start the Dictation session by calling the **`show()`** method on the Dictation client. Call **`await dictationClient.show({ ... })`** from a click handler (or similar) when the DOM is ready. Pass **`mode`**, **`fieldId`**, **`rootElement`**, **`onSubmit`**, and any optional fields you need. Refer to [Configuration](/dictation-sdk/guides/configuration) guide for more details on the available options and how to use them. **Code example for starting Dictation** ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} async function startDictation() { const root = document.getElementById("dictation-root"); const notes = document.getElementById("clinical-notes"); if (!root || !notes) { console.error("Missing dictation-root or clinical-notes in the DOM"); return; } try { await dictationClient.show({ mode: "in-field", // replace with your preferred mode - required fieldId: "clinical-notes", // often the same string as the textarea id rootElement: root, // replace with the DOM element where the dictation controls will be shown - required initialText: notes.value ?? "", // replace with the initial text for the dictation session - optional onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Dictation cancelled", fieldId); }, onDraft: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, }); } catch (err) { console.error("Dictation show() failed", err); } } document.getElementById("start-dictation")?.addEventListener("click", () => { void startDictation(); }); ``` **`onSubmit`** is required for a good user experience. If you omit it, Dictation often **closes immediately** after the user acts. ## Callbacks Every callback receives the same shape as shown in the code example below: ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} { fieldId: string, text: string } ``` Refer to [Callbacks](/dictation-sdk/guides/callbacks) guide for more details on the available callbacks and how to use them. ## Switching fields Calling **`show()`** again **replaces** the active session. You do **not** need to call **`hide()`** manually just to move from one field to another: ```javascript JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} await dictationClient.show({ /* field A options */ }); await dictationClient.show({ /* field B options */ }); ``` ## Complete code example Below is a complete code example in JavaScript for in-field mode with a single field. ```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} import { SukiAuthManager } from "@suki-sdk/core"; import { DictationClient } from "@suki-sdk/js"; const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); const dictationClient = new DictationClient({ authManager }); async function startClinicalNotesDictation() { const root = document.getElementById("dictation-root"); const notes = document.getElementById("clinical-notes"); if (!root || !notes) return; try { await dictationClient.show({ mode: "in-field", fieldId: "clinical-notes", rootElement: root, initialText: notes.value ?? "", onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Cancelled", fieldId); }, }); } catch (e) { console.error(e); } } document.addEventListener("DOMContentLoaded", () => { document .getElementById("start-dictation") ?.addEventListener("click", () => void startClinicalNotesDictation()); }); ``` This page focuses on **`in-field`** Dictation next to a specific input. If you want a **floating Dictation panel** instead, set **`mode`** to **`"scratchpad"`** and follow [Scratchpad mode](/dictation-sdk/guides/scratchpad-mode) guide. ## Best practices * **Reuse one Dictation client.** Build a single **DictationClient** for the page or shell and call it again for each Dictation session. Creating a new client on every click or for every field often resets the hosted UI and feels flaky. * **Reuse one auth manager.** Create **SukiAuthManager** once and pass that same instance into the client, the same pattern as in the steps above. * **Handle when the user commits.** You must supply a submit handler so the SDK can deliver the final text. Without it, Dictation often closes right after the user tries to finish. * **Pick a clear field label.** Each session needs a stable, unique **fieldId** in callbacks. Using the same value as the target input's **id** is a simple way to know which element to update. Refer to [Field IDs](/dictation-sdk/guides/configuration#field-ids-in-practice) guide for more details. * **Open Dictation only when the host is ready.** The DOM node you use as the Dictation host should exist and have real height before you open. Otherwise the Dictation area can look blank. Refer to [Error handling](/dictation-sdk/guides/error-handling) and [In-field mode](/dictation-sdk/guides/in-field-mode) guides for more details. * **Catch failures when opening Dictation.** Wrap the open call so auth or setup errors show up in your logs instead of disappearing. * **Move to another field by opening again.** A new open call replaces the active session. You usually do not need a separate hide step when you are only switching which field is dictating. ## Next steps Refer to the following guides for more information. [Configuration](/dictation-sdk/guides/configuration) to learn about the available options and how to use them. [React integration](/web-sdk/guides/dictation-react) to learn how to integrate audio Dictation in a React application using the Suki Web SDK. # Dictation Implementation in Web SDK for React Source: https://developer.suki.ai/web-sdk/guides/dictation-react Integrate Dictation in React with SukiAuthManager, DictationProvider, and the Dictation component in Web SDK This guide shows how to integrate Dictation capabilities into a browser-based React application with the Suki Web SDK. You will create the **Auth Manager** and **Dictation Client** (typically inside **`useMemo`** so they are not recreated on every render), wrap your component tree with the **Dictation Provider**, and render **Dictation** when the user should dictate. Use this approach if you are building with React and want to manage Dictation through components and hooks instead of imperative calls. Let's get started! ## Prerequisites Before you begin, you must have the following requirements met: * **Packages:** Install **`@suki-sdk/react`**, **`@suki-sdk/core`**. * **Partner credentials:** Obtain **`partnerId`** and **`partnerToken`** from Suki after [Partner onboarding](/documentation/get-started/partner-onboarding). * **Browser and layout:** Your app runs in a **browser**, with a real DOM and enough layout for the Dictation UI. Refer to [Prerequisites](/web-sdk/prerequisites) guide for more details. ## Install the packages Add the following packages to the same project you load in the browser: ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} pnpm add @suki-sdk/core @suki-sdk/react ``` ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} yarn add @suki-sdk/core @suki-sdk/react ``` ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}} npm install @suki-sdk/core @suki-sdk/react ``` After you install, pull the SDK into your files with **`import`**, the same way as in the examples below. Use whatever approach your project already uses for other npm libraries. ## Step 1: Add container and field layout For this example we will assume you are using **`in-field`** mode as your preferred mode. In **`in-field`** mode you need **two** parts in the UI: a **`div`** (or similar) that you can pass as **`rootElement`**, where the Dictation controls show up, and a **textarea** (or input) that **`onSubmit`** will update when the user finishes. The Dictation layer **matches the size of** **`rootElement`** when you set it, so that node should have a **height** you control. Refer to [Wrapper layout](/dictation-sdk/guides/configuration#wrapper-layout) guide for recommended markup and CSS. **Code example for container and field layout** ```jsx React theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}