API Overview
The Allign API v2 is a RESTful JSON API that powers the Allign telemedicine platform.
All endpoints live under /api/v2. Authentication uses JWT Bearer tokens.
Amounts are always in paise (1 INR = 100 paise). Dates follow ISO 8601.
REQUIRED — Field must be present in the request. Omitting it causes a
422 error.optional — Field can be omitted. Server uses the default value (or null) when absent.
Making Requests
Every request must include Content-Type: application/json for POST/PATCH/PUT bodies. Authenticated endpoints require the Authorization header.
Authenticated Request Pattern
curl example curl -X POST https://your-domain.com/api/v2/connect/sessions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \ -d '{ "target_doctor_id": "d3af4135-fd62-4148-a316-eb94b841f693", "category": "General Medicine" }'
Understanding Request Samples
request body { "phone": "+918090839108", // REQUIRED - must provide "platform": "android" // optional - can omit }
Understanding Response Samples
response 200 { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "ONGOING", "created_at": "2026-02-07T14:30:00Z", // ISO 8601 always in UTC "amount": 15000, // = 150.00 INR (paise) "optional_field": null // null when not set }
Authentication Guide
Three roles exist: Patient (client), Doctor, and Admin. Each authenticates differently.
Patient Login (OTP Flow)
step 1 curl -X POST /api/v2/auth/request-otp \ -H "Content-Type: application/json" \ -d '{ "phone": "+918090839108" }' // Response 202: { "message": "OTP sent if phone is valid" }
step 2 curl -X POST /api/v2/auth/verify-otp \ -H "Content-Type: application/json" \ -d '{ "phone": "+918090839108", "code": "743424" }' // Response 200: { "access_token": "eyJ...", "refresh_token": "eyJ...", "token_type": "bearer" }
step 3 — use token curl /api/v2/users/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." // Response 200: User profile JSON
Doctor Login
curl curl -X POST /api/v2/auth/doctor/login \ -H "Content-Type: application/json" \ -d '{ "email": "doctor@allign.in", "password": "secret" }' // Response 200: { "access_token": "...", "refresh_token": "...", "token_type": "bearer" }
Token Refresh (auto-call when access token expires with 401)
curl curl -X POST /api/v2/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbG..." }' // Old refresh token is revoked. Returns new pair.
HTTP Status Codes
| Code | Meaning | When It Happens |
|---|---|---|
| 200 | OK | Successful read, update, or idempotent action |
| 201 | Created | Resource successfully created (session, review, order) |
| 202 | Accepted | Request accepted for processing (OTP send) |
| 204 | No Content | Successful delete, no response body |
| 400 | Bad Request | Invalid input, business rule violation |
| 401 | Unauthorized | Missing, expired, or invalid JWT token |
| 403 | Forbidden | Valid token but wrong role or not allowed |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Duplicate resource (idempotency) or state conflict |
| 422 | Validation Error | Missing required field, wrong type, constraint violation |
| 429 | Too Many Requests | Rate limit (OTP). Check Retry-After header |
| 500 | Server Error | Unexpected backend failure |
| 503 | Service Unavailable | External service down (SMS, payment) |
Pagination
All list endpoints use a consistent pagination envelope.
request curl "/api/v2/analytics/user/sessions?limit=20&offset=0" \ -H "Authorization: Bearer ..."
response 200 { "items": [ ... ], // Array of resources (max `limit` items) "total": 142, // Total matching resources across all pages "limit": 20, // Requested page size "offset": 0, // Current offset (0-based) "has_more": true // true if (offset + limit) < total }
Auth
Patient OTP login, doctor email/password login, token refresh, and logout.
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| phone | string | REQUIRED | E.164 format, e.g. +918090839108 |
| platform | string | null | optional | "android" or "ios". Controls SMS sender ID. |
sample request { "phone": "+918090839108", // REQUIRED "platform": "android" // optional }
response 202 { "message": "OTP sent if phone is valid" }
Status Codes
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| phone | string | REQUIRED | Same phone from request-otp |
| code | string | REQUIRED | 6-digit OTP received via SMS |
| name | string | null | optional | Sets user display name on first login |
sample request { "phone": "+918090839108", // REQUIRED "code": "743424", // REQUIRED "name": "Rahul Sharma" // optional – set on first login }
response 200 { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" }
Status Codes
sample request { "email": "dr.smith@allign.in", // REQUIRED "password": "s3cur3P@ss" // REQUIRED }
response 200 { "access_token": "eyJ...", "refresh_token": "eyJ...", "token_type": "bearer" }
Status Codes
sample request { "refresh_token": "eyJhbGciOiJIUzI1NiIs..." // REQUIRED }
response 200 { "access_token": "new_eyJ...", // New access token "refresh_token": "new_eyJ...", // New refresh token (old one revoked) "token_type": "bearer" }
401.sample request curl -X POST /api/v2/auth/logout \ -H "Authorization: Bearer eyJhbGci..." // No request body needed
response 200 { "message": "Logged out" }
Users (Patient Profile)
Read and update the authenticated patient's profile. Role: client only.
sample request
curl /api/v2/users/me \
-H "Authorization: Bearer eyJ..."
response 200 — UserOut { "id": "644452ac-c508-422f-8910-f0be7a5393d3", "full_name": "Rahul Sharma", "phone": "+918090839108", "email": null, "avatar_url": "https://...assets/avatars/av_01.png", "avatar_source": "system", // "system" or "user" "member_since": "2025-08-15T10:30:00Z", "is_phone_verified": true, "profile_completed": true, // true when sex AND age set "profile_completion": 0.85, // 0.0 to 1.0 "age": 28, "sex": "male", // male|female|other|prefer_not_to_say "height_cm": 175.0, "weight_kg": 72.5, "bmi": 23.7 // auto-calculated from height+weight }
Request Body (all fields optional — send only what changed)
| Field | Type | R / O | Constraints |
|---|---|---|---|
| full_name | string | optional | 1–100 chars, non-empty |
| age | int | optional | 1–150 |
| sex | string | optional | male | female | other | prefer_not_to_say |
| height_cm | float | optional | 50.0–300.0 |
| weight_kg | float | optional | 10.0–500.0 |
sample request — update age and sex { "age": 28, // optional – only send fields you want to change "sex": "male" // optional }
response 200 — UserOut // Returns full updated UserOut (same schema as GET /users/me) // BMI is auto-recalculated if height or weight changed
Doctors — Public Discovery
Search, list, and view doctor profiles. Auth is optional (enables favourites).
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| q | string | REQUIRED | Search query (1–100 chars). Uses pg_trgm fuzzy matching. |
| limit | int | optional | Max 25, default 10 |
| offset | int | optional | Default 0 |
sample request
curl "/api/v2/doctors/search?q=ankit&limit=5"
response 200 — list[DoctorOut] [ { "id": "d3af4135-...", "full_name": "Dr. Ankit Shah", "slug": "dr-ankit-shah-urology", "speciality_category": "Urology", "rating": 4.8, "years_experience": 12, "rate_per_minute": 500, // paise (= 5.00 INR/min) "presence_status": "ONLINE", "is_favourite": false // only if auth token sent } ]
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| skip | int | optional | Default 0 |
| limit | int | optional | Default 50 |
| favourites_first | bool | optional | Requires auth. Default false |
| favourites_only | bool | optional | Requires auth. Default false |
sample request
curl "/api/v2/doctors/?limit=20&favourites_first=true" \
-H "Authorization: Bearer eyJ..."
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| status | string | optional | ONLINE, BUSY, OFFLINE |
| category | string | optional | Speciality category filter |
| available_for | string | optional | chat or call |
| featured_only | bool | optional | Featured doctors only |
| sort_by | string | optional | rate | rating | experience |
| sort_order | string | optional | asc or desc (default: asc) |
sample request
curl "/api/v2/doctors/all_doctors_list?status=ONLINE&category=Urology&sort_by=rating&sort_order=desc"
sample request
curl "/api/v2/doctors/slug/dr-ankit-shah-urology"
response 200 — DoctorDetailOut { "id": "d3af4135-...", "full_name": "Dr. Ankit Shah", "slug": "dr-ankit-shah-urology", "speciality_category": "Urology", "degrees": ["MBBS", "MS"], "years_experience": 12, "about_short": "Specialist in...", "rating": 4.8, "total_reviews": 42, "total_sessions": 197, "is_favourite": false, // only populated if auth token sent "presence_status": "ONLINE" }
sample request
curl "/api/v2/doctors/d3af4135-fd62-4148-a316-eb94b841f693"
Returns same DoctorDetailOut as the slug endpoint.
sample request
curl "/api/v2/doctors/d3af4135-.../reviews?limit=10&offset=0"
response 200 — PaginatedResponse[ReviewListItem] { "items": [ { "id": "a6c020eb-...", "rating": 5.0, "comment": "Excellent doctor, very helpful!", "patient_name_masked": "User****3d3", "created_at": "2026-02-07T21:56:25Z" } ], "total": 42, "limit": 10, "offset": 0, "has_more": true }
Doctors — Dashboard
Doctor-side dashboard. Requires doctor token.
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| timezone | string | optional | IANA tz (default UTC), e.g. Asia/Kolkata |
sample request
curl "/api/v2/doctors/me/overview?timezone=Asia/Kolkata" \
-H "Authorization: Bearer eyJ..."
response 200 — DoctorOverviewResponse { "doctor": { "id": "...", "name": "Dr. Ankit", ... }, "availability": { "is_online": true, "chat_enabled": true, "call_enabled": true }, "metrics": { "todays_sessions": 6, "ongoing": 0, "pending": 10, "missed": 2 } }
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| status | string | optional | REQUESTED | ONGOING | ENDED | all |
| from_date | date | optional | YYYY-MM-DD start |
| to_date | date | optional | YYYY-MM-DD end |
| has_followup | bool | optional | Filter by followup existence |
| skip | int | optional | Default 0 |
| limit | int | optional | 1–100, default 50 |
sample request
curl "/api/v2/doctors/me/sessions?status=ENDED&has_followup=true&limit=20" \
-H "Authorization: Bearer eyJ..."
sample request
curl "/api/v2/doctors/me/sessions/recent?limit=10&timezone=Asia/Kolkata" \
-H "Authorization: Bearer eyJ..."
response 200 (each item) { "session_id": "1d0fae55-...", "patient": { "id": "644452ac-...", "name": "Test Patient", "gender": "male", "age": 28, "avatar_url": "https://api.dicebear.com/9.x/avataaars/svg?seed=..." }, "status": "ENDED", "duration_display": "37m 7s", // ... other fields ... }
sample request { "online": true // true = online, false = offline }
sample request { "presence_status": "online" // REQUIRED – "online" | "offline" (BUSY is automatic) }
sample request
curl "/api/v2/doctors/favourites?skip=0&limit=50" \
-H "Authorization: Bearer eyJ..."
sample request { "action": "add" // REQUIRED – "add" or "remove" }
NotificationResult shape. Push notifications will be integrated in a future release.Doctors — Review Management
Doctor-side review dashboard with reply CRUD. Role: doctor.
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| limit | int | optional | 1–100, default 10 |
| offset | int | optional | Default 0 |
| rating | int | optional | Filter by star: 1–5 |
| has_reply | bool | optional | Filter by reply presence |
| date_from | string | optional | ISO 8601 start |
| date_to | string | optional | ISO 8601 end |
| sort_by | string | optional | date_desc | date_asc | rating_desc | rating_asc |
sample request
curl "/api/v2/doctors/me/reviews?has_reply=false&sort_by=rating_desc&limit=10" \
-H "Authorization: Bearer eyJ..."
sample request { "text": "Thank you for your feedback! Happy to help." // REQUIRED – 1-1000 chars }
Status Codes
sample request { "text": "Updated reply text here." // REQUIRED – 1-1000 chars }
sample request curl -X DELETE "/api/v2/doctors/me/reviews/a6c020eb-.../reply" \ -H "Authorization: Bearer eyJ..." // Response: 204 No Content (no body)
sample request { "scheduled_date": "2026-02-27", // REQUIRED – YYYY-MM-DD "scheduled_time": "10:30:00", // optional – HH:MM:SS "scheduled_timezone": "Asia/Kolkata" // optional – default Asia/Kolkata }
Status Codes
Doctors — Settings & Profile
sample request
curl "/api/v2/doctors/me/profile" -H "Authorization: Bearer eyJ..."
sample request — all fields optional, send only what changed { "full_name": "Dr. Ankit Shah", // optional – 2-100 chars "years_experience": 12, // optional – 0-60 "about_short": "Specialist in...", // optional – max 600 chars "degrees": ["MBBS", "MS"], // optional – min 1 if provided "speciality_category": "Urology", // optional – from allowed list "languages": ["English", "Hindi"], // optional – from allowed list "registration_number": "MCI12345" // optional – min 6 chars }
sample request curl -X POST /api/v2/doctors/me/avatar \ -H "Authorization: Bearer eyJ..." \ -F "file=@/path/to/avatar.jpg" // Supported: JPEG, PNG, WebP. Max 2MB.
sample request
curl -X DELETE /api/v2/doctors/me/avatar -H "Authorization: Bearer eyJ..."
Body: DoctorCreate. Requires admin token.
Body: DoctorUpdate.
Connect Now v2 — Sessions
Real-time consultation lifecycle. Uses LiveKit for media/data transport.
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| target_doctor_id | UUID | REQUIRED | Doctor to route request to |
| category | string | optional | Health category (e.g. "Urology") |
| symptoms | list[string] | optional | Patient symptoms. Default: [] |
| active_treatment | string | optional | Current treatment info |
| medical_history | string | optional | Relevant medical history |
| rate_per_minute | int | optional | Rate in paise/min |
sample request { "target_doctor_id": "d3af4135-fd62-4148-a316-eb94b841f693", // REQUIRED "category": "Urology", // optional "symptoms": ["back pain", "frequent urination"], // optional "medical_history": "Previous kidney stone 2024", // optional "rate_per_minute": 500 // optional }
response 201 { "session_id": "1d0fae55-fb8f-4085-b34c-b598e381b135", "status": "REQUESTED", "room_name": "cn-1d0fae55-fb8f-4085-b34c-b598e381b135", "expires_at": "2026-02-07T22:30:00Z", "livekit": { "token": "eyJ...", // Use this to join LiveKit room "ws_url": "wss://lk.allign.in", "identity": "patient-644452ac...", "expires_in": 3600 // seconds until token expires }, "created_at": "2026-02-07T21:56:24Z" }
sample request
curl "/api/v2/connect/sessions/requests" -H "Authorization: Bearer eyJ..."
response 200 { "items": [{ "session_id": "1d0fae55-...", "status": "REQUESTED", "requested_at": "2026-02-07T21:56:24Z", "expires_at": "2026-02-07T22:30:00Z", "category": "Urology", "symptoms": ["back pain"], "patient": { "user_id": "644452ac-...", "name": "Rahul", "age": 28, "sex": "male", "initials": "RA", "avatar_url": "https://api.dicebear.com/9.x/avataaars/svg?seed=0e542140...&style=circle&top=shortCurly,..." } }], "total": 1 }
Server-Sent Events stream. Athena opens this connection to receive new session requests instantly without polling.
sample request
curl -N "/api/v2/connect/sessions/requests/stream" -H "Authorization: Bearer eyJ..."
events (text/event-stream)
event: connected
data: {"doctor_id": "d3af4135-..."}
event: session_requested
data: {"session_id": "1d0fae55-...", "status": "REQUESTED", "patient": {...}}
sample request
curl "/api/v2/connect/sessions/1d0fae55-..." -H "Authorization: Bearer eyJ..."
response 200 { "id": "1d0fae55-...", "patient_id": "644452ac-...", "doctor_id": "d3af4135-...", "status": "ENDED", "room_name": "cn-1d0fae55-...", "category": "Urology", "started_at": "2026-02-11T19:15:43Z", "ended_at": "2026-02-11T19:52:50Z", "patient": { // enriched patient preview "user_id": "644452ac-...", "name": "Test Patient", "age": 28, "sex": "male", "initials": "TP", "avatar_url": "https://api.dicebear.com/9.x/avataaars/svg?seed=..." } }
patient object is always included with avatar_url (DiceBear gender-based avatar). Available on all session statuses (REQUESTED, ONGOING, ENDED, EXPIRED, REJECTED).sample request curl -X POST "/api/v2/connect/sessions/1d0fae55-.../accept" \ -H "Authorization: Bearer eyJ..." // No request body needed
response 200 { "session_id": "1d0fae55-...", "status": "ONGOING", "doctor_id": "d3af4135-...", "started_at": "2026-02-07T21:56:24Z", "livekit": { "token": "eyJ...", "ws_url": "wss://...", "identity": "doctor-...", "expires_in": 3600 } }
sample curl -X POST "/api/v2/connect/sessions/1d0fae55-.../reject" -H "Authorization: Bearer eyJ..." // No body. REQUESTED → REJECTED
sample request { "reason": "completed", // optional – max 50 chars "note": null // optional }
sample
curl "/api/v2/connect/sessions/1d0fae55-.../token" -H "Authorization: Bearer eyJ..."
409 if session is ENDED.Connect Now v2 — Messages
Message persistence and delivery/read receipts.
sample request { "client_message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", // REQUIRED – UUID for idempotency "content_type": "text", // REQUIRED – text|image|file|audio "content": "Hello doctor, I have a question." // REQUIRED }
Status Codes
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| limit | int | optional | Default 50 |
| before | datetime | optional | Cursor: messages before this timestamp |
| after | datetime | optional | Cursor: messages after this timestamp |
sample
curl "/api/v2/connect/sessions/1d0fae55-.../messages?limit=20" -H "Authorization: Bearer eyJ..."
sample request { "message_ids": [ // REQUIRED – list of message UUIDs "msg-uuid-1", "msg-uuid-2", "msg-uuid-3" ] }
response 200 { "updated": 3 }
updated: 0.sample request { "message_ids": ["msg-uuid-1", "msg-uuid-2"] // REQUIRED } // Messages must already have delivered_at set. Idempotent.
Connect Now v2 — Attachments
sample request { "filename": "xray_report.pdf", // REQUIRED "content_type": "application/pdf", // REQUIRED – MIME type "size_bytes": 524288, // REQUIRED – file size "upload_mode": "SAS" // optional – "SAS" (recommended) or "DIRECT" }
response 201 { "id": "07af53f0-...", "upload_url": "https://blob.core.windows.net/sessions/...?sv=...&sig=...", "upload_mode": "SAS", "status": "PENDING" } // Step 2: PUT the file to upload_url directly (client → Azure Blob) // Step 3: Call POST .../complete to finalize
sample curl -X POST "/api/v2/connect/sessions/.../attachments/07af53f0-.../complete" \ -H "Authorization: Bearer eyJ..." -H "Content-Type: application/json" -d '{}' // Verifies blob exists in Azure, validates size, marks UPLOADED
sample
curl "/api/v2/connect/sessions/1d0fae55-.../attachments?include_download_url=true" \
-H "Authorization: Bearer eyJ..."
Connect Now v2 — Recordings
sample curl -X POST "/api/v2/connect/sessions/1d0fae55-.../recordings" \ -H "Authorization: Bearer eyJ..." // No body. Session must be ONGOING. Idempotent: 201 new / 200 existing.
sample
curl -X POST "/api/v2/connect/sessions/.../recordings/.../stop" -H "Authorization: Bearer eyJ..."
sample
curl "/api/v2/connect/sessions/1d0fae55-.../recordings" -H "Authorization: Bearer eyJ..."
Connect Now v2 — Reports
Patient report uploads (PDF, images) via two-phase SAS flow. Max 10 MB. Patient uploads; both patient and doctor can view/download; only patient can delete.
sample
curl -X POST "/api/v2/connect/sessions/9e818202-.../reports/init?\
original_filename=blood_report.pdf&mime_type=application/pdf&size_bytes=524288" \
-H "Authorization: Bearer eyJ..."
response 201 { "report_id": "7a4ee7fb-...", "sas_url": "https://blob.core.windows.net/reports/...?sv=...&sig=...", "required_headers": { "x-ms-blob-type": "BlockBlob", "Content-Type": "application/pdf" }, "container_name": "reports", "blob_name": "staging/sessions/.../reports/2026/02/08/0afc7cc_blood_report.pdf" } // Step 2: PUT file bytes to sas_url with required_headers // Step 3: Call POST .../reports/{report_id}/complete to finalize
Validation
sample curl -X POST "/api/v2/connect/sessions/.../reports/7a4ee7fb-.../complete" \ -H "Authorization: Bearer eyJ..." -H "Content-Type: application/json" -d '{}' // Verifies blob exists in Azure, validates size, marks UPLOADED
response 200 { "report_id": "7a4ee7fb-...", "status": "UPLOADED", "verified_size_bytes": 524288, "verified_mime_type": "application/pdf" }
sample
curl "/api/v2/connect/sessions/9e818202-.../reports?include_download_url=true" \
-H "Authorization: Bearer eyJ..."
response 200 { "items": [ { "id": "7a4ee7fb-...", "original_filename": "blood_report.pdf", "mime_type": "application/pdf", "size_bytes": 524288, "created_at": "2026-02-08T01:12:26Z", "uploader_user_id": "644452ac-...", "download_url": "https://...?sv=...&sig=..." } ], "total": 1, "has_more": false }
sample
curl "/api/v2/connect/sessions/.../reports/7a4ee7fb-..." -H "Authorization: Bearer eyJ..."
response 200 { "report_id": "7a4ee7fb-...", "original_filename": "blood_report.pdf", "mime_type": "application/pdf", "size_bytes": 524288, "download_url": "https://...?sv=...&sig=...", "expires_in": 600, "created_at": "2026-02-08T01:12:26Z" } // download_url is a short-lived SAS URL (10 min expiry)
sample curl -X DELETE "/api/v2/connect/sessions/.../reports/7a4ee7fb-..." \ -H "Authorization: Bearer eyJ..." // Soft-delete. Only the patient (uploader) can delete. // Doctor will get 403 Forbidden.
response 200 { "report_id": "7a4ee7fb-...", "status": "DELETED", "deleted_at": "2026-02-08T01:12:27Z" }
Connect Now v2 — Post-Session
Follow-ups, prescriptions, prescription PDF, lab tests, and reviews scoped to a connect session.
sample request { "scheduled_date": "2026-02-27", // REQUIRED "scheduled_time": "10:30:00", // optional "scheduled_timezone": "Asia/Kolkata" // optional }
Status Codes
sample
curl "/api/v2/connect/sessions/1d0fae55-.../followup" -H "Authorization: Bearer eyJ..."sample request { "medications": [ // REQUIRED – at least 1 medication { "name": "Amoxicillin 500mg", // REQUIRED "dosage": "1 tablet 3x daily", // REQUIRED "duration": "7 days", // optional "instructions": "Take after meals" // optional } ], "notes": "Complete the full course" // optional }
sample
curl "/api/v2/connect/sessions/1d0fae55-.../prescription" -H "Authorization: Bearer eyJ..."Full replacement of medications and notes. Invalidates cached PDF. Sends push to patient. Same request body as POST.
sample
curl "/api/v2/connect/sessions/9e818202-.../prescription/pdf" \
-H "Authorization: Bearer eyJ..."
response 200 { "download_url": "https://blob.core.windows.net/prescriptions/staging/sessions/.../prescriptions/db1380a9-....pdf?sv=...&sig=...", "expires_in": 600, "generated_at": "2026-02-08T01:16:50Z" } // PDF is generated on first request and cached in Azure Blob (prescriptions container). // Subsequent calls return a fresh 10-min SAS download URL. // Both patient and doctor can download. Session must be ONGOING or ENDED.
sample request { "recommendations": [ // REQUIRED – at least 1 test { "test_name": "CBC", "priority": "routine", "instructions": "Fasting 8hrs" }, { "test_name": "HbA1c", "priority": "routine" } ], "notes": "Get done within 1 week" // optional }
sample
curl "/api/v2/connect/sessions/1d0fae55-.../lab-tests" -H "Authorization: Bearer eyJ..."Full replacement. Same body as POST. Sends push to patient.
response 200 { "id": "a6c020eb-...", "connect_session_id": "1d0fae55-...", "session_id": null, // null for v2 sessions "doctor_id": "d3af4135-...", "rating": 5.0, "comment": "Excellent consultation!", "created_at": "2026-02-07T21:56:25Z" }
Connect Now v2 — Video Permissions
Doctor-controlled patient video permission state machine. Doctor video is always on; patient needs explicit permission. State: NOT_ALLOWED → ALLOWED_BY_DOCTOR → VIDEO_ON / DECLINED_BY_PATIENT, with revoke returning to NOT_ALLOWED. All transitions publish to Redis for real-time delivery + FCM push.
response 200 { "session_id": "9e818202-...", "video_permission_state": "NOT_ALLOWED", // NOT_ALLOWED | ALLOWED_BY_DOCTOR | VIDEO_ON | VIDEO_OFF | DECLINED_BY_PATIENT "patient_video_enabled": false, "consent_round": 0 }
NOT_ALLOWED → ALLOWED_BY_DOCTOR. Sends video.permission push to patient.
ALLOWED_BY_DOCTOR → VIDEO_ON. Patient video becomes enabled.
ALLOWED_BY_DOCTOR → DECLINED_BY_PATIENT.
Either party revokes. ALLOWED_BY_DOCTOR / VIDEO_ON / VIDEO_OFF → NOT_ALLOWED.
Connect Now v2 — Call Sessions
Manage call sessions within a connect session’s LiveKit room. Tracks call type (audio/video) and video permission state. Idempotent — returns existing if one already exists for the room.
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| connect_session_id | UUID | REQUIRED | Connect session to create call for |
| call_type | string | optional | AUDIO (default) | VIDEO |
response 201 (or 200 if exists) { "id": "b4c55a12-...", "connect_session_id": "9e818202-...", "call_type": "AUDIO", "status": "CONNECTED", "livekit_room_name": "cn-9e818202-...", "video_permission_state": "NOT_ALLOWED", "patient_video_enabled": false }
Returns call session details including video permission state.
Device Tokens (Push Notifications)
Register FCM device tokens for push notifications. Both patients and doctors should call this on app launch and whenever the FCM token refreshes. Supports multiple devices per user. Call DELETE on logout.
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| token | string | REQUIRED | FCM registration token |
| platform | string | REQUIRED | android | ios |
| app_version | string | optional | App version string |
response 201 { "id": "a1b2c3d4-...", "user_id": "644452ac-...", "role": "client", "platform": "android", "is_active": true }
29 push events delivered: session.accepted, session.rejected, session.ended, session.requested, session.expired, message.new, message.attachment, prescription.ready, labtests.recommended, followup.scheduled, followup.reminder, report.uploaded, review.submitted, review.reply, review.reminder, payment.success, payment.failed, video.permission, community.article, community.event
Request Body
| Field | Type | R / O | Description |
|---|---|---|---|
| token | string | REQUIRED | FCM token to deactivate |
Reviews
sample request { "session_id": "1d0fae55-fb8f-4085-b34c-b598e381b135", // REQUIRED – v1 or v2 session UUID "rating": 5.0, // REQUIRED – 1.0 to 5.0 "comment": "Very helpful, explained everything clearly." // optional }
Status Codes
Follow-ups
Full follow-up lifecycle: create, list, respond, reschedule, cancel.
sample request { "parent_session_id": "session-uuid-here", // REQUIRED – v1 session ID "scheduled_date": "2026-03-15", // REQUIRED "scheduled_time": "14:00:00", // optional "scheduled_timezone": "Asia/Kolkata" // optional – default Asia/Kolkata }
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| limit | int | optional | 1–100, default 20 |
| offset | int | optional | Default 0 |
| status | string | optional | PENDING_PATIENT | ACCEPTED | REJECTED | CANCELLED |
| upcoming | bool | optional | Future follow-ups only |
| past | bool | optional | Past follow-ups only |
sample
curl "/api/v2/followups/?status=PENDING_PATIENT&upcoming=true&limit=10" \
-H "Authorization: Bearer eyJ..."
sample
curl "/api/v2/followups/a5eea92a-..." -H "Authorization: Bearer eyJ..."
sample request — accept { "action": "accept" // REQUIRED – "accept" | "reject" | "reschedule" }
sample request — reschedule { "action": "reschedule", // REQUIRED "proposed_date": "2026-03-20", // REQUIRED when action=reschedule "proposed_time": "15:00:00" // optional }
sample request { "accept": true // REQUIRED – true to accept patient's proposed date, false to reject }
sample request { "reason": "Schedule conflict" // optional – cancellation reason }
Analytics
response 200 { "sessions_count": 108, // completed sessions (v1+v2) "followups_count": 4, "bmi": 23.7, // from profile, nullable "doctors_consulted_count": 1 // distinct doctors (v1+v2) }
sample
curl "/api/v2/analytics/user/sessions?limit=20&offset=0" -H "Authorization: Bearer eyJ..."
sample
curl "/api/v2/analytics/user/orders?limit=20&offset=0" -H "Authorization: Bearer eyJ..."
sample
curl "/api/v2/analytics/user/recharges?limit=20&offset=0" -H "Authorization: Bearer eyJ..."
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| timezone | string | optional | Default UTC. e.g. Asia/Kolkata |
| date_range | string | optional | today | week | month | year | all_time (default) |
sample
curl "/api/v2/analytics/doctor/performance?date_range=month&timezone=Asia/Kolkata" \
-H "Authorization: Bearer eyJ..."
sample
curl "/api/v2/analytics/doctor/reviews/metrics?date_from=2026-01-01&date_to=2026-01-31" \
-H "Authorization: Bearer eyJ..."
Query Params
| Param | Type | R / O | Description |
|---|---|---|---|
| period | string | optional | day (default) | week | month |
| date_from | string | optional | ISO 8601 |
| date_to | string | optional | ISO 8601 |
sample
curl "/api/v2/analytics/doctor/reviews/rating-distribution" -H "Authorization: Bearer eyJ..."
Medicines (Search / Catalog)
Typeahead autocomplete for 31,200+ medicines. Uses a three-phase search strategy: prefix match → contains match → fuzzy fallback (pg_trgm). No auth required — this is public reference data. Frontend should debounce requests by 200–300ms.
Query Parameters
| Param | Type | R / O | Description |
|---|---|---|---|
| q | string | REQUIRED | Search query (min 2, max 100 chars). Brand name, generic name, or salt. |
| limit | integer | optional | 1–25, default 10 |
curl example curl "/api/v2/medicines/search?q=amoxyclav&limit=5"
response 200 [ { "id": "a16efb82-14a5-4429-92e7-855b009b5e4d", "name": "Amoxyclav 625 Tablet", "form": "tablet", // tablet | capsule | injection | syrup | cream | gel | drops | ... "provider": "1mg" }, { "id": "48219863-5d68-4667-8221-148a3c96d840", "name": "Amoxyclav 375 Tablet", "form": "tablet", "provider": "1mg" } ]
1. Prefix — names starting with query (fastest, B-tree index)
2. Contains — names containing query anywhere, e.g. “paracetamol” finds “Genericart Paracetamol 650mg Tablet” (GIN index)
3. Fuzzy — handles typos, e.g. “amoxyclv” finds “Amoxyclav” (pg_trgm similarity)
Path Parameters
| Param | Type | R / O | Description |
|---|---|---|---|
| medicine_id | UUID | REQUIRED | Medicine ID from search results |
response 200 { "id": "a16efb82-14a5-4429-92e7-855b009b5e4d", "name": "Amoxyclav 625 Tablet", "form": "tablet", "provider": "1mg", "product_introduction": "Amoxyclav 625 Tablet is used in the treatment of...", "uses": ["Bacterial infections", "Skin infections"], "how_it_works": "Amoxyclav 625 Tablet is a combination of...", "safety_advice": { "advice": "Alcohol\nCONSULT YOUR DOCTOR..." }, "source_url": "https://www.1mg.com/drugs/amoxyclav-625-tablet-12345", "created_at": "2026-02-11T22:02:06.360732Z" }
Lab Tests (Search / Catalog)
Typeahead autocomplete for 1,935+ lab tests (Dr. Lal PathLabs). Searches by test name and test code. Same three-phase strategy as medicines. No auth required.
Query Parameters
| Param | Type | R / O | Description |
|---|---|---|---|
| q | string | REQUIRED | Search query (min 2, max 100 chars). Test name or test code (e.g. “CBC”). |
| limit | integer | optional | 1–25, default 10 |
curl examples // Search by name curl "/api/v2/lab-tests/catalog/search?q=thyroid&limit=5" // Search by test code curl "/api/v2/lab-tests/catalog/search?q=CBC&limit=5"
response 200 [ { "id": "b7c8d9e0-1234-5678-abcd-ef0123456789", "name": "Thyroid Profile, Free", "code": "Z045", "provider": "lal_pathlabs" }, { "id": "c8d9e0f1-2345-6789-abcd-ef0123456789", "name": "Thyroid, Comprehensive Panel", "code": "Z120", "provider": "lal_pathlabs" } ]
code field via prefix match, making it fast to find tests by their lab code.
Attachments (General)
General-purpose file uploads. Scopes: PROFILE, SESSION, REPORT, RECORDING.
sample request { "scope_type": "SESSION", // REQUIRED – PROFILE|SESSION|REPORT|RECORDING "scope_id": "session-uuid-here", // REQUIRED for SESSION/REPORT/RECORDING "filename": "report.pdf", // REQUIRED "content_type": "application/pdf", // REQUIRED "size_bytes": 1048576, // REQUIRED "upload_mode": "SAS" // optional – SAS (default) or DIRECT }
sample
curl -X POST "/api/v2/attachments/07af53f0-.../upload" \
-H "Authorization: Bearer eyJ..." -F "file=@report.pdf"sample (multipart/form-data) curl -X POST /api/v2/attachments \ -H "Authorization: Bearer eyJ..." \ -F "scope_type=SESSION" \ -F "scope_id=session-uuid" \ -F "file=@report.pdf"
sample
curl "/api/v2/attachments?scope_type=SESSION&scope_id=uuid&include_download_url=true" \
-H "Authorization: Bearer eyJ..."sample curl -X DELETE "/api/v2/attachments/07af53f0-..." -H "Authorization: Bearer eyJ..." // Response: 204 No Content
Categories
sample
curl "/api/v2/categories/health" -H "Authorization: Bearer eyJ..."
profile_completed=true (sex + age set). Returns 409 PROFILE_INCOMPLETE if not set.Community
sample
curl "/api/v2/community/articles?limit=20&category=wellness&sort_by=published_at&sort_order=desc"sample
curl "/api/v2/community/events?event_type=online&status=upcoming&sort_by=event_date"Payments (Cashfree)
sample request { "amount": 50000, // REQUIRED – amount in paise (= 500.00 INR) "offer_id": "uuid" // optional – wallet offer to apply }
response 201 { "order_id": "cf_order_abc123", "payment_session_id": "session_xyz...", // Use in Cashfree SDK "amount": 50000, "status": "PENDING" }
sample curl "/api/v2/payments/cashfree/orders/cf_order_abc123/verify" -H "Authorization: Bearer eyJ..." // Idempotent: won't double-credit wallet
Wallet
sample curl "/api/v2/wallet/offers" // Returns list of WalletOfferOut. Cached 5 min (public).
Admin — Authentication
sample request { "username": "admin", // REQUIRED – username or email "password": "s3cur3P@ss" // REQUIRED }
sample
curl "/api/v2/admin/auth/me" -H "Authorization: Bearer eyJ..."Admin — User Management
All endpoints require Admin token.
sample
curl "/api/v2/admin/users?limit=20&offset=0" -H "Authorization: Bearer eyJ..."sample
curl "/api/v2/admin/users/644452ac-..." -H "Authorization: Bearer eyJ..."sample request { "full_name": "Updated Name", // optional "age": 30 // optional }
sample request { "is_active": false // REQUIRED }
sample
curl "/api/v2/admin/users/644452ac-.../analytics/overview" -H "Authorization: Bearer eyJ..."sample
curl "/api/v2/admin/users/644452ac-.../analytics/sessions?limit=20" -H "Authorization: Bearer eyJ..."Admin — Categories
CRUD for health categories. All require Admin.
sample request { "name": "Dermatology", // REQUIRED "description": "Skin care", // optional "is_active": true // optional – default true }
sample
curl "/api/v2/admin/categories?limit=50" -H "Authorization: Bearer eyJ..."sample request { "is_active": false } // all fields optional
sample curl -X DELETE "/api/v2/admin/categories/uuid-here" -H "Authorization: Bearer eyJ..." // 204 No Content
Admin — Wallet Offers
sample request { "title": "Starter Pack", // REQUIRED "amount": 500.00, // REQUIRED – INR (converted to paise internally) "bonus_amount": 50.00, // optional – bonus in INR "valid_from": "2026-02-01", // REQUIRED "valid_until": "2026-03-01" // REQUIRED }
Admin — Articles
sample request { "title": "5 Tips for Better Sleep", // REQUIRED "excerpt": "Sleep is essential...", // REQUIRED "content": "Full article body...", // REQUIRED "category": "wellness", // optional "author": "Dr. Smith", // optional "image_url": "https://..." // optional }
Admin — Events
sample request { "title": "Health Awareness Webinar", // REQUIRED "description": "Join us for...", // REQUIRED "event_date": "2026-03-15T10:00:00Z", // REQUIRED "event_type": "online", // optional – online|in_person|hybrid "category": "wellness", // optional "image_url": "https://..." // optional }