16 KiB
AI Patient Onboarding API — Complete Frontend Integration Guide
Version: 1.0.0
Target Audience: Frontend Engineers (React / React Native / Vue / Next.js / Mobile)
Backend Framework: FastAPI (Python 3.13)
Supported Protocols: HTTP/1.1 REST, JSON, Multipart/Form-Data Formats
Interactive API Documentation:
- Swagger UI:
{BASE_URL}/docs - ReDoc:
{BASE_URL}/redoc - OpenAPI Schema:
{BASE_URL}/openapi.json
1. Executive System Overview
The AI Patient Onboarding API is an enterprise multi-modal clinical intake system designed for hospitals, clinics, a
nd digital health platforms. It automates patient registration, symptom intake, medical history collection, document extraction, and specialty triage before a physician consultation.
Key Capabilities for Frontend Applications:
- Multi-Modal Onboarding:
- Text-Based Onboarding: Interactive chat-based intake powered by clinical LLM orchestrator.
- Voice-First Onboarding: Natural conversational voice intake supporting English (
en-IN), Tamil (ta-IN), Hindi (hi-IN), Telugu (te-IN), Kannada (kn-IN), Malayalam (ml-IN), and Marathi (mr-IN) using Sarvam AI ASR/TTS.
- Medical Document Analysis: Vision-based processing of lab reports, prescriptions, and discharge summaries (JPEG, PNG, WEBP, PDF up to 10MB).
- Session-Based State Engine: Stateful intake tracking stored in persistent backend database.
- Structured EHR Output: Automatic clinical JSON result extraction matching standard Electronic Health Record (EHR) models.
2. Server Base URLs & CORS Configuration
Server Base URLs:
- Local Development:
http://localhost:8000orhttp://127.0.0.1:8000 - Staging / Production: Configured via environment variable (
{BASE_URL})
CORS (Cross-Origin Resource Sharing) Policy:
The backend enforces production-safe CORSMiddleware.
- Allowed Origins:
http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://127.0.0.1:5173,https://onboarding.skyheal.ai(configurable viaCORS_ORIGINS). - Allowed Credentials:
true(Access-Control-Allow-Credentials: true). - Allowed Headers:
Authorization,Content-Type,X-API-Key,X-Patient-ID,X-Request-ID,Accept,Origin. - Exposed Headers:
X-Request-ID.
3. Quick Start Integration Flow
[ Frontend App ]
│
├── 1. POST /v1/onboarding/start (or /v1/voice-onboarding/start)
│ └─► Returns session_id (e.g. "ONB-8F12A9C4" or "VOICE-D3CAEA5C")
│
├── 2. POST /v1/onboarding/{session_id}/message (or /turn for voice)
│ └─► Exchanges multi-turn symptom history & receiving AI responses
│
├── 3. POST /v1/documents/{session_id}/upload (Optional)
│ └─► Uploads medical reports / lab results
│
└── 4. POST /v1/onboarding/{session_id}/complete
└─► Returns final structured EHR result (PatientOnboardingResult)
4. Master API Endpoint Directory
| HTTP Method | Endpoint Path | Auth Required | Rate Limit | Purpose |
|---|---|---|---|---|
GET |
/health |
No | None | Service health check & AI provider status |
POST |
/v1/onboarding/start |
Yes | 30 req/min | Start text onboarding session |
POST |
/v1/onboarding/{session_id}/message |
Yes | 30 req/min | Send text intake message to AI |
POST |
/v1/onboarding/{session_id}/complete |
Yes | 30 req/min | Finalize text session & output structured result |
POST |
/v1/voice-onboarding/start |
Yes | 30 req/min | Start voice onboarding session |
POST |
/v1/voice-onboarding/{session_id}/turn |
Yes | 30 req/min | Process speech recording or text fallback turn |
POST |
/v1/voice-onboarding/{session_id}/complete |
Yes | 30 req/min | Finalize voice session & output structured result |
GET |
/v1/voice-onboarding/audio/{audio_id} |
No | None | Stream TTS audio response (WAV/MP3) |
POST |
/v1/documents/{session_id}/upload |
Yes | 10 req/min | Upload medical document / report (10MB max) |
5. Authentication & Patient Security
Authentication Mechanisms:
Method A: HTTP Bearer Token (Standard)
Authorization: Bearer <ACCESS_TOKEN>
Method B: X-API-Key Custom Header
X-API-Key: <API_KEY>
Supported Access Tokens:
- Service Secret API Key:
skyheal_secure_api_key_2026(configurable viaAPI_SECRET_KEYin server environment). - Patient Development Tokens:
test_token_<PATIENT_ID>(e.g.test_token_PAT-10023). Automatically establishes patient identity context.
Patient Isolation & IDOR Protection Rules:
- When starting a session (
/v1/onboarding/start),patient.idis bound as session owner (session.patient_id). - Subsequent requests verify caller's authenticated
patient_idmatches session owner. - Access attempts by other patients return
HTTP 403 Forbidden.
6. Text Onboarding API Specifications
6.1. POST /v1/onboarding/start
Starts a new text-based clinical onboarding intake session.
Request Headers:
Content-Type: application/json
Authorization: Bearer test_token_PAT-10023
Request Body (StartOnboardingRequest):
{
"patient": {
"id": "PAT-10023",
"name": "Kavitha Ramesh",
"age": 35,
"gender": "female",
"phone": "+919876543210",
"abha_id": "91-1234-5678-9012",
"insurance_scheme": "PMJAY",
"dietary_habits": "Vegetarian"
},
"category": {
"type": "general",
"code": "general_medicine",
"name": "General Medicine"
},
"language": "en"
}
Field Descriptions:
| Field | Type | Required | Validation Rules | Description |
|---|---|---|---|---|
patient.id |
string | Yes | Min length 1 | Unique patient identifier |
patient.name |
string | No | Optional | Full name of patient |
patient.age |
integer | No | 0 \le \text{age} \le 120 |
Patient age in years |
patient.gender |
string | No | Optional | Gender identity ("male", "female", "other") |
category.type |
string | Yes | "general" or "speciality" |
Onboarding workflow type |
category.code |
string | Yes | Min length 1 | Specialty classification code |
category.name |
string | Yes | Min length 1 | Category display name |
language |
string | No | Default "en" |
Preferred intake language |
Successful Response (200 OK - StartOnboardingResponse):
{
"success": true,
"session_id": "ONB-8F12A9C4",
"patient_id": "PAT-10023",
"category": {
"type": "general",
"code": "general_medicine",
"name": "General Medicine"
},
"language": "en",
"status": "in_progress",
"stage": "symptoms",
"message": "Hello Kavitha Ramesh! I am your clinical onboarding assistant. What symptoms are you experiencing today?"
}
6.2. POST /v1/onboarding/{session_id}/message
Sends a patient chat response to the AI intake orchestrator.
Request Body (SendMessageRequest):
{
"message": "I have had severe chest tightness and shortness of breath for 2 days."
}
Successful Response (200 OK - SendMessageResponse):
{
"success": true,
"session_id": "ONB-8F12A9C4",
"stage": "medical_history",
"message": "Thank you for sharing. Does the chest tightness radiate to your arm or jaw, and do you have any history of high blood pressure?",
"status": "in_progress",
"response_time_ms": 1529.74,
"response_time_sec": 1.53
}
6.3. POST /v1/onboarding/{session_id}/complete
Finalizes the intake session and outputs the structured clinical EHR payload.
Request Body (CompleteOnboardingRequest):
{
"confirmed": true
}
Successful Response (200 OK - CompleteOnboardingResponse):
{
"success": true,
"session_id": "ONB-8F12A9C4",
"status": "completed",
"result": {
"patient_id": "PAT-10023",
"abha_id": "91-1234-5678-9012",
"phone": "+919876543210",
"insurance_scheme": "PMJAY",
"category": {
"type": "general",
"code": "general_medicine",
"name": "General Medicine"
},
"chief_complaint": "Chest tightness and shortness of breath for 2 days",
"symptoms": [
{
"name": "Chest tightness",
"duration": "2 days",
"severity": "severe",
"description": "Triggered during exertion"
}
],
"medical_history": ["Prehypertension"],
"medications": ["Metformin 500mg"],
"allergies": ["Penicillin"],
"dietary_habits": "Vegetarian",
"additional_information": "Patient confirmed details.",
"language": "en",
"onboarding_completed": true
},
"message": "Onboarding successfully completed and saved to patient record.",
"response_time_ms": 4075.41,
"response_time_sec": 4.08
}
7. Voice Onboarding API Specifications
7.1. POST /v1/voice-onboarding/start
Starts a voice-first onboarding session with Sarvam AI multilingual speech engine.
Supported Languages:
en-IN (Indian English), ta-IN (Tamil), hi-IN (Hindi), te-IN (Telugu), kn-IN (Kannada), ml-IN (Malayalam), mr-IN (Marathi).
Request Body:
{
"patient": {
"id": "PAT-VOICE-1",
"name": "Ramesh G",
"age": 34,
"gender": "male"
},
"category": {
"type": "general",
"code": "general_medicine",
"name": "General Medicine"
},
"language": "ta-IN"
}
Successful Response (200 OK):
{
"success": true,
"session_id": "VOICE-D3CAEA5C",
"patient_id": "PAT-VOICE-1",
"category": {
"type": "general",
"code": "general_medicine",
"name": "General Medicine"
},
"language": "ta-IN",
"status": "in_progress",
"stage": "greeting",
"greeting_text": "வணக்கம் Ramesh G, CureSelect மருத்துவமனைக்கு வரவேற்கிறோம். இன்று உங்களுக்கு என்ன சுகவீனம் உள்ளது?",
"audio_url": "/v1/voice-onboarding/audio/aud_a1b2c3d4e5f6",
"response_time_ms": 78.32,
"response_time_sec": 0.08
}
7.2. POST /v1/voice-onboarding/{session_id}/turn
Processes a conversational voice turn using audio recording or text fallback.
Multipart Form Data:
audio: Binary audio recording file (WAV,WEBM,MP3,OGGup to 10MB).text_fallback: String text transcript (used if WebSpeech STT processed client-side).
Successful Response (200 OK):
{
"success": true,
"session_id": "VOICE-D3CAEA5C",
"patient_transcript": "எனக்குகடந்த 3 நாளா நெஞ்சு பாரமா இருக்குங்க.",
"ai_text": "நன்றி. இந்த நெஞ்சு பாரம் உடற்பயிற்சி செய்யும் போது அதிகமாகிறதா?",
"stage": "symptoms",
"completed": false,
"audio_url": "/v1/voice-onboarding/audio/aud_f9e8d7c6b5a4",
"audio_base64": null,
"suggested_specialty": {
"specialty": "Cardiology",
"reason": "Chest tightness reported"
},
"response_time_ms": 1412.37,
"response_time_sec": 1.41
}
7.3. GET /v1/voice-onboarding/audio/{audio_id}
Streams generated TTS audio for browser or mobile playback.
const audio = new Audio(`${BASE_URL}/v1/voice-onboarding/audio/${audioId}`);
await audio.play();
8. Medical Document Analysis API
POST /v1/documents/{session_id}/upload
Uploads a medical report / prescription for vision extraction.
- Content-Type:
multipart/form-data - File Limit: Max
10MB(10,485,760 bytes). - Allowed Formats:
image/jpeg,image/png,image/webp,application/pdf.
Successful Response (200 OK):
{
"success": true,
"session_id": "ONB-8F12A9C4",
"document_type": "lab_report",
"summary": "Report indicates elevated HbA1c (7.2%) and stage 1 hypertension (130/85 mmHg).",
"findings": [
{
"test": "HbA1c",
"value": "7.2",
"unit": "%",
"interpretation": "Elevated"
}
],
"medications_found": ["Metformin 500mg"],
"allergies_found": ["Penicillin"],
"message": "Medical document analyzed and integrated into onboarding session."
}
9. Error Handling & Status Codes
| HTTP Status Code | Meaning | Cause & Resolution |
|---|---|---|
400 Bad Request |
Bad Request | Invalid category or unsupported file format. |
401 Unauthorized |
Unauthorized | Missing or invalid Authorization: Bearer or X-API-Key header. |
403 Forbidden |
Forbidden (IDOR) | Authenticated patient_id does not match session owner. |
404 Not Found |
Not Found | Session ID does not exist in backend database. |
413 Payload Too Large |
File Too Large | Uploaded document exceeds 10MB limit. |
422 Validation Error |
Pydantic Error | Request body violates schema rules (e.g. age < 0). |
429 Too Many Requests |
Rate Limited | Exceeded rate limit bucket (30 req/min). Check Retry-After header. |
500 Internal Error |
Server Error | Unhandled backend failure. |
10. Frontend React & TypeScript Implementation Examples
React API Client (src/api/onboardingClient.ts)
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';
export interface PatientContext {
id: string;
name?: string;
age?: number;
gender?: string;
phone?: string;
abha_id?: string;
}
export interface CategoryContext {
type: 'general' | 'speciality';
code: string;
name: string;
}
async function fetchApi<T>(endpoint: string, options: RequestInit = {}, patientId: string): Promise<T> {
const token = `test_token_${patientId}`;
const headers = new Headers(options.headers || {});
headers.set('Authorization', `Bearer ${token}`);
if (!(options.body instanceof FormData)) {
headers.set('Content-Type', 'application/json');
}
const response = await fetch(`${API_BASE_URL}${endpoint}`, { ...options, headers });
if (!response.ok) {
const errorBody = await response.json().catch(() => ({ detail: 'Network response error' }));
throw new Error(errorBody.detail || `HTTP Error ${response.status}`);
}
return response.json();
}
export async function startOnboarding(patient: PatientContext, category: CategoryContext, language: string = 'en') {
return fetchApi<any>('/v1/onboarding/start', {
method: 'POST',
body: JSON.stringify({ patient, category, language }),
}, patient.id);
}
export async function sendMessage(sessionId: string, patientId: string, message: string) {
return fetchApi<any>(`/v1/onboarding/${sessionId}/message`, {
method: 'POST',
body: JSON.stringify({ message }),
}, patientId);
}
export async function completeOnboarding(sessionId: string, patientId: string, confirmed: boolean = true) {
return fetchApi<any>(`/v1/onboarding/${sessionId}/complete`, {
method: 'POST',
body: JSON.stringify({ confirmed }),
}, patientId);
}
11. Frontend Integration Checklist
[ ] Configure API_BASE_URL in environment (VITE_API_BASE_URL=http://localhost:8000)
[ ] Verify CORS preflight request from localhost:3000 / localhost:5173
[ ] Attach Authorization: Bearer test_token_<PATIENT_ID> header
[ ] Call POST /v1/onboarding/start and store session_id
[ ] Multi-turn chat message sending via POST /v1/onboarding/{session_id}/message
[ ] Handle 401 Unauthorized & 403 Forbidden errors
[ ] Upload medical documents via POST /v1/documents/{session_id}/upload (10MB max)
[ ] Call POST /v1/onboarding/{session_id}/complete to retrieve final PatientOnboardingResult
[ ] Test voice onboarding audio streaming via GET /v1/voice-onboarding/audio/{audio_id}