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

# Quickstart Guide

> Step-by-step guide to integrate Suki's Ambient APIs and SDKs into your healthcare application

This quickstart guide will help you integrate Suki's ambient documentation capabilities into your healthcare application. You'll go from initial setup to your first successful <Tooltip tip="A single, time-bound instance of an ambient recording for a specific patient encounter that captures clinical conversations." cta="View in Glossary" href="/Glossary/a">ambient session</Tooltip> in just a few steps.

<Note>
  **New to Suki?**

  Consider following our comprehensive [Learning path](/documentation/learning-path) for a structured, step-by-step journey from onboarding to production deployment with progress tracking and time estimates.
</Note>

**What you'll accomplish**

By completing this guide, you will:

* Set up authentication with Suki developer tools
* Choose and integrate your preferred SDK or API
* Create your first ambient session with patient information
* Record and stream audio for at least 1 minute
* Retrieve a fully structured <Tooltip tip="The final structured medical documentation generated from a patient encounter, organized into standardized sections using LOINC codes." cta="View in Glossary" href="/Glossary/c">clinical note</Tooltip> with <Tooltip tip="The text version of recorded audio from clinical conversations, generated by automatic speech recognition." cta="View in Glossary" href="/Glossary/t">transcript</Tooltip>

**Estimated Time:** 30-45 minutes

