New feature / Change #8924
openEpics #8706: Bootstrap project and recover all feature we have so far (milestone #1)
Implement Fhir for external connectivity with health ecosystems
0%
Description
Summary¶
FHIR API integration for Appointment and Encounter resources.
Description¶
As an external EMR system, I need FHIR R4 compliant API endpoints to create appointments and retrieve encounters, enabling interoperability with healthcare systems like OpenEMR.
Requirements¶
FHIR Endpoints:
POST /api/fhir/Appointment → Create appointment (returns FHIR Appointment)
GET /api/fhir/Appointment → List appointments (returns FHIR Bundle)
GET /api/fhir/Appointment/:id → Get appointment (returns FHIR Appointment)
PUT /api/fhir/Appointment/:id → Update appointment
DELETE /api/fhir/Appointment/:id → Cancel appointment
GET /api/fhir/Encounter → List encounters (returns FHIR Bundle)
GET /api/fhir/Encounter/:id → Get encounter (returns FHIR Encounter)
FHIR → Internal Model Mapping:
| FHIR Resource | Internal Model |
|---|---|
| Appointment | Appointment + Consultation |
| Appointment.participant (Patient) | Participant (user, email, phone) |
| Appointment.participant (Practitioner) | Participant (doctor) |
| Encounter | Consultation |
Appointment Mapping:
| FHIR Field | Internal Field |
|---|---|
| Appointment.start | Appointment.scheduled_at |
| Appointment.end | Appointment.end_expected_at |
| Appointment.status | Appointment.status |
| Appointment.serviceType | Type (Online/InPerson) |
| Appointment.participant[Patient] | Participant (beneficiary) |
| Appointment.participant[Practitioner] | Participant (doctor) |
| Appointment.reason | Consultation.description |
| Appointment.identifier | External reference (store in metadata) |
Encounter Mapping:
| FHIR Field | Internal Field |
|---|---|
| Encounter.status | Consultation status |
| Encounter.period.start | Consultation.created_at |
| Encounter.period.end | Consultation.closed_at |
| Encounter.appointment | Reference to Appointment |
| Encounter.subject | Consultation.beneficiary |
| Encounter.participant | Consultation.owned_by (doctor) |
Status Mappings:
| FHIR Appointment | Internal Status |
|---|---|
| proposed | - |
| booked | Scheduled |
| cancelled | Cancelled |
| fulfilled | (completed) |
| FHIR Encounter | Internal Status |
|---|---|
| planned | pending |
| in-progress | active |
| finished | closed |
Request Body Example (Create Appointment):
{
"resourceType": "Appointment",
"status": "booked",
"start": "2025-01-15T10:00:00Z",
"end": "2025-01-15T10:30:00Z",
"serviceType": [{"coding": [{"code": "online"}]}],
"identifier": [{"system": "openemr", "value": "APT-12345"}],
"participant": [
{
"actor": {
"reference": "#patient1",
"type": "Patient"
},
"status": "accepted"
},
{
"actor": {
"reference": "#practitioner1",
"type": "Practitioner"
},
"status": "accepted"
}
],
"contained": [
{
"resourceType": "Patient",
"id": "patient1",
"name": [{"family": "Doe", "given": ["John"]}],
"telecom": [
{"system": "email", "value": "john@example.com"},
{"system": "phone", "value": "+1234567890"}
]
},
{
"resourceType": "Practitioner",
"id": "practitioner1",
"name": [{"family": "Smith", "given": ["Dr"]}],
"telecom": [{"system": "email", "value": "dr.smith@clinic.com"}]
}
]
}
Response (FHIR Appointment):
{
"resourceType": "Appointment",
"id": "123",
"status": "booked",
"start": "2025-01-15T10:00:00Z",
"end": "2025-01-15T10:30:00Z",
...
}
Validation Rules:
- Patient participant required with name and contact (email or phone)
- Practitioner participant required with email (must exist in system)
- Start date required and must be in future
- Cannot update after consultation started
Search Parameters:
- identifier - Search by external system ID
- appointment.identifier - Search encounters by appointment ID
Acceptance Criteria
- POST /fhir/Appointment creates Consultation + Appointment + Participants
- POST /fhir/Appointment returns valid FHIR Appointment response
- GET /fhir/Appointment returns FHIR Appointment or Bundle
- GET /fhir/Encounter returns FHIR Encounter or Bundle
- Search by external identifier works
- Invalid FHIR body returns 400 with validation errors
- Practitioner not in system returns 400 error
- Status mappings work bidirectionally
- Cannot modify appointment with active consultation
Notes
- Store original FHIR body for audit/reference
Updated by Gor Grigoryan 21 days ago
## Summary
FHIR R4 API integration for Appointment and Encounter resources.
## Description
As an external EMR system, I need FHIR R4 compliant API endpoints to create appointments and retrieve encounters, enabling interoperability with healthcare systems like OpenEMR.
## Requirements
FHIR Endpoints:
POST /api/fhir/Appointment → Create appointment (returns FHIR Appointment)
GET /api/fhir/Appointment → List appointments (returns FHIR Bundle)
GET /api/fhir/Appointment/:id → Get appointment (returns FHIR Appointment)
PUT /api/fhir/Appointment/:id → Update appointment
DELETE /api/fhir/Appointment/:id → Cancel appointment
GET /api/fhir/Encounter → List encounters (returns FHIR Bundle)
GET /api/fhir/Encounter/:id → Get encounter (returns FHIR Encounter)
FHIR → Internal Model Mapping:
| FHIR Resource | Internal Model |
|---------------|----------------|
| Appointment | Appointment + Consultation |
| Appointment.participant (Patient) | Participant (user, email, phone) |
| Appointment.participant (Practitioner) | Participant (doctor) |
| Encounter | Consultation |
Appointment Mapping:
| FHIR Field | Internal Field |
|------------|----------------|
| Appointment.start | Appointment.scheduled_at |
| Appointment.end | Appointment.end_expected_at |
| Appointment.status | Appointment.status |
| Appointment.serviceType | Type (Online/InPerson) |
| Appointment.participant[Patient] | Participant (beneficiary) |
| Appointment.participant[Practitioner] | Participant (doctor) |
| Appointment.reason | Consultation.description |
| Appointment.identifier | External reference (store in metadata) |
Encounter Mapping:
| FHIR Field | Internal Field |
|------------|----------------|
| Encounter.status | Consultation status |
| Encounter.period.start | Consultation.created_at |
| Encounter.period.end | Consultation.closed_at |
| Encounter.appointment | Reference to Appointment |
| Encounter.subject | Consultation.beneficiary |
| Encounter.participant | Consultation.owned_by (doctor) |
Status Mappings:
| FHIR Appointment | Internal Status |
|------------------|-----------------|
| proposed | - |
| booked | Scheduled |
| cancelled | Cancelled |
| fulfilled | (completed) |
| FHIR Encounter | Internal Status |
|----------------|-----------------|
| planned | pending |
| in-progress | active |
| finished | closed |
Request Body Example (Create Appointment):
{
"resourceType": "Appointment",
"status": "booked",
"start": "2025-01-15T10:00:00Z",
"end": "2025-01-15T10:30:00Z",
"serviceType": [{"coding": [{"code": "online"}]}],
"identifier": [{"system": "openemr", "value": "APT-12345"}],
"participant": [
{
"actor": {
"reference": "#patient1",
"type": "Patient"
},
"status": "accepted"
},
{
"actor": {
"reference": "#practitioner1",
"type": "Practitioner"
},
"status": "accepted"
}
],
"contained": [
{
"resourceType": "Patient",
"id": "patient1",
"name": [{"family": "Doe", "given": ["John"]}],
"telecom": [
{"system": "email", "value": "john@example.com"},
{"system": "phone", "value": "+1234567890"}
]
},
{
"resourceType": "Practitioner",
"id": "practitioner1",
"name": [{"family": "Smith", "given": ["Dr"]}],
"telecom": [{"system": "email", "value": "dr.smith@clinic.com"}]
}
]
}
Response (FHIR Appointment):
{
"resourceType": "Appointment",
"id": "123",
"status": "booked",
"start": "2025-01-15T10:00:00Z",
"end": "2025-01-15T10:30:00Z",
...
}
Validation Rules:
- Patient participant required with name and contact (email or phone)
- Practitioner participant required with email (must exist in system)
- Start date required and must be in future
- Cannot update after consultation started
Search Parameters:
- identifier - Search by external system ID
- appointment.identifier - Search encounters by appointment ID
Acceptance Criteria
- POST /fhir/Appointment creates Consultation + Appointment + Participants
- POST /fhir/Appointment returns valid FHIR Appointment response
- GET /fhir/Appointment returns FHIR Appointment or Bundle
- GET /fhir/Encounter returns FHIR Encounter or Bundle
- Search by external identifier works
- Invalid FHIR body returns 400 with validation errors
- Practitioner not in system returns 400 error
- Status mappings work bidirectionally
- Cannot modify appointment with active consultation
Notes
- Store original FHIR body for audit/reference