Kulcare Docs
DeveloperAuthentication Documentation04 featuresAudit_trail

Audit Trail API Integration Guide

Overview

This document provides comprehensive API integration details for the KulCare audit trail system. It covers all endpoints, parameters, response formats, and implementation guidelines for frontend applications and external integrations.

Table of Contents

Authentication

All audit trail endpoints require authentication using JWT Bearer tokens.

Header Format:

Authorization: Bearer <jwt_token>

Required Permissions:

  • Clinic Endpoints: User must be authorized for the specific clinic
  • Admin Endpoints: User must have admin role permissions

Base URLs

Production:  https://api.kulcare.com
Staging:     https://api-stg.kulcare.com

Clinic-Level Endpoints

1. GET /clinics/:clinic_id/audit_trails

Retrieve audit trails for a specific clinic with filtering and pagination.

URL: /clinics/{clinic_id}/audit_trails

Method: GET

Authentication: Required - Clinic authorization

Path Parameters:

ParameterTypeRequiredDescription
clinic_idintegerYesUnique clinic identifier

Query Parameters:

ParameterTypeRequiredDefaultDescription
pageintegerNo1Page number for pagination
per_pageintegerNo50Records per page (max: 200)
start_datestringNo-Filter start date (YYYY-MM-DD)
end_datestringNo-Filter end date (YYYY-MM-DD)
user_idintegerNo-Filter by specific user ID
event_keystringNo-Filter by event type
statusstringNo-Filter by status (success/failure/failed)
patient_idintegerNo-Filter by patient ID
clinic_patient_idintegerNo-Filter by clinic patient ID

Event Key Options:

Patient Management:
- patient.view
- patient.create
- patient.update
- patient.delete
- patient.medical_record.create
- patient.vital.create
- patient.medication.create

Appointments:
- appointment.book
- appointment.cancel
- appointment.update

Care Plans:
- careplan.update
- careplan.send
- careplan.email_send
- careplan.print

Billing:
- bill.create
- bill.delete
- payment.create
- payment.update
- payment.refund

Authentication:
- auth.login
- auth.logout
- auth.failed_login
- auth.registration

Administrative:
- audit.export

Example Request:

curl -X GET \
  "https://api.kulcare.com/clinics/123/audit_trails?page=1&per_page=50&start_date=2024-01-01&event_key=patient.create" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Success Response (200):

{
  "success": true,
  "message": "Audit trails fetched successfully",
  "data": {
    "audit_trails": [
      {
        "id": 12345,
        "timestamp": "2024-01-15T10:30:00Z",
        "created_at": "2024-01-15T10:30:00Z",
        "key": "patient.create",
        "event_status": "SUCCESS",
        "description": "Patient record created successfully",
        "ip_address": "192.168.1.100",
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
        "device_type": "desktop",
        "user_role": "doctor",
        "user": {
          "id": 789,
          "name": "Dr. John Smith",
          "type": "Doctor"
        },
        "patient": {
          "id": 456,
          "name": "Jane Doe"
        },
        "resource": {
          "type": "Patient",
          "id": 456
        },
        "parameters": {
          "patient_age": 35,
          "patient_gender": "female",
          "registration_source": "web_portal"
        }
      }
    ],
    "total_pages": 10,
    "total_records": 500
  }
}

2. POST /clinics/:clinic_id/audit_trails/export

Request an audit trail export in CSV format.

URL: /clinics/{clinic_id}/audit_trails/export

Method: POST

Authentication: Required - Clinic authorization

Path Parameters:

ParameterTypeRequiredDescription
clinic_idintegerYesUnique clinic identifier

Request Body:

ParameterTypeRequiredDescription
start_datestringNoExport start date (YYYY-MM-DD)
end_datestringNoExport end date (YYYY-MM-DD)
event_keystringNoFilter by specific event type

Validation Rules:

  • Maximum date range: 90 days
  • If only start_date provided, exports single day
  • If no dates provided, exports all available data

Example Request:

curl -X POST \
  "https://api.kulcare.com/clinics/123/audit_trails/export" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -d '{
    "start_date": "2024-01-01",
    "end_date": "2024-01-31",
    "event_key": "patient.create"
  }'

