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

# Add E/M Codes to an Ambient Session

> Opt into E/M Coding when you create an ambient session, send the visit details coding needs, and read the recommended codes with the note

Quick summary

Use this when Suki generates the clinical note from the clinician-patient conversation. Opt into E/M Coding on create with `artifacts: ["EM_CODES"]`, send patient and visit details before the recording ends, then read `em_codes` when the ambient session is `completed`.

Last updated:
November 2026

Use E/M Coding with an ambient session when Suki generates the clinical note from the visit. Opt in when you create the session, send the visit details coding needs before you end the recording, then read the recommended codes with the completed note.

You still get the note after the session completes and coding recommendations run after the note is ready, using that note and the details you sent.

> [!NOTE]
>
> If coding cannot produce a code, the note still finishes, but it does not include the codes.

You do not get a separate E/M coding `session_id` when you opt to generate codes with an ambient session, so use the ambient `ambient_session_id`, `note_id`, or `encounter_id` you already store for the visit to retrieve and display the codes in your review UI.

If your application or EHR already creates the clinical note and you are not recording this visit during an ambient session, submit the finished note through the standalone APIs instead. Refer to [Generate E/M codes from a note](https://developer.suki.ai/documentation/how-to/em-coding/generate-standalone.md) for more details.

> [!WARNING]
>
> Do not run both paths for the same encounter.

## Prerequisites

* A working ambient flow: create a session, send context, stream audio, end the session, and read the note. See [Create an ambient session](https://developer.suki.ai/documentation/how-to/ambient-clinical-notes/create-ambient-session.md).
* A Suki Token from Login. Refer to [Partner authentication](https://developer.suki.ai/documentation/how-to/partner-authentication.md) guide to learn more.
* E/M Coding enabled for your organization. Contact [support](mailto:support@suki.ai) if create rejects `EM_CODES`, or codes never appear.

## Steps to add E/M codes to an ambient visit

**1. Ask for Codes When You Create the Session**

Call [Create ambient session](https://developer.suki.ai/api-reference/ambient-sessions/create.md) and include `artifacts` with `EM_CODES`. That tells Suki to recommend an E/M code for this recording, in addition to the note.

### Create fields that matter for coding

Send your usual create body. Coding does not change those rules. The field that opts this visit into E/M Coding is `artifacts`.

**artifacts** `array`

Optional Extra outputs to generate with the note. Include `"EM_CODES"` so this session also runs coding. Today `EM_CODES` is the only supported value. If you omit it, coding does not run for this ambient visit.

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "artifacts": ["EM_CODES"]
}
```

Store `ambient_session_id` and `note_id` the same way you already do for the note.

**2. Send the Visit Details Before You End**

Coding is more accurate when it knows who the patient is, who saw them, and what the visit was. Send these on [Seed ambient session context](https://developer.suki.ai/api-reference/ambient-sessions/context.md), or later with [Update ambient session context](https://developer.suki.ai/api-reference/ambient-sessions/update-context.md), before you end the session. Context that arrives after end is too late for this visit.

You can still send the rest of your ambient context. Coding uses the fields below and ignores fields it does not need for E/M.

**patient** `object`

Optional Patient facts that can change new vs established coding and support the visit. Send what you have.

**properties**

**patient\_type** `string`

`NEW_PATIENT` or `ESTABLISHED_PATIENT`.

**dob** `string`

Date of birth as `YYYY-MM-DD`. Do not send a future date.

**sex** `string`

`male`, `female`, `other`, or `unknown`.

**mrn** `string`

Medical record number, up to 64 characters.

**insurance.coverages** `array`

Coverage rows when your EHR exposes them.

**provider** `object`

Optional Who saw the patient. Include name, NPI, and specialty when your system already stores them.

**properties**

**first\_name** `string`

Provider first name.

**last\_name** `string`

Provider last name.

**npi** `string`

National Provider Identifier, up to 64 characters.

**specialty** `string`

Provider specialty as your EHR stores it. On ambient context the field name is `specialty`.

**visit** `object`

Optional Visit-level details for the encounter you are coding. Use this when you bill by date of service, want time to influence the code, or need to keep your own visit identifiers with the request.

**properties**

**date\_of\_service** `string`

Encounter date as `YYYY-MM-DD`. Do not send a future date.

**total\_time\_minutes** `number`

Total visit time in minutes. Send this when you bill by time, and only when the value is greater than `0`.

**csn** `string`

Your contact serial number or equivalent visit id, up to 64 characters.

**visit\_type** `string`

The kind of visit. Use a type Suki supports, not a free-text label from the EHR. Refer to [Visit types](https://developer.suki.ai/api-reference/info/visit-types.md) for the supported values.

**diagnoses** `object`

Optional Diagnoses already recorded for the encounter. Include them in `diagnoses.values`, with a code and short description for each diagnosis. Suki uses ICD-10 and IMO diagnoses alongside the clinical note when recommending an E/M code. Your existing diagnoses remain unchanged. Refer to [Provide existing diagnoses](https://developer.suki.ai/documentation/concepts/em-coding/overview.md#provide-existing-diagnoses) for which diagnosis types to send.

**3. Finish the Ambient Visit**

Stream audio and end the session the way you already do, then wait until ambient status is `completed`, or until the ambient webhook arrives and you have confirmed [Session status](https://developer.suki.ai/api-reference/ambient-content/status.md). This is because an ambient webhook `SUCCESS` means processing finished and you should confirm status before you open the note or the codes.

**4. Read the Codes with the Note**

When ambient status is `completed`, the codes come back with the note under `em_codes`. Read them from the structured data you already fetch, or from the codes-only endpoints when you only need the E/M code:

| Scope | Endpoint | Path parameter |
| :- | :- | :- |
| This recording | `GET /api/v1/ambient/session/{ambient_session_id}/structured-data/em-codes` | `ambient_session_id` from create |
| The note | `GET /api/v1/ambient/note/{note_id}/structured-data/em-codes` | `note_id` from create |
| The encounter | `GET /api/v1/ambient/encounter/{encounter_id}/structured-data/em-codes` | `encounter_id` for the visit |

* Each dedicated endpoint returns `{ "em_codes": { "values": [ ... ] } }`. Combined structured-data responses place the same object under `structured_data.em_codes`.

* The ambient success webhook can also include `_links.em_codes` and `_links.encounter_em_codes` so you can call those URLs without building the path yourself.

* For the response fields and how to show them in a review UI, see [Get the generated E/M codes](https://developer.suki.ai/documentation/how-to/em-coding/retrieve-em-codes.md).

## Example create and context

### Create request

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "artifacts": ["EM_CODES"],
  "emr_encounter_id": "visit-123"
}
```

### Create response (`201`)

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "ambient_session_id": "123dfg-456dfg-789dfg-012dfg",
  "note_id": "123dfg-456dfg-789dfg-012dfg"
}
```

### Context request

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "patient": {
    "patient_type": "ESTABLISHED_PATIENT",
    "dob": "1952-03-15",
    "sex": "female",
    "mrn": "MRN-12345"
  },
  "provider": {
    "specialty": "INTERNAL_MEDICINE",
    "first_name": "Jane",
    "last_name": "Doe",
    "npi": "1234567893"
  },
  "visit": {
    "visit_type": "ESTABLISHED_PATIENT",
    "date_of_service": "2026-01-15",
    "total_time_minutes": 35
  }
}
```

### Codes response (after the note is ready)

When ambient status is `completed`, call a codes-only endpoint with the ambient id you stored. The response contains the recommended E/M codes in `em_codes.values`:

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "em_codes": {
    "values": [
      {
        "id": "01JQ8Z2W9X4Y6Z8A0B2C4D6E8F",
        "code": "99214",
        "family": "PROBLEM_BASED",
        "level": 4,
        "patient_type": "ESTABLISHED_PATIENT",
        "modifiers": ["25"],
        "add_on_codes": [],
        "mdm_based_features": {
          "problem_complexity": "PROBLEM_COMPLEXITY_MODERATE",
          "data_reviewed": "DATA_REVIEWED_LIMITED",
          "risk": "RISK_MODERATE",
          "rationale": "Moderate complexity with prescription drug management"
        }
      }
    ]
  }
}
```

Each object in `values` represents one recommended E/M code. Exactly one of `mdm_based_features`, `time_based_features`, or `wellness_features` is present on that object.

> [!NOTE]
>
> If `em_codes.values` is an empty array (`[]`), Suki **did not recommend** any E/M codes for this visit. Show the note either way.

## Code example

The following code shows the end-to-end logic: opt in on create, seed visit details, wait until the ambient session completes, then retrieve `em_codes.values`. Stream audio and end the session with your existing ambient flow.

**Language tabs (agents):** Equivalent code samples are available in: TypeScript, Python, Go. Humans see one language at a time. Use the variant that matches the user's stack; behavior is the same across tabs.

```typescript TypeScript expandable theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
// Headers on every ambient call after login:
//   sdp_suki_token: <suki_token from Login>
//   sdp_provider_id: <Provider ID>  // only when your partnership requires it

// 1. Create the ambient session and opt into E/M Coding
const createRes = await fetch("https://sdp.suki.ai/api/v1/ambient/session/create", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    sdp_suki_token: sukiToken,
  },
  body: JSON.stringify({
    artifacts: ["EM_CODES"],
    emr_encounter_id: "visit-123",
  }),
});
const { ambient_session_id, note_id } = await createRes.json();
// store ambient_session_id and note_id with the visit

