Skip to main content

Diagnose Endpoint

The diagnose endpoint is the core of the Knidian AI API, allowing you to generate differential diagnoses from clinical histories, optionally augmented with image or PDF files. You can receive the diagnosis asynchronously or via a Server-Sent Events (SSE) stream.

Generate Differential Diagnosis (Async)

This endpoint processes the clinical history and any provided files, returning the full differential diagnosis object once processing is complete.

Generate Differential Diagnosis (Async)
POST /diagnose

Request

Headers

HeaderRequiredDescription
Content-TypeYesMust be set to multipart/form-data
x-api-keyYesYour API key for authentication

Request Body (multipart/form-data)

The request should be sent as multipart/form-data.

ParameterTypeRequiredDescription
clinical_historystringNoThe clinical history text to analyze. Required if no files are provided.
languagestringNoThe language for the output diagnosis (e.g., 'en', 'es', 'pt'). Defaults to 'en' (English) if not provided. Input language is detected automatically.
filesFile (Array)NoAn array of files (images or PDFs) to include in the analysis. Required if clinical_history is not provided. Max 10 files. Max 20MB per file. Supported types: JPG, JPEG, PNG, WEBP, GIF, PDF.

Note: You must provide either clinical_history or at least one file in the files array.

Example Request (using JavaScript FormData)

const formData = new FormData();

formData.append('clinical_history', 'A 45-year-old male presents with chest pain...');
formData.append('language', 'en');

// Assuming 'fileInput' is an <input type="file" multiple> element
const fileInput = document.getElementById('fileInput');
for (const file of fileInput.files) {
formData.append('files', file, file.name);
}

fetch('/diagnose', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
// Content-Type is automatically set by the browser for FormData
},
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

Response

On success (HTTP Status 200 OK), the response body directly contains the DifferentialDiagnosisDto object.

Response Body (DifferentialDiagnosisDto)

The successful response body has the following structure:

FieldTypeDescription
diagnosisobjectContains the differential diagnosis information (See below)
triageobjectContains triage assessment information (See below)

Diagnosis Object

FieldTypeDescription
diseasesarrayArray of potential diagnoses (See Disease Object below)

Disease Object

Each disease in the diagnosis.diseases array contains:

FieldTypeDescription
namestringName of the disease
icd10_codestringICD-10 code for the disease
probabilitynumberCalculated probability (0.00-1.00)
whystringExplanation of why this diagnosis is being considered
diagnostic_testsarray of stringsRecommended tests for this diagnosis
standard_carearray of objectsEvidence-based interventions
drugsarray of objectsRecommended medications (optional)
categorystringClassification as "most-likely", "expanded", or "cant-miss"

Standard Care Object

Each item in the standard_care array contains:

FieldTypeDescription
namestringName of the standard of care
urlstringLink to the source (optional)

Drug Object

Each item in the drugs array contains:

FieldTypeDescription
namestringName of the medication
classstringMedication class (e.g., ACE Inhibitor)
dosagestringGeneral dosage information
considerationsstringImportant considerations
first_linebooleanWhether this is a first-line treatment

Triage Object

The triage object contains:

FieldTypeDescription
triage_levelstring"RED" (urgent) or "WHITE" (non-urgent)
triage_justificationstringExplanation for the triage level
triage_recommendationstringRecommended course of action

Example Response

Below is an example of a response from the API:

