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

# Generate E/M Codes with Existing Note

> Submit a completed clinical note through the standalone E/M Coding APIs, wait until coding finishes, and retrieve the recommended codes

Quick summary

When your application or EHR already has a completed clinical note, submit it with the standalone E/M Coding APIs.
Suki analyzes the submitted note and returns recommended E/M codes. Store the coding `session_id` from generate so you can check status and retrieve the codes.

Last updated:
November 2026

Use the standalone E/M Coding APIs when your application or EHR creates the clinical note. Once the note is complete, call [Generate E/M codes](https://developer.suki.ai/em-coding-api-reference/em-coding-sessions/generate.md) with the note sections and visit details.

Suki analyzes the note and visit details to recommend Evaluation and Management (E/M) codes based on the services documented for the encounter.

> [!NOTE]
>
> The standalone E/M Coding APIs do not create or modify clinical notes. Suki bases its recommendations on the documentation you submit and does not infer services that are not recorded in the note.

The response includes a `session_id` that identifies the coding request. Store this ID with the encounter and use it to check the processing status and retrieve the recommended codes when processing is complete, passing the coding `session_id` to these endpoints rather than an ambient session ID.

If Suki generates the clinical note from the clinician-patient conversation, enable E/M Coding on the ambient session instead. Suki returns the recommended codes with the completed note. Do not submit the same encounter through the standalone APIs. See [Add E/M codes to an ambient visit](https://developer.suki.ai/documentation/how-to/em-coding/generate-with-ambient.md).

## Prerequisites

* 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 you are unsure.
* At least one note section with a [LOINC code](https://developer.suki.ai/documentation/concepts/ambient-clinical-notes/note-sections.md) and the section text.

## Steps to generate E/M codes from a note

**1. Authenticate**

Call Login, and Register once if this user is new. Send the returned token as `sdp_suki_token` on every E/M Coding request. If your partnership uses a Provider ID on each call, send `sdp_provider_id` as well.

**2. Submit the Note**

POST the completed note to `/api/v1/em-codes`, and Suki starts coding recommendations after this call returns. The generated response does not include the recommended codes.

### Request body

Send the finished note in `sections`. Add patient, provider, encounter, and diagnoses when your EHR already has them, since those fields are optional and an ICD-10 or IMO diagnosis is a problem Suki uses with the note when it recommends the E/M code.

**sections** `array` *required*

The clinical note Suki codes from. Each item is one note section with a [LOINC code](https://developer.suki.ai/documentation/concepts/ambient-clinical-notes/note-sections.md) in `loinc` and the section text in `content`. Set `content.type` to `TEXT` and put the prose in `content.text`. At least one section must include non-empty text, or generate returns `400`.

**properties**

**loinc** `string` *required*

LOINC for that note section, for example `10164-2` for History of Present Illness.

**content** `object` *required*

Section body. `type` must be `TEXT`. `text` is the section prose.

**patient** `object`

Optional Patient facts that can change new vs established coding and support the visit. Send what you have. Leave the object out when you have nothing useful.

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

**speciality** `string`

Provider specialty as your EHR stores it. The API field name is `speciality`.

**encounter** `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.

A successful call returns `201` and a `session_id`. Store that `session_id` with the note.

**3. Wait Until Coding Finishes**

Poll [Get E/M coding status](https://developer.suki.ai/em-coding-api-reference/em-coding-sessions/status.md) with that `session_id` until status is `completed` or `failed`. Status values are `created`, `running`, `completed`, and `failed`.

If webhooks are enabled, you can wait for the E/M Coding notification instead. On that payload, `additional_info.session_type` is `EM_CODES`. See [E/M Coding webhook events](https://developer.suki.ai/documentation/webhook/em-coding/overview.md).

**4. Retrieve the Codes**

When status is `completed`, call [Get E/M codes](https://developer.suki.ai/em-coding-api-reference/em-coding-sessions/get.md) and show `em_codes.values` in your review UI. Standalone codes stay available for 30 days. After that, retrieve can return that the codes are no longer available. See [Get the generated E/M codes](https://developer.suki.ai/documentation/how-to/em-coding/retrieve-em-codes.md) for the response fields.

## Example request body

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "sections": [
    {
      "loinc": "10164-2",
      "content": {
        "type": "TEXT",
        "text": "Established patient follow-up for hypertension. Medication adjusted."
      }
    }
  ],
  "patient": {
    "patient_type": "ESTABLISHED_PATIENT",
    "dob": "1952-03-15"
  },
  "encounter": {
    "date_of_service": "2026-01-15",
    "total_time_minutes": 30
  }
}
```

## Example responses

### Generate (`201`)

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

### Status (while you poll)

```json theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
{
  "status": "completed"
}
```

### Get codes (when status is `completed`)

When the coding session reaches `completed`, call [Get E/M codes](https://developer.suki.ai/em-coding-api-reference/em-coding-sessions/get.md) with the same `session_id` to retrieve Suki's recommendations.

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": [
      /* One object for each recommended E/M code */
    ]
  }
}
```

Each object in `values` represents one recommended E/M code. Use the following fields to display the recommendation in your review UI:

| Field | Description |
| :- | :- |
| `code` | The recommended E/M code, such as `99214`. |
| `family` | The E/M code family. |
| `level` | The recommended coding level. |
| `patient_type` | The patient category used for the recommendation (`NEW_PATIENT` or `ESTABLISHED_PATIENT`). |
| `modifiers` | Any applicable code modifiers. Display this field only when the array contains values. |
| `add_on_codes` | Any additional codes recommended with the E/M code. Display this field only when the array contains values. |

### Explain why Suki recommended the code in your review UI

Each code object includes exactly **one** set of supporting details: `mdm_based_features`, `time_based_features`, or `wellness_features`. The object present identifies the basis for the recommendation. Use its contents to explain the coding rationale in your review UI.

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

For a complete response example and descriptions of all response fields, refer to [Get the generated E/M codes](https://developer.suki.ai/documentation/how-to/em-coding/retrieve-em-codes.md#example-em_codes-response).

## Code example

The following code shows the end-to-end logic: submit the finished note, poll status until coding finishes, then retrieve `em_codes.values`.

**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 E/M Coding call after login:
//   sdp_suki_token: <suki_token from Login>
//   sdp_provider_id: <Provider ID>  // only when your partnership requires it

// 1. Submit the finished note (201 → coding session_id; codes are not in this response)
const generateRes = await fetch("https://sdp.suki.ai/api/v1/em-codes", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    sdp_suki_token: sukiToken,
  },
  body: JSON.stringify({
    sections: [
      {
        loinc: "10164-2",
        content: {
          type: "TEXT",
          text: "Established patient with hypertension. Medication adjusted. Follow-up planned.",
        },
      },
    ],
    patient: {
      dob: "1952-03-15",
      sex: "female",
      patient_type: "ESTABLISHED_PATIENT",
    },
    encounter: {
      date_of_service: "2026-01-15",
      total_time_minutes: 30,
      visit_type: "ESTABLISHED_PATIENT",
    },
  }),
});
const { session_id } = await generateRes.json(); // store with the note

// 2. Wait until coding finishes (created → running → completed | failed)
let status = "created";
while (status !== "completed" && status !== "failed") {
  const statusRes = await fetch(
    `https://sdp.suki.ai/api/v1/em-codes/${session_id}/status`,
    { headers: { sdp_suki_token: sukiToken } },
  );
  ({ status } = await statusRes.json());
  if (status === "completed" || status === "failed") break;
  // Sleep a few seconds between polls, or wait for the E/M Coding webhook instead
  await new Promise((r) => setTimeout(r, 3000));
}
if (status !== "completed") {
  throw new Error(`Coding ended with status=${status}`);
}