// 2. Seed visit details coding needs (before you end the recording)
await fetch(`https://sdp.suki.ai/api/v1/ambient/session/${ambient_session_id}/context`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    sdp_suki_token: sukiToken,
  },
  body: JSON.stringify({
    patient: {
      patient_type: "ESTABLISHED_PATIENT",
      dob: "1952-03-15",
      sex: "female",
    },
    visit: {
      date_of_service: "2026-01-15",
      total_time_minutes: 35,
      visit_type: "ESTABLISHED_PATIENT",
    },
  }),
});

// 3. Stream audio and end the session with your existing ambient flow
// 4. Wait until ambient status is completed (poll status, or confirm after webhook SUCCESS)

// 5. Retrieve recommended codes for this recording
const codesRes = await fetch(
  `https://sdp.suki.ai/api/v1/ambient/session/${ambient_session_id}/structured-data/em-codes`,
  { headers: { sdp_suki_token: sukiToken } },
);
const { em_codes } = await codesRes.json();
// Review UI: em_codes.values[].code plus the single populated reason object
// note_id is available when you prefer note-scoped retrieve
void note_id;
void em_codes;
```

```python Python expandable theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
# Headers on every ambient call after login:
#   sdp_suki_token: <suki_token from Login>
#   sdp_provider_id: <Provider ID>  # only when your partnership requires it