<Tip>
  **Using an AI coding tool?**

  Copy the following prompt to add the Suki developer documentation as a skill and [MCP server](/documentation/mcp) to your tool for better AI-assisted coding during the integration process. For all AI options (contextual menu, `llms.txt`, and `skill.md`), refer to [AI-optimized documentation](/documentation/ai-optimized-documentation).

  <Prompt description="Install the Suki developer docs as a skill to get context on Suki's developer tools, APIs, and SDKs. Add the [MCP server](/documentation/mcp) for documentation search." icon="gear" iconType="regular" actions={["copy", "cursor"]}>
    Install the Suki developer docs as skill to get context on Suki's developer tools, APIs, and SDKs.

    npx skills add [https://developer.suki.ai](https://developer.suki.ai)

    Then add the Suki developer docs MCP server for access to documentation search. Follow the MCP instructions at [https://developer.suki.ai/documentation/mcp](https://developer.suki.ai/documentation/mcp).
  </Prompt>
</Tip>

## Before you begin

To integrate your application with Suki developer tools, you must meet the following requirements:

<CardGroup cols={2}>
  <Card title="OAuth-compliant authentication system" icon="shield-check">
    For secure user management
  </Card>

  <Card title="JWT tokens with consistent user identifiers" icon="key">
    For user authentication
  </Card>

  <Card title="Publicly accessible JWKS endpoint" icon="link">
    For token validation
  </Card>

  <Card title="ES6 compatible browser" icon="globe">
    Modern browser support (for Web SDK)
  </Card>
</CardGroup>

You'll also need the following from Suki to get started:

* **<Tooltip tip="A unique identifier assigned by Suki during onboarding that links an application to its configuration in the Suki Developer Platform." cta="View in Glossary" href="/Glossary/p">Partner ID</Tooltip>**:
  Unique identifier provided by Suki that you will use to authenticate our SDKs and APIs.

## How authentication works

Suki supports the following public key sharing authentication mechanisms. You will use your own identity provider to issue the token.

* **Stored Secret** - You provide your public key to Suki, and we store it securely in our database as an encrypted file.
* **JWKS URL**: You host your public keys at a public JSON Web Key Set (<Tooltip tip="JSON Web Key Set. A set of keys containing the public keys used to verify any JWT issued by the authorization server." cta="View in Glossary" href="/Glossary/j">JWKS</Tooltip>) endpoint, and Suki fetches them dynamically to verify tokens.
* **Okta** - You use Okta as your Identity Provider, and Suki obtains the public key from your Okta issuer URL.
* **JWT Assertion** - You share your public key as a signed JWT that follows the RFC 7523 standard. Suki then verifies this JWT using our public key.

Refer to the [Partner onboarding](/documentation/partner-onboarding) and [Partner authentication](/documentation/partner-authentication) guides for more information.

<Warning>
  **Need Access?**

  If you don't have the required information yet, contact our [partnership team](https://www.suki.ai/suki-partners/) to begin the onboarding process.
</Warning>

## Step 1: Choose your use case and workflow

Select the integration method that best fits your application requirements: Refer to the [Choose your workflow](/documentation/workflows) to help you decide.

## Step 2: Get started

Select a workflow below to get started. For ambient workflows, choose Web SDK, Mobile SDK, or Ambient APIs. For Form filling workflows, choose the appropriate integration method.

<Tabs>
  <Tab title="Ambient Workflow" icon="waveform">
    <CardGroup cols={3}>
      <Card title="Web SDK" icon="globe">
        **Best for:** React/JavaScript web applications

        Pre-built UI components with automatic state management
      </Card>

      <Card title="Mobile SDK" icon="mobile">
        **Best for:** Native iOS applications

        Native framework optimized for mobile audio capture
      </Card>

      <Card title="Ambient APIs" icon="code">
        **Best for:** Custom implementations

        Maximum flexibility with direct API control
      </Card>
    </CardGroup>

    <Callout>
      **Headless Web SDK** and **Dictation SDK** are additional integration options on Suki for Partners (**Beta**). Use the quickstarts below for install steps and configuration.

      * [Headless Web SDK quickstart](/headless-web-sdk/quickstart)
      * [Dictation SDK quickstart](/dictation-sdk/quickstart)
    </Callout>

    <Tabs>
      <Tab title="Web SDK" icon="globe">
        <Steps>
          <Step title="Install the package">
            Choose the appropriate package for your framework:

            <Tabs>
              <Tab title="JavaScript">
                ```bash Bash theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
                npm install @suki-sdk/js @suki-sdk/core
                ```
              </Tab>

              <Tab title="React">
                ```bash Bash theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
                npm install @suki-sdk/react @suki-sdk/core
                ```
              </Tab>
            </Tabs>
          </Step>

          <Step title="Initialize SDK">
            Install `@suki-sdk/core` with `@suki-sdk/js` or `@suki-sdk/react`. Wrap your app with `SukiProvider`, create `SukiAuthManager` with your partner and provider values, then pass `authManager` into `initialize()` or `init()`. For details, see [Web SDK Quickstart](/web-sdk/quickstart) and [Migrating to Web SDK v3](/web-sdk/product-updates/migration-to-v3).

            <CodeGroup>
              ```js JavaScript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              import { SukiAuthManager } from "@suki-sdk/core";
              import { initialize } from "@suki-sdk/js";

              const authManager = new SukiAuthManager({
                partnerId: "f80c8db8-a4d0-4b75-8d63-56c82b5413f0", // Replace with your actual partner ID - REQUIRED
                partnerToken:
                  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30", // Replace with your actual partner token - REQUIRED
                providerName: "John doe", // Replace with the full name of the provider - REQUIRED
                providerOrgId: "1234", // Replace with the provider's organization ID - REQUIRED
                environment: "production", // Replace with the environment - REQUIRED
                loginOnInitialize: true, // Replace with false if you want to manually sign in the provider
                autoRegister: false, // Replace with true if you want to auto-register the provider
                providerId: "provider-123", // Replace with the provider's ID
                providerSpecialty: "FAMILY_MEDICINE", // Replace with the provider's specialty
              });

              const sdkClient = initialize({
                authManager,
              });
              ```

              ```jsx React theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              import { SukiProvider } from "@suki-sdk/react";
              function App() {
              return (
                <SukiProvider>
                  {/* Your application components go here */}
                  <ComponentA />
                </SukiProvider>
              );
              }
              ```
            </CodeGroup>
          </Step>

          <Step title="Mount UI">
            In the same component where you initialized the SDK, mount the `SukiAssistant` component with encounter data:

            <CodeGroup>
              ```js JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
                    import { SukiAuthManager } from "@suki-sdk/core";
                    import { initialize } from "@suki-sdk/js";

                    // replace this with your actual encounter data
                    const encounterDetails = {
                      identifier: "6ec3920f-b0b1-499d-a4e9-889bf788e5ab",
                      patient: {
                        identifier: "905c2521-25eb-4324-9978-724636df3436",
                        name: {
                          use: "official",
                          family: "Doe",
                          given: ["John"],
                          suffix: ["MD"],
                        },
                        birthDate: "1990-01-01",
                        gender: "Male",
                      },
                    };

                    const authManager = new SukiAuthManager({
                      partnerId: "f80c8db8-a4d0-4b75-8d63-56c82b5413f0", // Replace with your actual partner ID
                      partnerToken:
                        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30", // Replace with your actual partner token
                      providerName: "John doe", // Replace with the full name of the provider
                      providerOrgId: "1234", // Replace with the provider's organization ID
                      environment: "production", // Replace with the environment
                      loginOnInitialize: true, // Replace with false if you want to manually sign in the provider
                      autoRegister: false, // Replace with true if you want to auto-register the provider
                      providerId: "provider-123", // Replace with the provider's ID
                      providerSpecialty: "FAMILY_MEDICINE", // Replace with the provider's specialty
                    });

                    const sdkClient = initialize({
                      authManager,
                    });

                    const unsubscribeInit = sdkClient.on("init:change", (isInitialized) => {
                      if (isInitialized) {
                        sdkClient.mount({
                          rootElement: document.getElementById("suki-root"), // The root element to mount the SDK into
                          encounter: encounterDetails,
                        });
                      }
                    });

                    // unsubscribe from the init event when no longer needed
                    window.addEventListener("beforeunload", () => {
                      unsubscribeInit();
                    });
              ```

              ```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              import { useEffect, useMemo } from "react";
              import { SukiAuthManager } from "@suki-sdk/core";
              import { useSuki, SukiAssistant } from "@suki-sdk/react";

              function ComponentA() {
              const authManager = useMemo(
              () =>
                new SukiAuthManager({
                  partnerId: "f80c8db8-a4d0-4b75-8d63-56c82b5413f0", // Replace with your actual partnerId
                  partnerToken:
                    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30", // Replace with your actual Partner Token
                  providerName: "John doe", // Replace with the full name of the provider
                  providerOrgId: "1234", // Replace with the provider's organization ID
                  environment: "production", // Replace with the environment
                  loginOnInitialize: true, // Replace with false if you want to manually sign in the provider
                  autoRegister: false, // Replace with true if you want to auto-register the provider
                  providerId: "provider-123", // Replace with the provider's ID
                  providerSpecialty: "FAMILY_MEDICINE", // Replace with the provider's specialty
                }),
              [],
              );

              const { init, isInitialized } = useSuki();

              // replace this with your actual encounter data
              const currentEncounter = {
              identifier: "6ec3920f-b0b1-499d-a4e9-889bf788e5ab",
              patient: {
                identifier: "905c2521-25eb-4324-9978-724636df3436",
                name: {
                  use: "official",
                  family: "Doe",
                  given: ["John"],
                  suffix: ["MD"],
                },
                birthDate: "1990-01-01",
                gender: "Male",
              },
              };

              useEffect(() => {
              if (!isInitialized) {
                init({ authManager });
              }
              }, [init, isInitialized, authManager]);

              return (
              <SukiAssistant encounter={currentEncounter} />
              {/* rest of your code */}
              );
              }
              ```
            </CodeGroup>
          </Step>

          <Step title="Start recording">
            Click the recording button in the Suki web SDK UI to start capturing the conversation.
          </Step>

          <Step title="Record for at least 1 minute">
            Record a test conversation. The session should be at least **1 minute long** for note generation to occur.
          </Step>

          <Step title="Stop and retrieve note">
            Click stop recording button in the Suki web SDK UI. The generated note will automatically appear in the web SDK UI panel.
          </Step>
        </Steps>

        <Note>
          For complete web SDK capabilities, refer to the [Web SDK section](/web-sdk/overview) of the documentation.
        </Note>
      </Tab>

      <Tab title="Mobile SDK" icon="mobile">
        <Steps>
          <Step title="Install the framework">
            Add the Suki Mobile SDK to your iOS project following the [Installation guide](/mobile-sdk/installation).
          </Step>

          <Step title="Initialize the SDK">
            Configure the SDK when your application starts:

            <CodeGroup>
              ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              import SukiAmbientCore

              // Set the SDK environment
              SukiAmbientCoreManager.shared.environment = .stage

              // Initialize the SDK with partner information
              let partnerInfo: [String: AnyHashable] = [
                  SukiAmbientConstant.kPartnerId: "your-partner-id",
                  SukiAmbientConstant.kProviderInfo: [
                      SukiAmbientConstant.kOrgId: "provider_org_id",
                      SukiAmbientConstant.kName: "Dr. Jane Smith",
                      SukiAmbientConstant.kId: "providerId",
                      SukiAmbientConstant.kSpeciality: "FAMILY_MEDICINE"
                  ]
              ]

              do {
                  try SukiAmbientCore.shared.initialize(
                      withPartnerInfo: partnerInfo,
                      with: true,
                      onCompletion: { result in
                          // Handle initialization result
                      },
                      withSessionDelegate: self,
                      withTokenProvider: self
                  )
              } catch {
                  print("Initialization failed: \(error)")
              }
              ```
            </CodeGroup>
          </Step>

          <Step title="Create session">
            Initialize an ambient session with patient information:

            <CodeGroup>
              ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              let sessionContext = [
                      SukiAmbientConstant.kSessionId: <encounter-id>,
                      SukiAmbientConstant.kIsMultilingual:isMultilingual
                  ] as [String : AnyHashable]        
                  SukiAmbientCoreManager.shared.createSession(with: sessionContext, onCompletion: { result in
                      switch result {
                      case .success(let sessionResponse):
                          print("Success")
                      case .failure(let error):
                          print("error = \(error)")
                      }
                  })
              ```
            </CodeGroup>
          </Step>

          <Step title="Start recording">
            Begin capturing the clinical conversation:

            <CodeGroup>
              ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              do {
                  try SukiAmbientCore.shared.start()
              } catch {
                  print("Recording failed: \(error)")
              }
              ```
            </CodeGroup>
          </Step>

          <Step title="Record for at least 1 minute">
            Capture audio for at least **1 minute** to ensure note generation occurs.
          </Step>

          <Step title="End session">
            Stop the recording and trigger note generation:

            <CodeGroup>
              ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              do {
                  try SukiAmbientCore.shared.end()
              } catch {
                  print("End session failed: \(error)")
              }
              ```
            </CodeGroup>
          </Step>

          <Step title="Retrieve generated content">
            Get the generated clinical note and transcript:

            <CodeGroup>
              ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              // Get the recording ID from the session
              let recordingId = sessionId // Use the session ID as recording ID

              // Retrieve content
              SukiAmbientCore.shared.content(for: recordingId) { result in
                  switch result {
                  case .success(let suggestions):
                      print("Generated Note: \(suggestions)")
                  case .failure(let error):
                      print("Failed to retrieve content: \(error)")
                  }
              }

              // Retrieve transcript
              SukiAmbientCoreManager.shared.transcript(for: recordingId) { result in
                  switch result {
                  case .success(let response):
                      let transcriptText = (response.finalTranscript ?? []).compactMap { $0.transcript }.joined(separator: " ")
                      print("Transcript: \(transcriptText)")
                  case .failure(let error):
                      print("Failed to retrieve transcript: \(error)")
                  }
              }
              ```
            </CodeGroup>
          </Step>
        </Steps>

        <Note>
          For complete mobile SDK capabilities, refer to the [Mobile SDK section](/mobile-sdk/overview) of the documentation.
        </Note>
      </Tab>

      <Tab title="Ambient APIs" icon="code">
        <Steps>
          <Step title="Authenticate and get token">
            Get your access token by calling the login endpoint. If you have not registered with Suki, call the [Register](/api-reference/authentication/register) endpoint first to register a new user.

            <CodeGroup>
              ```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-jwt-token",
                  "provider_id": "provider-123"
                }'
              ```
            </CodeGroup>

            <Tip>
              Save the `suki_token` from the response. This token is valid for **1 hour** and must be included as `sdp_suki_token` header for all subsequent API calls.
            </Tip>

            <Callout icon="code" color="#FFC107" iconType="regular">
              **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.
            </Callout>
          </Step>

          <Step title="Create ambient session">
            Start a new ambient session:

            <CodeGroup>
              ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              curl -X POST https://sdp.suki-stage.com/api/v1/ambient/session/create \
                -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
              -H "sdp_provider_id: <sdp_provider_id>" \
                -H "Content-Type: application/json" \
                -d '{
                  "ambient_session_id": "123dfg-456dfg-789dfg-012dfg",
                  "encounter_id": "123dfg-456dfg-789dfg-012dfg",
                  "multilingual": false
                }'
              ```
            </CodeGroup>

            <Tip>
              Save the `ambient_session_id` from the response. You'll need it to stream audio and retrieve content. A successful create returns **201 Created**.
            </Tip>
          </Step>

          <Step title="Post session context">
            Before you open the audio WebSocket, seed context for the session (improves note quality). Send <Badge color="blue" size="sm">POST</Badge> to `/api/v1/ambient/session/{ambient_session_id}/context` with a JSON body that matches the [Context API](/api-reference/ambient-sessions/context) schema.

            <CodeGroup>
              ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              curl -X POST "https://sdp.suki-stage.com/api/v1/ambient/session/YOUR_SESSION_ID/context" \
                -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
              -H "sdp_provider_id: <sdp_provider_id>" \
                -H "Content-Type: application/json" \
                -d '{}'
              ```
            </CodeGroup>

            <Note>
              Replace the empty JSON with the fields your integration needs. Opening `/ws/stream` before create and context are complete often causes failures.
            </Note>
          </Step>

          <Step title="Stream audio via WebSocket">
            Stream over **WebSocket** (`wss://`, not plain HTTPS). Refer to [Audio streaming API reference](/api-reference/ambient-sessions/audio-stream) for authentication,
            and [Audio streaming guide](/documentation/ambient-audio-streaming) for the **JSON text frame** wire format, and **Python** and **TypeScript** examples.

            <Warning>
              **Non-browser clients** must send `sdp_suki_token` and `ambient_session_id` as HTTP headers on the WebSocket **upgrade** request. **Browser clients** must send **`Sec-WebSocket-Protocol`** as a single comma-separated value: `SukiAmbientAuth`, then ambient session ID, then `sdp_suki_token` (see [Audio streaming API reference](/api-reference/ambient-sessions/audio-stream)). Each outbound message is one JSON text frame: **START\_TIME**, then **AUDIO** chunks (Base64 PCM), then an **AUDIO** frame whose `data` is Base64 of bytes **`EOF`** (**`RU9G`**).
            </Warning>
          </Step>

          <Step title="End session">
            Signal that the conversation is over to trigger note generation:

            <CodeGroup>
              ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              curl -X POST "https://sdp.suki-stage.com/api/v1/ambient/session/YOUR_SESSION_ID/end" \
                -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
              -H "sdp_provider_id: <sdp_provider_id>"
              ```
            </CodeGroup>
          </Step>

          <Step title="Retrieve generated content">
            After ending the session, wait a few seconds for processing, then fetch the clinical note:

            <CodeGroup>
              ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
              curl -X GET "https://sdp.suki-stage.com/api/v1/ambient/session/YOUR_SESSION_ID/content?cumulative=false" \
                -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
              -H "sdp_provider_id: <sdp_provider_id>"
              ```
            </CodeGroup>
          </Step>
        </Steps>

        <Warning>
          **Session Duration Requirement**

          Your ambient session must be **at least 1 minute long** for note generation to occur. Sessions shorter than 1 minute receive a `SKIPPED` status, and Suki does not generate a clinical note.

          For complete API capabilities, refer to the [API reference](/api-reference/overview) of the documentation.
        </Warning>
      </Tab>
    </Tabs>

    ## Verify success

    After completing your first session, you should see:

    <Tabs>
      <Tab title="For Web SDK">
        * The generated clinical note automatically appears in the Suki UI panel
        * Sections are organized according to your LOINC configuration
        * Transcript is available within the UI
      </Tab>

      <Tab title="For Mobile SDK">
        * Call `content()` and `transcript()` to retrieve the note and transcript respectively
        * Check the session status to confirm successful completion
        * Access structured sections and conversation transcript programmatically
      </Tab>

      <Tab title="For Ambient APIs">
        * <Badge color="green" size="sm">GET</Badge> request to `/api/v1/ambient/session/{ambient_session_id}/content` returns:
          * `summary` - Array of structured clinical note sections
        * <Badge color="green" size="sm">GET</Badge> request to `/api/v1/ambient/session/{ambient_session_id}/transcript` returns:
          * `final_transcript` - Complete conversation transcript
        * <Badge color="green" size="sm">GET</Badge> request to `/api/v1/ambient/session/{ambient_session_id}/status` returns:
          * `status` - Session status (`created`, `ready`, `running`, `aborted`, `skipped`, `failed`, `completed`)
      </Tab>
    </Tabs>

    ## Step 3: Advanced configuration (optional but recommended)

    Configure the generated note in many ways. For example, to generate a customized clinical note, refer to the [LOINC codes](/documentation/note-sections) to define the sections you want to generate.

    <CodeGroup>
      ```json Json theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "sections": [
          {
            "loinc": "10164-2",
            "title": "History of Present Illness"
          },
          {
            "loinc": "51847-2", 
            "title": "Assessment and Plan"
          }
        ]
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Form Filling Workflow" icon="file-lines">
    <CardGroup cols={3}>
      <Card title="Form Filling APIs" icon="code">
        **Best for:** Custom implementations

        REST session lifecycle plus shared Partner WebSocket audio for structured medical forms
      </Card>
    </CardGroup>

    <Steps>
      <Step title="Authenticate and get token">
        Get your access token by calling the login endpoint. If you have not registered with Suki, call the [Register](/form-filling-api-reference/authentication/register) endpoint first to register a new user.

        <CodeGroup>
          ```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-jwt-token",
              "provider_id": "provider-123"
            }'
          ```
        </CodeGroup>

        <Tip>
          Save the `suki_token` from the response. This token is valid for **1 hour** and must be included as `sdp_suki_token` header for all subsequent API calls.
        </Tip>
      </Step>

      <Step title="Create Form Filling Session">
        Start a new Form filling session:

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
          curl -X POST https://sdp.suki-stage.com/api/v1/form-filling/session/create \
            -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
          -H "sdp_provider_id: <sdp_provider_id>" \
            -H "Content-Type: application/json" \
            -d '{}'
          ```
        </CodeGroup>

        <Note>
          In Form Filling APIs, the session ID field is named **`ambient_session_id`**, but it is **not** the same ID as an Ambient API session. Use only the value returned from **Form filling** `/session/create` for Form filling REST calls and for **`/ws/stream`**.
        </Note>

        <Tip>
          Save the **`ambient_session_id`** from the response. You need it for context, streaming, **end**, **status**, and **structured-data** calls. A successful create returns **201 Created**.
        </Tip>
      </Step>

      <Step title="Seed context (optional)">
        Provide form template metadata before you stream audio. Send <Badge color="blue" size="sm">POST</Badge> to `/api/v1/form-filling/session/{ambient_session_id}/context` with **`form_filling.values`** entries that include **`form_template_id`** for each template you want to use.

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
          curl -X POST "https://sdp.suki-stage.com/api/v1/form-filling/session/YOUR_SESSION_ID/context" \
            -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
          -H "sdp_provider_id: <sdp_provider_id>" \
            -H "Content-Type: application/json" \
            -d '{
              "form_filling": {
                "values": [
                  { "form_template_id": "YOUR_FORM_TEMPLATE_UUID" }
                ]
              }
            }'
          ```
        </CodeGroup>

        <Note>
          The request body is optional. You can skip this step and continue to audio capture. To list available templates, see [Suki medical form templates](/form-filling-api-reference/info/suki-medical-form-templates).
        </Note>
      </Step>

      <Step title="Stream audio via WebSocket">
        Stream over **WebSocket** (`wss://`, not plain HTTPS). Use your **Form filling** **`ambient_session_id`** and **`sdp_suki_token`**. Refer to [Audio streaming API reference](/api-reference/ambient-sessions/audio-stream) and [Ambient audio streaming](/documentation/ambient-audio-streaming) for authentication, the **JSON text frame** wire format, and client examples.

        <Warning>
          **Non-browser clients** must send `sdp_suki_token` and `ambient_session_id` as HTTP headers on the WebSocket **upgrade** request. **Browser clients** must send **`Sec-WebSocket-Protocol`** as a single comma-separated value: `SukiAmbientAuth`, then ambient session ID, then `sdp_suki_token` (see [Audio streaming API reference](/api-reference/ambient-sessions/audio-stream)). Each outbound message is one JSON text frame: **START\_TIME**, then **AUDIO** chunks (Base64 PCM), then an **AUDIO** frame whose `data` is Base64 of bytes **`EOF`** (**`RU9G`**).
        </Warning>
      </Step>

      <Step title="End session">
        Signal that the visit is over and processing can begin:

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
          curl -X POST "https://sdp.suki-stage.com/api/v1/form-filling/session/YOUR_SESSION_ID/end" \
            -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
          -H "sdp_provider_id: <sdp_provider_id>"
          ```
        </CodeGroup>
      </Step>

      <Step title="Retrieve structured data">
        After ending the session, poll status until processing completes, then fetch structured form output. You can also use a **webhook** when processing finishes (see [Webhook notifications](/api-reference/asynchronous/webhook)).

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
          # Check status
          curl -X GET "https://sdp.suki-stage.com/api/v1/form-filling/session/YOUR_SESSION_ID/status" \
            -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
          -H "sdp_provider_id: <sdp_provider_id>"
          # Get structured data
          curl -X GET "https://sdp.suki-stage.com/api/v1/form-filling/session/YOUR_SESSION_ID/structured-data" \
            -H "sdp_suki_token: YOUR_SUKI_TOKEN" \
          -H "sdp_provider_id: <sdp_provider_id>"
          ```
        </CodeGroup>
      </Step>
    </Steps>

    <Note>
      For complete Form Filling API capabilities, refer to the [Form Filling API overview](/form-filling-api-reference/overview) and [Form Filling API quickstart](/form-filling-api-reference/quickstart).
    </Note>

    ## Verify success

    After completing your first Form filling session, you should see:

    * <Badge color="green" size="sm">GET</Badge> request to `/api/v1/form-filling/session/{ambient_session_id}/status` returns a terminal status when processing is done
    * <Badge color="green" size="sm">GET</Badge> request to `/api/v1/form-filling/session/{ambient_session_id}/structured-data` returns:
      * **`generated_values`** and **`non_generated_values`** for the session
    * Structured fields map to the templates you supplied in context (when provided)

    ## Next steps (Form filling)

    <Icon icon="file-lines" iconType="solid" /> Refer to the [Form Filling overview](/documentation/form-filling) to learn how Form filling workflows fit your product.

    <Icon icon="file-lines" iconType="solid" /> Refer to the [Form Filling API quickstart](/form-filling-api-reference/quickstart) for the full step-by-step API walkthrough.

    <Icon icon="file-lines" iconType="solid" /> Refer to the [Form Filling integration decision guide](/documentation/form-filling-integration-decision-guide) to compare integration options.
  </Tab>
