Skip to content

eClinicalWorks

  • No self-service portal: API access is arranged through eClinicalWorks support.
  • SMART Backend Services with a JWT. Each practice has an endpoint code in the FHIR base URL; the token server is shared. A staging host exists for testing.
  • Bulk and REST are separate registrations with separate client ids, sharing your JWKS. A bulk client id gets 401 on every REST endpoint even with the right scopes, and a REST registration has no group id.
  • Request every scope you need; the server grants the intersection with what was provisioned.
  • The practice list is available from eClinicalWorks’ public developer organisation bundle.

Group/<groupId>/$export?_type=<one type>&_since=<date>

  • One resource type per job, run sequentially. A typical order: Practitioner, Patient, Encounter, Condition, Observation, DocumentReference, MedicationRequest, DiagnosticReport, Procedure, QuestionnaireResponse.
  • Send only Accept, Prefer: respond-async and Authorization on kickoff. A Content-Type header gets the kickoff rejected.
  • Always export Practitioner in full. With _since, older but still-active providers are dropped — in one case about 1 in 5 attending NPIs went blank.
  • Poll the X-Progress header; FAILED is terminal. Polling more often than every few minutes gains nothing.
  • A “duplicate” or “already in progress” response means a job is already running for that group.
  • A 401/403, or an OperationOutcome mentioning scope, means that one type is not granted — skip it rather than failing the whole run.
  • Re-mint the token periodically during long downloads (every 25 files works).
  • An OperationOutcome with severity information and no data means “nothing to export” — success.
  • Many empty NDJSON files in one export usually means the export is broken; restart that type.
Symptom Action
Unexpected response from the server Reset; if it persists for two days, delete the job and start again
Status cannot be read and the job keeps auto-resetting Wait, or delete the job — it can loop indefinitely
ZIP archive creation error Delete and restart that type
“Ready for download” for more than 24 hours Reset that type
X-Progress: FAILED Delete and restart that type

Cap automatic recovery — without a cap, jobs have been seen looping for months. Format errors so they can be pasted straight into an eClinicalWorks support ticket.

Many reasonable-looking queries are rejected with 400:

Query Result
Any search with _count 400 — page only with link.next (a literal page=1 is also 400)
Observation?patient=&date= 400
Observation?patient= with no code or category 400
Observation?patient=&category=vital-signs 200 with 0 entries — search code=85354-9 and read the components
Procedure?patient=&code= 400
DocumentReference?patient=&date= 400
Patient?birthdate= alone 400 — family+given+birthdate+gender gives a clean single match

Do not add vendor parameters (such as the endpoint code) to REST query strings; they break REST calls.

For each A1c order, eClinicalWorks can emit two observations: a LOINC-coded A1c, and an uncoded duplicate (labelled like HbA1cWB) whose value is on the glucose scale in mg/dL, often with the same timestamp. Picking the wrong one turns a 7.1% A1c into “142”.

Handle it by ranking results by day first, preferring the coded result within a day, and rejecting uncoded values above 30 as implausible for a percentage.

Scopes being granted does not mean data is populated. In one practice, PHQ scores existed only in HTML attachments on DocumentReference, and mammograms never appeared as DiagnosticReport.

When PHQ scores are in embedded document tables, they are laid out as columns rather than rows.

  • Encounter.type is a data-absent reason, so encounter-type value sets cannot qualify visits.
  • identifier[0] is often the FHIR id restated; the MRN is usually identifier[1].
  • The middle initial is the second element of name.given.