import requests

BASE_URL = "https://sdp.suki.ai"
headers = {
    "Content-Type": "application/json",
    "sdp_suki_token": suki_token,
}

# 1. Create the ambient session and opt into E/M Coding
create_res = requests.post(
    f"{BASE_URL}/api/v1/ambient/session/create",
    headers=headers,
    json={
        "artifacts": ["EM_CODES"],
        "emr_encounter_id": "visit-123",
    },
    timeout=60,
)
create_body = create_res.json()
ambient_session_id = create_body["ambient_session_id"]
note_id = create_body["note_id"]
# store ambient_session_id and note_id with the visit

# 2. Seed visit details coding needs (before you end the recording)
requests.post(
    f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/context",
    headers=headers,
    json={
        "patient": {
            "patient_type": "ESTABLISHED_PATIENT",
            "dob": "1952-03-15",
            "sex": "female",
        },
        "visit": {
            "date_of_service": "2026-01-15",
            "total_time_minutes": 35,
            "visit_type": "ESTABLISHED_PATIENT",
        },
    },
    timeout=60,
)

# 3. Stream audio and end the session with your existing ambient flow
# 4. Wait until ambient status is completed (poll status, or confirm after webhook SUCCESS)

# 5. Retrieve recommended codes for this recording
codes_res = requests.get(
    f"{BASE_URL}/api/v1/ambient/session/{ambient_session_id}/structured-data/em-codes",
    headers={"sdp_suki_token": suki_token},
    timeout=60,
)
em_codes = codes_res.json()["em_codes"]
# Review UI: em_codes["values"][i]["code"] plus the single populated reason object
# note_id is available when you prefer note-scoped retrieve
```

```go Go expandable theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
// Headers on every ambient call after login:
//   sdp_suki_token: <suki_token from Login>
//   sdp_provider_id: <Provider ID>  // only when your partnership requires it
//
// Uses: bytes, encoding/json, net/http

const baseURL = "https://sdp.suki.ai"

// 1. Create the ambient session and opt into E/M Coding
createBody, _ := json.Marshal(map[string]any{
	"artifacts":         []string{"EM_CODES"},
	"emr_encounter_id": "visit-123",
})
createReq, _ := http.NewRequest(http.MethodPost, baseURL+"/api/v1/ambient/session/create", bytes.NewReader(createBody))
createReq.Header.Set("Content-Type", "application/json")
createReq.Header.Set("sdp_suki_token", sukiToken)
createRes, _ := http.DefaultClient.Do(createReq)
defer createRes.Body.Close()
var createOut struct {
	AmbientSessionID string `json:"ambient_session_id"`
	NoteID           string `json:"note_id"`
}
json.NewDecoder(createRes.Body).Decode(&createOut)
ambientSessionID := createOut.AmbientSessionID // store with the visit
noteID := createOut.NoteID