// 3. Retrieve recommended codes (available for 30 days)
const codesRes = await fetch(`https://sdp.suki.ai/api/v1/em-codes/${session_id}`, {
  headers: { sdp_suki_token: sukiToken },
});
const { em_codes } = await codesRes.json();
// Review UI: em_codes.values[].code plus the single populated reason object
// (mdm_based_features | time_based_features | wellness_features)
```

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

import time
import requests

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

# 1. Submit the finished note (201 → coding session_id; codes are not in this response)
generate_res = requests.post(
    f"{BASE_URL}/api/v1/em-codes",
    headers=headers,
    json={
        "sections": [
            {
                "loinc": "10164-2",
                "content": {
                    "type": "TEXT",
                    "text": (
                        "Established patient with hypertension. "
                        "Medication adjusted. Follow-up planned."
                    ),
                },
            }
        ],
        "patient": {
            "dob": "1952-03-15",
            "sex": "female",
            "patient_type": "ESTABLISHED_PATIENT",
        },
        "encounter": {
            "date_of_service": "2026-01-15",
            "total_time_minutes": 30,
            "visit_type": "ESTABLISHED_PATIENT",
        },
    },
    timeout=60,
)
session_id = generate_res.json()["session_id"]  # store with the note

# 2. Wait until coding finishes (created → running → completed | failed)
status = "created"
while status not in ("completed", "failed"):
    status_res = requests.get(
        f"{BASE_URL}/api/v1/em-codes/{session_id}/status",
        headers={"sdp_suki_token": suki_token},
        timeout=60,
    )
    status = status_res.json()["status"]
    if status in ("completed", "failed"):
        break
    # Sleep a few seconds between polls, or wait for the E/M Coding webhook instead
    time.sleep(3)
if status != "completed":
    raise RuntimeError(f"Coding ended with status={status}")

# 3. Retrieve recommended codes (available for 30 days)
codes_res = requests.get(
    f"{BASE_URL}/api/v1/em-codes/{session_id}",
    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
# (mdm_based_features | time_based_features | wellness_features)
```

