Skip to main content

Overview

The Patient API provides endpoints for searching patient records in the OpenEyes system. This API is used for patient lookup, integration with external systems, and patient data retrieval. Source: protected/modules/Api/controllers/PatientController.php

Authentication

All Patient API endpoints require:
  • HTTP Basic Authentication
  • User must have the OprnApi role
  • Authenticated user access (users => ['@'])
See Authentication for details.

Endpoints

Search Patients

Search for patients by term and optional identifier type.
GET /api/v1/patient/search?term={term}&patient_identifier_type={type}

Query Parameters

term
string
required
Search term for patient lookup. Can be a name, identifier, or partial match.The term is validated using PatientSearch::getValidSearchTerm() before processing.
patient_identifier_type
integer
Filter by specific patient identifier type ID.When provided, searches only within that identifier type. When omitted, searches across all identifier types and uses the primary identifier for display.

Response

Returns an array of patient objects matching the search criteria.
id
integer
Patient database ID
first_name
string
Patient’s first name
last_name
string
Patient’s last name
age
string
Patient age or “Deceased” if patient has died
genderletter
string
Patient gender code (e.g., “M”, “F”)
dob
string
Date of birth in YYYY-MM-DD format
is_deceased
boolean
Whether the patient is deceased
patient_identifiers
array
Array of all patient identifiers
primary_patient_identifiers
object
Primary patient identifier based on institution settings

Response Example

[
  {
    "id": 12345,
    "first_name": "John",
    "last_name": "Smith",
    "age": "54",
    "genderletter": "M",
    "dob": "1970-03-15",
    "is_deceased": false,
    "patient_identifiers": [
      {
        "title": "Hospital Number",
        "value": "H123456"
      },
      {
        "title": "NHS Number",
        "value": "1234567890"
      }
    ],
    "primary_patient_identifiers": {
      "title": "Hospital Number",
      "value": "H123456"
    }
  },
  {
    "id": 12346,
    "first_name": "Jane",
    "last_name": "Smith",
    "age": "Deceased",
    "genderletter": "F",
    "dob": "1945-07-22",
    "is_deceased": true,
    "patient_identifiers": [
      {
        "title": "Hospital Number",
        "value": "H789012"
      }
    ],
    "primary_patient_identifiers": {
      "title": "Hospital Number",
      "value": "H789012"
    }
  }
]

Empty Results

When no patients match the search criteria, an empty array is returned:
[]
HTTP Status: 200 OK

Implementation Details

Search Logic

The search functionality (lines 42-91 in PatientController.php):
  1. Retrieves search parameters from the request
  2. Creates a PatientSearch instance
  3. Validates the search term using getValidSearchTerm()
  4. Executes the search with PatientSearch::search()
  5. Iterates through results to build response array
  6. Collects all patient identifiers
  7. Determines primary identifier based on institution settings
  8. Returns JSON response with status 200

Primary Identifier Logic

When patient_identifier_type is NOT specified:
$primary_identifier = PatientIdentifierHelper::getIdentifierForPatient(
    SettingMetadata::model()->getSetting('display_primary_number_usage_code'),
    $patient->id,
    \Institution::model()->getCurrent()->id,
    Yii::app()->session['selected_site_id']
);
Source: PatientController.php:64-69 When patient_identifier_type IS specified:
$primary_identifier = null;
Source: PatientController.php:61-63

Access Control

The controller enforces strict access control:
public function accessRules()
{
    return [
        [
            'allow',
            'actions' => ['search'],
            'users' => ['@'],  // authenticated users only
        ],
        [
            'deny',
            'users' => ['*'],
        ],
    ];
}
Source: PatientController.php:20-33

Behaviors

public function behaviors()
{
    return array_merge(parent::behaviors(), [
        'BasicAuthBehavior' => ['class' => 'application.modules.Api.behaviors.BasicAuthBehavior'],
    ]);
}
Source: PatientController.php:35-40

Patient Model Reference

The Patient model (protected/models/Patient.php) includes:

Core Attributes

  • id - Primary key
  • title - Patient title (Mr, Mrs, Dr, etc.)
  • first_name - First name
  • last_name - Last name
  • dob - Date of birth
  • date_of_death - Date of death (if applicable)
  • gender - Gender
  • hos_num - Hospital number (legacy)
  • nhs_num - NHS number (legacy)
  • primary_phone - Primary phone number
  • deleted - Soft delete flag
  • ethnic_group_id - Ethnic group
  • patient_source - Source of patient record
  • primary_institution_id - Primary institution
  • episodes[] - Patient episodes
  • addresses[] - Patient addresses
  • contact - Contact information
  • identifiers[] - Patient identifiers (modern approach)
  • allergies[] - Patient allergies
  • trials[] - Clinical trials
Source: protected/models/Patient.php:1-100

Usage Examples

Search by Name

curl -u api_user:password \
  "https://openeyes.example.com/api/v1/patient/search?term=Smith"

Search by Hospital Number

curl -u api_user:password \
  "https://openeyes.example.com/api/v1/patient/search?term=H123456"

Search by NHS Number

curl -u api_user:password \
  "https://openeyes.example.com/api/v1/patient/search?term=1234567890"

Search with Specific Identifier Type

curl -u api_user:password \
  "https://openeyes.example.com/api/v1/patient/search?term=123456&patient_identifier_type=2"

Integration Example (Python)

import requests
from requests.auth import HTTPBasicAuth

class OpenEyesPatientAPI:
    def __init__(self, base_url, username, password):
        self.base_url = base_url
        self.auth = HTTPBasicAuth(username, password)
    
    def search_patients(self, term, identifier_type=None):
        url = f"{self.base_url}/api/v1/patient/search"
        params = {'term': term}
        
        if identifier_type:
            params['patient_identifier_type'] = identifier_type
        
        response = requests.get(url, params=params, auth=self.auth)
        response.raise_for_status()
        return response.json()
    
    def get_patient_by_hospital_number(self, hos_num):
        patients = self.search_patients(hos_num)
        return patients[0] if patients else None

# Usage
api = OpenEyesPatientAPI(
    'https://openeyes.example.com',
    'api_user',
    'secure_password'
)

results = api.search_patients('Smith')
for patient in results:
    print(f"{patient['first_name']} {patient['last_name']} - {patient['age']}")

Error Handling

Invalid Search Term

If the search term fails validation, an empty result set is returned:
[]

Authentication Failure

Status: 401 Unauthorized
"401 Unauthorized"

Insufficient Permissions

Status: 403 Forbidden
"403 Forbidden"

Best Practices

Always provide meaningful search terms. Empty or very short terms may not return results depending on the PatientSearch validation rules.
Always check for empty arrays in responses. Not finding a patient is a valid outcome, not an error.
const patients = await searchPatients('term');
if (patients.length === 0) {
  console.log('No patients found');
}
The primary_patient_identifiers field provides the institution-configured primary identifier, which should be used for display purposes.
Always check the is_deceased field and age value before displaying patient information or scheduling appointments.

Next Steps

Events API

Access clinical events and attachments

Authentication

Learn about API security

Build docs developers (and LLMs) love