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.
Request
Headers
Header | Required | Description |
---|---|---|
Content-Type | Yes | Must be set to multipart/form-data |
x-api-key | Yes | Your API key for authentication |
Request Body (multipart/form-data
)
The request should be sent as multipart/form-data
.
Parameter | Type | Required | Description |
---|---|---|---|
clinical_history | string | No | The clinical history text to analyze. Required if no files are provided. |
language | string | No | The language for the output diagnosis (e.g., 'en', 'es', 'pt'). Defaults to 'en' (English) if not provided. Input language is detected automatically. |
files | File (Array) | No | An 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:
Field | Type | Description |
---|---|---|
diagnosis | object | Contains the differential diagnosis information (See below) |
triage | object | Contains triage assessment information (See below) |
Diagnosis Object
Field | Type | Description |
---|---|---|
diseases | array | Array of potential diagnoses (See Disease Object below) |
Disease Object
Each disease in the diagnosis.diseases
array contains:
Field | Type | Description |
---|---|---|
name | string | Name of the disease |
icd10_code | string | ICD-10 code for the disease |
probability | number | Calculated probability (0.00-1.00) |
why | string | Explanation of why this diagnosis is being considered |
diagnostic_tests | array of strings | Recommended tests for this diagnosis |
standard_care | array of objects | Evidence-based interventions |
drugs | array of objects | Recommended medications (optional) |
category | string | Classification as "most-likely", "expanded", or "cant-miss" |
Standard Care Object
Each item in the standard_care
array contains:
Field | Type | Description |
---|---|---|
name | string | Name of the standard of care |
url | string | Link to the source (optional) |
Drug Object
Each item in the drugs
array contains:
Field | Type | Description |
---|---|---|
name | string | Name of the medication |
class | string | Medication class (e.g., ACE Inhibitor) |
dosage | string | General dosage information |
considerations | string | Important considerations |
first_line | boolean | Whether this is a first-line treatment |
Triage Object
The triage
object contains:
Field | Type | Description |
---|---|---|
triage_level | string | "RED" (urgent) or "WHITE" (non-urgent) |
triage_justification | string | Explanation for the triage level |
triage_recommendation | string | Recommended 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 Code | Description |
---|---|
200 | Success - The differential diagnosis has been successfully generated |
400 | Bad Request - Invalid request format, missing required fields (e.g., no history or files), file validation failed (type, size, count) |
401 | Unauthorized - Invalid or missing API key |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal 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.
Request
Headers
Header | Required | Description |
---|---|---|
Content-Type | Yes | Must be set to application/json |
x-api-key | Yes | Your API key for authentication |
Accept | Yes | Must be text/event-stream |
Request Body (application/json
)
Parameter | Type | Required | Description |
---|---|---|---|
clinical_history | string | Yes | The clinical history text to analyze. |
language | string | No | The 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
Request
Headers
Header | Required | Description |
---|---|---|
Content-Type | Yes | Must be multipart/form-data |
x-api-key | Yes | Your API key for authentication |
Request Body (multipart/form-data
)
The request body is identical to the POST /diagnose
endpoint:
Parameter | Type | Required | Description |
---|---|---|---|
clinical_history | string | No | The clinical history text to analyze. Required if no files are provided. |
language | string | No | The language for the output diagnosis (e.g., 'en', 'es', 'pt'). Defaults to 'en' (English) if not provided. |
files | File (Array) | No | An 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
Use the sessionId
(or the full streamUrl
) obtained from Step 1 to establish the SSE connection.
Request
Headers
Header | Required | Description |
---|---|---|
x-api-key | Yes | Your API key (must match Step 1) |
Accept | Yes | Must be text/event-stream |
Path Parameters
Parameter | Type | Description |
---|---|---|
sessionId | string | The 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. Thedata
field contains a JSON string representing the evolvingDifferentialDiagnosisDto
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. Thedata
field contains the completeDifferentialDiagnosisDto
JSON string. After receiving this event, the stream will close.event: error
: Indicates an error occurred during stream generation. Thedata
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
Endpoint | Status Code | Description |
---|---|---|
POST /diagnose/stream | 201 | Success - SSE connection opened for text-only stream |
POST /diagnose/stream/files | 201 | Success - Stream session prepared, response contains session details |
GET /diagnose/stream/{id} | 200 | Success - SSE connection opened using session ID |
All Streaming | 400 | Bad Request - Invalid request format, missing fields, validation |
All Streaming | 401 | Unauthorized - Invalid or missing API key |
GET /diagnose/stream/{id} | 401 | Unauthorized - API key doesn't match the key used for Step 1 |
GET /diagnose/stream/{id} | 404 | Not Found - Invalid or expired sessionId |
All Streaming | 429 | Too Many Requests - Rate limit exceeded |
All Streaming | 500 | Internal 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",
}