# Diagnose

```
The Diagnose endpoint surfaces potential differential diagnoses for clinicians to consider with explainable and referenced rationale
```

## Overview

The Diagnose API analyzes a patient's clinical data — represented as a structured graph — and returns a ranked list of candidate diagnoses, each supported by evidence-based rationale drawn from clinical guidelines and diagnostic criteria.

The patient graph submitted to the Diagnose API follows the same structure produced by the [Assemble API](#assemble-api), which builds a patient graph from a FHIR bundle. It is recommended to use the Assemble API to construct and validate your patient graph before passing it to the Diagnose API.

***

## Workflow

```
FHIR Bundle ──► POST /v1/assemble ──► Patient Graph ──► POST /v1/diagnose ──► Diagnoses
```

{% stepper %}
{% step %}

### Assemble

Submit a FHIR bundle to `POST /v1/assemble` to construct a structured patient graph (`AssembledPatient`).
{% endstep %}

{% step %}

### Diagnose

Submit the resulting patient graph to `POST /v1/diagnose` to retrieve ranked candidate diagnoses.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Note:** While the Assemble API returns an `AssembledPatient` object, the Diagnose API accepts a `CustomAssembledPatient` object. This is an extended variant that supports additional metadata fields such as `family_member_history_metadata` and a custom observation metadata model. Ensure your patient graph conforms to the `CustomAssembledPatient` schema described below before submitting to the Diagnose endpoint.
{% endhint %}

***

## Endpoint

```
POST /v1/diagnose
```

### Authentication

All requests require an API key passed in the request header:

```
x-api-key: <your-api-key>
```

***

## Request

### Headers

| Header         | Value              | Required |
| -------------- | ------------------ | -------- |
| `x-api-key`    | Your API key       | Yes      |
| `Content-Type` | `application/json` | Yes      |

### Request Body

The request body must be a `CustomAssembledPatient` object — an extended form of the patient graph produced by the Assemble API. It contains the patient's clinical graph as a set of nodes, edges, and demographic information.

| Field           | Type                   | Required | Description                                                 |
| --------------- | ---------------------- | -------- | ----------------------------------------------------------- |
| `nodes`         | `CustomAssembleNode[]` | Yes      | Array of clinical graph nodes representing patient findings |
| `relationships` | `AssembleEdge[]`       | Yes      | Array of edges connecting nodes in the patient graph        |
| `demographics`  | `PatientDemographics`  | Yes      | Patient demographic information                             |

#### Patient Demographics

| Field    | Type            | Required | Description    |
| -------- | --------------- | -------- | -------------- |
| `age`    | integer \| null | Yes      | Patient age    |
| `gender` | string \| null  | Yes      | Patient gender |
| `race`   | string \| null  | Yes      | Patient race   |

#### Node Object (`CustomAssembleNode`)

Each node represents a clinical finding or concept in the patient's history. This extends the `AssembleNode` structure returned by the Assemble API with additional metadata support.

| Field                   | Type                                 | Required | Description                                       |
| ----------------------- | ------------------------------------ | -------- | ------------------------------------------------- |
| `node_type`             | string                               | Yes      | Discriminator for the node subtype                |
| `fhir_id`               | string \| null                       | Yes      | FHIR resource identifier                          |
| `notable`               | boolean                              | Yes      | Whether this node is notable/clinically important |
| `system_id`             | string \| null                       | Yes      | System identifier for the node                    |
| `system_preferred_name` | string \| null                       | Yes      | Preferred clinical name                           |
| `other_system_ids`      | string\[] \| null                    | No       | Additional system identifiers                     |
| `coding`                | `ExternalCoding[]` \| null           | No       | External coding references (e.g. SNOMED, ICD)     |
| `metadata`              | `CustomAssembleNodeMetadata` \| null | No       | Clinical metadata for the node                    |

#### External Coding (`ExternalCoding`)

| Field     | Type           | Required | Description                                   |
| --------- | -------------- | -------- | --------------------------------------------- |
| `code`    | string \| null | Yes      | Clinical code                                 |
| `system`  | string \| null | Yes      | Coding system (e.g. `http://snomed.info/sct`) |
| `display` | string \| null | Yes      | Human-readable display name                   |

#### Node Metadata (`CustomAssembleNodeMetadata`)

This extends the `AssembleNodeMetadata` structure from the Assemble API with support for `family_member_history_metadata` and a custom observation metadata model.

| Field                            | Type                                  | Required | Description                             |
| -------------------------------- | ------------------------------------- | -------- | --------------------------------------- |
| `condition_metadata`             | `ConditionMetadata` \| null           | No       | Metadata for condition nodes            |
| `observation_metadata`           | `CustomObservationMetadata` \| null   | No       | Metadata for observation nodes          |
| `intervention_metadata`          | `InterventionMetadata` \| null        | No       | Metadata for medication/procedure nodes |
| `allergy_metadata`               | `AllergyMetadata` \| null             | No       | Metadata for allergy nodes              |
| `family_member_history_metadata` | `FamilyMemberHistoryMetadata` \| null | No       | Metadata for family history nodes       |

#### Condition Metadata

| Field               | Type                 | Required | Description                      |
| ------------------- | -------------------- | -------- | -------------------------------- |
| `clinicalStatus`    | `ClinicalStatusEnum` | Yes      | Clinical status of the condition |
| `ccsr_categories`   | string\[] \| null    | No       | CCSR classification categories   |
| `ccsr_body_systems` | string\[] \| null    | No       | Affected body systems            |
| `onsetDateTime`     | datetime \| null     | No       | Date/time of condition onset     |
| `recordedDate`      | datetime \| null     | No       | Date/time condition was recorded |

**`ClinicalStatusEnum` values:**\
`active` | `recurrence` | `relapse` | `inactive` | `remission` | `resolved` | `unknown`

#### Observation Metadata (`CustomObservationMetadata`)

{% hint style="info" %}
**Note:** The Diagnose API uses a `CustomObservationMetadata` model rather than the standard `ObservationMetadata` returned by the Assemble API. The key difference is the addition of a `value_quantity` field using a `CustomQuantityType`, which corrects a known handling issue with numeric values in the standard `QuantityType`.
{% endhint %}

| Field              | Type                                    | Required | Description                          |
| ------------------ | --------------------------------------- | -------- | ------------------------------------ |
| `category`         | string\[] \| null                       | No       | Observation category                 |
| `interpretation`   | `ObservationInterpretationEnum` \| null | No       | Clinical interpretation of the value |
| `risk`             | `RiskTypeEnum`                          | Yes      | Risk classification                  |
| `risk_direction`   | `RiskDirectionEnum`                     | Yes      | Direction of risk                    |
| `observation_time` | datetime                                | Yes      | Time the observation was recorded    |
| `value_quantity`   | `CustomQuantityType` \| null            | No       | Quantitative observation value       |

**`RiskTypeEnum` values:**\*\* `optimal` | `low` | `normal` | `high`\
\&#xNAN;**`RiskDirectionEnum` values:**\*\* `high` | `very high` | `low` | `very low`

#### Quantity Type (`CustomQuantityType`)

| Field        | Type           | Required | Description                 |
| ------------ | -------------- | -------- | --------------------------- |
| `value`      | number \| null | No       | Numeric value               |
| `unit`       | string \| null | No       | Unit of measure             |
| `system`     | string \| null | No       | Unit coding system          |
| `code`       | string \| null | No       | Unit code                   |
| `comparator` | string \| null | No       | Comparator (e.g. `<`, `>=`) |

#### Intervention Metadata

| Field               | Type                     | Required | Description          |
| ------------------- | ------------------------ | -------- | -------------------- |
| `intervention_type` | `InterventionTypeEnum`   | Yes      | Type of intervention |
| `status`            | `InterventionStatusEnum` | Yes      | Current status       |
| `intervention_time` | datetime                 | Yes      | Time of intervention |

**`InterventionTypeEnum` values:**\*\* `medication` | `procedure` | `immunization`\
\&#xNAN;**`InterventionStatusEnum` values:**\*\* `active` | `on-hold` | `cancelled` | `completed` | `stopped` | `draft` | `unknown` | `entered-in-error` | `not-done` | `in-progress`

#### Allergy Metadata

| Field                | Type                             | Required | Description                    |
| -------------------- | -------------------------------- | -------- | ------------------------------ |
| `clinicalStatus`     | `ClinicalStatusEnum` \| null     | No       | Clinical status of the allergy |
| `verificationStatus` | `VerificationStatusEnum` \| null | No       | Verification status            |
| `criticality`        | `CriticalityEnum` \| null        | No       | Criticality level              |
| `recordedDate`       | datetime \| null                 | No       | Date allergy was recorded      |

**`VerificationStatusEnum` values:**\*\* `unconfirmed` | `confirmed` | `refuted` | `entered-in-error`\
\&#xNAN;**`CriticalityEnum` values:**\*\* `low` | `high` | `unable-to-assess`

#### Family Member History Metadata

{% hint style="info" %}
**Note:** This metadata type is available in the Diagnose API's `CustomAssembleNodeMetadata` but is not present in the base `AssembleNodeMetadata` returned by the Assemble API. It must be added to the patient graph prior to submitting to the Diagnose endpoint where family history is clinically relevant.
{% endhint %}

| Field      | Type                                    | Required | Description                                       |
| ---------- | --------------------------------------- | -------- | ------------------------------------------------- |
| `status`   | `FamilyMemberHistoryStatusEnum` \| null | No       | Status of the family history record               |
| `relation` | string \| null                          | No       | Relationship to patient (e.g. `father`, `mother`) |
| `sex`      | string \| null                          | No       | Sex of the family member                          |
| `onsetAge` | integer \| null                         | No       | Age of condition onset in the family member       |

**`FamilyMemberHistoryStatusEnum` values:**\*\* `partial` | `completed` | `entered-in-error` | `health-unknown`

#### Edge Object (`AssembleEdge`)

Edges follow the same structure as those produced by the Assemble API.

| Field             | Type   | Required | Description                         |
| ----------------- | ------ | -------- | ----------------------------------- |
| `source`          | string | Yes      | `system_id` of the source node      |
| `target`          | string | Yes      | `system_id` of the target node      |
| `relationship_id` | string | Yes      | Identifier of the relationship type |

***

## Response

### Success Response — `200 OK`

Returns a `DiagnoseOutput` object containing a ranked list of candidate diagnoses.

```json
{
  "diagnoses": [
    {
      "system_id": "string",
      "display_name": "string",
      "score": 0.95,
      "rationale": {
        "overview": {
          "text": "string",
          "references": []
        },
        "diagnostic_evidence": [],
        "relevant_family_history": []
      }
    }
  ]
}
```

### Response Schema

#### `DiagnoseOutput`

| Field       | Type          | Required | Description                        |
| ----------- | ------------- | -------- | ---------------------------------- |
| `diagnoses` | `Diagnosis[]` | Yes      | Ranked list of candidate diagnoses |

#### `Diagnosis`

| Field          | Type                | Required | Description                                              |
| -------------- | ------------------- | -------- | -------------------------------------------------------- |
| `system_id`    | string              | Yes      | System Interoperable Variable ID for the diagnosis       |
| `display_name` | string \| null      | No       | Human-readable diagnosis name                            |
| `score`        | number \| integer   | Yes      | Evidence score — higher values indicate stronger support |
| `rationale`    | `Rationale` \| null | No       | Detailed evidence rationale for the diagnosis            |

#### `Rationale`

| Field                     | Type                              | Description                                |
| ------------------------- | --------------------------------- | ------------------------------------------ |
| `overview`                | `DiagnosisOverview` \| null       | Summary and guideline references           |
| `diagnostic_evidence`     | `DiagnosticCriterion[]` \| null   | Criteria evaluated against patient data    |
| `relevant_family_history` | `RelevantFamilyHistory[]` \| null | Clinically relevant family history entries |

#### `DiagnosisOverview`

| Field        | Type                           | Description                                                     |
| ------------ | ------------------------------ | --------------------------------------------------------------- |
| `text`       | string \| null                 | Plain-language summary of why the diagnosis is being considered |
| `references` | `GuidelineReference[]` \| null | Clinical guidelines used to evaluate the diagnosis              |

#### `GuidelineReference`

| Field                 | Type              | Required | Description                               |
| --------------------- | ----------------- | -------- | ----------------------------------------- |
| `title`               | string            | Yes      | Title of the guideline document           |
| `authoring_societies` | string\[] \| null | No       | Organizations that authored the guideline |

#### `DiagnosticCriterion`

Represents a single diagnostic criterion evaluated against the patient's data.

| Field             | Type             | Required | Description                                                                   |
| ----------------- | ---------------- | -------- | ----------------------------------------------------------------------------- |
| `evidence_type`   | string           | Yes      | Whether this criterion `matches`, is `missing`, or `contradicts` patient data |
| `criterion`       | string           | Yes      | Criterion expression as stated in guidelines (e.g. `"TSH high"`)              |
| `patient_finding` | string \| null   | No       | The corresponding patient finding                                             |
| `fhir_id`         | string \| null   | No       | FHIR ID of the supporting resource                                            |
| `patient_value`   | string \| null   | No       | Observed value from the patient                                               |
| `time_recorded`   | datetime \| null | No       | When the finding was recorded                                                 |

#### `RelevantFamilyHistory`

| Field              | Type                           | Required | Description                                        |
| ------------------ | ------------------------------ | -------- | -------------------------------------------------- |
| `condition_name`   | string                         | Yes      | Name of the family member's condition              |
| `explanation`      | string                         | Yes      | Clinical explanation of relevance to the diagnosis |
| `relation_code`    | string \| null                 | No       | Coded relation to patient                          |
| `relation_display` | string \| null                 | No       | Human-readable relation (e.g. `"mother"`)          |
| `onset_age`        | integer \| null                | No       | Age of onset in the family member                  |
| `references`       | `GuidelineReference[]` \| null | No       | Supporting guideline references                    |

***

## Error Responses

| HTTP Status                | Description                                                            |
| -------------------------- | ---------------------------------------------------------------------- |
| `200 OK`                   | Successful response with diagnoses                                     |
| `422 Unprocessable Entity` | Request body failed validation — check field types and required fields |

### Validation Error Schema

```json
{
  "detail": [
    {
      "loc": ["body", "nodes"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
```

***

## Example Request

The following example submits a patient graph with a single condition node (hypothyroidism) and observation node (elevated TSH) to retrieve candidate diagnoses. This graph was first assembled using the Assemble API from a FHIR bundle, then extended with family history metadata before being submitted here.

```bash
curl -X POST https://cg-api-prod.system.com/v1/diagnose \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "nodes": [
    {
      "node_type": "condition",
      "fhir_id": "condition-001",
      "notable": true,
      "system_id": "sys-hypothyroidism",
      "system_preferred_name": "Hypothyroidism",
      "coding": [
        {
          "code": "40930008",
          "system": "http://snomed.info/sct",
          "display": "Hypothyroidism"
        }
      ],
      "metadata": {
        "condition_metadata": {
          "clinicalStatus": "active",
          "ccsr_body_systems": ["Endocrine system"],
          "onsetDateTime": "2023-01-15T00:00:00Z"
        }
      }
    },
    {
      "node_type": "observation",
      "fhir_id": "obs-001",
      "notable": true,
      "system_id": "sys-tsh-high",
      "system_preferred_name": "TSH elevated",
      "metadata": {
        "observation_metadata": {
          "risk": "high",
          "risk_direction": "high",
          "observation_time": "2024-03-01T08:30:00Z",
          "interpretation": "high",
          "value_quantity": {
            "value": 8.5,
            "unit": "mIU/L",
            "system": "http://unitsofmeasure.org",
            "code": "mIU/L"
          }
        }
      }
    },
    {
      "node_type": "family_history",
      "fhir_id": "fh-001",
      "notable": false,
      "system_id": "sys-fh-thyroid",
      "system_preferred_name": "Family history of thyroid disorder",
      "metadata": {
        "family_member_history_metadata": {
          "status": "completed",
          "relation": "mother",
          "sex": "female",
          "onsetAge": 52
        }
      }
    }
  ],
  "relationships": [
    {
      "source": "sys-tsh-high",
      "target": "sys-hypothyroidism",
      "relationship_id": "rel-tsh-hypothyroidism"
    },
    {
      "source": "sys-fh-thyroid",
      "target": "sys-hypothyroidism",
      "relationship_id": "rel-fh-hypothyroidism"
    }
  ],
  "demographics": {
    "age": 45,
    "gender": "female",
    "race": "white"
  }
}'
```

## Example Response

```json
{
  "diagnoses": [
    {
      "system_id": "sys-hypothyroidism-primary",
      "display_name": "Primary Hypothyroidism",
      "score": 0.92,
      "rationale": {
        "overview": {
          "text": "Patient presents with elevated TSH and active hypothyroidism diagnosis, consistent with primary hypothyroidism per ATA guidelines. Maternal history of thyroid disorder further supports this diagnosis.",
          "references": [
            {
              "title": "American Thyroid Association Guidelines for Hypothyroidism in Adults",
              "authoring_societies": ["American Thyroid Association"]
            }
          ]
        },
        "diagnostic_evidence": [
          {
            "evidence_type": "matches",
            "criterion": "TSH high",
            "patient_finding": "TSH elevated",
            "fhir_id": "obs-001",
            "patient_value": "8.5 mIU/L",
            "time_recorded": "2024-03-01T08:30:00Z"
          }
        ],
        "relevant_family_history": [
          {
            "condition_name": "Thyroid disorder",
            "explanation": "Maternal history of thyroid disorder increases risk of primary hypothyroidism.",
            "relation_code": "MTH",
            "relation_display": "mother",
            "onset_age": 52,
            "references": [
              {
                "title": "American Thyroid Association Guidelines for Hypothyroidism in Adults",
                "authoring_societies": ["American Thyroid Association"]
              }
            ]
          }
        ]
      }
    }
  ]
}
```

***

## Key Concepts

### Patient Graph and the Assemble API

The Diagnose API requires the patient's clinical data to be represented as a structured **graph**. The recommended approach is to use the `POST /v1/assemble` endpoint to generate this graph from a FHIR bundle. The Assemble API resolves FHIR resources into typed, system-mapped nodes and edges that are directly compatible with the Diagnose API's input schema.

Once assembled, the graph may be enriched with additional data — such as family member history metadata — before being submitted to the Diagnose endpoint.

* **Nodes** represent individual clinical findings such as conditions, observations, medications, allergies, and family history entries
* **Edges (Relationships)** represent the clinical connections between those findings

### Evidence Scoring

Each returned diagnosis is assigned a **score** reflecting the strength of supporting evidence from clinical guidelines and diagnostic criteria. Higher scores indicate stronger alignment with established diagnostic criteria.

### Diagnostic Evidence Types

Each `DiagnosticCriterion` within the rationale includes an `evidence_type` field indicating its relationship to the patient's data:

| Evidence Type | Meaning                                                       |
| ------------- | ------------------------------------------------------------- |
| `matches`     | The patient's data satisfies this diagnostic criterion        |
| `missing`     | This criterion is expected but absent from the patient's data |
| `contradicts` | The patient's data is inconsistent with this criterion        |

***

## Notes

* Use `POST /v1/assemble` to build the patient graph from a FHIR bundle before calling this endpoint.
* The `demographics` object requires `age`, `gender`, and `race` — all are required fields.
* The `notable` flag on each node should be set to `true` for clinically significant findings that should be weighted more heavily during diagnosis evaluation.
* Family history nodes with `family_member_history_metadata` can influence diagnosis scoring where hereditary factors are clinically relevant. This metadata is an extension beyond what the Assemble API returns and must be added manually if required.
* The `CustomObservationMetadata` used by this endpoint differs from the standard `ObservationMetadata` in the Assemble API — specifically in its handling of the `value_quantity` field. Ensure observation nodes use the `CustomQuantityType` format when submitting quantitative values.
