TheFhirStorm

eClinicalWorks FHIR R4 in practice: where the API departs from the spec

Vendor APIs · · Abhinav Srivastava

You register on the eClinicalWorks developer portal, build the signed JWT, get a token, and the first Patient search returns something the documentation did not describe. That is the normal first day on an eClinicalWorks integration. This post covers what the API is, where its behavior departs from the written spec in our experience, and the client we published so the next team does not rediscover the same gaps.

What the API is

eClinicalWorks publishes its provider-facing and backend FHIR APIs through a developer portal at fhir.eclinicalworks.com. Patient-facing APIs live on a separate portal, connect4.healow.com. The company's certified health IT page names both portals and states that the FHIR APIs are offered as required by the ONC Health IT Certification Program.

Server to server access uses SMART Backend Services. Your application holds a private key. For each token request it signs a JWT assertion with RS384, posts it to the token endpoint as a client credentials grant, and receives a bearer token scoped to system level reads. The FHIR base URL is scoped to one practice, so a vendor that serves many practices holds one registration per practice and one token per practice.

Where behavior departs from the documentation

In our integration work, the behavior of the eClinicalWorks FHIR R4 endpoints often does not match the portal documentation, and in places does not match the FHIR R4 specification. The pattern repeats across resource types:

  • Search parameters that the capability statement lists return results that ignore the parameter, or return an operation outcome that the documentation does not mention.
  • Fields that US Core marks as must support arrive empty or arrive in a shape that differs from the profile.
  • Paging behavior differs between resource types, so a client that follows Bundle.link correctly on one resource stops early on another.
  • Error responses do not always carry an OperationOutcome, so a client has to treat HTTP status and body shape as separate signals.

None of these are blocking on their own. The cost is that each one is discovered by a failing request in production rather than by reading. When we asked the vendor's support channels to confirm correct usage, the answers we received were often incomplete, and other integration teams have described the same experience to us. We treat every documented behavior as a hypothesis until a request against a live practice confirms it.

The open source client

We published the client we use, in two languages, under the MIT license at github.com/thefhirstorm:

Both implement the SMART Backend Services flow with an RS384 assertion, patient read and patient search, and the Healow scheduling calls for slot search and appointment booking. Where the live API departs from the documentation, the client follows the live API and the code comments say why. The vendor factory takes a vendor name and connection parameters and returns a constructed client, so a second vendor can be added without changing calling code.

from fhirstorm import fhir

with fhir(
    "eclinicalworks",
    client_id="your-client-id",
    private_key="/path/to/private_key.pem",
    key_id="your-key-id",
    practice_code="your-practice-code",
) as client:
    patient = client.get_patient("12345")
    results = client.search_patients(family="Smith", birthdate="1990-01-01")

The client implements the standard documented authentication flow against an API the vendor publishes for third party integration. It does not bypass or circumvent any access control. It is independent software and is not affiliated with or endorsed by eClinicalWorks.

Public record

Engineers who plan around this vendor should know the public record, because it explains why interoperability behavior at eClinicalWorks draws scrutiny. In May 2017 the Department of Justice announced that eClinicalWorks and certain employees agreed to pay $155 million to resolve a False Claims Act suit. The government alleged that the company misrepresented the capabilities of its software during certification testing and failed to meet data portability requirements. The release states that the claims resolved by the settlement are allegations only and that there was no determination of liability. As part of the resolution the company entered a five year Corporate Integrity Agreement with the HHS Office of Inspector General.

In July 2018 the company paid a stipulated penalty of $132,500 under that agreement for failing to report patient safety issues on time, according to the OIG's record of the agreement.

Separately, the ONC information blocking rule at 45 CFR Part 171, in effect since April 2021, prohibits practices by certified health IT developers that interfere with access, exchange or use of electronic health information, subject to listed exceptions. Whether a given vendor's API documentation falls short of that rule is a determination for regulators, not for this post. The practical point for an engineer is simpler: the certification program requires a standardized FHIR API, the API exists, and the published description of it is not enough on its own to build against.

How we build against it

We hold a sandbox practice for every vendor we connect to and run the full client test suite against it on every change. We record the shape of every response per resource type and alert when the shape changes, because vendor releases change behavior without a documentation update. We treat the vendor documentation as the starting point and the recorded responses as the source of truth. The open source client carries those recordings forward as tests, so a change in the live API shows up as a failing test rather than as a support ticket from a customer.

All posts