View Example Response (Success - 200 OK)
{
"diagnosis": {
"diseases": [
{
"name": "Acute Myocardial Infarction",
"icd10_code": "I21.9",
"probability": 0.85,
"why": "The patient presents with classic symptoms of myocardial infarction: chest pain radiating to the left arm, shortness of breath, and fatigue. The pain is described as pressure-like and worsens with exertion. Risk factors include hypertension, hyperlipidemia, and family history of early MI.",
"diagnostic_tests": [
"12-lead ECG",
"Cardiac troponin levels",
"Complete blood count",
"Basic metabolic panel",
"Chest X-ray"
],
"standard_care": [
{
"name": "ACC/AHA Guidelines for the Management of Patients With ST-Elevation Myocardial Infarction",
"url": "https://www.ahajournals.org/doi/10.1161/CIR.0000000000000617"
}
],
"drugs": [
{
"name": "Aspirin",
"class": "Antiplatelet",
"dosage": "162-325 mg loading dose, then 81 mg daily",
"considerations": "Contraindicated in patients with active bleeding or severe hypersensitivity",
"first_line": true
},
{
"name": "Nitroglycerin",
"class": "Nitrate",
"dosage": "0.4 mg sublingual every 5 minutes, up to 3 doses",
"considerations": "Contraindicated in patients taking phosphodiesterase inhibitors",
"first_line": true
}
],
"category": "most-likely"
},
{
"name": "Unstable Angina",
"icd10_code": "I20.0",
"probability": 0.65,
"why": "The patient's symptoms are consistent with unstable angina: chest pain that worsens with exertion and is associated with shortness of breath. Risk factors include hypertension and hyperlipidemia.",
"diagnostic_tests": [
"12-lead ECG",
"Cardiac troponin levels",
"Stress test (after ruling out acute MI)",
"Coronary angiography"
],
"standard_care": [
{
"name": "ACC/AHA Guidelines for the Management of Patients With Non-ST-Elevation Acute Coronary Syndromes",
"url": "https://www.ahajournals.org/doi/10.1161/CIR.0000000000000134"
}
],
"drugs": [
{
"name": "Aspirin",
"class": "Antiplatelet",
"dosage": "81-325 mg daily",
"considerations": "Contraindicated in patients with active bleeding or severe hypersensitivity",
"first_line": true
}
],
"category": "most-likely"
},
{
"name": "Aortic Dissection",
"icd10_code": "I71.0",
"probability": 0.25,
"why": "Although less likely, aortic dissection should be considered in patients with acute chest pain, especially with a history of hypertension. The absence of a tearing or ripping quality to the pain makes this diagnosis less likely.",
"diagnostic_tests": [
"CT angiography of the chest",
"Transesophageal echocardiography",
"MRI of the chest"
],
"standard_care": [
{
"name": "ACC/AHA Guidelines for the Diagnosis and Management of Patients With Thoracic Aortic Disease",
"url": "https://www.ahajournals.org/doi/10.1161/CIR.0b013e3181d4739e"
}
],
"drugs": [
{
"name": "Labetalol",
"class": "Combined alpha and beta-blocker",
"dosage": "10-20 mg IV, followed by 20-80 mg IV every 10 minutes (max 300 mg)",
"considerations": "Target systolic blood pressure 100-120 mmHg",
"first_line": true
}
],
"category": "cant-miss"
}
]
},
"triage": {
"triage_level": "RED",
"triage_justification": "The patient's symptoms are consistent with an acute coronary syndrome, which is a life-threatening emergency requiring immediate medical attention.",
"triage_recommendation": "Immediate emergency department evaluation with cardiac monitoring, 12-lead ECG, and cardiac biomarkers."
}
}

Response Codes

Status CodeDescription
200Success - The differential diagnosis has been successfully generated
400Bad Request - Invalid request format, missing required fields (e.g., no history or files), file validation failed (type, size, count)
401Unauthorized - Invalid or missing API key
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong on our end

Generate Differential Diagnosis (Streaming)

For real-time updates as the diagnosis is generated, you can use the streaming endpoints. There are two ways to initiate a stream depending on whether you need to upload files.

1. Text-Only Stream

Use this endpoint if you are only providing clinical_history text and do not need to upload files.

Generate Differential Diagnosis (Stream - Text Only)
POST /diagnose/stream

Request

Headers
HeaderRequiredDescription
Content-TypeYesMust be set to application/json
x-api-keyYesYour API key for authentication
AcceptYesMust be text/event-stream
Request Body (application/json)
ParameterTypeRequiredDescription
clinical_historystringYesThe clinical history text to analyze.
languagestringNoThe language for the output diagnosis (e.g., 'en', 'es', 'pt'). Defaults to 'en' (English) if not provided.
Example Request
fetch('/diagnose/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY',
'Accept': 'text/event-stream'
},
body: JSON.stringify({
clinical_history: 'A 45-year-old male presents with chest pain...',
language: 'en'
})
})
.then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();

function read() {
reader.read().then(({ done, value }) => {
if (done) {
console.log('Stream finished.');
return;
}
const chunk = decoder.decode(value, { stream: true });
// Process the SSE chunk (see SSE Format section below)
console.log('Received chunk:', chunk);
read(); // Continue reading
});
}
read();
})
.catch(error => console.error('Error:', error));

Response

This endpoint immediately returns an HTTP 201 Created status and opens a connection for Server-Sent Events (SSE). See the SSE Format section below for details on the event stream.


2. Stream with File Uploads (Two-Step Process)

If you need to include files (images or PDFs) in your streaming request, you must use a two-step process: first, prepare a stream session by uploading the data, and second, connect to the stream using the provided session ID.

Step 1: Prepare Stream Session

Prepare Stream Session (Files)
POST /diagnose/stream/files
Request
Headers
HeaderRequiredDescription
Content-TypeYesMust be multipart/form-data
x-api-keyYesYour API key for authentication
Request Body (multipart/form-data)

The request body is identical to the POST /diagnose endpoint:

ParameterTypeRequiredDescription
clinical_historystringNoThe clinical history text to analyze. Required if no files are provided.
languagestringNoThe language for the output diagnosis (e.g., 'en', 'es', 'pt'). Defaults to 'en' (English) if not provided.
filesFile (Array)NoAn array of files (images or PDFs). Required if clinical_history is not provided. Max 5 files. Max 10MB per file. Supported types: JPEG, PNG, WEBP, GIF, PDF.
Example Request (using JavaScript FormData)
// FormData setup is the same as the POST /diagnose example
const formData = new FormData();
formData.append('clinical_history', 'Patient history...');
// ... append files ...