Success Response (200):

{
  "success": true,
  "message": "Audit trail export enqueued",
  "data": {
    "export_id": 456,
    "estimated_completion": "2024-01-15T10:35:00Z"
  }
}

Export Process:

  1. Request creates an export job in the background
  2. User receives email notification when export is ready
  3. Export file is available for 7 days
  4. File is automatically deleted after expiration

3. GET /clinics/:clinic_id/patients/:patient_id/audit_trails

Retrieve audit trails specific to a patient.

URL: /clinics/{clinic_id}/patients/{patient_id}/audit_trails

Method: GET

Authentication: Required - Clinic authorization

Path Parameters:

ParameterTypeRequiredDescription
clinic_idintegerYesUnique clinic identifier
patient_idintegerYesUnique patient identifier

Query Parameters: Same as general audit trails endpoint, except patient filtering is automatic.

Example Request:

curl -X GET \
  "https://api.kulcare.com/clinics/123/patients/456/audit_trails?page=1&per_page=50" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Response Format: Same as general audit trails endpoint, but all entries are filtered to the specified patient.

Admin-Level Endpoints

1. GET /admin/audit_trails

Admin access to audit trails across all clinics with advanced filtering.

URL: /admin/audit_trails

Method: GET

Authentication: Required - Admin role

Query Parameters:

ParameterTypeRequiredDefaultDescription
pageintegerNo1Page number for pagination
per_pageintegerNo50Records per page (max: 200)
start_datestringNo30 days agoFilter start date (YYYY-MM-DD)
end_datestringNotodayFilter end date (YYYY-MM-DD)
clinic_idintegerNo-Filter by single clinic
clinic_idsarrayNo-Filter by multiple clinics
user_idintegerNo-Filter by specific user
user_typestringNo-Filter by user type
event_keystring/arrayNo-Filter by event type(s)
statusstringNo-Filter by status
patient_idintegerNo-Filter by patient
ip_addressstringNo-Filter by IP (supports wildcards)
resource_typestringNo-Filter by resource type
sort_bystringNocreated_atSort column
sort_directionstringNodescSort direction (asc/desc)
include_summarybooleanNofalseInclude summary statistics

User Type Options:

  • owner - Clinic owners
  • consultant - Consultant doctors
  • staff - Staff members
  • admin - System administrators

Resource Type Options:

  • appointment - Appointment records
  • careplan - Care plan records
  • patient - Patient records
  • user - User records
  • clinic - Clinic records

Sort By Options:

  • created_at - Date/time of event
  • event_type - Event type
  • user - User who performed action
  • status - Event status

Example Request:

curl -X GET \
  "https://api.kulcare.com/admin/audit_trails?page=1&per_page=100&user_type=owner&status=failure&include_summary=true" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Success Response (200):

{
  "success": true,
  "message": "Admin audit trails fetched successfully",
  "data": {
    "audit_trails": [
      {
        "id": 12345,
        "timestamp": "2024-01-15T10:30:00Z",
        "key": "auth.failed_login",
        "event_status": "FAILURE",
        "description": "Failed login attempt",
        "ip_address": "192.168.1.100",
        "user_agent": "Mozilla/5.0...",
        "device_type": "desktop",
        "user_role": "owner",
        "user": {
          "id": 789,
          "name": "Dr. John Smith",
          "type": "User"
        },
        "parameters": {
          "error_code": "INVALID_CREDENTIALS",
          "attempt_count": 3
        }
      }
    ],
    "total_pages": 25,
    "total_records": 2500,
    "current_page": 1,
    "per_page": 100,
    "summary": {
      "total_records": 2500,
      "event_breakdown": {
        "auth.login": 1200,
        "auth.failed_login": 85,
        "patient.create": 450,
        "appointment.book": 765
      },
      "status_breakdown": {
        "SUCCESS": 2350,
        "FAILURE": 125,
        "UNAUTHORIZED": 25
      },
      "user_type_breakdown": {
        "owner": 800,
        "consultant": 1200,
        "staff": 450,
        "admin": 50
      },
      "clinic_breakdown": {
        "City Medical Center": 400,
        "Downtown Clinic": 350,
        "Suburban Health": 275
      },
      "daily_activity": {
        "2024-01-14": 450,
        "2024-01-15": 520,
        "2024-01-16": 480
      },
      "top_ip_addresses": {
        "192.168.1.100": 45,
        "10.0.0.15": 32,
        "172.16.0.5": 28
      }
    }
  }
}

