# Patient Records & Sessions API ## Overview Patient records track patients per entity (doctor or clinic). Each record holds multiple sessions (visits). Access requires an active subscription with the `patient_records` feature. **Base path:** `/api/v1` **Auth:** Bearer JWT (doctor, clinic, or secretary with `appointments.view` permission required) --- ## Endpoints ### List Patients ``` GET /api/v1/patients ``` Returns a paginated list of patient records belonging to the authenticated entity. **Query params:** | Param | Type | Default | Description | |-------|------|---------|-------------| | `page` | int | 1 | Page number | | `limit` | int | 20 | Items per page (10–50) | | `search` | string | — | Search by patient name or phone | **Response 200:** ```json { "success": true, "data": [ { "uuid": "...", "entity_type": "doctor", "entity_id": 5, "user": { "uuid": "...", "fullName": "علی رضایی", "phone": "09123456789" }, "created_by_type": "doctor", "created_by_id": 5, "created_at": 1718375000 } ], "meta": { "totalRecords": 42, "totalPages": 3, "currentPage": 1 } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_SUBSCRIPTION_REQUIRED` | 403 | No active plan with `patient_records` feature | --- ### Create Patient Record ``` POST /api/v1/patient ``` Creates a patient record for a user under the current entity. If the record already exists, returns the existing record (idempotent). **Request body:** ```json { "user_uuid": "string (required)" } ``` **Response 201:** ```json { "success": true, "data": { "uuid": "...", "entity_type": "doctor", "entity_id": 5, "user": { "uuid": "...", "fullName": "...", "phone": "..." }, "created_by_type": "doctor", "created_by_id": 5, "created_at": 1718375000 } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_VALIDATION_001` | 422 | `user_uuid` missing | | `ERR_NOT_FOUND_001` | 404 | User not found | | `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature | --- ### Get Patient Record ``` GET /api/v1/patient/{uuid} ``` Returns a single patient record. **Response 200:** ```json { "success": true, "data": { "uuid": "...", "entity_type": "doctor", "entity_id": 5, "user": { "uuid": "...", "fullName": "...", "phone": "..." }, "created_by_type": "doctor", "created_by_id": 5, "created_at": 1718375000 } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller | | `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature | --- ### List Patient Sessions ``` GET /api/v1/patient/{uuid}/sessions ``` Returns paginated sessions for a patient record. **Query params:** `page`, `limit` (same as list) **Response 200:** ```json { "success": true, "data": [ { "uuid": "...", "record_uuid": "...", "appointment_uuid": null, "insurance_base_id": null, "insurance_supplementary_id": null, "visit_price_rials": 200000, "base_insurance_discount_percent": "10.00", "supplementary_discount_percent": "5.00", "services_total_rials": 50000, "final_price_rials": 230000, "payment_method": "cash", "notes": "...", "created_at": 1718375000, "updated_at": 1718375000 } ], "meta": { "totalRecords": 8, "totalPages": 1, "currentPage": 1 } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller | | `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature | --- ### Create Session ``` POST /api/v1/patient/{uuid}/session ``` Creates a new visit session for a patient record. **Request body:** ```json { "visit_price_rials": 200000, "base_insurance_discount_percent": 10, "supplementary_discount_percent": 5, "insurance_base_id": null, "insurance_supplementary_id": null, "payment_method": "cash", "notes": "...", "services": [ { "service_item_uuid": "...", "staff_uuid": null } ] } ``` **Field notes:** - `payment_method`: `cash` | `card` | `insurance` | `online` | `pending` - `services`: array of service items to attach; `price_rials` is snapshot-copied from ServiceItem - `final_price_rials` is computed: `(visit_price × (1 - base%) × (1 - supp%)) + services_total` **Response 201:** ```json { "success": true, "data": { ...session object... } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned | | `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature | --- ### Update Session ``` PATCH /api/v1/session/{uuid} ``` Updates mutable fields on a session. **Request body (all optional):** ```json { "notes": "...", "payment_method": "card" } ``` **Response 200:** ```json { "success": true, "data": { ...session object... } } ``` **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_SESSION_NOT_FOUND` | 404 | Session not found or not owned | --- ## Auto-Creation on Appointment Confirm When an appointment's status changes to `confirmed` via `PATCH /api/v1/appointment/{uuid}/status`, the system automatically: 1. Creates a `PatientRecord` for the appointment's user (if not already existing) under the doctor entity 2. Creates a blank `PatientSession` linked to the appointment This only runs if the doctor has the `patient_records` subscription feature active.