Skip to content

OSCAR EMR SOAP API Reference

Last Updated: 2026-03-09

Complete reference for all SOAP web services exposed by OSCAR EMR via Apache CXF. This is the authoritative API surface used by VitaraVox's OscarSoapAdapter.

VitaraVox Operations Actually Used

Of the 14 SOAP services and 50+ operations, VitaraVox calls only 8 operations across 3 services:

  • ScheduleService: getDayWorkSchedule, getAppointmentsForDateRangeAndProvider2, addAppointment, updateAppointment, getScheduleTemplateCodes
  • DemographicService: getDemographic, searchDemographicByName
  • ProviderService: getProviders2(true)

When preferRest=true (Kai-hosted OSCAR), all operations route to OAuth 1.0a REST endpoints instead. See Adapter Implementations and OSCAR OAuth Flow.


Overview

Three API Surfaces

This page covers Surface 1: SOAP Web Services only. OSCAR also exposes Cookie-Authenticated REST (/ws/rs/*) and OAuth-Protected REST (/ws/services/*). For the full picture — including Cloudflare WAF behavior on Kai-hosted instances — see OSCAR API Protocol Analysis.

OSCAR exposes 14 SOAP web services at the base path /oscar/ws/. Services use document/literal SOAP binding over HTTP with GZIP compression enabled on all endpoints (threshold: 0 bytes).

Cloudflare WAF on Kai-Hosted Instances

Kai-hosted OSCAR instances (e.g., fbh.kai-oscar.com) have a Cloudflare WAF that blocks SOAP requests. The WAF triggers on Content-Type: text/xml combined with a <soapenv:Envelope> body. For Kai-hosted clinics, use the OAuth REST path (preferRest=true) instead. See Protocol Analysis for the 8-test proof matrix.

# Service Endpoint Path Auth Required
1 DemographicService /oscar/ws/DemographicService Yes
2 ProviderService /oscar/ws/ProviderService Yes
3 ScheduleService /oscar/ws/ScheduleService Yes
4 AllergyService /oscar/ws/AllergyService Yes
5 PrescriptionService /oscar/ws/PrescriptionService Yes
6 MeasurementService /oscar/ws/MeasurementService Yes
7 DocumentService /oscar/ws/DocumentService Yes
8 PreventionService /oscar/ws/PreventionService Yes
9 BookingService /oscar/ws/BookingService Yes
10 ProgramService /oscar/ws/ProgramService Yes
11 FacilityService /oscar/ws/FacilityService Yes
12 LabUploadService /oscar/ws/LabUploadService Yes
13 LoginService /oscar/ws/LoginService No
14 SystemInfoService /oscar/ws/SystemInfoService No

WSDL Discovery

Append ?wsdl to any endpoint path to retrieve the WSDL definition. Example: https://your-oscar:8443/oscar/ws/DemographicService?wsdl


Authentication

WS-Security (WSS4J) — UsernameToken Profile

All endpoints except LoginService and SystemInfoService require WS-Security authentication via the UsernameToken profile.

How It Works

  1. Every SOAP request must include a WS-Security header with a UsernameToken element
  2. OSCAR uses Apache CXF's WSS4JInInterceptor configured for UsernameToken action with PasswordText type
  3. The OscarUsernameTokenValidator validates credentials against the security database table
  4. On success, a LoggedInInfo session is created for the request; on failure, a SoapFault is thrown

Credential Format

Field Value Description
Username Security ID (integer) The security_no from the security table — not the login username
Password Password or Security Token Either the user's actual password, or a session token from LoginWs.login2()
Password Type PasswordText Plaintext password (not digest)
Timestamp Not required hasTimeStamp: false
Nonce Not required hasNonce: false

Username is NOT the login name

The WS-Security Username field expects the numeric Security ID (e.g., "1"), not the text login username (e.g., "admin"). Use the LoginService.login2() method first to exchange a username/password for a Security ID and token.

Two-Step Authentication Flow

Step 1: Call LoginService.login2(username, password)
        → Returns: { securityId: 1, securityTokenKey: "8374629103847" }

Step 2: Use securityId as WS-Security Username,
        securityTokenKey as WS-Security Password
        for all subsequent SOAP calls

Security Token Generation

The security token is deterministic per JVM session — it's derived from:

  • JVM start time (ManagementFactory.getRuntimeMXBean().getStartTime())
  • Password hash (a numeric mangling of the user's stored password)

This means tokens are invalidated on OSCAR/Tomcat restart.

SOAP Header Example

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:ws="http://ws.oscarehr.org/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>1</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">8374629103847</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <!-- method call here -->
  </soapenv:Body>
</soapenv:Envelope>

Authentication Logging

All auth attempts are logged to the oscar_log table:

Event Action Logged Fields
Success WS_LOGIN_SUCCESS provider_no, IP address
Failure WS_LOGIN_FAILURE IP address

Account Expiry

Accounts with date_expiredate in the past are rejected, even with valid credentials.


Common Patterns

Date/Time Parameters

All date/time parameters use ISO 8601 format: YYYY-MM-DDTHH:MM:SS

Example: 2026-02-16T14:30:00

VitaraVox Implementation Note

Our OscarSoapAdapter always appends T00:00:00 to date-only strings. OSCAR's JAXB layer rejects bare YYYY-MM-DD format. See Adapter Implementations for details.

Pagination Parameters

Many list methods accept pagination:

Parameter Type Description
startIndex int Starting position (0-based)
itemsToReturn int Maximum results to return

Program/Provider/Demographic Filter

A common pattern for filtering clinical data:

Parameter Type Description
programId int Program ID filter (0 = all programs)
providerNo string Provider number filter ("" = all providers)
demographicId int Patient ID number
updatedAfterThisDate dateTime Only return records modified after this date

GMT Time Flag

Schedule-related methods have v1 (deprecated, local time) and v2 (with useGMTTime boolean) variants. Always prefer the v2 methods.

WSDL Positional Arguments

OSCAR SOAP WSDL uses positional args (arg0, arg1, ...) not named parameters. Always check the WSDL complexType definitions for the correct argument order.


Service Details


DemographicService

Patient demographics management. The most commonly used service for patient lookups, searches, and synchronization.

Java class: org.oscarehr.ws.DemographicWs WSDL: /oscar/ws/DemographicService?wsdl

No addDemographic

OSCAR's DemographicService has no addDemographic operation. Patient registration must be done through the OSCAR web UI. Our voice agent Registration flow creates a notification for the clinic rather than directly creating patients.

Operations

Operation Parameters Returns Notes
getDemographic arg0: int (demographicNo) demographicTransfer Basic patient record
getDemographic2 arg0: int (demographicNo) demographicTransfer2 Enhanced record with extra fields
getDemographics arg0: int[] (array of IDs) demographicTransfer[] Batch lookup
searchDemographicByName arg0: string (searchString), arg1: int (startIndex), arg2: int (itemsToReturn) demographicTransfer[] Name search
searchDemographicsByAttributes arg0: string (hin), arg1: string (firstName), arg2: string (lastName), arg3: string (gender), arg4: dateTime (dob), arg5: string (city), arg6: string (province), arg7: string (phone), arg8: string (email), arg9: string (alias), arg10: int (startIndex), arg11: int (itemsToReturn) demographicTransfer[] Multi-field search
getActiveDemographicsAfter lastUpdate: dateTime, fields: string demographicTransfer[] Sync — deprecated
getActiveDemographicsAfter2 lastUpdate: dateTime, fields: string demographicTransfer2[] Sync — preferred
getConsentedDemographicIdsAfter lastUpdate: dateTime int[] PHR-consented patients
getAdmittedDemographicIdsByProgramProvider arg0: int (programId), arg1: string (providerNo) int[] Admitted patient IDs
getDemographicIdsWithMyOscarAccounts arg0: int (startIdExclusive), arg1: int (itemsToReturn) int[] MyOscar-linked patients
getDemographicByMyOscarUserName arg0: string (myOscarUserName) demographicTransfer Lookup by MyOscar
getLatestPhrVerificationByDemographic arg0: int (demographicId) phrVerificationTransfer PHR verification status
isPhrVerifiedToSendMessages arg0: int (demographicId) boolean PHR messaging check
isPhrVerifiedToSendMedicalData arg0: int (demographicId) boolean PHR data sharing check
writePHRId arg0: int (demographicNo), arg1: string (phrId) string Write PHR identifier

demographicTransfer Fields

firstName, lastName, dateOfBirth, email, phone, phone2, cellPhone,
gender, sex, title, address, city, postal, province,
patientStatus, rosterStatus, familyDoctor, activeCount, hsAlertCount,
headRecord, chartNo, hin, dateJoined, lastUpdateDate, patientStatusDate

demographicTransfer2 Additional Fields

middleNames, newsletter, consentToUseEmailForCare,
countryOfOrigin, residentialAddress (extended fields)

ProviderService

Provider/clinician management.

Java class: org.oscarehr.ws.ProviderWs WSDL: /oscar/ws/ProviderService?wsdl

No getProvider(id)

There is no single-provider lookup. Use getProviders2(true) and filter client-side. Our OscarSoapAdapter caches the full provider list to avoid repeated calls.

Operations

Operation Parameters Returns Notes
getLoggedInProviderTransfer (none) providerTransfer Current authenticated provider
getProviders arg0: boolean (active) providerTransfer[] Deprecated — use getProviders2
getProviders2 arg0: Boolean (active) providerTransfer[] List providers by active status
getProviderProperties arg0: string (providerNo), arg1: string (propertyName) providerPropertyTransfer[] Provider config properties

providerTransfer Fields

firstName, lastName, email, phone, workPhone, address, dob, sex,
specialty, providerType, providerActivity, status, team,
billingNo, ohipNo, practitionerNo, practitionerNoType,
rmaNo, hsoNo, title, comments, signedConfidentiality

ScheduleService

Appointments and scheduling. The largest service with 20 operations covering appointment CRUD, schedule templates, and work schedules.

Java class: org.oscarehr.ws.ScheduleWs WSDL: /oscar/ws/ScheduleService?wsdl

Appointment Retrieval

Operation Parameters Returns Notes
getAppointment arg0: int (appointmentId) appointmentTransfer Deprecated — local time
getAppointment2 arg0: int (appointmentId), arg1: boolean (useGMTTime) appointmentTransfer Preferred
getAppointmentsForProvider arg0: string (providerNo), arg1: dateTime (date) appointmentTransfer[] Deprecated
getAppointmentsForProvider2 arg0: string, arg1: dateTime, arg2: boolean (useGMTTime) appointmentTransfer[] Preferred
getAppointmentsForPatient arg0: int (demographicId), arg1: int (startIndex), arg2: int (itemsToReturn) appointmentTransfer[] Deprecated
getAppointmentsForPatient2 arg0: int, arg1: int, arg2: int, arg3: boolean (useGMTTime) appointmentTransfer[] Preferred
getAppointmentsForDateRangeAndProvider arg0: dateTime (start), arg1: dateTime (end), arg2: string (providerNo) appointmentTransfer[] Deprecated
getAppointmentsForDateRangeAndProvider2 arg0: dateTime, arg1: dateTime, arg2: string, arg3: boolean (useGMTTime) appointmentTransfer[] Preferred — date range query
getAppointmentsByDemographicIdAfter lastUpdate: dateTime, demographicId: int, useGMTTime: boolean appointmentTransfer[] Patient sync
getAppointmentsByProgramProviderDemographicDate arg0: int (programId), arg1: string (providerNo), arg2: int (demographicId), arg3: dateTime, arg4: int (limit), arg5: boolean (useGMTTime) appointmentTransfer[] Filtered query
getAppointmentsUpdatedAfterDate arg0: dateTime, arg1: int (limit), arg2: boolean (useGMTTime) appointmentTransfer[] Global sync
getAppointmentArchivesUpdatedAfterDate arg0: dateTime, arg1: int (limit), arg2: boolean (useGMTTime) appointmentArchiveTransfer[] Archived appointments

Appointment Mutation

Operation Parameters Returns Notes
addAppointment arg0: appointmentTransfer int (appointmentId) Create new appointment
updateAppointment arg0: appointmentTransfer (void) Update existing appointment

appointmentTransfer is a wrapped object

Both addAppointment and updateAppointment take arg0: appointmentTransfer as a wrapped object, not flat fields. The WSDL defines this as a complexType. Our adapter wraps all fields inside the appointmentTransfer element.

Schedule Configuration

Operation Parameters Returns Notes
getScheduleTemplateCodes (none) scheduleTemplateCodeTransfer[] Slot type definitions
getDayWorkSchedule arg0: string (providerNo), arg1: dateTime (date) dayWorkScheduleTransfer Provider's day schedule
getAppointmentTypes (none) appointmentTypeTransfer[] All appointment types
getAllDemographicIdByProgramProvider arg0: int (programId), arg1: string (providerNo) int[] Patient IDs for program/provider

getDayWorkSchedule Returns Schedule Codes, Not Times

getDayWorkSchedule returns {date, scheduleCode}NOT {startTime, endTime}. The scheduleCode is an integer code point (JAXB Calendar), not a character. Use String.fromCharCode() to decode. See OSCAR Schedule Deep Dive for the full decoding algorithm.

appointmentTransfer Fields

id, demographicNo, programId, providerNo,
appointmentStartDateTime, appointmentEndDateTime,
name, type, status, location, reason, remarks, notes,
resources, billing, urgency, style, bookingSource,
createDateTime, creator, updateDateTime, lastUpdateUser

scheduleTemplateCodeTransfer Fields

id, code, description, color, duration, bookinglimit, confirm

Non-Bookable Schedule Codes

The following schedule codes should be filtered when computing available slots:

Code Char Meaning
76 L Lunch
80 P Personal
86 V Vacation
65 A Administrative
97 a Admin (lowercase)
66 B Break
72 H Holiday
82 R Reserved
69 E Emergency
71 G Government
77 M Meeting
109 m Meeting (lowercase)
100 d Do Not Book
116 t Travel

AllergyService

Patient allergy records.

Java class: org.oscarehr.ws.AllergyWs WSDL: /oscar/ws/AllergyService?wsdl

Operations

Operation Parameters Returns
getAllergy arg0: int (allergyId) allergyTransfer
getAllergiesByDemographicIdAfter lastUpdate: dateTime, demographicId: int allergyTransfer[]
getAllergiesUpdatedAfterDate arg0: dateTime, arg1: int (limit) allergyTransfer[]
getAllergiesByProgramProviderDemographicDate arg0: int (programId), arg1: string (providerNo), arg2: int (demographicId), arg3: dateTime, arg4: int (limit) allergyTransfer[]

allergyTransfer Fields

id, demographicNo, description, reaction, severityOfReaction,
onsetOfReaction, ageOfOnset, startDate, entryDate, lastUpdateDate,
providerNo, typeCode, lifeStage, regionalIdentifier,
agccs, agcsp, hicSeqno, hiclSeqno

PrescriptionService

Prescription and drug records.

Java class: org.oscarehr.ws.PrescriptionWs WSDL: /oscar/ws/PrescriptionService?wsdl

Operations

Operation Parameters Returns
getPrescription arg0: int (prescriptionId) prescriptionTransfer
getPrescriptionsByDemographicIdAfter lastUpdate: dateTime, demographicId: int prescriptionTransfer[]
getPrescriptionUpdatedAfterDate arg0: dateTime, arg1: int (limit) prescriptionTransfer[]
getPrescriptionsByProgramProviderDemographicDate arg0: int, arg1: string, arg2: int, arg3: dateTime, arg4: int prescriptionTransfer[]

prescriptionTransfer Fields

id, demographicId, providerNo, datePrescribed, datePrinted,
datesReprinted, textView, comments, lastUpdateDate,
drugs (array of drugTransfer)

drugTransfer Fields (55 fields)

id, gcnSeqNo, archived, archivedDate, archivedReason,
customName, customInstructions, dosage, drugForm, quantity,
unit, method, route, duration, durUnit, frequency,
dispenseInterval, refillQuantity, refillDuration, repeat,
prn, noSubs, startDateUnknown, endDate, rxDate, writtenDate,
pickupDateTime, lastRefillDate, lastUpdateDate, comments,
createDate, rxStatus, scriptNo, special, protocol,
priorRxProtocol, patientCompliance, nonAuthoritative,
outsideProviderName, outsideProviderOhip, longTerm, pastMed,
hideFromDrugProfile, hideFromCpp, takeMin, takeMax, position,
regionalIdentifier, genericName, brandName, atc,
eTreatmentType, customNote, special_instruction

MeasurementService

Vital signs and clinical measurements.

Java class: org.oscarehr.ws.MeasurementWs WSDL: /oscar/ws/MeasurementService?wsdl

Operations

Operation Parameters Returns Notes
getMeasurement arg0: int (measurementId) measurementTransfer Single lookup
getMeasurementsByDemographicIdAfter lastUpdate: dateTime, demographicId: int measurementTransfer[] Patient sync
getMeasurementsCreatedAfterDate arg0: dateTime, arg1: int (limit) measurementTransfer[] Global sync
getMeasurementsByProgramProviderDemographicDate arg0: int, arg1: string, arg2: int, arg3: dateTime, arg4: int measurementTransfer[] Filtered query
getMeasurementMaps (none) measurementMapTransfer[] Measurement type definitions
addMeasurement arg0: measurementTransfer int (measurementId) Create new measurement

measurementTransfer Fields

id, demographicId, providerNo, type, dataField,
dateObserved, createDate, comments, measuringInstruction, appointmentNo

measurementMapTransfer Fields

id, name, identCode, loincCode, labType

DocumentService

Clinical documents and file attachments.

Java class: org.oscarehr.ws.DocumentWs WSDL: /oscar/ws/DocumentService?wsdl

Operations

Operation Parameters Returns
getDocument arg0: int (documentNo) documentTransfer
getDocumentsByDemographicIdAfter lastUpdate: dateTime, demographicId: int documentTransfer[]
getDocumentsUpdateAfterDate arg0: dateTime, arg1: int (limit) documentTransfer[]
getDocumentsByProgramProviderDemographicDate arg0: int, arg1: string, arg2: int, arg3: dateTime, arg4: int documentTransfer[]
getProvidersThatHaveAcknowledgedDocument arg0: int (documentId) providerTransfer[]

documentTransfer Fields

documentNo, doccreator, docdesc, doctype, docClass, docSubClass,
docfilename, contenttype, numberofpages, observationdate,
responsible, reviewer, reviewdatetime, ctlModule, ctlModuleId,
ctlStatus, source, sourceFacility, public1, status,
updatedatetime, programId, appointmentNo, docxml,
fileContents (base64Binary)

PreventionService

Preventive care / immunization records.

Java class: org.oscarehr.ws.PreventionWs WSDL: /oscar/ws/PreventionService?wsdl

Operations

Operation Parameters Returns
getPrevention arg0: int (preventionId) preventionTransfer
getPreventionsByDemographicIdAfter lastUpdate: dateTime, demographicId: int preventionTransfer[]
getPreventionsUpdatedAfterDate arg0: dateTime, arg1: int (limit) preventionTransfer[]
getPreventionsByProgramProviderDemographicDate arg0: int, arg1: string, arg2: int, arg3: dateTime, arg4: int preventionTransfer[]

preventionTransfer Fields

id, demographicId, preventionType, preventionDate, nextDate,
never, refused, deleted, creatorProviderNo, creationDate,
lastUpdateDate, providerNo,
preventionExts (array of preventionExtTransfer: id, key, value, preventionId)

BookingService

External / patient-facing appointment booking.

Java class: org.oscarehr.ws.BookingWs WSDL: /oscar/ws/BookingService?wsdl

VitaraVox uses ScheduleService, not BookingService

Our OscarSoapAdapter uses ScheduleService (addAppointment, updateAppointment, getDayWorkSchedule) for direct appointment manipulation rather than BookingService's encrypted-slot workflow. BookingService is designed for patient-facing web portals with an additional encryption layer.

Operations

Operation Parameters Returns Notes
getAppointmentTypesByProvider arg0: string (providerNo) bookingType[] Available booking types for a provider
getExternalAppointmentTypes arg0: int (demographicNo) bookingType[] Patient-visible booking types
findAppointment arg0: int (demographicNo), arg1: string (appointmentType), arg2: dateTime (startDate) appointmentResults Search available slots
bookAppointment arg0: string (encryptedTimeSlot), arg1: string (notes) appointmentConfirmationTransfer Book a slot

appointmentConfirmationTransfer Fields

appointmentTime, appointmentEndTime, appointmentDescription,
location, providerName,
bookingError (code, description)

ProgramService

Clinical programs and provider assignments.

Java class: org.oscarehr.ws.ProgramWs WSDL: /oscar/ws/ProgramService?wsdl

Operations

Operation Parameters Returns
getAllPrograms (none) programTransfer[]
getAllProgramProviders (none) programProviderTransfer[]

programTransfer Fields

id, facilityId, name, type, description, programStatus,
email, phone, fax, address, location, ageMin, ageMax,
mentalHealth, physicalHealth, firstNation, housing, alcohol,
hic, transgender, enableEncounterTime,
enableEncounterTransportationTime, allowBatchAdmission,
allowBatchDischarge, siteSpecificField, userDefined, url, queueSize

programProviderTransfer Fields

id, programId, providerNo, roleId

FacilityService

Clinic/facility configuration.

Java class: org.oscarehr.ws.FacilityWs WSDL: /oscar/ws/FacilityService?wsdl

Operations

Operation Parameters Returns Notes
getDefaultFacility (none) facilityTransfer Primary facility
getDefaultFacilities (none) facilityTransfer Deprecated (typo in name)
getAllFacilities arg0: Boolean (active) facilityTransfer[] All facilities

facilityTransfer Fields

id, name, description, contactName, contactPhone, contactEmail,
address, location, disabled, lastUpdated, hic,
allowSims, enableDigitalSignatures, enableHealthNumberRegistry,
enableIntegratedReferrals, enableOcanForms, enableEncounterTime,
enableEncounterTransportationTime, enableGroupNotes, enableAnonymous,
integratorEnabled, integratorUrl, integratorUser, integratorPassword,
sectorId, ocanServiceOrgNumber, orgId, facilityId,
rxInteractionWarningLevel

LabUploadService

Laboratory result file uploads. Supports multiple Canadian lab formats.

Java class: org.oscarehr.ws.LabUploadWs WSDL: /oscar/ws/LabUploadService?wsdl

Text Upload Operations

All text-based upload operations share the same signature:

Operation Lab System Format
uploadCML CML Labs HL7 text
uploadLifelabs LifeLabs (MDS) HL7 text
uploadExcelleris Excelleris (PATHL7) HL7 text
uploadIHA Interior Health Authority HL7 text
uploadGammaDynacare Gamma-Dynacare (GDML) HL7 text
uploadCDL CDL Labs HL7 text
uploadCLS CLS Labs HL7 text

Text upload parameters:

Parameter Type Description
file_name string Original filename
contents string HL7 message content
oscar_provider_no string Receiving provider number

Binary Upload Operations

Operation Description Content Type
uploadPDF PDF lab report base64Binary
uploadDocumentReference Generic document base64Binary

Returns: string — JSON response with success/failure status.


LoginService

Authentication and token exchange. This is the only service (along with SystemInfoService) that does not require WS-Security headers.

Java class: org.oscarehr.ws.LoginWs WSDL: /oscar/ws/LoginService?wsdl

Operations

Operation Parameters Returns Notes
login arg0: string (userName), arg1: string (password) loginResultTransfer Deprecated (2015-01-28)
login2 arg0: string (userName), arg1: string (password) loginResultTransfer2 Preferred — includes provider info

Fault: Throws NotAuthorisedException on invalid credentials.

loginResultTransfer Fields

securityId (int), securityTokenKey (string)

loginResultTransfer2 Fields

securityId (int), securityTokenKey (string),
provider (providerTransfer — full provider record)

SystemInfoService

Health checks and server metadata. Does not require WS-Security authentication.

Java class: org.oscarehr.ws.SystemInfoWs WSDL: /oscar/ws/SystemInfoService?wsdl

Operations

Operation Parameters Returns Description
helloWorld (none) string Basic connectivity test
isAlive (none) string Health check
getServerTime (none) dateTime Current server timestamp
getServerTimeGmtOffset (none) int Server timezone offset (hours)
getMaxListReturnSize (none) int Maximum items per list response

CXF Configuration Reference

The SOAP stack is configured in spring_ws.xml:

Endpoint Wiring

<!-- No auth required -->
<jaxws:endpoint implementor="#systemInfoWs" address="/SystemInfoService"/>
<jaxws:endpoint implementor="#loginWs" address="/LoginService"/>

<!-- Auth required (WSS4J interceptor) -->
<jaxws:endpoint implementor="#demographicWs" address="/DemographicService">
  <jaxws:inInterceptors>
    <ref bean="authenticationInWSS4JInterceptor"/>
  </jaxws:inInterceptors>
</jaxws:endpoint>
<!-- ... same pattern for all other authenticated endpoints -->

WSS4J Interceptor Configuration

// AuthenticationInWSS4JInterceptor.java
properties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);

Global Bus Properties

<cxf:bus>
  <cxf:properties>
    <entry key="ws-security.ut.validator"
           value="org.oscarehr.ws.OscarUsernameTokenValidator"/>
  </cxf:properties>
</cxf:bus>

REST Bridge SOAP Mapping

The OSCAR REST Bridge translates REST/JSON calls into these SOAP operations. It uses the node-soap library with WS-Security.

Bridge Client Configuration

// soap-client.js — WS-Security setup
const wsSecurity = new soap.WSSecurity(
  config.oscar.username,    // OSCAR_WS_USERNAME (Security ID)
  config.oscar.password,    // OSCAR_WS_PASSWORD (password or token)
  {
    passwordType: 'PasswordText',
    hasTimeStamp: false,
    hasNonce: false
  }
);

Bridge Environment Variables

Variable Description
OSCAR_SOAP_BASE_URL Base URL (e.g., http://oscar:8080/oscar/ws)
OSCAR_WS_USERNAME Security ID (numeric)
OSCAR_WS_PASSWORD Password or security token
REQUEST_TIMEOUT SOAP call timeout in ms (default: 30000)
WSDL_CACHE_TTL WSDL cache lifetime in ms (default: 300000 / 5 min)

Bridge Method to SOAP Mapping

Bridge Method SOAP Operation Service
getDemographic(id) getDemographic(arg0: id) DemographicService
searchDemographicByName(name) searchDemographicByName(arg0, arg1, arg2) DemographicService
getAllDemographics() getActiveDemographicsAfter2(lastUpdate: '2000-01-01T00:00:00') DemographicService
getProviders() getProviders2() ProviderService
getAppointments(provider, start, end) getAppointmentsForDateRangeAndProvider2(...) ScheduleService
addAppointment(data) addAppointment(arg0: data) ScheduleService
updateAppointment(data) updateAppointment(arg0: data) ScheduleService
cancelAppointment(id) updateAppointment(arg0: {id, status:'C'}) ScheduleService
getDayWorkSchedule(provider, date) getDayWorkSchedule(arg0, arg1) ScheduleService
getAllergies(demographicId) getAllergiesByProgramProviderDemographicDate(...) AllergyService
getPrescriptions(demographicId) getPrescriptionsByProgramProviderDemographicDate(...) PrescriptionService
getMeasurements(demographicId) getMeasurementsByProgramProviderDemographicDate(...) MeasurementService
addMeasurement(data) addMeasurement(arg0: data) MeasurementService

Error Handling

Common SOAP Faults

Fault Cause Resolution
WSSecurityException: FAILED_AUTHENTICATION Invalid Security ID or password/token Verify credentials via LoginService
NotAuthorisedException Invalid username/password on LoginService Check credentials
Method not found in WSDL Calling non-existent operation Verify method name against WSDL
ECONNREFUSED OSCAR Tomcat not running Check container status
ETIMEDOUT Request exceeded timeout Increase timeout or reduce query scope
SecurityError with <wsu:Timestamp> WS-Security includes timestamp Set hasTimeStamp: false — CXF has no Timestamp action configured

Bridge Retry Logic

The REST bridge implements automatic retry with exponential backoff:

  • Max retries: 3 attempts
  • Backoff: 1s → 2s → 4s
  • Reconnect trigger: ECONNREFUSED or ETIMEDOUT errors force a fresh SOAP client connection
  • WSDL cache: 5-minute TTL; stale connections are automatically refreshed

OscarSoapAdapter Circuit Breaker

Our production SOAP adapter uses a 4-second circuit breaker timeout (under Vapi's 5-second tool timeout):

  • Timeout: 4000ms per SOAP call
  • Cold start: First call after PM2 restart fetches WSDL (may be slower)
  • Warmup: SOAP clients should be warmed on server startup to avoid cold-start penalties

VitaraVox Services Used

Not all 14 OSCAR SOAP services are used by VitaraVox. Here's the subset our OscarSoapAdapter actually calls (verified against source code):

Service Operations Called Purpose
ScheduleService getDayWorkSchedule, getAppointmentsForDateRangeAndProvider2, addAppointment, updateAppointment, getScheduleTemplateCodes Schedule slots, appointment CRUD, template codes
DemographicService getDemographic, searchDemographicByName Patient lookup by ID or name
ProviderService getProviders2 Provider roster

Operations NOT Called

The adapter does not call: searchDemographicsByAttributes, getAppointmentsForProvider2, getAppointmentTypes, LoginService.login2, or SystemInfoService.isAlive.

  • Authentication: Uses direct WS-Security credentials via soap.WSSecurity() -- NOT the two-step LoginService.login2() flow. The adapter receives the Security ID and password/token at construction time.
  • Health check: The healthCheck() method verifies WSDL reachability by creating the SOAP client -- it does NOT call SystemInfoService.isAlive.
  • Patient search: Only uses searchDemographicByName (not the multi-attribute variant). Phone search falls back to the REST bridge.

Services not currently used: LoginService, SystemInfoService, AllergyService, PrescriptionService, MeasurementService, DocumentService, PreventionService, BookingService, ProgramService, FacilityService, LabUploadService.