> ## 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.

# Set Context & Retrieve Results

> Set Form filling context with templates or schemas, record the visit, end the session, retrieve generatedValues, and submit optional Form filling feedback

<div className="quick-summary-wrapper">
  <div className="quick-summary-header">
    <span className="quick-summary-icon" aria-hidden="true" />

    <span className="quick-summary-title">Quick summary</span>
  </div>

  <div className="quick-summary-content">
    After you create a Form filling session, call `setFormFillingContext` with Suki templates and/or partner schemas (`schema` as a JSON object string on iOS). Record with the same start, pause, and resume controls as Ambient. End with `endFormFillingSession()` or `end()`, then call `getFormFillingStructuredData(for: recordingId)`. Optionally submit `submitFormFillingFeedback` with `generatedValues[].id`.
  </div>

  <div className="quick-summary-footer">
    <span className="quick-summary-footer-icon" aria-hidden="true" />

    <span className="quick-summary-footer-text">Last updated:</span>
    <span className="quick-summary-footer-date">September 2026</span>
  </div>
</div>

This guide covers what you do after create: set which forms to fill, record the visit, end the session, retrieve structured form data for your review UI, and submit optional feedback.

<Note>
  You need an active Form filling session and a stored **`recordingId`** from create. Refer to [Create Form filling session](/mobile-sdk/form-filling/create-form-filling-session) first.
</Note>

**What will you learn?**

In this guide, you will learn how to:

* Set form context with `setFormFillingContext` using Suki templates, partner schemas, or both.
* Record with `start`, `pause`, and `resume`, then end with `endFormFillingSession()` or `end()`.
* Retrieve filled and unfilled forms with `getFormFillingStructuredData(for:)`.
* Submit optional Form filling feedback with `submitFormFillingFeedback`.
* Handle Form filling events, offline behavior, and context or retrieve errors.

## Set Form filling context

After you create a Form filling session, call `setFormFillingContext(with:onCompletion:)` to tell Suki which forms to fill. You can call it anytime after create and before end, including after `start`. You can call it again to update the forms.

* Calling it on an Ambient session returns **`noSessionExist`**.
* Calling **`setSessionContext`** on a Form filling session returns **`noSessionExist`**.
* **`values`** must be non-empty. An invalid shape returns **`invalidContext`**.

