Patient Symptoms API Documentation
Overview
The Patient Symptoms API provides endpoints for managing patient symptoms, including CRUD operations and symptom associations. This API allows patients to track their medical symptoms, severity levels, duration, and relationships between different symptoms.
Base URL
/api/v1/patients/{patient_id}/patient_symptomsAuthentication
All endpoints require patient authentication. The API uses JWT tokens and the AuthenticablePatient concern to ensure patients can only access their own symptoms.
Error Response Format
All errors follow this format:
{
"success": false,
"errors": [
{
"source": "field_name",
"title": "Error message"
}
]
}Endpoints
1. List Patient Symptoms
Endpoint: GET /api/v1/patients/{patient_id}/patient_symptoms
Description: Retrieves a paginated list of active patient symptoms with optional filtering and sorting.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | Integer | 1 | Page number for pagination |
per_page | Integer | 20 | Number of records per page (max 100) |
category | String | - | Filter by symptom category |
severity | String | - | Filter by severity level (MILD, MODERATE, SEVERE) |
impact_level | String | - | Filter by impact level (NONE, LOW, MEDIUM, HIGH) |
start_date | String | - | Filter symptoms from this date (ISO 8601) |
end_date | String | - | Filter symptoms until this date (ISO 8601) |
recent | String | - | Set to 'true' to get symptoms from last week |
sort_by | String | logged_at | Sort field (logged_at, severity, created_at, symptom) |
sort_order | String | desc | Sort order (asc, desc) |
Request Example:
GET /api/v1/patients/123/patient_symptoms?page=1&per_page=10&severity=SEVERE&recent=true&sort_by=severity&sort_order=descSuccess Response (200):
{
"success": true,
"message": "Patient symptoms retrieved successfully",
"data": {
"patient_symptoms_list": [
{
"id": 456,
"patient_id": 123,
"prescription_complaint_id": null,
"basic_complaint_id": null,
"category": "NEUROLOGICAL",
"symptom": "Migraine",
"severity": "SEVERE",
"duration_value": 4,
"duration_unit": "HOURS",
"impact_level": "HIGH",
"possible_triggers": ["Stress", "Lack of sleep"],
"other_trigger": "Bright lights",
"relief_methods": ["Dark room", "Pain medication"],
"other_relief_method": "Cold compress",
"notes": "Patient reports throbbing pain on right side of head",
"deleted": false,
"deleted_at": null,
"logged_at": "2025-11-28T08:00:00Z",
"created_at": "2025-11-28T08:30:00Z",
"updated_at": "2025-11-28T08:30:00Z",
"associated_symptoms": [
{
"id": 457,
"symptom": "Nausea",
"category": "GENERAL",
"severity": "MODERATE"
}
]
}
],
"total_pages": 3,
"total_records": 25
}
}2. Get Single Patient Symptom
Endpoint: GET /api/v1/patients/{patient_id}/patient_symptoms/{id}
Description: Retrieves detailed information about a specific patient symptom.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
patient_id | Integer | ID of the patient |
id | Integer | ID of the symptom |
Request Example:
GET /api/v1/patients/123/patient_symptoms/456Success Response (200):
{
"success": true,
"message": "Patient symptom retrieved successfully",
"data": {
"patient_symptom": {
"id": 456,
"patient_id": 123,
"prescription_complaint_id": null,
"basic_complaint_id": null,
"category": "NEUROLOGICAL",
"symptom": "Migraine",
"severity": "SEVERE",
"duration_value": 4,
"duration_unit": "HOURS",
"impact_level": "HIGH",
"possible_triggers": ["Stress", "Lack of sleep"],
"other_trigger": "Bright lights",
"relief_methods": ["Dark room", "Pain medication"],
"other_relief_method": "Cold compress",
"notes": "Patient reports throbbing pain on right side of head",
"deleted": false,
"deleted_at": null,
"logged_at": "2025-11-28T08:00:00Z",
"created_at": "2025-11-28T08:30:00Z",
"updated_at": "2025-11-28T08:30:00Z",
"associated_symptoms": [
{
"id": 457,
"symptom": "Nausea",
"category": "GENERAL",
"severity": "MODERATE"
}
]
}
}
}Error Response (404):
{
"success": false,
"errors": [
{
"source": "patient_symptom",
"title": "not found"
}
]
}3. Create Patient Symptom
Endpoint: POST /api/v1/patients/{patient_id}/patient_symptoms
Description: Creates a new patient symptom with optional associations to existing symptoms.
Request Body:
{
"symptom_details": {
"symptom": "Headache",
"category": "NEUROLOGICAL",
"severity": "MODERATE",
"logged_at": "2025-11-28T09:00:00Z",
"duration_value": 2,
"duration_unit": "HOURS",
"impact_level": "MEDIUM",
"possible_triggers": ["Stress", "Lack of sleep"],
"other_trigger": "Bright lights",
"relief_methods": ["Rest", "Dark room"],
"other_relief_method": "Pain medication",
"notes": "Patient reports frontal headache",
"prescription_complaint_id": null,
"basic_complaint_id": null,
"associated_symptom_ids": [457, 458]
}
}Required Fields:
| Field | Type | Description | Validation |
|---|---|---|---|
symptom | String | Name/description of the symptom | Required |
category | String | Symptom category | Required |
severity | String | Severity level | Must be one of: MILD, MODERATE, SEVERE |
Optional Fields:
| Field | Type | Description | Validation |
|---|---|---|---|
logged_at | DateTime | When symptom was logged | Defaults to current time |
duration_value | Integer | Duration value | Must be ≥ 0 |
duration_unit | String | Duration unit | Must be one of: MINUTES, HOURS, DAYS, WEEKS |
impact_level | String | Impact on daily life | Must be one of: NONE, LOW, MEDIUM, HIGH |
possible_triggers | Array/String | List of possible triggers | Converted to array |
other_trigger | String | Other trigger description | Max 500 characters |
relief_methods | Array/String | List of relief methods | Converted to array |
other_relief_method | String | Other relief method | Max 500 characters |
notes | String | Additional notes | Max 1000 characters |
prescription_complaint_id | Integer | Reference to prescription complaint | Optional |
basic_complaint_id | Integer | Reference to basic complaint | Optional |
associated_symptom_ids | Array | IDs of associated symptoms | Must belong to same patient |
Success Response (201):
{
"success": true,
"message": "Patient symptom created successfully",
"data": {
"patient_symptom": {
"id": 459,
"patient_id": 123,
"prescription_complaint_id": null,
"basic_complaint_id": null,
"category": "NEUROLOGICAL",
"symptom": "Headache",
"severity": "MODERATE",
"duration_value": 2,
"duration_unit": "HOURS",
"impact_level": "MEDIUM",
"possible_triggers": ["Stress", "Lack of sleep"],
"other_trigger": "Bright lights",
"relief_methods": ["Rest", "Dark room"],
"other_relief_method": "Pain medication",
"notes": "Patient reports frontal headache",
"deleted": false,
"deleted_at": null,
"logged_at": "2025-11-28T09:00:00Z",
"created_at": "2025-11-28T09:15:00Z",
"updated_at": "2025-11-28T09:15:00Z",
"associated_symptoms": [
{
"id": 457,
"symptom": "Nausea",
"category": "GENERAL",
"severity": "MODERATE"
},
{
"id": 458,
"symptom": "Sensitivity to light",
"category": "NEUROLOGICAL",
"severity": "MILD"
}
]
}
}
}Error Response (400):
{
"success": false,
"errors": [
{
"source": "symptom",
"title": "is required"
},
{
"source": "category",
"title": "is required"
},
{
"source": "severity",
"title": "is required"
}
]
}4. Update Patient Symptom
Endpoint: PUT /api/v1/patients/{patient_id}/patient_symptoms/{id}
Description: Updates an existing patient symptom. Supports partial updates and can modify associations.
Request Body:
{
"symptom_details": {
"symptom": "Updated Headache",
"category": "NEUROLOGICAL",
"severity": "SEVERE",
"duration_value": 3,
"duration_unit": "HOURS",
"impact_level": "HIGH",
"notes": "Updated notes about headache",
"associated_symptom_ids": [457, 459]
}
}Success Response (200):
{
"success": true,
"message": "Patient symptom updated successfully",
"data": {
"patient_symptom": {
"id": 456,
"patient_id": 123,
"symptom": "Updated Headache",
"category": "NEUROLOGICAL",
"severity": "SEVERE",
"duration_value": 3,
"duration_unit": "HOURS",
"impact_level": "HIGH",
"notes": "Updated notes about headache",
"updated_at": "2025-11-28T10:00:00Z",
"associated_symptoms": [
{
"id": 457,
"symptom": "Nausea",
"category": "GENERAL",
"severity": "MODERATE"
},
{
"id": 459,
"symptom": "Eye strain",
"category": "OPHTHALMOLOGIC",
"severity": "MILD"
}
]
}
}
}5. Delete Patient Symptom (Soft Delete)
Endpoint: DELETE /api/v1/patients/{patient_id}/patient_symptoms/{id}
Description: Soft deletes a patient symptom. The record is marked as deleted but remains in the database for audit purposes.
Request Example:
DELETE /api/v1/patients/123/patient_symptoms/456Success Response (200):
{
"success": true,
"message": "Patient symptom deleted successfully"
}Error Response (404):
{
"success": false,
"errors": [
{
"source": "patient_symptom",
"title": "not found"
}
]
}6. Associate Symptoms
Endpoint: POST /api/v1/patients/{patient_id}/patient_symptoms/{id}/associate
Description: Creates an association between two symptoms belonging to the same patient.
Request Body:
{
"associated_symptom_id": 457
}Path Parameters:
| Parameter | Type | Description |
|---|---|---|
patient_id | Integer | ID of the patient |
id | Integer | ID of the source symptom |
Success Response (200):
{
"success": true,
"message": "Symptoms associated successfully",
"data": {
"id": 789,
"patient_symptom_id": 456,
"associated_patient_symptom_id": 457,
"created_at": "2025-11-28T10:30:00Z",
"updated_at": "2025-11-28T10:30:00Z"
}
}Error Response (400):
{
"success": false,
"errors": [
{
"source": "associated_symptom",
"title": "cannot be the same as the symptom"
}
]
}Error Response (409):
{
"success": false,
"errors": [
{
"source": "association",
"title": "already exists"
}
]
}Data Models
PatientSymptom
| Field | Type | Required | Description |
|---|---|---|---|
id | Integer | Yes | Unique identifier |
patient_id | Integer | Yes | Reference to patient |
prescription_complaint_id | Integer | No | Reference to prescription complaint |
basic_complaint_id | Integer | No | Reference to basic complaint |
category | String | Yes | Symptom category |
symptom | String | Yes | Symptom description |
severity | String | Yes | MILD, MODERATE, or SEVERE |
duration_value | Integer | No | Duration in specified units |
duration_unit | String | No | MINUTES, HOURS, DAYS, or WEEKS |
impact_level | String | No | NONE, LOW, MEDIUM, or HIGH |
possible_triggers | JSON Array | No | List of possible triggers |
other_trigger | String | No | Other trigger (max 500 chars) |
relief_methods | JSON Array | No | List of relief methods |
other_relief_method | String | No | Other relief method (max 500 chars) |
notes | String | No | Additional notes (max 1000 chars) |
deleted | Boolean | Yes | Soft delete flag |
deleted_at | DateTime | No | When record was soft deleted |
logged_at | DateTime | Yes | When symptom was logged |
created_at | DateTime | Yes | Record creation time |
updated_at | DateTime | Yes | Last update time |
PatientSymptomAssociation
| Field | Type | Required | Description |
|---|---|---|---|
id | Integer | Yes | Unique identifier |
patient_symptom_id | Integer | Yes | Source symptom ID |
associated_patient_symptom_id | Integer | Yes | Associated symptom ID |
created_at | DateTime | Yes | Association creation time |
updated_at | DateTime | Yes | Last update time |
Business Rules
- Patient Scope: Patients can only access and modify their own symptoms
- Soft Delete: Deleted symptoms are not returned in list/show operations
- Association Rules:
- A symptom cannot be associated with itself
- Associations must be between symptoms of the same patient
- Both symptoms must be active (not soft deleted)
- Duplicate associations are not allowed
- Validation Rules:
- Severity must be MILD, MODERATE, or SEVERE
- Duration unit must be MINUTES, HOURS, DAYS, or WEEKS
- Impact level must be NONE, LOW, MEDIUM, or HIGH
- Duration value must be a non-negative integer
- Pagination: Maximum 100 records per page
- Array Handling: Single string values for array fields are automatically converted to arrays
Common Use Cases
1. Daily Symptom Tracking
POST /api/v1/patients/123/patient_symptoms
{
"symptom_details": {
"symptom": "Morning headache",
"category": "NEUROLOGICAL",
"severity": "MILD",
"logged_at": "2025-11-28T07:30:00Z"
}
}2. Get Recent Symptoms
GET /api/v1/patients/123/patient_symptoms?recent=true&per_page=53. Filter by Severity
GET /api/v1/patients/123/patient_symptoms?severity=SEVERE&sort_by=logged_at&sort_order=desc4. Associate Related Symptoms
POST /api/v1/patients/123/patient_symptoms/456/associate
{
"associated_symptom_id": 457
}5. Update Symptom with Additional Details
PUT /api/v1/patients/123/patient_symptoms/456
{
"symptom_details": {
"severity": "SEVERE",
"duration_value": 6,
"duration_unit": "HOURS",
"impact_level": "HIGH",
"notes": "Symptoms worsened throughout the day"
}
}Error Codes
| Status Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request (validation errors) |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 409 | Conflict (duplicate association) |
| 422 | Unprocessable Entity |
| 500 | Internal Server Error |
Rate Limiting
API endpoints are subject to rate limiting as defined by the RateLimitable concern. Current limits:
- 100 requests per minute per authenticated patient
Testing
Example Request/Response Tests
# Test creating a symptom
curl -X POST "http://localhost:3000/api/v1/patients/1/patient_symptoms" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"symptom_details": {
"symptom": "Test headache",
"category": "NEUROLOGICAL",
"severity": "MILD"
}
}'
# Test listing symptoms
curl -X GET "http://localhost:3000/api/v1/patients/1/patient_symptoms?page=1&per_page=5" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
# Test associating symptoms
curl -X POST "http://localhost:3000/api/v1/patients/1/patient_symptoms/1/associate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"associated_symptom_id": 2}'Changelog
Version 1.0.0
- Initial release with basic CRUD operations
- Symptom associations functionality
- Pagination and filtering support
- Soft delete implementation
- Comprehensive validation rules