2. GET /admin/audit_trails/summary

Get summary statistics for admin dashboard.

URL: /admin/audit_trails/summary

Method: GET

Authentication: Required - Admin role

Query Parameters:

ParameterTypeRequiredDefaultDescription
start_datestringNo30 days agoSummary start date
end_datestringNotodaySummary end date
clinic_idintegerNo-Filter by clinic
user_typestringNo-Filter by user type

Example Request:

curl -X GET \
  "https://api.kulcare.com/admin/audit_trails/summary?start_date=2024-01-01&end_date=2024-01-31" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Success Response (200):

{
  "success": true,
  "message": "Audit trail summary fetched successfully",
  "data": {
    "total_records": 15750,
    "date_range": {
      "start_date": "2024-01-01",
      "end_date": "2024-01-31"
    },
    "event_breakdown": {
      "auth.login": 3500,
      "patient.create": 2200,
      "appointment.book": 4500,
      "careplan.send": 1800,
      "auth.failed_login": 250
    },
    "status_breakdown": {
      "SUCCESS": 14800,
      "FAILURE": 750,
      "UNAUTHORIZED": 200
    },
    "user_type_breakdown": {
      "owner": 4200,
      "consultant": 7800,
      "staff": 3200,
      "admin": 550
    },
    "top_clinics": {
      "City Medical Center": 2800,
      "Downtown Clinic": 2400,
      "Suburban Health": 2100,
      "Metro Healthcare": 1900,
      "Community Clinic": 1650
    },
    "top_ip_addresses": {
      "192.168.1.100": 450,
      "10.0.0.15": 380,
      "172.16.0.5": 320,
      "192.168.2.50": 285,
      "10.0.1.25": 240
    },
    "daily_activity": {
      "2024-01-01": 485,
      "2024-01-02": 520,
      "2024-01-03": 495,
      "2024-01-04": 510,
      "2024-01-05": 475
    }
  }
}

Response Formats

Standard Response Structure

All API responses follow a consistent structure:

{
  "success": boolean,
  "message": string,
  "data": object
}

Audit Trail Entry Structure

{
  "id": integer,
  "timestamp": "ISO 8601 string",
  "created_at": "ISO 8601 string",
  "key": "string (event type)",
  "event_status": "SUCCESS|FAILURE|UNAUTHORIZED",
  "description": "string",
  "ip_address": "string",
  "user_agent": "string",
  "device_type": "mobile|tablet|desktop",
  "user_role": "string",
  "user": {
    "id": integer,
    "name": "string",
    "type": "string"
  },
  "patient": {
    "id": integer,
    "name": "string"
  } | null,
  "resource": {
    "type": "string",
    "id": integer
  } | null,
  "parameters": object
}

Pagination Structure

{
  "audit_trails": [...],
  "total_pages": integer,
  "total_records": integer,
  "current_page": integer,
  "per_page": integer
}

Error Handling

Error Response Format

{
  "success": false,
  "message": "Error description",
  "errors": {
    "field_name": ["Error message"]
  }
}

HTTP Status Codes

CodeDescriptionCommon Causes
200SuccessRequest completed successfully
400Bad RequestInvalid parameters or request format
401UnauthorizedMissing or invalid authentication token
403ForbiddenUser lacks permission for requested resource
404Not FoundClinic or resource doesn't exist
422Unprocessable EntityValidation errors in request data
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error occurred

Common Error Examples

Invalid Date Format (422):

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "start_date": ["invalid date format"]
  }
}

Date Range Too Large (422):

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "date_range": ["export limited to 90 days"]
  }
}