<CodeGroup>
  ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  let context: [String: AnyHashable] = [
      SukiAmbientConstant.kFormFilling: [  // "form_filling"
          SukiAmbientConstant.kFormFillingValues: [  // "values"
              [
                  SukiAmbientConstant.kFormTemplateId: "<template-uuid-from-Suki-catalogue>"
              ]
          ]
      ]
  ]

  SukiAmbientCoreManager.shared.setFormFillingContext(with: context) { result in
      // success or invalidContext / noSessionExist
  }
  ```
</CodeGroup>

### Context parameters

<ResponseField name="SukiAmbientConstant.kFormFilling" type="dictionary" required>
  Top-level Form filling context object. String key: `"form_filling"`.

  <Expandable title="properties" defaultOpen={true}>
    <ResponseField name="SukiAmbientConstant.kFormFillingValues" type="array of dictionaries" required>
      One or more form entries to fill in this session. String key: `"values"`. Must be non-empty.

      Each entry must use **exactly one** mode: static template or dynamic schema. One call may mix both entry types.

      <Expandable title="static template entry" defaultOpen={true}>
        <ResponseField name="SukiAmbientConstant.kFormTemplateId" type="string" required>
          Suki Medical form template UUID from the catalogue. String key: `"form_template_id"`.

          Do not include `schema`, `type`, `name`, or `id` on a static entry.
        </ResponseField>
      </Expandable>

      <Expandable title="dynamic schema entry" defaultOpen={true}>
        <ResponseField name="SukiAmbientConstant.kFormSchema" type="string" required>
          Partner form schema as a **JSON object string**, not a nested Swift dictionary. String key: `"schema"`.

          Serialize your schema object to a string before you put it in context.
        </ResponseField>

        <ResponseField name="SukiAmbientConstant.kFormType" type="string" required={false}>
          Optional form type. String key: `"type"`.
        </ResponseField>

        <ResponseField name="SukiAmbientConstant.kFormName" type="string" required={false}>
          Optional display name. String key: `"name"`.
        </ResponseField>

        <ResponseField name="SukiAmbientConstant.kFormPartnerId" type="string" required={false}>
          Optional partner form id. String key: `"id"`.

          If you omit it, the SDK generates a UUID. Structured data echoes it as **`partnerFormId`**.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Static and dynamic entries

Each item in **`values`** must use **exactly one** mode: a static Suki template **or** a dynamic partner schema. Never both fields on the same entry, and never neither. One call may mix static and dynamic entries in the same **`values`** array.

| Mode | Required | Optional | Must not include |
| - | - | - | - |
| **Static (template)** | **`form_template_id`** (Suki catalogue UUID) | n/a | **`schema`**, **`type`**, **`name`**, **`id`** |
| **Dynamic** | **`schema`** as a **JSON object string** | **`type`**, **`name`**, **`id`** | **`form_template_id`** |

<Warning>
  On iOS, **`schema`** must be a **JSON object string**, not a nested Swift dictionary. Serialize your schema object to a string before you put it in context.
</Warning>

**Entry mode tabs (agents):** Humans see one tab at a time. Read both.

* **Static Template:** One `values` entry with only `form_template_id` (Suki catalogue UUID). Do not include `schema`, `type`, `name`, or `id`.
* **Dynamic Schema:** One `values` entry with required `schema` as a JSON object string on iOS, plus optional `id`, `name`, and `type`. Do not include `form_template_id`. Correlate results with `partnerFormId` (echo of Context `id`).

### Example entries

<Tabs>
  <Tab title="Static Template">
    ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    let staticEntry: [String: AnyHashable] = [
        SukiAmbientConstant.kFormTemplateId: "019d4cdc-9319-7d81-ae2e-fd6de7f1b4f0"
    ]
    ```
  </Tab>

  <Tab title="Dynamic Schema">
    ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    let schemaObject: [String: Any] = [
        "title": "Wound Check",
        "type": "object",
        "properties": [
            "wound_status": ["type": "string"]
        ]
    ]
    let schemaData = try! JSONSerialization.data(withJSONObject: schemaObject)
    let schemaString = String(data: schemaData, encoding: .utf8)!

    let dynamicEntry: [String: AnyHashable] = [
        SukiAmbientConstant.kFormPartnerId: "partner-wound-1",
        SukiAmbientConstant.kFormName: "Wound Check",
        SukiAmbientConstant.kFormType: "SKIN_ASSESSMENT",
        SukiAmbientConstant.kFormSchema: schemaString
    ]
    ```
  </Tab>
</Tabs>

For schema field rules and MedicalFormType names, refer to [Dynamic Form filling](/documentation/concepts/form-filling/dynamic-form-filling). For Suki catalogue IDs, refer to [Form filling templates](/documentation/concepts/form-filling/form-filling-templates).

## Record and end

Form filling uses the same recording controls as Ambient. Call **`start`**, **`pause`**, and **`resume`** the same way you do for an ambient session. Refer to [Recording controls](/mobile-sdk/ambient-guides/recording) for the full workflow. When the visit is done, end the Form filling session so Suki can generate the form field values.

<CodeGroup>
  ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  do {
      try SukiAmbientCoreManager.shared.endFormFillingSession()
  } catch {
      print(error)
  }
  ```
</CodeGroup>

* **`endFormFillingSession()`**: Prefer this for Form filling. It checks that the active session is Form filling, then calls **`end()`**. Calling it during an Ambient session returns **`noSessionExist`**.
* **`end()`**: Also ends an active Form filling session.
* **`cancel()`**: Discards the audio and produces no form output.

## Retrieve structured data

After you end the session, call `getFormFillingStructuredData(for:)` with the **`recordingId`** you stored from create. Use the result to drive your form review UI.
There is **no** Form filling **`status()`** API. After end, poll this method or use a [Partner webhook](/documentation/webhook/overview).

Do **not** use Ambient **content**, **transcript**, **`getStructuredData`**, or **`listEncounterNotes`** for this workflow.