</Tabs>

## Success checklist

Before moving to production, ensure you have successfully completed these steps:

<AccordionGroup>
  <Accordion title="Authentication Works" icon="check">
    * Successfully call the `/api/v1/auth/login` endpoint
    * You receive a valid `suki_token` in the response
    * Your JWT token is properly formatted and not expired
    * Your JWKS endpoint is publicly accessible
  </Accordion>

  <Accordion title="Session Creation Works" icon="check">
    * Create an ambient session with patient information
    * You receive an `ambient_session_id` in the response
    * The session status is valid (not `FAILED`)
  </Accordion>

  <Accordion title="Audio streaming works" icon="check">
    * WebSocket connection establishes successfully
    * Audio chunks are being sent to Suki
    * No connection errors or timeouts occur
    * Session duration is at least 1 minute
  </Accordion>

  <Accordion title="Content Retrieval Works" icon="check">
    * Fetch session content using the `ambient_session_id`
    * Response includes structured `summary` array with clinical content
    * Response includes a complete `transcript` of the conversation
    * Session status shows `COMPLETED` (not `SKIPPED` or `FAILED`)
  </Accordion>

  <Accordion title="Integration Quality" icon="check">
    * Generated notes are accurate and clinically relevant
    * Transcript content is accurate and complete
    * LOINC sections match your requested configuration
    * Error handling is implemented for all API calls
  </Accordion>