fetch('/diagnose/stream/files', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
// Content-Type is automatic for FormData
},
body: formData
})
.then(response => response.json())
.then(data => {
console.log('Session prepared:', data);
// data will contain { sessionId: '...', streamUrl: '...' }
// Now use data.streamUrl or data.sessionId to connect
})
.catch(error => console.error('Error preparing session:', error));
Response (Success - 201 Created)

On success, the API returns a JSON object containing the session details:

{
"sessionId": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8",
"streamUrl": "/diagnose/stream/a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8"
}
  • sessionId: A unique identifier for this stream session.
  • streamUrl: The relative URL path to connect to for the SSE stream.

Important: The stream session is valid for 10 minutes. You must connect to the streamUrl within this time.

Step 2: Connect to the Stream

Connect to Diagnosis Stream
GET /diagnose/stream/:sessionId

Use the sessionId (or the full streamUrl) obtained from Step 1 to establish the SSE connection.

Request
Headers
HeaderRequiredDescription
x-api-keyYesYour API key (must match Step 1)
AcceptYesMust be text/event-stream
Path Parameters
ParameterTypeDescription
sessionIdstringThe session ID from Step 1.
Example Request (using JavaScript EventSource)
// Assuming 'sessionId' was received from Step 1
const sessionId = 'a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8';
const streamUrl = `/diagnose/stream/${sessionId}`; // Or use the streamUrl directly


// Using Fetch API (similar to Text-Only stream example)
fetch(streamUrl, {
method: 'GET',
headers: {
'x-api-key': 'YOUR_API_KEY', // Must be the same key used in Step 1
'Accept': 'text/event-stream'
}
})
.then(response => {
// ... process stream using response.body.getReader() ...
console.log('Connected to stream for session:', sessionId);
})
.catch(error => console.error('Error connecting to stream:', error));
Response

This endpoint immediately returns an HTTP 200 OK status and opens the connection for Server-Sent Events (SSE).


SSE Format (Applies to Both Streaming Methods)

The server sends events in the standard SSE format. Each message contains event and data fields.

  • event: partial: Indicates a partial update to the diagnosis object. The data field contains a JSON string representing the evolving DifferentialDiagnosisDto object. You can parse this JSON and update your UI incrementally.
  • event: final: Indicates the stream is complete and this is the final diagnosis object. The data field contains the complete DifferentialDiagnosisDto JSON string. After receiving this event, the stream will close.
  • event: error: Indicates an error occurred during stream generation. The data field may contain a JSON string with error details. The stream will close after this event.

Example SSE Messages:

event: partial
data: {"diagnosis":{"diseases":[{"name":"Possible Condition A","probability":0.3,"why":"Reasoning..."}]},"triage":{"triage_level":"WHITE"}}

event: partial
data: {"diagnosis":{"diseases":[{"name":"Possible Condition A","probability":0.3,"why":"Reasoning...","diagnostic_tests":["Test 1"]},{"name":"Possible Condition B","probability":0.6}]},"triage":{"triage_level":"RED","triage_justification":"Urgent signs..."}}

event: final
data: {"diagnosis":{"diseases":[{"name":"Possible Condition A", ... complete object ...},{"name":"Possible Condition B", ... complete object ...}]},"triage":{ ... complete object ...}}

event: error
data: {"statusCode": 500, "message": "Internal processing error"}

You should parse the data field (which is a JSON string) on each event to get the diagnosis object or error details.

Streaming Response Codes

EndpointStatus CodeDescription
POST /diagnose/stream201Success - SSE connection opened for text-only stream
POST /diagnose/stream/files201Success - Stream session prepared, response contains session details
GET /diagnose/stream/{id}200Success - SSE connection opened using session ID
All Streaming400Bad Request - Invalid request format, missing fields, validation
All Streaming401Unauthorized - Invalid or missing API key
GET /diagnose/stream/{id}401Unauthorized - API key doesn't match the key used for Step 1
GET /diagnose/stream/{id}404Not Found - Invalid or expired sessionId
All Streaming429Too Many Requests - Rate limit exceeded
All Streaming500Internal Server Error - Processing error during streaming

Error Responses

When an error occurs (outside of the SSE error event), the API returns the appropriate HTTP status code (4xx or 5xx) and a JSON response body containing error details:

// Example Error (400 Bad Request - File Upload)
{
"statusCode": 400,
"message": [
"File type not supported: document.txt",
"File size exceeds limit: large_image.png (15MB)"
],
"error": "Bad Request"
}
// Example Error (401 Unauthorized)
{
"statusCode": 401,
"message": "Invalid API key",
}