OSCAR REST Bridge API¶
REST-to-SOAP bridge for OSCAR EMR integration
Status: Live and tested (January 14, 2026) Version: 1.3.0 (Admission records, config centralization)
Overview¶
The Oscar REST Bridge is a Node.js microservice that provides a modern REST/JSON API interface to Oscar EMR's legacy SOAP web services.
Why Two Data Sources?¶
| Operation | Data Source | Reason |
|---|---|---|
| Get patient details | SOAP | Full SOAP support |
| Search patients | SOAP + DB | SOAP for name, DB for phone/quick search |
| Register patient | Database | SOAP doesn't support patient creation |
| Get appointments | SOAP | Full SOAP support |
| Provider availability | Database | SOAP method is buggy (returns empty) |
| Clinical data | SOAP | Full SOAP support |
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ External Clients │
│ (VitaraVox Voice Agent, Mobile Apps) │
└─────────────────────┬───────────────────────────────────────┘
│ REST/JSON + API Key
▼
┌─────────────────────────────────────────────────────────────┐
│ Oscar REST Bridge (:3000) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Middleware │ │
│ │ [Rate Limiter] → [Auth] → [Logger] → [Routes] │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Services │ │
│ │ DemographicService ScheduleService ProviderService│ │
│ └───────────────┬─────────────────────┬───────────────┘ │
│ │ │ │
│ ┌───────────────┴───────────────┐ ┌──┴──────────────────┐ │
│ │ SOAP Client │ │ Database Service │ │
│ │ (WS-Security, Retry Logic) │ │ (Direct MySQL) │ │
│ └───────────────┬───────────────┘ └──────────┬──────────┘ │
│ │ │ │
└──────────────────┼────────────────────────────┼─────────────┘
│ SOAP/XML │ SQL
▼ ▼
┌─────────────────────────────────┐ ┌─────────────────────────┐
│ Oscar EMR (:8080) │ │ MariaDB (:3306) │
│ SOAP Web Services │ │ oscar database │
└─────────────────────────────────┘ └─────────────────────────┘
Connection Details¶
| Setting | Value |
|---|---|
| Base URL | http://15.222.50.48:3000/api/v1 |
| Authentication | X-API-Key header |
| Timeout | 30 seconds |
Quick Start¶
# Health Check (no auth required)
curl http://15.222.50.48:3000/api/v1/health
# Search Patient by Phone
curl -H "X-API-Key: YOUR_API_KEY" \
"http://15.222.50.48:3000/api/v1/demographics/search?phone=2367770690"
# Get Provider Availability
curl -H "X-API-Key: YOUR_API_KEY" \
"http://15.222.50.48:3000/api/v1/appointments/availability?providerId=100&date=2026-01-14"
Endpoints¶
Health Check¶
No authentication required.
Response:
{
"status": "healthy",
"timestamp": "2026-01-13T15:30:00Z",
"services": {
"soap": "connected",
"database": "connected"
}
}
Demographics (Patients)¶
Quick Search¶
Multi-field search across name, phone, HIN, chart number.
| Parameter | Type | Required | Description |
|---|---|---|---|
term |
string | Yes | Search term (min 2 chars) |
limit |
number | No | Max results (default 20, max 100) |
Search by Name or Phone¶
GET /api/v1/demographics/search?name={lastName}&firstName={firstName}
GET /api/v1/demographics/search?phone={phoneNumber}
Response:
{
"success": true,
"data": [
{
"demographicNo": 78,
"firstName": "Charles",
"lastName": "Don",
"dateOfBirth": "1985-06-15",
"sex": "M",
"phone": "+12367770690"
}
]
}
Get Patient by ID¶
Register New Patient (v1.3.0)¶
Request Body:
{
"firstName": "Jane",
"lastName": "Doe",
"dateOfBirth": "1990-05-20",
"gender": "female",
"phone": "+12367770690",
"email": "jane@example.com",
"address": "123 Main St",
"city": "Vancouver",
"province": "BC",
"postalCode": "V6B 1A1",
"healthCardNumber": "1234567890"
}
Response:
v1.3.0 Features:
- Creates admission record automatically linking patient to OSCAR Service program
- Patient appears in provider rosters immediately
- Uses OSCAR_DEFAULT_PROGRAM_ID (default: 10034) for admission program
- Direct database insert (SOAP doesn't support patient creation)
Providers¶
List Providers¶
Response:
{
"success": true,
"data": [
{
"providerNo": "100",
"firstName": "Sarah",
"lastName": "Anderson",
"specialty": "Family Medicine"
}
]
}
Appointments¶
Get Provider Availability (v1.2.0)¶
Returns available time slots based on provider's schedule template.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerId |
string | Yes | Provider number (e.g., "100") |
date |
date | Yes | Date to check (YYYY-MM-DD) |
Response (with schedule):
{
"success": true,
"data": {
"providerId": "100",
"date": "2026-01-14",
"available": true,
"holiday": false,
"timeSlots": [
{
"startTime": "09:00",
"endTime": "09:15",
"status": "available",
"code": "B",
"description": "Behavioral Science",
"duration": 15
},
{
"startTime": "09:15",
"endTime": "09:30",
"status": "available",
"code": "B",
"description": "Behavioral Science",
"duration": 15
}
]
}
}
Response (no schedule configured):
Implementation Note: This endpoint queries the database directly because Oscar's SOAP getDayWorkSchedule method is buggy and returns empty results even when schedule data exists.
Get Appointment Types¶
Response:
{
"success": true,
"data": [
{ "code": "B", "name": "Behavioral Science", "duration": 15 },
{ "code": "2", "name": "New Concern", "duration": 30 },
{ "code": "3", "name": "Annual Physical", "duration": 45 },
{ "code": "P", "name": "Phone Consultation", "duration": 15 }
]
}
List Appointments¶
Create Appointment¶
Request Body:
{
"demographicId": 78,
"providerId": "100",
"appointmentDate": "2026-01-15",
"startTime": "09:00",
"duration": 15,
"reason": "Follow-up"
}
Update Appointment¶
Cancel Appointment¶
Note: Oscar doesn't support true deletion. This sets status to 'C' (Cancelled).
Oscar Schedule Pattern Encoding¶
Oscar uses character patterns for provider schedules:
// Oscar Schedule Pattern Encoding
// Each character = 15 minute slot
// '_' = unavailable
// 'B', '1', '2', etc. = available (template code)
// Example 48-char pattern (clinic hours, 8 AM start):
"____BBBBBBBBBBBB________BBBBBBBBBBBB____________"
// └──┘ 8-9 AM unavailable
// └────────────┘ 9 AM - 12 PM available
// └────────┘ 12-2 PM lunch
// └────────────┘ 2-5 PM available
// └────────────┘ 5-8 PM unavailable
Pattern Details:
- 48 chars = 12-hour day (8 AM - 8 PM)
- 96 chars = 24-hour day (midnight start)
- Each character = 15-minute slot
- _ = unavailable
- Letters = appointment type code from scheduletemplatecode table
Configuration (v1.3.0)¶
Environment variables for customizing bridge behavior:
| Variable | Default | Purpose |
|---|---|---|
OSCAR_DEFAULT_PROGRAM_ID |
10034 |
Admission program ID for new patients |
OSCAR_DEFAULT_PROVIDER_ID |
(empty) | Fallback provider for admissions |
OSCAR_DEFAULT_PROVINCE |
BC |
Default patient province |
OSCAR_DEFAULT_COUNTRY |
CA |
Default patient country |
OSCAR_DEFAULT_LANGUAGE |
English |
Default patient language |
OSCAR_CHART_PREFIX |
NEW |
Chart number prefix for new patients |
Database Configuration:
| Variable | Default | Purpose |
|---|---|---|
DB_HOST |
localhost |
MariaDB host |
DB_PORT |
3306 |
MariaDB port |
DB_USER |
root |
Database user |
DB_PASSWORD |
- | Database password |
DB_NAME |
oscar |
Database name |
DB_CONNECTION_LIMIT |
10 |
Connection pool size |
Endpoint Summary (v1.3.0)¶
GET /api/v1/health ← v1.3.0 (singleton, SOAP+DB check)
GET /api/v1/demographics
GET /api/v1/demographics/:id
GET /api/v1/demographics/search?name=xxx OR ?phone=xxx
GET /api/v1/demographics/quickSearch?term=xxx
POST /api/v1/demographics ← v1.3.0 (creates admission record)
GET /api/v1/appointments?providerId=&startDate=&endDate=
GET /api/v1/appointments/availability?providerId=&date= ← v1.2.0 (DB direct)
GET /api/v1/appointments/types
POST /api/v1/appointments
PUT /api/v1/appointments/:id
DELETE /api/v1/appointments/:id
GET /api/v1/providers
GET /api/v1/providers/current
GET /api/v1/allergies
GET /api/v1/prescriptions
GET /api/v1/measurements
Known Issues & Workarounds¶
SOAP getDayWorkSchedule Bug¶
Issue: Oscar's SOAP getDayWorkSchedule method returns empty timeSlots even when schedule data exists in the database.
Workaround: The /appointments/availability endpoint queries the scheduledate and scheduletemplatecode tables directly.
// SOAP returns this (buggy):
{ holiday: false, timeSlotDurationMin: 15, timeSlots: [] }
// Database has actual data in scheduledate.hour:
"____BBBBBBBBBBBB________BBBBBBBBBBBB____________"
No SOAP Patient Creation¶
Issue: Oscar's SOAP DemographicWs service doesn't provide a method to create new patients.
Workaround: POST /demographics inserts directly into the demographic table.
Test Data¶
| ID | Name | Phone | Provider |
|---|---|---|---|
| 78 | Charles Don | +12367770690 | - |
| 100 | Sarah Anderson | - | Provider with schedule |
Security¶
| Feature | Implementation |
|---|---|
| API Authentication | X-API-Key header |
| Rate Limiting | 100 req/15 min per API key |
| SQL Injection | Parameterized queries |
| Input Validation | Route-level checks |
Infrastructure (v1.3.0)¶
Health Check Improvements¶
- Singleton services: SOAP client and database service are singleton instances (no longer created per request)
- Dual connectivity check: Health endpoint verifies both SOAP and database connections
- Response format: Returns service status for each backend
{
"status": "healthy",
"timestamp": "2026-01-14T00:00:00Z",
"services": {
"soap": "connected",
"database": "connected"
}
}
Graceful Shutdown¶
The bridge handles SIGTERM/SIGINT signals for clean shutdown:
- Receives shutdown signal
- Logs:
"SIGTERM received, shutting down gracefully" - Closes database connection pool
- Logs:
"Closing database connection pool" - Exits cleanly
This ensures: - No orphaned database connections - Clean container restarts in Docker/Kubernetes - No data corruption during deployments
Files Modified (v1.3.0)¶
| File | Changes |
|---|---|
src/config/environment.js |
Added database config and Oscar defaults |
src/services/database-service.js |
Added createAdmission(), uses centralized config |
src/transformers/demographic-transformer.js |
Uses config for country/province defaults |
src/index.js |
Singleton services, improved health check, graceful shutdown |
Error Codes¶
| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid API key |
MISSING_PARAMETERS |
400 | Required query parameters missing |
INVALID_DATE_FORMAT |
400 | Date must be YYYY-MM-DD |
DUPLICATE_PATIENT |
409 | Patient already exists |
NOT_FOUND |
404 | Resource not found |
SOAP_ERROR |
502 | Oscar SOAP service error |
SERVICE_UNAVAILABLE |
503 | Backend service unreachable |