```go Go expandable theme={"theme":{"light":"one-light","dark":"material-theme-darker"}}
// Headers on every E/M Coding 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, fmt, net/http, time

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

// 1. Submit the finished note (201 → coding session_id; codes are not in this response)
payload, _ := json.Marshal(map[string]any{
	"sections": []map[string]any{
		{
			"loinc": "10164-2",
			"content": map[string]any{
				"type": "TEXT",
				"text": "Established patient with hypertension. Medication adjusted. Follow-up planned.",
			},
		},
	},
	"patient": map[string]any{
		"dob":          "1952-03-15",
		"sex":          "female",
		"patient_type": "ESTABLISHED_PATIENT",
	},
	"encounter": map[string]any{
		"date_of_service":    "2026-01-15",
		"total_time_minutes": 30,
		"visit_type":         "ESTABLISHED_PATIENT",
	},
})
req, _ := http.NewRequest(http.MethodPost, baseURL+"/api/v1/em-codes", bytes.NewReader(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("sdp_suki_token", sukiToken)
generateRes, _ := http.DefaultClient.Do(req)
defer generateRes.Body.Close()
var generateOut struct {
	SessionID string `json:"session_id"`
}
json.NewDecoder(generateRes.Body).Decode(&generateOut)
sessionID := generateOut.SessionID // store with the note

// 2. Wait until coding finishes (created → running → completed | failed)
status := "created"
for status != "completed" && status != "failed" {
	statusReq, _ := http.NewRequest(http.MethodGet, baseURL+"/api/v1/em-codes/"+sessionID+"/status", nil)
	statusReq.Header.Set("sdp_suki_token", sukiToken)
	statusRes, _ := http.DefaultClient.Do(statusReq)
	var statusOut struct {
		Status string `json:"status"`
	}
	json.NewDecoder(statusRes.Body).Decode(&statusOut)
	statusRes.Body.Close()
	status = statusOut.Status
	if status == "completed" || status == "failed" {
		break
	}
	// Sleep a few seconds between polls, or wait for the E/M Coding webhook instead
	time.Sleep(3 * time.Second)
}
if status != "completed" {
	panic(fmt.Sprintf("Coding ended with status=%s", status))
}

// 3. Retrieve recommended codes (available for 30 days)
codesReq, _ := http.NewRequest(http.MethodGet, baseURL+"/api/v1/em-codes/"+sessionID, 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
// (mdm_based_features | time_based_features | wellness_features)
_ = emCodes
```

## Best practices

> [!TIP]
>
> * Store the coding `session_id` with the note. Do not pass an ambient session ID to these endpoints.
> * 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` when you bill by time, and only when the value is greater than 0.
> * Use `YYYY-MM-DD` for `dob` and `date_of_service`, and do not send future dates.
> * Match validation and retention errors from [E/M Coding error messages](https://developer.suki.ai/em-coding-api-reference/error-messages-em-coding.md) by the message text. The API returns sentences, not error ids.

## Troubleshooting

> [accordion] Status Is Failed
>
> Retrieve does not return usable codes for that session. Show the failure, retry generate if appropriate, or fall back to manual coding.

> [accordion] Session Older Than 30 Days
>
> Retrieve returns 404 with a retention message. Call retrieve within 30 days of generate.

> [accordion] Empty Sections or No Section Text
>
> Generate returns 400. Send at least one section with `loinc`, `content`, and non-empty text.

> [accordion] Ambient Session Id Used as Session Id
>
> Status or retrieve returns 404 (`invalid em coding session id`). Use the `session_id` from the generate `201` response.

## Next steps

&#x20;**[E/M Coding API quickstart](https://developer.suki.ai/em-coding-api-reference/quickstart.md)** - Paste-ready Python and TypeScript for the same flow.

&#x20;**[Get the generated E/M codes](https://developer.suki.ai/documentation/how-to/em-coding/retrieve-em-codes.md)** - What each field in the code means.

&#x20;**[Choose Ambient or standalone](https://developer.suki.ai/documentation/concepts/em-coding/choose-ambient-or-standalone.md)** - Confirm you should submit the note through the standalone APIs.


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