// 2. Seed visit details coding needs (before you end the recording)
contextBody, _ := json.Marshal(map[string]any{
	"patient": map[string]any{
		"patient_type": "ESTABLISHED_PATIENT",
		"dob":          "1952-03-15",
		"sex":          "female",
	},
	"visit": map[string]any{
		"date_of_service":    "2026-01-15",
		"total_time_minutes": 35,
		"visit_type":         "ESTABLISHED_PATIENT",
	},
})
contextReq, _ := http.NewRequest(
	http.MethodPost,
	baseURL+"/api/v1/ambient/session/"+ambientSessionID+"/context",
	bytes.NewReader(contextBody),
)
contextReq.Header.Set("Content-Type", "application/json")
contextReq.Header.Set("sdp_suki_token", sukiToken)
contextRes, _ := http.DefaultClient.Do(contextReq)
contextRes.Body.Close()

// 3. Stream audio and end the session with your existing ambient flow
// 4. Wait until ambient status is completed (poll status, or confirm after webhook SUCCESS)

// 5. Retrieve recommended codes for this recording
codesReq, _ := http.NewRequest(
	http.MethodGet,
	baseURL+"/api/v1/ambient/session/"+ambientSessionID+"/structured-data/em-codes",
	nil,
)
codesReq.Header.Set("sdp_suki_token", sukiToken)
codesRes, _ := http.DefaultClient.Do(codesReq)
defer codesRes.Body.Close()
var codesOut struct {
	EMCodes json.RawMessage `json:"em_codes"`
}
json.NewDecoder(codesRes.Body).Decode(&codesOut)
emCodes := codesOut.EMCodes
// Review UI: em_codes.values[].code plus the single populated reason object
_ = noteID
_ = emCodes
```

## Best practices

> [!TIP]
>
> * Turn on E/M Coding when you create the session by setting `artifacts` to `EM_CODES`, because if you leave it out, coding does not run for that visit.
> * Send patient, visit, and diagnosis details before you end the session. Details that arrive after the session ends are too late for this visit.
> * Send ICD-10 or IMO on diagnoses, since those are the problem codes Suki uses with the note when it recommends the E/M code, and you can include SNOMED even though Suki does not use it for that recommendation. Do not send HCC, because that type is not accepted.
> * Send `total_time_minutes` only when you bill by time, and only when the value is greater than 0.
> * Confirm ambient status is `completed` before you treat the note or the codes as ready. Webhook `SUCCESS` means processing finished; still confirm status.

## Troubleshooting

> [accordion] Coding Fails or Is Skipped
>
> The ambient job can still complete, and the ambient success webhook can still fire. Show the note. Treat empty `em_codes.values` as no recommendation for this visit.

> [accordion] No Codes Generated
>
> Dedicated E/M endpoints return `{ "em_codes": { "values": [] } }`. Read `values.length` (or equivalent). Do not treat a missing code list as a transport error.

> [accordion] Encounter EM Retrieve Before Session Completes
>
> Response can be `200` with empty `values`. Wait until ambient status is `completed`, then call again.

> [accordion] Retention Error on EM Retrieve
>
> Ambient E/M retrieve can return `404` with a retention message after the codes are no longer available. Retrieve soon after the ambient session completes. Do not assume the standalone 30-day window applies here.

> [accordion] Note-Level vs Session-Level EM Retrieve
>
> Note returns codes stored for that note across sessions. Session returns codes for that recording. Encounter uses the latest completed session for that encounter. Pick the scope that matches the screen you are building.

## Next steps

&#x20;**[Get the generated E/M codes](https://developer.suki.ai/documentation/how-to/em-coding/retrieve-em-codes.md)** - Response fields and how to show the reason in your review UI.

&#x20;**[Choose Ambient or standalone](https://developer.suki.ai/documentation/concepts/em-coding/choose-ambient-or-standalone.md)** - Confirm this is the right path for the visit.

&#x20;**[Create an ambient session](https://developer.suki.ai/documentation/how-to/ambient-clinical-notes/create-ambient-session.md)** - Start the ambient visit and store the session and note ids.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.