Unauthorized Clinic Access (403):

{
  "success": false,
  "message": "You do not have permission to access this clinic's audit trails"
}

Invalid Authentication (401):

{
  "success": false,
  "message": "Authentication token is invalid or expired"
}

Rate Limiting

Limits:

  • Standard Users: 100 requests per minute
  • Admin Users: 500 requests per minute
  • Export Requests: 5 exports per hour per user

Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642680000

Rate Limit Exceeded Response (429):

{
  "success": false,
  "message": "Rate limit exceeded. Please try again later."
}

Integration Examples

Basic Integration Pattern

// Basic audit trail fetch
const fetchAuditTrails = async (clinicId, filters = {}) => {
  const params = new URLSearchParams(filters);
  
  const response = await fetch(
    `${API_BASE_URL}/clinics/${clinicId}/audit_trails?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }
  
  return response.json();
};

Export Request Pattern

// Request audit trail export
const exportAuditTrails = async (clinicId, exportParams) => {
  const response = await fetch(
    `${API_BASE_URL}/clinics/${clinicId}/audit_trails/export`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(exportParams)
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Export request failed');
  }
  
  return response.json();
};

Error Handling Pattern

// Comprehensive error handling
const handleApiError = (error, response) => {
  if (response?.status === 401) {
    // Redirect to login
    window.location.href = '/login';
    return;
  }
  
  if (response?.status === 403) {
    // Show permission denied message
    showError('You do not have permission to access this resource');
    return;
  }
  
  if (response?.status === 422) {
    // Handle validation errors
    const errors = error.errors || {};
    Object.keys(errors).forEach(field => {
      showFieldError(field, errors[field].join(', '));
    });
    return;
  }
  
  // General error handling
  showError(error.message || 'An unexpected error occurred');
};

Pagination Pattern

// Handle pagination
const loadAuditTrailPage = async (clinicId, page, filters) => {
  try {
    const response = await fetchAuditTrails(clinicId, {
      ...filters,
      page,
      per_page: 50
    });
    
    return {
      entries: response.data.audit_trails,
      pagination: {
        currentPage: page,
        totalPages: response.data.total_pages,
        totalRecords: response.data.total_records
      }
    };
  } catch (error) {
    console.error('Failed to load audit trails:', error);
    throw error;
  }
};

Filtering Pattern

// Apply filters with debouncing
const applyFilters = debounce(async (clinicId, filters) => {
  // Clean up empty filter values
  const cleanFilters = Object.fromEntries(
    Object.entries(filters).filter(([_, value]) => 
      value !== null && value !== undefined && value !== ''
    )
  );
  
  try {
    const response = await fetchAuditTrails(clinicId, {
      ...cleanFilters,
      page: 1 // Reset to first page when filtering
    });
    
    return response.data;
  } catch (error) {
    handleApiError(error);
    throw error;
  }
}, 300);

Admin Integration Pattern

// Admin audit trail fetch with summary
const fetchAdminAuditTrails = async (filters = {}) => {
  const params = new URLSearchParams({
    ...filters,
    include_summary: 'true'
  });
  
  const response = await fetch(
    `${API_BASE_URL}/admin/audit_trails?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${adminToken}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }
  
  return response.json();
};

Best Practices

Performance Optimization

  1. Use Pagination: Always implement pagination for large datasets
  2. Apply Filters: Use date ranges and event filters to reduce data volume
  3. Cache Responses: Cache frequently accessed data with appropriate TTL
  4. Batch Requests: Avoid making multiple rapid requests

Security Considerations

  1. Token Management: Implement token refresh mechanisms
  2. Permission Validation: Always validate user permissions before API calls
  3. Input Sanitization: Sanitize all user inputs before sending to API
  4. Error Logging: Log errors for monitoring but don't expose sensitive data

Integration Guidelines

  1. Error Handling: Implement comprehensive error handling for all scenarios
  2. Loading States: Show appropriate loading indicators during API calls
  3. Rate Limiting: Respect rate limits and implement backoff strategies
  4. Data Validation: Validate data on client side before API submission


Last updated: January 2024

On this page