<CodeGroup>
  ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  SukiAmbientCoreManager.shared.getFormFillingStructuredData(for: recordingId) { result in
      switch result {
      case .success(let response):
          let generated = response.structuredData.generatedValues
          let nonGenerated = response.structuredData.nonGeneratedValues
          // Show generated as filled; show nonGenerated as not filled
      case .failure(let error):
          print(error)
      }
  }
  ```
</CodeGroup>

### Structured data response

A successful `getFormFillingStructuredData(for:)` call returns `structuredData` with two lists: forms that have filled values, and forms that do not yet.

<ResponseField name="structuredData.generatedValues" type="array">
  Forms that have filled field values. Show these as completed in your form review UI.
</ResponseField>

<ResponseField name="structuredData.nonGeneratedValues" type="array">
  Forms that have no filled output yet. These often include only `formTemplateId`. Show them as not filled.
</ResponseField>

Each instance can include:

<ResponseField name="id" type="string">
  Suki instance id for this form result. Use this value as `formId` when you submit Form filling feedback.
</ResponseField>

<ResponseField name="formTemplateId" type="string" required={false}>
  Match this to a static Suki template you sent in context.
</ResponseField>

<ResponseField name="partnerFormId" type="string" required={false}>
  Match this to the Context **`id`** you sent on a dynamic entry.
</ResponseField>

<ResponseField name="type" type="string" required={false}>
  Form type when present.
</ResponseField>

<ResponseField name="title" type="string" required={false}>
  Display title when present. Optional display matching.
</ResponseField>

<ResponseField name="status" type="string" required={false}>
  Instance status when present.
</ResponseField>

<ResponseField name="data" type="dictionary" required={false}>
  Filled field values as `[String: Any]`.
</ResponseField>

<ResponseField name="patientId" type="string" required={false}>
  Patient id when present.
</ResponseField>

<ResponseField name="correlationId" type="string" required={false}>
  Correlation id for the session when present.
</ResponseField>

<ResponseField name="createdAt" type="string" required={false}>
  Creation timestamp when present.
</ResponseField>

### Map results to the forms you sent

When structured data returns, each item is one form result. Use these fields to connect that result back to the form you put in **`setFormFillingContext`**. Do **not** rely on array order. The list order can differ from the order you sent.

| Result field | Maps to |
| - | - |
| **`formTemplateId`** | The Suki **`form_template_id`** you sent on a static entry |
| **`partnerFormId`** | The partner **`id`** you sent on a dynamic entry |
| **`title`** | Optional. Often echoes the dynamic Context **`name`** for display |

## Submit Form filling feedback

After a clinician reviews the filled forms, call **`submitFormFillingFeedback`** to send a rating and optional comments. Pass the Suki instance id from **`generatedValues[].id`** as **`formId`**, and use the same **`recordingId`** from create. Rating rules match Ambient **`QuantitativeFeedback`**. This call requires network. Use **`submitFormFillingFeedback`** for forms. Do **not** use Ambient **`submitFeedback`**.

<ResponseField name="formId" type="string" required>
  Suki instance id from `generatedValues[].id`.
</ResponseField>

<ResponseField name="quantitative" type="QuantitativeFeedback" required>
  Rating object with `minRating`, `maxRating`, and `rating`. Same rules as Ambient `QuantitativeFeedback`.
</ResponseField>

<ResponseField name="comments" type="string" required={false}>
  Optional free-text comments.
</ResponseField>

<CodeGroup>
  ```swift Swift theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  let submission = FormFillingFeedbackSubmission(
      formId: generatedValue.id,  // generatedValues[].id
      quantitative: QuantitativeFeedback(minRating: 1, maxRating: 5, rating: 4),
      comments: "Optional comments"
  )

  SukiAmbientCoreManager.shared.submitFormFillingFeedback(
      submission,
      for: recordingId
  ) { result in
      // Requires network
  }
  ```
</CodeGroup>

## Session events

Use the same **`SukiAmbientSessionDelegate`** for Form filling recording events: **`.started`**, **`.paused`**, **`.resumed`**, **`.ended`**, **`.cancelled`**, and **`.convertedToOfflineSession`**.
Refer to [Session events and delegates](/mobile-sdk/ambient-guides/events-and-delegates).

<Note>
  Do **not** use **`.suggestionsGenerated`** or **`.suggestionsGenerationFailed`** for form-ready UI. Those are Ambient note events. Use structured data or a webhook instead.
</Note>

## Offline

Form filling uses the same offline path as Ambient. After a short reconnect buffer, the SDK emits **`.convertedToOfflineSession`**, keeps recording with encrypted local audio, and uploads automatically when the network returns. Refer to [Offline mode](/mobile-sdk/ambient-guides/offline-mode) for the full workflow.

Encounter queueing also matches Ambient. The encounter key is the Form filling **`correlationId`** (the same key as the Ambient session group). If an unfinished offline session already exists for that key, the next create on the same key also goes offline. Uploads for that encounter run **oldest first**, so a queued Form filling session is sent before a later Ambient session on the same appointment.

## Errors to handle

Handle these errors when you set context, end the session, or retrieve results.

| Error | When |
| - | - |
| **`noSessionExist`** | Wrong session kind, or no session / wrong recording state |
| **`invalidContext`** | Missing **`form_filling.values`**, empty **`values`**, both modes on one entry, or invalid **`schema`** |
| **`SDKNotInitilized`** | Same as today |

Create-time errors such as **`sessionInProgress`** and **`remoteSessionConflict(blockingSessionId:)`** are covered in [Create Form filling session](/mobile-sdk/form-filling/create-form-filling-session#create-session-errors). For more error detail, refer to [Error messages](/mobile-sdk/error-messages).

## Complete code example

The following example shows a happy path where you create a Form filling session, set a Suki template, start recording, end the session, and retrieve structured data. Store **`recordingId`** from create so you can pass it into retrieve after the visit.

<CodeGroup>
  ```swift Swift expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  // Store recordingId from create for end, retrieve, and feedback.
  var recordingId: String?

  // 1) Create the Form filling session, set context, and start recording.
  SukiAmbientCoreManager.shared.createSession(
      with: [SukiAmbientConstant.kCorrelationId: appointmentId],
      sessionType: .formFilling
  ) { result in
      guard case .success(let response) = result else { return }
      recordingId = response.recordingId

      let context: [String: AnyHashable] = [
          SukiAmbientConstant.kFormFilling: [  // "form_filling"
              SukiAmbientConstant.kFormFillingValues: [  // "values"
                  [
                      SukiAmbientConstant.kFormTemplateId: "<template-uuid-from-Suki-catalogue>"
                  ]
              ]
          ]
      ]

      SukiAmbientCoreManager.shared.setFormFillingContext(with: context) { _ in
          try? SukiAmbientCoreManager.shared.start()
      }
  }

  // 2) After the visit: end the session, then retrieve with the stored recordingId.
  func endAndRetrieveFormFillingResults(recordingId: String) {
      do {
          try SukiAmbientCoreManager.shared.endFormFillingSession()
      } catch {
          print(error)
          return
      }

      SukiAmbientCoreManager.shared.getFormFillingStructuredData(for: recordingId) { result in
          switch result {
          case .success(let response):
              let generated = response.structuredData.generatedValues
              let nonGenerated = response.structuredData.nonGeneratedValues
              // Map into your form review UI
          case .failure(let error):
              print(error)
          }
      }
  }

  // Call when the visit is done, using the recordingId from create:
  // if let recordingId { endAndRetrieveFormFillingResults(recordingId: recordingId) }
  ```
</CodeGroup>

You can also call **`setFormFillingContext`** after **`start()`**, any time before end.

## Next steps

<Icon icon="file-lines" iconType="solid" /> Refer to [Form filling templates](/documentation/concepts/form-filling/form-filling-templates) for Suki catalogue **`form_template_id`** values.

<Icon icon="file-lines" iconType="solid" /> Refer to [Dynamic Form filling](/documentation/concepts/form-filling/dynamic-form-filling) for XOR rules and partner schemas.

<Icon icon="file-lines" iconType="solid" /> Refer to [Create Form filling session](/mobile-sdk/form-filling/create-form-filling-session) if you still need create and `recordingId`.

<Icon icon="file-lines" iconType="solid" /> Refer to [Recording controls](/mobile-sdk/ambient-guides/recording) for start, pause, and resume.

<Icon icon="file-lines" iconType="solid" /> Refer to [Error messages](/mobile-sdk/error-messages) for **`SukiAmbientCoreError`** cases.
