> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://imo.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://imo.ferndocs.com/_mcp/server.

# Sessions and feedback

Normalization returns ranked candidates. Which one a clinician *picked* is the
signal that improves future results — and the only way IMO learns your
population's intent.

Two endpoints close that loop:

#### Create a session

`GET /precision/normalize/session` issues a `session_id`.

**`TypeScript`**

```typescript title="TypeScript"
const { sessionId } = await client.sessions.create();
```

**`Python`**

```python title="Python"
session = client.sessions.create()
session_id = session.session_id
```

**`Java`**

```java title="Java"
SessionResponse session = client.sessions().create();
String sessionId = session.getSessionId().orElseThrow();
```

#### Pass it on your normalize calls

Both `normalize` and `enrich` accept a top-level `session_id`:

```typescript
const result = await client.normalize.normalize({
  clientRequestId: "search-42",
  sessionId,
  requests: [{ recordId: "1", domain: "Problem", inputTerm: "chest pain" }],
});
```

#### Log what the user selected

`POST /precision/normalize/event/selection` reports the chosen lexicals.

**`TypeScript`**

```typescript title="TypeScript"
await client.events.logSelection({
  sessionId,
  resultSelected: [
    { recordId: "1", imoLexicalCode: "3763" },
  ],
});
```

**`Python`**

```python title="Python"
from imo_precision_normalize import EventSelectionRequestResultSelectedItem

client.events.log_selection(
    session_id=session_id,
    result_selected=[
        EventSelectionRequestResultSelectedItem(
            record_id="1", imo_lexical_code="3763"
        )
    ],
)
```

**`Java`**

```java title="Java"
client.events().logSelection(
    EventSelectionRequest.builder()
        .sessionId(sessionId)
        .resultSelected(List.of(
            ResultSelected.builder()
                .recordId("1")
                .imoLexicalCode("3763")
                .build()))
        .build());
```

## Field reference

**`session_id`** `string` — required

The session identifier from `sessions.create()`. Maximum 36 characters.

---

**`result_selected`** `array` — required

Up to **300** selections per call. Each entry pairs the `record_id` from your
normalize request with the `imo_lexical_code` the user chose.

---

**`result_selected[].record_id`** `string`

Your record identifier, matching the one you sent to normalize. Nullable,
maximum 300 characters.

---

**`result_selected[].imo_lexical_code`** `string`

The `lexical_code` of the selected item. Nullable, maximum 500 characters.

---

## A realistic flow

A clinician types into a problem-list search box. You normalize, show the top
candidates, and report the click.

```typescript
// One session per user search session, reused across keystrokes.
const { sessionId } = await client.sessions.create();

async function search(text: string) {
  const result = await client.normalize.normalize({
    clientRequestId: crypto.randomUUID(),
    sessionId,
    preferences: { threshold: 0.5, size: 8 },
    requests: [{ recordId: "q", domain: "Problem", inputTerm: text }],
  });
  return result.requests?.[0]?.response?.items ?? [];
}

async function onPick(lexicalCode: string) {
  // Fire-and-forget: feedback should never block the UI.
  void client.events.logSelection({
    sessionId,
    resultSelected: [{ recordId: "q", imoLexicalCode: lexicalCode }],
  });
}
```

> **Tip**
>
> Create one session per user workflow, not per request. Reusing a session is what
> lets IMO tie a sequence of searches to the single selection that ended it.

> **Note**
>
> Selection events are for continuous improvement and usage tracking. Sending them
> is optional — normalization works without a session — but the ranking quality you
> get back improves when you do.