Kulcare Docs
DeveloperAuthentication Documentation04 featuresPatient

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_symptoms

Authentication

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:

ParameterTypeDefaultDescription
pageInteger1Page number for pagination
per_pageInteger20Number of records per page (max 100)
categoryString-Filter by symptom category
severityString-Filter by severity level (MILD, MODERATE, SEVERE)
impact_levelString-Filter by impact level (NONE, LOW, MEDIUM, HIGH)
start_dateString-Filter symptoms from this date (ISO 8601)
end_dateString-Filter symptoms until this date (ISO 8601)
recentString-Set to 'true' to get symptoms from last week
sort_byStringlogged_atSort field (logged_at, severity, created_at, symptom)
sort_orderStringdescSort 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=desc

Success 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:

ParameterTypeDescription
patient_idIntegerID of the patient
idIntegerID of the symptom

Request Example:

GET /api/v1/patients/123/patient_symptoms/456

Success 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:

FieldTypeDescriptionValidation
symptomStringName/description of the symptomRequired
categoryStringSymptom categoryRequired
severityStringSeverity levelMust be one of: MILD, MODERATE, SEVERE

Optional Fields:

FieldTypeDescriptionValidation
logged_atDateTimeWhen symptom was loggedDefaults to current time
duration_valueIntegerDuration valueMust be ≥ 0
duration_unitStringDuration unitMust be one of: MINUTES, HOURS, DAYS, WEEKS
impact_levelStringImpact on daily lifeMust be one of: NONE, LOW, MEDIUM, HIGH
possible_triggersArray/StringList of possible triggersConverted to array
other_triggerStringOther trigger descriptionMax 500 characters
relief_methodsArray/StringList of relief methodsConverted to array
other_relief_methodStringOther relief methodMax 500 characters
notesStringAdditional notesMax 1000 characters
prescription_complaint_idIntegerReference to prescription complaintOptional
basic_complaint_idIntegerReference to basic complaintOptional
associated_symptom_idsArrayIDs of associated symptomsMust 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/456

Success 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:

ParameterTypeDescription
patient_idIntegerID of the patient
idIntegerID 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

FieldTypeRequiredDescription
idIntegerYesUnique identifier
patient_idIntegerYesReference to patient
prescription_complaint_idIntegerNoReference to prescription complaint
basic_complaint_idIntegerNoReference to basic complaint
categoryStringYesSymptom category
symptomStringYesSymptom description
severityStringYesMILD, MODERATE, or SEVERE
duration_valueIntegerNoDuration in specified units
duration_unitStringNoMINUTES, HOURS, DAYS, or WEEKS
impact_levelStringNoNONE, LOW, MEDIUM, or HIGH
possible_triggersJSON ArrayNoList of possible triggers
other_triggerStringNoOther trigger (max 500 chars)
relief_methodsJSON ArrayNoList of relief methods
other_relief_methodStringNoOther relief method (max 500 chars)
notesStringNoAdditional notes (max 1000 chars)
deletedBooleanYesSoft delete flag
deleted_atDateTimeNoWhen record was soft deleted
logged_atDateTimeYesWhen symptom was logged
created_atDateTimeYesRecord creation time
updated_atDateTimeYesLast update time

PatientSymptomAssociation

FieldTypeRequiredDescription
idIntegerYesUnique identifier
patient_symptom_idIntegerYesSource symptom ID
associated_patient_symptom_idIntegerYesAssociated symptom ID
created_atDateTimeYesAssociation creation time
updated_atDateTimeYesLast update time

Business Rules

  1. Patient Scope: Patients can only access and modify their own symptoms
  2. Soft Delete: Deleted symptoms are not returned in list/show operations
  3. 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
  4. 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
  5. Pagination: Maximum 100 records per page
  6. 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=5

3. Filter by Severity

GET /api/v1/patients/123/patient_symptoms?severity=SEVERE&sort_by=logged_at&sort_order=desc
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 CodeDescription
200Success
201Created
400Bad Request (validation errors)
401Unauthorized
403Forbidden
404Not Found
409Conflict (duplicate association)
422Unprocessable Entity
500Internal 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

On this page