</AccordionGroup>

## Troubleshooting

<Tabs>
  <Tab title="Common issues">
    <AccordionGroup>
      <Accordion title="Authentication Failed - 401 Unauthorized">
        **Problem:** Login request returns 401 Unauthorized error

        **Solution:**

        * Verify your `partner_id` matches the one provided by Suki
        * Ensure your JWT token (`partner_token`) is valid and not expired
        * Check that your JWT token includes the correct user identifier field
        * Verify your JWKS endpoint is publicly accessible and returning valid keys
        * Confirm your public key matches what was registered with Suki
      </Accordion>

      <Accordion title="Session Creation Failed">
        **Problem:** Cannot create ambient session or receive error response

        **Solution:**

        * Confirm you have a valid `suki_token` from the login endpoint
        * Use `sdp_suki_token` header (not `Authorization: Bearer`) for all API calls
        * Verify `ambient_session_id` and `encounter_id` are **at most 36 characters** (<Tooltip tip="VARCHAR is a variable-length SQL string type. varchar(36) caps these identifiers at 36 characters. See the Glossary." cta="View in Glossary" href="/Glossary/v#varchar-36">varchar(36)</Tooltip>) when you set them, where applicable.
        * Check that `multilingual` is a boolean value (true/false)
        * Verify your partner account has the necessary permissions for ambient sessions
      </Accordion>

      <Accordion title="WebSocket Connection Failed">
        **Problem:** WebSocket connection fails or immediately disconnects

        **Solution:**

        * Verify you're using the correct WebSocket URL: `wss://sdp.suki-stage.com/ws/stream`
        * For browser clients, ensure you're using `Sec-WebSocket-Protocol` header with format: `SukiAmbientAuth,<ambient_session_id>,<sdp_suki_token>`
        * For non-browser clients, include both `sdp_suki_token` and `ambient_session_id` as separate headers in the WebSocket upgrade request
        * Check network connectivity and firewall settings allow WebSocket connections
        * Ensure your `suki_token` hasn't expired (valid for 1 hour)
      </Accordion>

      <Accordion title="Session status shows SKIPPED">
        **Problem:** Session completes but status is `SKIPPED` and no note is generated

        **Solution:**

        * Ensure your session duration is at least **1 minute long**
        * Verify audio is being properly captured and streamed
        * Check that audio chunks contain actual speech (not silence)
        * Confirm WebSocket connection remained stable throughout the session

        <Note>
          A `SKIPPED` status is expected for sessions shorter than 1 minute or with no audible speech. This is not a system error.
        </Note>
      </Accordion>

      <Accordion title="Audio Not Processing">
        **Problem:** Audio streams but transcript is empty or note not generated

        **Solution:**

        * Verify audio format is correct (PCM, 16-bit, 16kHz mono recommended)
        * Ensure audio chunks are the correct size (100ms chunks recommended)
        * Check that you end the stream with an **AUDIO** message whose `data` is Base64 of bytes **`EOF`** (value **`RU9G`**), then close the WebSocket and call the session **end** REST endpoint
        * Verify microphone permissions are granted in your application
        * Test with a known working audio sample first
      </Accordion>

      <Accordion title="Content Retrieval Returns Empty or Incomplete Data">
        **Problem:** Session completes but content endpoint returns no data or incomplete note

        **Solution:**

        * Wait at least 5-10 seconds after ending the session before retrieving content
        * Check the session `status` - it should be `COMPLETED`, not `PROCESSING`
        * Verify you're using the correct `ambient_session_id` in the URL path
        * Use `sdp_suki_token` header (not `Authorization: Bearer`)
        * Ensure your `suki_token` is still valid (valid for 1 hour)
        * Check if session was `SKIPPED` due to short duration (less than 1 minute)
        * Verify you called the `/end` endpoint to trigger note generation
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="Getting help">
    * Technical Issues: Review our <a href="/documentation/faqs/general">FAQs</a>

    * Integration Support: Contact our{" "}
      <a href="https://forms.suki.ai/SukiSupport/form/SukiSDKSupport/formperma/T3z7hYJ7Ph-J7JrWSN08QJn32BYjarkxqm8Lm8XFPow">Support team</a>

    * Partnership Questions: Reach out to our{" "}
      <a href="https://www.suki.ai/suki-partners/">Partnership team</a>
  </Tab>
</Tabs>

## Next steps

<Icon icon="file-lines" iconType="solid" /> Refer to the [Ambient Documentation Guide](/documentation/ambient-documentation) to learn more about how ambient documentation works.

<Icon icon="file-lines" iconType="solid" /> Refer to the [Authentication Setup](/documentation/partner-authentication) to understand how to authenticate your application with Suki.

<Icon icon="file-lines" iconType="solid" /> Refer to the [Note Sections](/documentation/note-sections) to customize the clinical note structure and LOINC codes.

<Icon icon="file-lines" iconType="solid" /> Refer to the [API Reference](/api-reference/overview) to explore detailed API specifications.
