<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://www.medplum.com.ar/blog</id>
    <title>Medplum Blog</title>
    <updated>2026-07-01T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://www.medplum.com.ar/blog"/>
    <subtitle>Medplum Blog</subtitle>
    <icon>https://www.medplum.com.ar/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Forward Deployed Engineering, Medplum-Style]]></title>
        <id>https://www.medplum.com.ar/blog/fde</id>
        <link href="https://www.medplum.com.ar/blog/fde"/>
        <updated>2026-07-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[You have probably noticed that "Forward Deployed Engineer" is having a moment. Over the last couple of years the role has spread from]]></summary>
        <content type="html"><![CDATA[<p>You have probably noticed that "Forward Deployed Engineer" is having a moment. Over the last couple of years the role has spread from
a Palantir-specific curiosity to the role every enterprise software company suddenly wants to hire for.
OpenAI, Anthropic, Ramp, and dozens of others have stood up FDE teams, and the VC blog and tech newsletters alike have declared it
the hottest new role in tech.</p>
<p>We are excited about it too. However, healthtech has been doing this for more than 40 years.</p>
<p>At Medplum, forward deployed engineering is not a trend we picked up. Healthtech companies have always built software in a "forward-deployed"
manner, embedding engineers directly in the clinic to learn directly from interactions between healthcare providers and patients. This post is
about what an FDE is, why healthcare got here early, how we think about the role at Medplum, and the values our team lives by. And, if any of
this resonates, we would love to hear from you.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="what-is-a-forward-deployed-engineer">What is a Forward Deployed Engineer?<a href="https://www.medplum.com.ar/blog/fde#what-is-a-forward-deployed-engineer" class="hash-link" aria-label="Direct link to What is a Forward Deployed Engineer?" title="Direct link to What is a Forward Deployed Engineer?" translate="no">​</a></h2>
<p>Forward Deployed Engineers (FDEs) were first coined by Palantir, and initially, these engineers were literally deployed at military bases and
other customers sites to build and deploy software. Sitting next to the people using the product meant engineers understood the real problem and
could iterate in hours instead of quarters. For over a decade it stayed mostly a Palantir thing. Then it spread across enterprise software: Scale
AI and C3 AI took the title directly, and Databricks and Snowflake built equivalents.</p>
<p>In the last two years, AI has made software itself easier and cheaper, shifting the bottleneck for growth to everything around
the code itself: integrating with messy existing systems, mapping a product onto a customer's actual workflow, and getting them to adoption.
That work is irreducibly human and contextual, and it is where FDEs live. OpenAI, Anthropic, Ramp, and ElevenLabs have
all built FDE functions of their own.
<a href="https://engineering.ramp.com/post/forward-deployed-engineering" target="_blank" rel="noopener noreferrer" class="">Leo Mehr's post on Ramp's FDE team</a> is some of the best writing on this shift.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="fde-is-table-stakes-in-healthcare">FDE is table stakes in healthcare<a href="https://www.medplum.com.ar/blog/fde#fde-is-table-stakes-in-healthcare" class="hash-link" aria-label="Direct link to FDE is table stakes in healthcare" title="Direct link to FDE is table stakes in healthcare" translate="no">​</a></h2>
<p>While enterprise tech treats forward deployed as a new idea, healthcare buyers have expected white-glove, on-the-ground engineering for as long as the industry has existed.</p>
<p>Epic, the largest healthtech player in the United States, started with white-glove engineering.
<a href="https://www.epic.com/epic/post/with-the-patient-at-the-center-judy-faulkner-on-epics-enduring-values/" target="_blank" rel="noopener noreferrer" class="">Judy Faulkner founded what became Epic Systems in 1979</a>,
building a custom solution to track patient data over time for a single group of physicians. For roughly the first decade, Faulkner and her team kept building one-off solutions
for physician groups, using what they learned in the field to eventually ship EpicCare, their first EHR, in 1992. The philosophy of designing software
from inside the doctor's office never left. To this day Epic sends all engineers on <a href="https://www.beckershospitalreview.com/healthcare-information-technology/ehrs/why-judy-faulkner-sends-epic-employees-to-hospitals/" target="_blank" rel="noopener noreferrer" class="">"immersion trips"</a>,
where they sit in on patient visits and watch clinicians use the software in the room where the work actually happens.</p>
<p>Healthcare systems are complex and bureaucratic, the stakes are high, and the largest vendor in the market built its reputation and empire by
putting engineers on-site. Buyers have come to expect exactly that. So for a company like Medplum, the FDE function is not optional.</p>
<p>What is different for us is the surface area. Medplum is an open-source, FHIR-native developer platform. At this stage, our customers are primarily not buying a finished
clinical workflow off the shelf; they are building on top of us. So our version of an immersion trip is going deep on a customer's integration and
interoperability problems — their data model, their existing systems, the standards they need to speak — and building alongside them.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="how-we-run-fde">How we run FDE<a href="https://www.medplum.com.ar/blog/fde#how-we-run-fde" class="hash-link" aria-label="Direct link to How we run FDE" title="Direct link to How we run FDE" translate="no">​</a></h2>
<p>In healthcare, the complexity and the revenue concentrate in the same place: large, sophisticated organizations, often running on legacy technology.
Those are the customers with the largest operational challenges, who will likely not succeed on self-serve SaaS alone, and the customers worth winning. FDE is the engineering
capability that lets us land them, get them to production, and keep them there. It is how Medplum moves upmarket. An FDE team is not a cost of
doing enterprise business; it is the thing that makes Medplum's enterprise business possible.</p>
<p>To do that well, we map FDEs to the entire customer lifecycle rather than siloing it to a single function. The same person who scopes a pilot is there
for our customers through implementation and rollout and into long-tail support. Context never gets lost in a handoff, relationships compound, and we
stay accountable for whether a customer is actually getting value — not just whether we closed the deal or hit an implementation milestone.</p>
<p>Two structural facts about Medplum sharpen this. We have no product managers (as of this writing), and we are open source. At most companies, an FDE deploys
the product as it is, and product managers decide what gets built next. We do neither. Our FDEs are the primary input to the roadmap: we triage every issue,
feature request, and bug from customers and the community, set the priorities, and when it's the right call, ship the code ourselves. An FDE here owns both ends:
not just getting a customer to value on today's product, but shaping what the product becomes.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bedside-manner-and-the-values-of-our-fde-team">Bedside manner, and the values of our FDE team<a href="https://www.medplum.com.ar/blog/fde#bedside-manner-and-the-values-of-our-fde-team" class="hash-link" aria-label="Direct link to Bedside manner, and the values of our FDE team" title="Direct link to Bedside manner, and the values of our FDE team" translate="no">​</a></h2>
<p>There is a concept our FDE team borrows directly from our customers: bedside manner.</p>
<p>Bedside manner is a clinician's way of relating to a patient: communicating without jargon, respecting the patient's time and privacy, listening
actively, and carrying warmth in the small nonverbal cues. It is what produces a good clinician-patient relationship: clearer communication, more
trust and honesty, higher satisfaction with care.</p>
<p>The stakes of FDE bedside manner are lower, but the mechanism is identical: trust is built in how you show up, and trust is the whole job.
Let me be clear about what this is <em>not</em> — it is not a substitute for engineering depth. A great clinician is both deeply knowledgeable and has
excellent bedside manner; one without the other does not work. The same is true of an FDE. We hire strong engineers, many of them from pure software
backgrounds, and then we explicitly train the relational skills, because both halves are the job.</p>
<p>Our six values make this concrete. They fall into three pairs.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="bedside-manner-empathy-and-expertise">Bedside manner: empathy and expertise<a href="https://www.medplum.com.ar/blog/fde#bedside-manner-empathy-and-expertise" class="hash-link" aria-label="Direct link to Bedside manner: empathy and expertise" title="Direct link to Bedside manner: empathy and expertise" translate="no">​</a></h3>
<p><strong>Develop Customer Empathy.</strong> Always assume the best of a customer. Steel-man their position before you argue with it. Know exactly what you have committed to, and hold yourself absolutely accountable to it.</p>
<p><strong>Present Expertise.</strong> An FDE is not a router or a recorder — you are <em>the</em> expert in the room. Be comfortable telling a customer what they need, and present it calmly and confidently. Confidence, delivered with empathy, is what instills trust.</p>
<p>These two are bedside manner in full: the warmth to assume good faith and the authority to lead. Empathy without expertise is a pleasant meeting
that goes nowhere. Expertise without empathy is a correct answer nobody acts on.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="drive-keep-moving-keep-improving">Drive: keep moving, keep improving<a href="https://www.medplum.com.ar/blog/fde#drive-keep-moving-keep-improving" class="hash-link" aria-label="Direct link to Drive: keep moving, keep improving" title="Direct link to Drive: keep moving, keep improving" translate="no">​</a></h3>
<p><strong>Keep the Ball in Our Court.</strong> There is always an action we can take to move a customer forward, and we follow through on our own ideas. Even when we are waiting on someone else, the wait is a deliberate move with a clear objective — never a stall.</p>
<p><strong>Continually Improve.</strong> We do more with less by automating our own jobs. The FDE who automates a task out of existence has just bought time for the next customer.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="rigor-zero-ambiguity-built-to-last">Rigor: zero ambiguity, built to last<a href="https://www.medplum.com.ar/blog/fde#rigor-zero-ambiguity-built-to-last" class="hash-link" aria-label="Direct link to Rigor: zero ambiguity, built to last" title="Direct link to Rigor: zero ambiguity, built to last" translate="no">​</a></h3>
<p><strong>Leave Zero Ambiguity.</strong> Internally, everything is written down — preferably in a public channel — so understanding is shared and nothing is lost when context changes hands. Externally, we relentlessly seek ground truth from the customer and validate every assumption rather than guessing.</p>
<p><strong>Build Resilience.</strong> Assume chaos and plan for it. Cultivate more than one relationship inside each account. Write defensive, well-tested code. Build redundant team processes so that no single point of failure — a person, a relationship, a script — can take a customer down.</p>
<p>It is worth noting that this last pair is not in the standard FDE playbook. Most FDE writing stops at empathy and hustle. We hold ourselves to
writing everything down and engineering for failure because healthcare is unforgiving in a way most software is not: the systems are chaotic,
the data is sensitive, and the cost of an outage or a misunderstanding is measured in patient care, not just churn.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="who-thrives-here">Who thrives here<a href="https://www.medplum.com.ar/blog/fde#who-thrives-here" class="hash-link" aria-label="Direct link to Who thrives here" title="Direct link to Who thrives here" translate="no">​</a></h2>
<p>If you are reading this as a prospective FDE, here is what we actually screen for.</p>
<p>Drive comes first. It is the best predictor we have found of who will be great at this job. The combination of engineering depth, the industry we work in, and the communication
skills we need for this job are rare, and thus we expect to do some level of training with everyone who joins. However, the drive to learn what needs to be learned cannot be replaced.</p>
<p>Engineering fundamentals are a bar to clear, not a number to maximize. You need to be a genuinely capable engineer; you do not need to be the strongest competitive programmer we have ever
interviewed. Modern AI tooling has lowered the cost of writing and learning code, which means judgment, ownership, and the ability to learn a new domain fast matter more than raw algorithmic horsepower.</p>
<p>Customer empathy and communication are the bedside-manner half, and we weight them heavily. Can you defuse a tense call? Can you tell a customer "no" or "not like that" and have them thank
you for it? Can you write something clear enough that a stranger understands it next week?</p>
<p>You do not need to come from healthcare. You do need an appetite for its complexity — the standards, the regulation, the clinical reality — and the patience to learn it properly. We hire strong engineers and teach the rest.</p>
<p>If that sounds like you, we are hiring. Come build with us! <a href="https://www.medplum.com/careers/forward-deployed-engineer" target="_blank" rel="noopener noreferrer" class="">https://www.medplum.com/careers/forward-deployed-engineer</a></p>]]></content>
        <author>
            <name>Maddy Li</name>
            <uri>https://github.com/maddyli</uri>
        </author>
        <category label="forward-deployed-engineering" term="forward-deployed-engineering"/>
        <category label="hiring" term="hiring"/>
        <category label="customers" term="customers"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - June 2026]]></title>
        <id>https://www.medplum.com.ar/blog/june-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/june-2026-update"/>
        <updated>2026-07-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The headline this month: Medplum achieved HITRUST certification, a validation of our security and compliance program. June was also another busy month of shipping, with 200+ commits from 25+ contributors and nine patch releases — v5.1.14 through v5.1.22.]]></summary>
        <content type="html"><![CDATA[<p>The headline this month: <strong>Medplum achieved <a class="" href="https://www.medplum.com.ar/blog/hitrust-e1-certification">HITRUST certification</a></strong>, a validation of our security and compliance program. June was also another busy month of shipping, with 200+ commits from 25+ contributors and nine patch releases — v5.1.14 through v5.1.22.</p>
<p><a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling</a> saw a lot of activity. The <a href="https://provider.medplum.com/" target="_blank" rel="noopener noreferrer" class="">Provider App</a> gained a reusable inbox shell, and operation-based claim submission. SMART Health Cards and Links arrived with a QR code scanner, the Enterprise data warehouse export was released, and the AI workspace added configurable model routing. The platform also gained email-based <a class="" href="https://www.medplum.com.ar/docs/auth/mfa">multi-factor authentication</a>, enforceable per project.</p>
<p>All of this continues to drive forward our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/june-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling">Scheduling<a href="https://www.medplum.com.ar/blog/june-2026-update#scheduling" class="hash-link" aria-label="Direct link to Scheduling" title="Direct link to Scheduling" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>Building on May's operation suite, June moved <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#scheduling">scheduling</a> to a Beta release and tightened the rules around how appointments are booked:</p>
<ul>
<li class=""><strong>Scheduling API Beta</strong> — The appointment operation suite is now a Beta release, and the older Slot-based alpha implementations have been removed in favor of the appointment-based flow</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-book"><code>$book</code> alignment enforcement</a></strong> — Booking now enforces scheduling alignment, and <a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-find"><code>$find</code></a> supports nondivisible alignment times so slots respect configured intervals</li>
<li class=""><strong>Planning horizon constraints</strong> — Scheduling operations are now constrained by <code>Schedule.planningHorizon</code>, and scheduling parameters can be inherited from the <code>HealthcareService</code></li>
<li class=""><strong>Availability defaults</strong> — Availability now defaults to "always" when unset, with the requested time slot included in availability error messages for clearer feedback (<a href="https://github.com/RohithVangalla1" target="_blank" rel="noopener noreferrer" class="">Rohith Vangalla</a>)</li>
<li class=""><strong>Provider scheduling flow</strong> — The <a class="" href="https://www.medplum.com.ar/docs/provider/schedule">Provider App</a> streamlines encounter creation, links <code>Appointment.slot</code>, adds an Appointment confirm button, and moves to FullCalendar v7</li>
<li class=""><strong>Cancelled-appointment slots</strong> — The schedule view now hides slots tied to cancelled appointments, so a cancellation frees the time back up instead of leaving a stale block</li>
</ul>
<img src="https://www.medplum.com.ar/img/blog/2026-06-appointment-confirm.png" alt="Appointment confirm button in the Provider App schedule view" style="max-height:400px;max-width:100%">
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app">Provider App<a href="https://www.medplum.com.ar/blog/june-2026-update#provider-app" class="hash-link" aria-label="Direct link to Provider App" title="Direct link to Provider App" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>The <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#provider-application">Provider App</a> gained reusable building blocks and revenue-cycle improvements:</p>
<ul>
<li class=""><strong>ResourceBoard inbox shell</strong> — A new React shell that encapsulates inbox logic, providing a reusable foundation for task and worklist views</li>
<li class=""><strong>Performing practitioner in care teams</strong> — Care team fields now support a performing practitioner, improving attribution in clinical workflows</li>
<li class=""><strong>Operation-based claim submission</strong> — Claim submission now uses a server-side FHIR operation, and the app creates or updates the <code>Claim</code> during export or submit, simplifying the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#revenue-cycle--billing">billing</a> integration</li>
<li class=""><strong>Patient documents tab</strong> — A dedicated documents tab on the patient view, with inbound faxes now stored as <code>DocumentReference</code> resources so they land in the chart alongside other records</li>
<li class=""><strong>Medications in the patient summary</strong> — <code>MedicationStatement</code> resources appear in the <code>PatientSummary</code> component, and both <code>MedicationStatement</code> and <code>DocumentReference</code> now resolve to readable display strings (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Self-service registration</strong> — A Register page for the Provider App lets new users sign up directly, with the reCAPTCHA widget hidden in the app shell (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Navigation polish</strong> — Navbar visual tweaks and a HeaderDropdown refactor (<a href="https://github.com/kevinwadeshaw" target="_blank" rel="noopener noreferrer" class="">Kevin Shaw</a>), plus fixes to the back button after fax loading and to autoscrolling (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
</ul>
<img src="https://www.medplum.com.ar/img/blog/2026-06-provider-navbar.png" alt="Refreshed Provider App navbar and header dropdown" style="max-height:400px;max-width:100%">
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="ai">AI<a href="https://www.medplum.com.ar/blog/june-2026-update#ai" class="hash-link" aria-label="Direct link to AI" title="Direct link to AI" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong> and <img src="https://github.com/maddyli.png" alt="Maddy Li" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a></strong></p>
<p><a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#ai">AI</a> work centered on the <a class="" href="https://www.medplum.com.ar/docs/provider/spaces">Spaces</a> workspace — the in-app AI assistant in the Provider App — and real-time documentation:</p>
<ul>
<li class=""><strong>Configurable model routing</strong> — <a class="" href="https://www.medplum.com.ar/docs/provider/spaces#model-selection">Spaces</a> now supports a configurable base URL and a dynamic model list, so deployments can route AI requests through their own gateway to control cost and security</li>
<li class=""><strong>AI real-time questionnaire form</strong> and <strong>real-time voice</strong> — A real-time questionnaire form plus <a class="" href="https://www.medplum.com.ar/docs/provider/spaces#voice-input">voice input</a> improvements that keep the socket active during a session</li>
<li class=""><strong>Spaces UX</strong> — Prompt composer UI updates and grouping of each FHIR request with its corresponding response for clearer traceability</li>
</ul>
<p>The <a class="" href="https://www.medplum.com.ar/docs/provider/spaces">Spaces documentation</a> covers setup, the agent loop, and how to author the system prompts that drive its behavior. Here is a short walkthrough:</p>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/f2Hv79Irew8" title="Medplum Spaces walkthrough" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></div>
<br>
<img src="https://www.medplum.com.ar/img/blog/2026-06-spaces-composer.png" alt="Updated Spaces prompt composer in the Provider App" style="max-height:400px;max-width:100%">
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="identity-sharing-and-documents">Identity, Sharing, and Documents<a href="https://www.medplum.com.ar/blog/june-2026-update#identity-sharing-and-documents" class="hash-link" aria-label="Direct link to Identity, Sharing, and Documents" title="Direct link to Identity, Sharing, and Documents" translate="no">​</a></h3>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/mfa">Multi-factor authentication</a></strong> — A new email-based MFA method, plus a project-level <code>mfaRequired</code> setting that enforces MFA for every member, with documentation for enabling it (<a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a>)</li>
<li class=""><strong>External token exchange across project memberships</strong> — Token exchange now works across project memberships, for users who span multiple projects</li>
<li class=""><strong>Attachment handling</strong> — Inline attachments in <code>Patient/$everything</code>, base64 data support in <code>&lt;AttachmentDisplay&gt;</code>, and cursor pagination across patient-everything and multi-type searches</li>
<li class=""><strong>Patient invite with RelatedPerson</strong> — The user invite endpoint accepts a <code>Patient</code> to support RelatedPerson, enabling caregiver and proxy access (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="enterprise-data-warehouse-and-reliability">Enterprise: Data Warehouse and Reliability<a href="https://www.medplum.com.ar/blog/june-2026-update#enterprise-data-warehouse-and-reliability" class="hash-link" aria-label="Direct link to Enterprise: Data Warehouse and Reliability" title="Direct link to Enterprise: Data Warehouse and Reliability" translate="no">​</a></h3>
<p><img src="https://github.com/The-Alchemist.png" alt="Karl Pietrzak" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/The-Alchemist" target="_blank" rel="noopener noreferrer" class="">Karl Pietrzak</a></strong> and <img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<p><a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#enterprise-scale--infrastructure">Enterprise scale and infrastructure</a> work made the <a class="" href="https://www.medplum.com.ar/docs/analytics">analytics</a> export production-ready and hardened the data layer:</p>
<ul>
<li class=""><strong>Data warehouse export controls</strong> — Configuration for which tables to sync, include/exclude filters, restored <code>ORDER BY</code>, and DuckDB lifecycle cleanup give data teams precise control over what reaches their lakehouse</li>
<li class=""><strong>Transaction-scoped repositories</strong> — Repository connections are now transaction-scoped, with idle-in-transaction time tracked, improving reliability under load</li>
<li class=""><strong>FHIRPath Patch</strong> — A <a class="" href="https://www.medplum.com.ar/docs/fhir-datastore">FHIRPath Patch</a> utility wired into the server for targeted resource updates (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
<li class=""><strong>Project-level SMTP</strong> — Projects can now configure their own SMTP settings for sending email (<a href="https://github.com/daream" target="_blank" rel="noopener noreferrer" class="">Darren Eam</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="agent-and-connectivity">Agent and Connectivity<a href="https://www.medplum.com.ar/blog/june-2026-update#agent-and-connectivity" class="hash-link" aria-label="Direct link to Agent and Connectivity" title="Direct link to Agent and Connectivity" translate="no">​</a></h3>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<p>The on-premise <a class="" href="https://www.medplum.com.ar/docs/agent">Agent</a> — Medplum's connectivity service for legacy healthcare systems and HL7 interfaces — saw a concentrated round of reliability work this month:</p>
<ul>
<li class=""><strong>Durable HL7 message queue</strong> — The Agent now persists inbound HL7 messages to a durable queue, so messages survive restarts and transient outages instead of living only in memory</li>
<li class=""><strong>Resilient <code>Agent/$upgrade</code></strong> — A batch of fixes to the <a class="" href="https://www.medplum.com.ar/docs/agent/upgrade">Agent upgrade flow</a>: no more duplicated messages during an upgrade, a guard that checks for the upgrade artifact before unlinking it, and a documented upgrade bugfix, alongside a new <a class="" href="https://www.medplum.com.ar/docs/agent/upgrade"><code>Agent/$upgrade</code> documentation page</a></li>
<li class=""><strong>Reconnection hardening</strong> — The Agent now reconnects across a range of error states, records the acknowledgement before returning in <a class="" href="https://www.medplum.com.ar/docs/agent/acknowledgement-modes">acknowledgement-only mode</a>, and triggers a clean shutdown before awaiting channel start</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/agent/reload-config"><code>Agent/$reload-config</code></a></strong> — A documented operation to reload a deployed Agent's configuration without a full restart</li>
<li class=""><strong>WebSocket subscription reliability</strong> — A series of fixes recreate <a class="" href="https://www.medplum.com.ar/docs/subscriptions">WebSocket subscriptions</a> on reconnect, tear down the Redis listener cleanly on shutdown, bind the message listener before subscribing, and send a handshake on connection establishment</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="compliance">Compliance<a href="https://www.medplum.com.ar/blog/june-2026-update#compliance" class="hash-link" aria-label="Direct link to Compliance" title="Direct link to Compliance" translate="no">​</a></h2>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong> and <img src="https://github.com/reshmakh.png" alt="Reshma Khilnani" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a></strong></p>
<p><strong>Medplum achieved <a class="" href="https://www.medplum.com.ar/blog/hitrust-e1-certification">HITRUST certification</a> this month</strong> — the headline of our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#compliance-h1-2026">compliance</a> track. HITRUST is one of the most rigorous, prescriptive security frameworks in healthcare, and certification gives customers third-party assurance of Medplum's security and compliance program for their own vendor reviews. Several other pieces of the track also moved:</p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/compliance/hitrust">HITRUST documentation</a></strong> — Published HITRUST documentation alongside the certification, and pointed compliance references at the <a href="https://trust.medplum.com/" target="_blank" rel="noopener noreferrer" class="">Medplum Trust Center</a> (with an updated Vanta Trust Center link)</li>
<li class=""><strong>SMART Health Cards and Links</strong> — Support for SMART Health Cards and Links, including a QR code scanner and updates for the CMS "Keep the Card" (KTC) program, giving patients a verifiable, portable record</li>
</ul>
<img src="https://www.medplum.com.ar/img/blog/2026-06-smart-health-link-qr.png" alt="SMART Health Link QR code scanner" style="max-height:400px;max-width:100%">
<img src="https://www.medplum.com.ar/img/blog/2026-06-smart-health-link-ktc.png" alt="SMART Health Links for the CMS Keep the Card program" style="max-height:400px;max-width:100%">
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/patient-match"><code>Patient/$match</code></a> with CMS criteria</strong> — The patient match operation now follows CMS matching criteria, aligning identity resolution with federal guidance</li>
<li class=""><strong>Patient data access fixes</strong> — Corrected <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/patient-everything"><code>Patient/$everything</code></a> pagination links and normalized C-CDA address handling, keeping patient-record exchange complete and standards-conformant (<a href="https://github.com/jdjkelly" target="_blank" rel="noopener noreferrer" class="">Joshua Kelly</a>)</li>
<li class=""><strong>Electronic prior authorization</strong> — Continued progress on electronic prior authorization toward the <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4</a> requirements ahead of the January 2027 enforcement date</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/june-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong></p>
<ul>
<li class=""><strong>Self-hosting fixes</strong> — Corrections across the Azure, GCP, and Kubernetes self-hosting guides, a Debian package fix that preserves local edits on upgrade and restores the DuckDB native dependency, and production Docker base images pinned to Node 24.18 (<a href="https://github.com/The-Alchemist" target="_blank" rel="noopener noreferrer" class="">Karl Pietrzak</a>)</li>
</ul>
<p><strong>Provider App and platform</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/access">Shared Projects</a></strong> — New documentation on shared projects (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/multilingual-support">Multi-lingual FHIR support</a></strong> — Docs and a demo app for multi-lingual FHIR support (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
<li class=""><strong>Agentic engineering guide</strong> — A new agentic engineering guide and companion blog post (<a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/provider/spaces">AI real-time docs</a></strong> and <strong>Alpha/Beta feature expectations</strong> — Documentation for the AI real-time operation and a guide to what Alpha and Beta feature labels mean (<a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a>, <a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
</ul>
<p><strong>Integrations</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration">Electronic prescribing</a></strong> — Expanded e-prescribe documentation, including prescriber profile setup and staging NPI creation (<a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a>, <a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration">Lab orders</a></strong> — Public docs for lab account number updates (<a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/billing">Clearinghouse claim submission</a></strong> — Claim submission documentation for clearinghouse connectivity (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/june-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>FHIR and billing</strong></p>
<ul>
<li class="">Render CMS-1500 Box 24E diagnosis pointers correctly (contributed by <a href="https://github.com/ajwwong" target="_blank" rel="noopener noreferrer" class="">Andrew Wong</a>)</li>
<li class="">Prevent duplicate resources in <code>convertToTransactionBundle</code> (contributed by <a href="https://github.com/slmatthiesen" target="_blank" rel="noopener noreferrer" class="">Steven Matthiesen</a>)</li>
<li class="">Normalize address part text nodes in C-CDA <code>mapAddresses</code> (contributed by <a href="https://github.com/jdjkelly" target="_blank" rel="noopener noreferrer" class="">Joshua Kelly</a>)</li>
</ul>
<p><strong>Server and async</strong></p>
<ul>
<li class="">Stop polling a cancelled <code>AsyncJob</code> by returning 200 from the status endpoint, and add <code>Accept-Encoding: identity</code> to token exchange (contributed by <a href="https://github.com/rtmalikian" target="_blank" rel="noopener noreferrer" class="">Raphael Malikian</a>)</li>
<li class="">Bound the 401 retry in <code>MedplumClient</code> to prevent infinite retry loops (contributed by <a href="https://github.com/jdjkelly" target="_blank" rel="noopener noreferrer" class="">Joshua Kelly</a>)</li>
<li class="">Paginate AWS Textract results via <code>NextToken</code> (contributed by <a href="https://github.com/lolkat247" target="_blank" rel="noopener noreferrer" class="">Jake Diaz-Iglesias</a>)</li>
<li class="">Recreate WebSocket subscriptions on reconnect (contributed by <a href="https://github.com/d-vincent" target="_blank" rel="noopener noreferrer" class="">Drew McDonald</a>)</li>
<li class="">Record the authenticating <code>ClientApplication</code> on <code>AuditEvent.agent[]</code> (contributed by <a href="https://github.com/WonderPanda" target="_blank" rel="noopener noreferrer" class="">Jesse Carter</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="from-the-blog">From the Blog<a href="https://www.medplum.com.ar/blog/june-2026-update#from-the-blog" class="hash-link" aria-label="Direct link to From the Blog" title="Direct link to From the Blog" translate="no">​</a></h2>
<p>Longer-form writing published this month:</p>
<ul>
<li class=""><img src="https://github.com/reshmakh.png" alt="Reshma Khilnani" width="24" height="24" style="border-radius:50%;vertical-align:middle"> <strong><a class="" href="https://www.medplum.com.ar/blog/hitrust-e1-certification">Medplum Achieves HITRUST e1 Certification</a></strong> by Reshma Khilnani — The certification announcement and what it means for customers</li>
<li class=""><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="24" height="24" style="border-radius:50%;vertical-align:middle"> <strong><a class="" href="https://www.medplum.com.ar/blog/scheduling-beta">Medplum Scheduling API: Beta Release</a></strong> by Noah Silas — A deeper look at the appointment operation suite now in Beta</li>
<li class=""><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="24" height="24" style="border-radius:50%;vertical-align:middle"> <strong><a class="" href="https://www.medplum.com.ar/blog/large-patient-charts">Large Patient Charts</a></strong> by Cody Ebberson — Handling patients with very large charts at scale</li>
<li class=""><img src="https://github.com/everett-williams.png" alt="Everett Williams" width="24" height="24" style="border-radius:50%;vertical-align:middle"> <strong><a class="" href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai">Vibe Coding on Medplum</a></strong> by Everett Williams — Building on Medplum with AI coding assistants, the companion to the agentic engineering guide</li>
<li class=""><img src="https://github.com/sainejob.png" alt="Stephen Saine" width="24" height="24" style="border-radius:50%;vertical-align:middle"> <strong><a class="" href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum">From BLE to FHIR: Streaming Clinical-Grade Biosignals with AnyBio + Medplum</a></strong> by Stephen Saine — Streaming device biosignals into FHIR</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/june-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.14" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.14</strong></a> — June 1</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.15" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.15</strong></a> — June 3</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.16" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.16</strong></a> — June 8</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.17" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.17</strong></a> — June 9</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.18" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.18</strong></a> — June 15</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.19" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.19</strong></a> — June 20</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.20" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.20</strong></a> — June 20</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.21" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.21</strong></a> — June 20</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.22" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.22</strong></a> — June 24</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/june-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>June brought scheduling to Beta, made the Enterprise data warehouse export production-ready with selectable table sync, and added configurable model routing to the AI workspace. SMART Health Cards and Links, operation-based claim submission, and a reusable inbox shell round out a month focused on Provider App depth and platform reliability.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Scheduling API - Beta Release]]></title>
        <id>https://www.medplum.com.ar/blog/scheduling-beta</id>
        <link href="https://www.medplum.com.ar/blog/scheduling-beta"/>
        <updated>2026-06-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After several months of preview as an Alpha product, we are pleased to announce that Medplum's Scheduling API has graduated to Beta.]]></summary>
        <content type="html"><![CDATA[<p>After several months of preview as an <a class="" href="https://www.medplum.com.ar/docs/compliance/alpha-beta">Alpha</a> product, we are pleased to announce that <a class="" href="https://www.medplum.com.ar/docs/scheduling">Medplum's Scheduling API</a> has graduated to <a class="" href="https://www.medplum.com.ar/docs/compliance/alpha-beta">Beta</a>.</p>
<p>Medplum's Scheduling API provides an interface for applications to atomically interact with <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/schedule">Schedule</a>, <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/slot">Slot</a>, and <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/appointment">Appointment</a> resources to safely create and manage bookings without creating scheduling conflicts. Developing a feature like this required the ability to iterate as we learned, and our Alpha period provided exactly that.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="what-changed-during-alpha">What changed during Alpha<a href="https://www.medplum.com.ar/blog/scheduling-beta#what-changed-during-alpha" class="hash-link" aria-label="Direct link to What changed during Alpha" title="Direct link to What changed during Alpha" translate="no">​</a></h2>
<p>We made some breaking changes over the course of the Alpha period to simplify the API surface and support multi-resource scheduling:</p>
<ul>
<li class=""><strong>Removed <code>Schedule/:id/$find</code></strong>: This route has been replaced by <code>Appointment/$find</code>, which handles single-Schedule lookups as a basic case of its ability to query multiple Schedules at once.</li>
<li class=""><strong>Removed slot-based <code>Appointment/$book</code></strong>: The <code>slot</code> parameter input to <code>$book</code> has been removed. The operation now only accepts an <code>appointment</code> as input, which can act as a container for the potentially many Slot resources involved in a single atomic booking operation.</li>
<li class=""><strong><code>HealthcareService</code> as required service type</strong>: Our original specification considered using <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/activitydefinition">ActivityDefinition</a> resources as an optional place to store shared service type definitions. After considering the impact it would have when booking appointments with several participants, we decided to require that service types be explicitly defined as <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/healthcareservice"><code>HealthcareService</code></a> resources, and a reference to such a healthcare service must be included to search for available appointments in <code>$find</code>.</li>
<li class=""><strong>Changed <code>availability</code> format</strong>: We've chosen a storage format for customizing availability that mirrors the <a href="https://hl7.org/fhir/R5/metadatatypes.html#Availability" target="_blank" rel="noopener noreferrer" class="">FHIR R5 Availability type</a>. This will let us migrate these definitions easily when Medplum Server adds support for later FHIR releases.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-beta-api-surface">The Beta API surface<a href="https://www.medplum.com.ar/blog/scheduling-beta#the-beta-api-surface" class="hash-link" aria-label="Direct link to The Beta API surface" title="Direct link to The Beta API surface" translate="no">​</a></h2>
<p>The Beta API consists of five operations:</p>
<table><thead><tr><th>Operation</th><th>Description</th></tr></thead><tbody><tr><td><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-find"><code>Appointment/$find</code></a></td><td>Find available slots across one or more Schedules</td></tr><tr><td><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-book"><code>Appointment/$book</code></a></td><td>Book an appointment in one step</td></tr><tr><td><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-hold"><code>Appointment/$hold</code></a></td><td>Temporarily hold a slot</td></tr><tr><td><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-confirm"><code>Appointment/$confirm</code></a></td><td>Confirm a held appointment</td></tr><tr><td><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-cancel"><code>Appointment/$cancel</code></a></td><td>Cancel an appointment</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="what-beta-means">What Beta means<a href="https://www.medplum.com.ar/blog/scheduling-beta#what-beta-means" class="hash-link" aria-label="Direct link to What Beta means" title="Direct link to What Beta means" translate="no">​</a></h2>
<p>The core API contract is now stable. Breaking changes are still possible during Beta, but we will note them in release notes and provide a migration path where practical. The API is appropriate for production use in non-critical workflows. See our <a class="" href="https://www.medplum.com.ar/docs/compliance/alpha-beta">Alpha &amp; Beta policy</a> for the full details.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="get-started">Get started<a href="https://www.medplum.com.ar/blog/scheduling-beta#get-started" class="hash-link" aria-label="Direct link to Get started" title="Direct link to Get started" translate="no">​</a></h2>
<p>Check out the <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling documentation</a> for a full reference, including how to define availability, find open slots, and book appointments.</p>
<p>Thank you to all our partners who experimented with the API during the Alpha period and provided such valuable feedback!</p>]]></content>
        <author>
            <name>Noah Silas</name>
            <uri>https://github.com/noahsilas</uri>
        </author>
        <category label="fhir" term="fhir"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[From BLE to FHIR: Streaming Clinical-Grade Biosignals with AnyBio + Medplum]]></title>
        <id>https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum</id>
        <link href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum"/>
        <updated>2026-06-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[If you're building a digital health product, you've probably hit the same wall everyone hits: the gap between a wearable's raw signal and a clinical-grade artifact in the EHR that is actionable by a clinician.]]></summary>
        <content type="html"><![CDATA[<p>If you're building a digital health product, you've probably hit the same wall everyone hits: the gap between a wearable's raw signal and a clinical-grade artifact in the EHR that is actionable by a clinician.</p>
<p>There's a lot of plumbing in that gap: device integration, real-time ingest, signal processing, derived metrics, provenance, governance, FHIR projection, US Core conformance, and most of it is undifferentiated infrastructure that takes a year or more to build properly.</p>
<p><a href="https://anybio.io/" target="_blank" rel="noopener noreferrer" class="">AnyBio</a> handles the upstream half of that pipeline. <a href="https://medplum.com/" target="_blank" rel="noopener noreferrer" class="">Medplum</a> handles the downstream half.</p>
<p>Together they give you a standards-based path from a BLE sensor on a patient's wrist to a <a href="https://build.fhir.org/ig/HL7/US-Core/index.html" target="_blank" rel="noopener noreferrer" class="">US-Core-conformant</a> Observation in a queryable FHIR record - and on the AnyBio side, wiring up that path is a configuration step, not an engineering project.</p>
<p>This post walks through what each side does and how the data is shaped, then gives you two ways in: a two-minute path that exports a synthetic demo run to your own Medplum instance with zero setup, and the full production wire-up. And - because "it works in the demo" is not the same as "I'd run this in production" - how the pipeline behaves when things go wrong.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-pipeline-at-a-glance">The pipeline at a glance<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#the-pipeline-at-a-glance" class="hash-link" aria-label="Direct link to The pipeline at a glance" title="Direct link to The pipeline at a glance" translate="no">​</a></h2>
<div class="language-text codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-text codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">BLE device / wearable</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -&gt; AnyBio SDK: Web Bluetooth (browser) or iOS (real-time stream, zero-data-loss buffer)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    -&gt; AnyBio ingest (multi-device session handling: time-aligns and</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        deduplicates concurrent streams from multiple sensors)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      -&gt; Signal pipeline (DSP, partner algorithms via WASM)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        -&gt; Composite + derived metrics (multi-modal correlation)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          -&gt; Governance + audit (BAA, chain-of-custody)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            -&gt; FHIR projection (US Core 6.1.0, multi-coded)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              -&gt; Medplum (FHIR R4 transaction Bundle POST)</span><br></div></code></pre></div></div>
<p>Two things worth saying up front:</p>
<ol>
<li class="">
<p><strong>FHIR is the delivery format, not the work.</strong> By the time data reaches Medplum it has been through a real-time pipeline that includes provenance stamping, algorithm execution, and US Core profile validation. The "FHIR-native" claim has teeth because the pipeline is engineered around producing valid resources - not because we serialize to JSON at the end.</p>
</li>
<li class="">
<p><strong>Medplum is the right downstream for this.</strong> It's open-source, fully FHIR-native on R4 (4.0.1), runs a permissive but conformant validator, and - critically for development - auto-creates referenced Patient resources on first write, so you can stand up an end-to-end demo without wiring identity matching first. (More on why that's a dev-only convenience below.)</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="what-anybio-sends-to-medplum">What AnyBio sends to Medplum<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#what-anybio-sends-to-medplum" class="hash-link" aria-label="Direct link to What AnyBio sends to Medplum" title="Direct link to What AnyBio sends to Medplum" translate="no">​</a></h2>
<p>The standard payload is a FHIR R4 <strong>transaction Bundle</strong> containing:</p>
<ul>
<li class=""><strong>Observation</strong> resources - one per measurement or derived metric: vital signs, HRV, derived classifications, multi-modal composites.</li>
<li class=""><strong>DocumentReference + Attachment</strong> - for telemetry strips (ECG, EDA, PPG waveforms) rendered as PNG/PDF artifacts.</li>
<li class=""><strong>Provenance</strong> - chain-of-custody from device through algorithm to derived artifact.</li>
<li class=""><strong>Patient</strong> reference - a logical reference; Medplum resolves or auto-creates it.</li>
</ul>
<p>Every Observation carries its lineage and its reproducibility metadata using <strong>standard FHIR elements</strong> - not custom fields:</p>
<ul>
<li class=""><strong>Multi-coded <code>code</code></strong> - LOINC primary, <a href="https://api.anybio.io/fhir/CodeSystem/biosignal" target="_blank" rel="noopener noreferrer" class="">AnyBio CodeSystem</a> secondary. The AnyBio CodeSystem lives at a public, dereferenceable canonical URL (<code>https://api.anybio.io/fhir/CodeSystem/biosignal</code>) generated from our biosignal registry, so <code>Coding.system</code> resolves to a real CodeSystem resource.</li>
<li class=""><strong><code>derivedFrom</code></strong> - derived metrics reference the source Observation(s) they were computed from, so any classification traces back to the raw signal it came from. This is FHIR's standard <code>Observation.derivedFrom</code>, a <code>Reference(Observation)</code>.</li>
<li class=""><strong><code>device</code></strong> - points to a <code>Device</code> resource representing the algorithm/sensor that produced the value, with the algorithm version in <code>Device.version</code> (e.g., <code>anybio-hrv-v3.2</code>). That's where reproducibility lives.</li>
<li class=""><strong><code>Provenance</code></strong> - the emitted Provenance resource stamps the full device -&gt; algorithm -&gt; artifact chain with timestamps and version identifiers, so "which version produced this value" is answerable from the record itself.</li>
<li class=""><strong>US Core <code>meta.profile</code></strong> - asserted per resource type and validated in CI (details in the next section).</li>
</ul>
<p>Here's a heart-rate Observation on the wire - a primary vital sign, with a <code>device</code> reference for reproducibility:</p>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"resourceType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Observation"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"status"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"final"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"meta"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"profile"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"http://hl7.org/fhir/us/core/StructureDefinition/us-core-heart-rate"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"category"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://terminology.hl7.org/CodeSystem/observation-category"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"vital-signs"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://loinc.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8867-4"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Heart rate"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://api.anybio.io/fhir/CodeSystem/biosignal"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"heart-rate"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Heart rate"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Patient/&lt;patient-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"effectiveDateTime"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2026-06-15T14:32:11Z"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"valueQuantity"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"value"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">72</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"unit"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"beats/minute"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://unitsofmeasure.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/min"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"device"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Device/&lt;algorithm-device-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>A <strong>derived</strong> metric - say an HRV-based autonomic-state classification - links back to its sources via <code>derivedFrom</code> and names the producing pipeline via <code>method</code> and <code>device</code>:</p>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"resourceType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Observation"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"status"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"final"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"category"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://terminology.hl7.org/CodeSystem/observation-category"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"procedure"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://api.anybio.io/fhir/CodeSystem/biosignal"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"hrv-autonomic-state"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"HRV-based autonomic state"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Patient/&lt;patient-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"effectiveDateTime"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2026-06-15T14:32:11Z"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"method"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://api.anybio.io/fhir/CodeSystem/method"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"anybio-hrv-v3.2"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"AnyBio HRV pipeline v3.2"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"device"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Device/&lt;algorithm-device-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"derivedFrom"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Observation/&lt;source-rr-interval-obs-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"valueCodeableConcept"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://api.anybio.io/fhir/CodeSystem/autonomic-state"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"balanced"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Balanced"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Blood pressure is the case worth showing explicitly, because it's the classic conformance trap: there is <strong>no top-level value</strong>, only <code>component</code> entries. AnyBio ships it as a <code>us-core-blood-pressure</code> panel:</p>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"resourceType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Observation"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"status"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"final"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"meta"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"profile"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"http://hl7.org/fhir/us/core/StructureDefinition/us-core-blood-pressure"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"category"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://terminology.hl7.org/CodeSystem/observation-category"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"vital-signs"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://loinc.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"85354-9"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Blood pressure panel"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"reference"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Patient/&lt;patient-id&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"effectiveDateTime"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2026-06-15T14:32:11Z"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"component"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://loinc.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8480-6"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Systolic blood pressure"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"valueQuantity"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"value"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">118</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"unit"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"mmHg"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://unitsofmeasure.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"mm[Hg]"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"coding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://loinc.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8462-4"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"display"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Diastolic blood pressure"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"valueQuantity"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"value"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">76</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"unit"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"mmHg"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://unitsofmeasure.org"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"mm[Hg]"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Waveform artifacts ship as DocumentReference + Attachment, with the source signal coded in <code>category</code>. For dense numeric series (the raw samples behind those strips), FHIR's <code>valueSampledData</code> packs a regularly-sampled run into a single Observation — see Medplum's <a class="" href="https://www.medplum.com.ar/docs/charting/chart-data-model#using-valuesampleddata-for-time-series">Using valueSampledData for Time Series</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="conformance-and-validation---the-part-you-can-check">Conformance and validation - the part you can check<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#conformance-and-validation---the-part-you-can-check" class="hash-link" aria-label="Direct link to Conformance and validation - the part you can check" title="Direct link to Conformance and validation - the part you can check" translate="no">​</a></h2>
<p>Conformance here is structural, not aspirational, and we've tried to make every claim verifiable rather than asking you to take our word for it:</p>
<ul>
<li class=""><strong>Registry-driven projection.</strong> Adding a new biosignal is a row in our registry, not a code change. The projection logic is identical for every signal type, which is what keeps conformance consistent across the board.</li>
<li class=""><strong>Validated in CI against the real tool.</strong> Every resource type is validated against US Core 6.1.0 using the official <strong>HL7 FHIR Validator</strong> (<code>validator_cli.jar</code>), and the build fails on any validation <em>error</em>. We track warnings separately - US Core emits informational warnings even on fully conformant resources, so "zero errors" is the meaningful bar, and that's the one CI enforces.</li>
<li class=""><strong>Published conformance.</strong> AnyBio exposes a <code>CapabilityStatement</code> describing the resources, profiles, and interactions it produces, so you can diff our asserted conformance against what actually lands in your server.</li>
</ul>
<p><strong>A note on the version pin.</strong> We target <strong>US Core 6.1.0</strong> deliberately - not because it's the newest (it isn't; US Core is now published through 8.0.0, with 9.0.0 in ballot), but because 6.1.0 is the version aligned with ONC's (g)(10) certification criteria that production EHRs are held to. Medplum's own API is an open-source implementation of those same (g)(10) criteria, so the two line up by design. US Core remains FHIR R4-based - the move to R6 is under consideration but has no timeline - so R4 here is the standard, not a legacy choice. When the certification baseline moves, the registry-driven projection lets us re-target with a profile bump rather than a rewrite.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="try-it-in-two-minutes---no-hardware-no-code">Try it in two minutes - no hardware, no code<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#try-it-in-two-minutes---no-hardware-no-code" class="hash-link" aria-label="Direct link to Try it in two minutes - no hardware, no code" title="Direct link to Try it in two minutes - no hardware, no code" translate="no">​</a></h2>
<p>The fastest way to watch US-Core Observations land in your own Medplum is the Device Console demo export. It runs a synthetic biosignal scenario in your browser and ships the result to your sandbox Medplum, so you can see the conformant output end to end before wiring up a single device.</p>
<ol>
<li class=""><strong>Sign in.</strong> Go to <a href="https://secure.anybio.io/" target="_blank" rel="noopener noreferrer" class=""><code>secure.anybio.io</code></a> and sign in with Apple, Google, or Microsoft. A sandbox environment is provisioned for you automatically.</li>
<li class=""><strong>Run the demo.</strong> Open the <strong>Device Console</strong> and click <strong>Try Demo</strong>. AnyBio streams a synthetic scenario (ECG, PPG, HR, SpO2) in the browser and shows a live summary with the derived metrics.</li>
<li class=""><strong>Export.</strong> On the summary, click <strong>Export to EHR / Medplum</strong> and paste your sandbox Medplum <strong>client ID</strong>, <strong>client secret</strong>, and <strong>FHIR base URL</strong> (prefilled with <code>https://api.medplum.com/fhir/R4</code>).</li>
<li class=""><strong>Watch it land.</strong> AnyBio builds a US-Core <strong>transaction Bundle</strong> from the demo's Observations using the <em>same registry-driven projection production uses</em>, exchanges a one-shot OAuth token, and POSTs it to your Medplum. The panel reports the created resource references, or the receiver's <code>OperationOutcome</code> if Medplum rejects the Bundle.</li>
</ol>
<p>Because the demo data is <strong>synthetic</strong>, there is no PHI and no BAA required: it maps to Medplum's auto-create-Patient (<code>medplum_demo</code>) mode, which stands up the referenced <code>Patient</code> on first write. What lands is real and conformant, not a simplified mock - it goes through the same registry-driven projection and US Core 6.1.0 validation the production pipeline uses.</p>
<p>The demo exports the run's scalar <strong>Observations</strong> (heart rate, HRV, SpO2, …) with full <strong>Provenance</strong> and the synthetic Patient. Waveform artifacts (<code>DocumentReference</code> telemetry strips) and panel signals like blood pressure belong to the production <strong>episode</strong> pipeline - which renders strips from real signal data - not the synthetic demo, so they don't appear in the demo export (blood pressure comes back in the response's <code>skipped</code> list instead).</p>
<p>Behind the button is a single stateless call (<code>POST /api/v1/demo/fhir-export</code>) that takes the demo's features plus your pasted Medplum credentials, projects, and forwards. The credentials are used once for the token exchange and never stored, and the endpoint is locked to Medplum hosts.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="wire-it-for-production">Wire it for production<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#wire-it-for-production" class="hash-link" aria-label="Direct link to Wire it for production" title="Direct link to Wire it for production" translate="no">​</a></h2>
<p>The two-minute demo skips the upstream half (it uses synthetic data in the browser). For a real deployment, here is the full path. On the AnyBio side it is configuration, not an engineering project.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="1-create-your-anybio-account">1. Create your AnyBio account<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#1-create-your-anybio-account" class="hash-link" aria-label="Direct link to 1. Create your AnyBio account" title="Direct link to 1. Create your AnyBio account" translate="no">​</a></h3>
<p><a href="https://secure.anybio.io/" target="_blank" rel="noopener noreferrer" class=""><code>secure.anybio.io</code></a> -&gt; social sign-in -&gt; you land in the dashboard with a <strong>sandbox</strong> environment. Copy a <strong>developer key</strong> (<code>sk_sandbox_*</code>) from <strong>Settings -&gt; API Keys</strong>. It is the bearer token for every AnyBio API call below.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="2-stand-up-medplum">2. Stand up Medplum<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#2-stand-up-medplum" class="hash-link" aria-label="Direct link to 2. Stand up Medplum" title="Direct link to 2. Stand up Medplum" translate="no">​</a></h3>
<p>If you don't already have a Medplum project, the fastest path is the hosted version at <a href="https://app.medplum.com/" target="_blank" rel="noopener noreferrer" class=""><code>app.medplum.com</code></a> — <a class="" href="https://www.medplum.com.ar/docs/tutorials/register">register a new project</a> in a couple of minutes. Then create a <strong>ClientApplication</strong> from the <strong>Project Admin</strong> page; that gives you a <code>client_id</code> and <code>client_secret</code> for the <a class="" href="https://www.medplum.com.ar/docs/auth/client-credentials">OAuth 2.0 Client Credentials flow</a>. Medplum's hosted FHIR base URL is <code>https://api.medplum.com/fhir/R4</code> and its token endpoint is <code>https://api.medplum.com/oauth2/token</code>; tokens are issued with a one-hour lifetime (<code>expires_in: 3600</code>).</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="3-get-a-biosignal-flowing-into-anybio">3. Get a biosignal flowing into AnyBio<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#3-get-a-biosignal-flowing-into-anybio" class="hash-link" aria-label="Direct link to 3. Get a biosignal flowing into AnyBio" title="Direct link to 3. Get a biosignal flowing into AnyBio" translate="no">​</a></h3>
<p>Connect a device and start streaming. The most accessible path needs no native app: <strong>Web Bluetooth</strong> via AnyBio's web SDK. Drop the CDN script (<code>https://cdn.anybio.io/biosdk-web/v1/bioui.js</code>), configure a <code>&lt;bio-provider&gt;</code> with your sandbox key, and pair a supported BLE device straight from the browser; frames stream to <code>POST /ingest/raw-packet</code>. For production real-device capture the <strong>iOS SDK</strong> is the native path; for no-hardware testing the <strong>synthetics</strong> generator simulates a device. Either way the signal attaches to an <strong>episode</strong> under a program/profile you enroll a patient into. That episode is what the export fires on.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="4-register-the-medplum-endpoint-with-anybio">4. Register the Medplum endpoint with AnyBio<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#4-register-the-medplum-endpoint-with-anybio" class="hash-link" aria-label="Direct link to 4. Register the Medplum endpoint with AnyBio" title="Direct link to 4. Register the Medplum endpoint with AnyBio" translate="no">​</a></h3>
<p>Create an <strong>OAuth provider</strong> holding your Medplum <code>client_id</code> / <code>client_secret</code>, then register the FHIR config (credentials are referenced by FK, not inlined):</p>
<div class="language-text codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-text codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">POST /api/v1/fhir-medplum-configs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "base_url": "https://api.medplum.com/fhir/R4",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "oauth_provider_id": &lt;id&gt;,</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "binding_mode": "medplum_demo"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p><code>binding_mode</code> is <code>medplum_demo</code> for development (Medplum auto-creates the <code>Patient</code>) and <code>provider_logical</code> for production, where a provider-issued logical identifier is used because patient identity is owned by an upstream EHR.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="5-create-the-export-and-attach-a-trigger">5. Create the export and attach a trigger<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#5-create-the-export-and-attach-a-trigger" class="hash-link" aria-label="Direct link to 5. Create the export and attach a trigger" title="Direct link to 5. Create the export and attach a trigger" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-text codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">POST /api/v1/data-exports</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "kind": "fhir_medplum",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "target_ref": { "kind": "fhir_medplum", "fhir_medplum_config_id": "&lt;config-id&gt;" }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Then attach the export to your program by adding it to the profile's <code>spec.exports[]</code> with a trigger such as <code>on_episode_end</code>. The trigger lives on the profile binding, not on the <code>data_export</code> itself.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="6-close-an-episode-and-verify">6. Close an episode and verify<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#6-close-an-episode-and-verify" class="hash-link" aria-label="Direct link to 6. Close an episode and verify" title="Direct link to 6. Close an episode and verify" translate="no">​</a></h3>
<p>Stream some data, then close the episode (manually or via an end-condition). <code>on_episode_end</code> fires, AnyBio builds the transaction Bundle and POSTs it to Medplum under your cached OAuth token (Redis, 1h TTL, auto-refreshed). Confirm the round-trip:</p>
<div class="language-shell codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-shell codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">curl -X GET "https://api.medplum.com/fhir/R4/Observation?subject=Patient/&lt;id&gt;" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -H "Authorization: Bearer &lt;medplum-access-token&gt;"</span><br></div></code></pre></div></div>
<p>You should see the Observations AnyBio wrote, with US Core profile metadata, multi-coded <code>code</code>, the <code>device</code> and <code>derivedFrom</code> links, the Provenance resource, and any DocumentReferences for waveform artifacts.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="what-happens-when-it-breaks">What happens when it breaks<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#what-happens-when-it-breaks" class="hash-link" aria-label="Direct link to What happens when it breaks" title="Direct link to What happens when it breaks" translate="no">​</a></h2>
<p>A happy-path demo tells you the integration <em>can</em> work. Here's how it behaves when it doesn't - which is the part that decides whether you'd put it in front of patients.</p>
<p><strong>Transaction Bundles are all-or-nothing.</strong> A <code>transaction</code> Bundle either fully applies or fully rejects; one invalid resource or one broken reference fails the entire episode's export, and the server returns an <code>OperationOutcome</code> describing why. AnyBio validates the Bundle against US Core <em>in-pipeline before</em> the POST, so most of this is caught early. If Medplum still rejects it, the Bundle is quarantined with the returned <code>OperationOutcome</code> attached - so you can see exactly which resource and which constraint failed instead of reverse-engineering it from logs.</p>
<p><strong>Transient failures retry; persistent ones dead-letter.</strong> Network errors, 5xx responses, and expired tokens trigger exponential backoff with jitter and a capped retry count. A 401 refreshes the token and retries. Once retries are exhausted, the Bundle moves to a dead-letter queue and raises an alert rather than being silently dropped.</p>
<p><strong>Re-fired triggers don't create duplicates.</strong> Idempotency is the failure mode people forget until they have three copies of every heart-rate reading. If a trigger fires twice - a retry after an ambiguous timeout, a replayed episode close - the write has to be a no-op, not a duplicate. AnyBio stamps a stable business <code>identifier</code> on every resource and writes with conditional semantics: <code>ifNoneExist</code> on that identifier (the server no-ops if a matching resource already exists), or a client-assigned ID via <code>PUT</code> (a replay upserts rather than duplicates). Either way, replaying a Bundle is safe.</p>
<p><strong>Late and out-of-order data resolve cleanly.</strong> Biosignals don't always arrive in order - a buffer flush after a connectivity gap can backfill readings minutes late. Because every Observation carries its own <code>effectiveDateTime</code> and stable identifier, a late write is just an idempotent upsert keyed on time and identifier, and downstream queries order by <code>effectiveDateTime</code>, not by when the data happened to land.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="security-and-governance">Security and governance<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#security-and-governance" class="hash-link" aria-label="Direct link to Security and governance" title="Direct link to Security and governance" translate="no">​</a></h2>
<p>This is clinical data, so the controls matter as much as the pipeline:</p>
<ul>
<li class=""><strong>Authentication.</strong> Client secret is fine for development; for production, JWT client assertion (RFC 7523, asymmetric keys) is the stronger option - no shared secret crosses the wire, and you can rotate keys per instance. Medplum supports both and mandates JWT-based client auth for SMART Backend Services-style integrations.</li>
<li class=""><strong>Transport and logging.</strong> PHI travels over TLS only, and identifiers go in the request body or headers - never in URLs or query strings, so PHI never lands in access logs.</li>
<li class=""><strong>Audit.</strong> Every write Medplum performs generates an <code>AuditEvent</code>, and Medplum can strip human-readable detail (patient names, clinical descriptions) from those events while retaining the machine-readable identifiers - so the audit trail itself isn't a disclosure risk. On top of that, AnyBio's <code>Provenance</code> gives you clinical chain-of-custody from device to derived artifact: auditing any signal back to its origin is one query.</li>
<li class=""><strong>BAA before PHI.</strong> A Business Associate Agreement is signed before any PHI flows. The <code>medplum_demo</code> auto-create mode is dev-only for exactly this reason - it's built for synthetic and test data, not real patients.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="why-this-composition-works">Why this composition works<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#why-this-composition-works" class="hash-link" aria-label="Direct link to Why this composition works" title="Direct link to Why this composition works" translate="no">​</a></h2>
<ul>
<li class=""><strong>Conformance is structural, not bolted on.</strong> The projection is registry-driven and validated against US Core 6.1.0 in CI at zero errors. Medplum's permissive-but-conformant validator accepts that output cleanly.</li>
<li class=""><strong>Provenance survives the wire.</strong> The Provenance resource chains device -&gt; algorithm -&gt; artifact with timestamps and version identifiers. Auditing a clinical signal back to its origin is a single query, not a forensics exercise.</li>
<li class=""><strong>The pipeline does the work; FHIR delivers it.</strong> What makes AnyBio + Medplum useful isn't that FHIR works - that's table stakes. It's that real-time biosignals become US-Core-conformant clinical artifacts <em>before</em> they ever hit FHIR. The wire format is the easy part.</li>
</ul>
<p>The same conformant Bundle is also the starting point for stricter downstream EHRs: the projection is designed so that Epic and Cerner targets are a matter of adapter-specific profiling on top of the same US Core base, rather than a separate pipeline.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="whats-next">What's next<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>We're using the Medplum integration as the reference implementation for AnyBio's broader EHR integration framework. The same <code>ExportAdapter</code> pattern that wires up Medplum is what we're building other connectors with and HL7v2-over-MLLP on. If you're building on AnyBio and want to write to a different FHIR destination, the lift is configuration, not engineering.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="get-started">Get started<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#get-started" class="hash-link" aria-label="Direct link to Get started" title="Direct link to Get started" translate="no">​</a></h2>
<p><strong>Try it in two minutes — no hardware, no code:</strong></p>
<ol>
<li class="">Sign in at <a href="https://secure.anybio.io/" target="_blank" rel="noopener noreferrer" class="">secure.anybio.io</a>.</li>
<li class="">Open the <strong>Device Console</strong> and click <strong>Try Demo</strong>.</li>
<li class="">Click <strong>Export to EHR / Medplum</strong> and paste your sandbox Medplum credentials.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="related-reading">Related reading<a href="https://www.medplum.com.ar/blog/ble-to-fhir-anybio-medplum#related-reading" class="hash-link" aria-label="Direct link to Related reading" title="Direct link to Related reading" translate="no">​</a></h2>
<p>To go deeper on the Medplum side of the pipeline:</p>
<ul>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/working-with-fhir">Working with FHIR Data</a> — how Medplum stores and serves FHIR R4.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/charting/chart-data-model">Chart Data Model</a> — modeling Observations and vital signs, including <a class="" href="https://www.medplum.com.ar/docs/charting/chart-data-model#using-valuesampleddata-for-time-series"><code>valueSampledData</code> for time series</a>.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/terminology/common-terminologies">Commonly Used Terminologies</a> — LOINC, SNOMED CT, and UCUM, and how multi-coded <code>code</code> works.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/fhir-batch-requests#batches-vs-transactions">Batch &amp; Transaction Requests</a> and <a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/fhir-batch-requests#conditional-batch-actions">Conditional Batch Actions</a> — atomic Bundles and idempotent (<code>ifNoneExist</code>) writes.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/profiles">FHIR Profiles &amp; Validation</a> and <a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/understanding-uscdi-dataclasses">Understanding USCDI Data Classes</a> — US Core conformance.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/patient-deduplication">Patient Deduplication</a> — identity matching versus auto-create.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/external-documents">External Files and Document References</a> — storing waveform strips and other binary artifacts.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/auth/client-credentials">Client Credentials</a> and <a class="" href="https://www.medplum.com.ar/docs/auth/client-assertion">Client Assertion (JWT)</a> — OAuth for backend integrations.</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/compliance/onc">ONC Certification</a> — Medplum's (g)(10) implementation.</li>
</ul>]]></content>
        <author>
            <name>Stephen Saine</name>
            <uri>https://github.com/sainejob</uri>
        </author>
        <category label="integration" term="integration"/>
        <category label="fhir-datastore" term="fhir-datastore"/>
        <category label="interop" term="interop"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Large Patient Charts]]></title>
        <id>https://www.medplum.com.ar/blog/large-patient-charts</id>
        <link href="https://www.medplum.com.ar/blog/large-patient-charts"/>
        <updated>2026-06-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[There's a piece of conventional wisdom in health tech that won't die: FHIR is fine for interoperability, but too slow and bloated for real-time clinical apps.]]></summary>
        <content type="html"><![CDATA[<p>There's a piece of conventional wisdom in health tech that won't die: FHIR is fine for interoperability, but too slow and bloated for real-time clinical apps.</p>
<p>The skepticism isn't unreasonable. FHIR resources can be verbose, real charts are messy, and clinical workflows don't forgive much. A physician who opens a chart and watches a spinner for five seconds has already been let down by the architecture.</p>
<!-- -->
<p>We've <a class="" href="https://www.medplum.com.ar/blog/medplum-performance-test-2026">benchmarked Medplum's performance before</a>, mostly around throughput — can a FHIR server handle millions of small requests at once. A customer recently pushed us on the inverse question, which turns out to be harder: can a FHIR-native system handle one enormous chart?</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-test-case">The test case<a href="https://www.medplum.com.ar/blog/large-patient-charts#the-test-case" class="hash-link" aria-label="Direct link to The test case" title="Direct link to The test case" translate="no">​</a></h2>
<p>We built the largest patient we could justify: a synthetic chart with roughly 131,000 FHIR resources. Tens of thousands of Observations, a multi-year longitudinal history, dozens of resource types all referencing each other. No real clinician will ever open a chart like this. That was the point — we wanted something pathological enough to surface whatever breaks.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="four-ways-to-load-a-chart">Four ways to load a chart<a href="https://www.medplum.com.ar/blog/large-patient-charts#four-ways-to-load-a-chart" class="hash-link" aria-label="Direct link to Four ways to load a chart" title="Direct link to Four ways to load a chart" translate="no">​</a></h2>
<p>Most "FHIR is slow" complaints assume you have to pull the entire payload in one shot. You don't. We tested four approaches:</p>
<ul>
<li class=""><strong>Patient/$everything</strong> — the standard FHIR operation for retrieving a full chart.</li>
<li class=""><strong>Resource-type queries</strong> — fetching Medications, Labs, and so on independently and in parallel.</li>
<li class=""><strong>Recent-first loading</strong> — load the last 30 days of clinically relevant data first, then hydrate the older history in the background.</li>
<li class=""><strong>Full browser download</strong> — a React demo that streams the entire chart into the app with a live progress bar.</li>
</ul>
<p>The recent-first strategy is the one that matters in practice. A doctor shouldn't be blocked on ten years of history before they can start working. Load what's actionable now, fill in the rest behind it, and the UI is usable almost immediately.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="results">Results<a href="https://www.medplum.com.ar/blog/large-patient-charts#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<div class="responsive-iframe-wrapper"><iframe src="https://www.youtube.com/embed/rdhEx6T8Qu0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>
<p>The full, unmitigated 131,000-resource chart downloaded into the browser in about five seconds. That's not a backend microbenchmark — it's a React app pulling the whole thing over the wire, progress bar and all. With progressive loading, the critical data was on screen in a fraction of that time.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="fhir-isnt-the-bottleneck">FHIR isn't the bottleneck<a href="https://www.medplum.com.ar/blog/large-patient-charts#fhir-isnt-the-bottleneck" class="hash-link" aria-label="Direct link to FHIR isn't the bottleneck" title="Direct link to FHIR isn't the bottleneck" translate="no">​</a></h2>
<p>131,000 resources. Five seconds. In a browser.</p>
<p>Speed isn't a property of the data standard — it comes from query strategy, indexing, pagination, streaming, and front-end design. Get those right and a FHIR-native architecture delivers the lightning-fast experience clinicians expect, on a fully open standard. You don't have to choose between interoperability and performance.</p>
<p>Want to see it for yourself? <a href="https://github.com/medplum/medplum-large-chart-demo" target="_blank" rel="noopener noreferrer" class="">Try the demo</a> or <a href="https://app.medplum.com/register" target="_blank" rel="noopener noreferrer" class="">spin up a free Medplum project</a>. The whole platform is open source at <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">github.com/medplum/medplum</a> — clone it, load your own monster chart, and time it.</p>]]></content>
        <author>
            <name>Cody Ebberson</name>
            <uri>https://github.com/codyebberson</uri>
        </author>
        <category label="fhir" term="fhir"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Vibe Coding on Medplum]]></title>
        <id>https://www.medplum.com.ar/blog/building-on-medplum-with-ai</id>
        <link href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai"/>
        <updated>2026-06-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[More and more Medplum users are building with AI coding assistants — Cursor, Claude, Copilot, and others. We have been talking to users about what works and wrote up what we have learned in a new guide: Building on Medplum with AI Coding Assistants. This post is the short version of what is in there.]]></summary>
        <content type="html"><![CDATA[<p>More and more Medplum users are building with AI coding assistants — Cursor, Claude, Copilot, and others. We have been talking to users about what works and wrote up what we have learned in a new guide: <a class="" href="https://www.medplum.com.ar/docs/building-with-ai-coding-assistants">Building on Medplum with AI Coding Assistants</a>. This post is the short version of what is in there.</p>
<!-- -->
<p>The single biggest lever we have found is this: <strong>make your AI tools learn from Medplum's open-source code and docs rather than from solely generic FHIR training data.</strong> This dramatically improves the outputs you get from any request you make.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="give-your-tools-access-to-medplum">Give your tools access to Medplum<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#give-your-tools-access-to-medplum" class="hash-link" aria-label="Direct link to Give your tools access to Medplum" title="Direct link to Give your tools access to Medplum" translate="no">​</a></h2>
<p>Medplum is FHIR-native, so any LLM with baseline FHIR training has a head start. But FHIR is a standard, not an implementation - and the gap between knowing the spec and knowing how to build something real is where most AI-generated code falls apart. Medplum's open-source docs and codebase cover that gap directly: real patterns and working examples. Point the LLM there, and you get code that actually works instead of plausible-looking output that doesn't.</p>
<p>The simplest way to set this up, and the one we reach for first, is to clone the <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">Medplum repo</a> and symlink it into your project:</p>
<div class="language-bash codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-bash codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">ln -s /absolute/path/to/medplum medplum-link</span><br></div></code></pre></div></div>
<p>Then tell the model it can read <code>medplum-link/</code>. If you would rather not clone, you can give the agent docs and GitHub search instead, or connect Medplum's MCP server — the guide covers both.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="plan-and-prompt-with-medplum-as-the-source-of-truth">Plan and prompt with Medplum as the source of truth<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#plan-and-prompt-with-medplum-as-the-source-of-truth" class="hash-link" aria-label="Direct link to Plan and prompt with Medplum as the source of truth" title="Direct link to Plan and prompt with Medplum as the source of truth" translate="no">​</a></h2>
<p>The setup only pays off if your prompts push the model toward it. The pattern that has worked best, in our experience, is to <strong>plan before you build</strong>: ask the model to read the relevant docs and code (or have a rule file do this for you — more on that below), explain the common design patterns and their tradeoffs, and only then implement. It is far cheaper to catch a wrong architectural turn while it is still a paragraph than after it is a few hundred lines. Where you can, point the agent at the closest existing implementation to adapt rather than asking it to start from a blank file.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="keep-conversations-short">Keep conversations short<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#keep-conversations-short" class="hash-link" aria-label="Direct link to Keep conversations short" title="Direct link to Keep conversations short" translate="no">​</a></h2>
<p>One thing that is a real risk - long conversations decay. An agent that started with the right context drifts as the thread grows and earlier details get summarized away — strong answers early, subtle regressions later. We have had the best luck keeping a conversation scoped to a single task, starting fresh often, and re-pointing the model at the docs at checkpoints, for instance right after it generates a resource.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="verify-the-output">Verify the output<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#verify-the-output" class="hash-link" aria-label="Direct link to Verify the output" title="Direct link to Verify the output" translate="no">​</a></h2>
<p>An agent's confidence is not a measure of correctness, so build verification in. The cheapest check — and one the agent can run itself if it has terminal access — is to <strong>compile the generated code against Medplum's TypeScript types.</strong> The types are strict, so a hallucinated field on a typed FHIR resource is a compile error rather than a production surprise. Tests and linting catch more, and when you want the real thing, Medplum's server-side validation will check resources against the actual FHIR and profile definitions.</p>
<p>And the part we would never skip, because this is healthcare: <strong>review the output, especially the sensitive parts.</strong> LLMs make mistakes, and a wrong access policy does not throw an error — it quietly exposes data. Anything touching access control, auth scopes, or PHI deserves a careful human read before it ships.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="put-it-in-a-rule-file">Put it in a rule file<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#put-it-in-a-rule-file" class="hash-link" aria-label="Direct link to Put it in a rule file" title="Direct link to Put it in a rule file" translate="no">​</a></h2>
<p>Everything above works better when you write it down once instead of repeating it in every prompt. A rule file — <code>CLAUDE.md</code>, Cursor rules, or an <code>AGENTS.md</code> — gets read on every turn, so it keeps the model pointed at Medplum's docs without being told, and it survives the context decay from the last section. We offer a starter rule file you can drop in and adapt; grab it from the <a class="" href="https://www.medplum.com.ar/docs/building-with-ai-coding-assistants#5-encode-your-conventions-in-a-rule-file">guide</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="advanced-direct-data-access">Advanced: direct data access<a href="https://www.medplum.com.ar/blog/building-on-medplum-with-ai#advanced-direct-data-access" class="hash-link" aria-label="Direct link to Advanced: direct data access" title="Direct link to Advanced: direct data access" translate="no">​</a></h2>
<p>Finally, an aspect that should be treated with care: giving your AI tool direct access to your Medplum data, through an API token or the MCP server. It can speed things up, but the caveats are real. If the tool can reach live PII or PHI, you <strong>must</strong> have a BAA with your LLM vendor; if you do not, scope an access policy so the token only ever reaches non-PII/PHI data.</p>
<hr>
<p>None of this is that complicated, but together it changes how much you can trust what your agent hands back. The full write-up — setup options, prompting patterns, the validation tiers, and the data-access caveats — lives in <a class="" href="https://www.medplum.com.ar/docs/building-with-ai-coding-assistants">Building on Medplum with AI Coding Assistants</a>. Give your tools the source of truth, plan before you build, verify the output, and keep a human in the loop. Then go build something, and let us know what you make.</p>]]></content>
        <author>
            <name>Everett Williams</name>
            <uri>https://github.com/everett-williams</uri>
        </author>
        <category label="ai" term="ai"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Achieves HITRUST e1 Certification]]></title>
        <id>https://www.medplum.com.ar/blog/hitrust-e1-certification</id>
        <link href="https://www.medplum.com.ar/blog/hitrust-e1-certification"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Demonstrating commitment to cybersecurity and information protection: HITRUST Certification validates the Medplum Platform is meeting rigorous cybersecurity and data protection standards through independent assessment and assurance.]]></summary>
        <content type="html"><![CDATA[<p><em>Demonstrating commitment to cybersecurity and information protection: HITRUST Certification validates the Medplum Platform is meeting rigorous cybersecurity and data protection standards through independent assessment and assurance.</em></p>
<a href="https://hitrustalliance.net/"><img src="https://www.medplum.com.ar/img/compliance/hitrust-e1-badge.svg" alt="HITRUST e1 Certification badge" width="200" height="200"></a>
<p><strong>San Francisco, Calif., June 1, 2026</strong> – Medplum, a leading provider of open-source healthcare developer infrastructure, today announced its Medplum Platform residing at Amazon Web Services (AWS) has earned certified status from HITRUST for cybersecurity and information protection.</p>
<!-- -->
<p>The HITRUST e1 Certification demonstrates that Medplum has met requirements defined by a leading cybersecurity assurance leader, confirming that strong controls are in place to protect sensitive data and manage risk effectively.</p>
<p>Built on the HITRUST Assurance Program, this achievement reflects independent third-party testing, centralized quality assurance, and certification backed by HITRUST's Cyber Threat-Adaptive engine. These elements ensure continuous alignment with the latest threat intelligence and evolving standards across NIST, ISO, and OWASP.</p>
<p>"As cybersecurity expectations rise, our stakeholders expect credible, validated assurance," said Reshma Khilnani, CEO at Medplum. "Achieving HITRUST Certification reinforces our ongoing commitment to protecting data, managing risk, and maintaining the trust of those we serve."</p>
<p>"Earning HITRUST Certification demonstrates Medplum's commitment to managing information risk and protecting sensitive data through a rigorous, proven assurance process," said Gregory Webb, CEO at HITRUST. "This achievement reflects the organization's proactive approach to cybersecurity and trust."</p>
<p>HITRUST certification was a key commitment on the compliance theme of our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap</a>. The HITRUST e1 Certification joins Medplum's existing compliance portfolio, including <a class="" href="https://www.medplum.com.ar/docs/compliance/soc2">SOC 2 Type 2</a>, <a class="" href="https://www.medplum.com.ar/docs/compliance/hipaa">HIPAA</a>, and <a class="" href="https://www.medplum.com.ar/docs/compliance/onc">ONC certification</a> — see the <a class="" href="https://www.medplum.com.ar/docs/compliance">compliance overview</a> for details. For organizations pursuing their own HITRUST certification using Medplum as a primary application backend, our <a class="" href="https://www.medplum.com.ar/docs/compliance/hitrust">HITRUST documentation</a> describes how we can support your certification process.</p>
<p>To learn more about the HITRUST framework, assurance methodology, and its measurable results in reducing the risk of cyber breaches, see the <a href="https://hitrustalliance.net/trust-report" target="_blank" rel="noopener noreferrer" class="">HITRUST Trust Report</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="about-medplum">About Medplum<a href="https://www.medplum.com.ar/blog/hitrust-e1-certification#about-medplum" class="hash-link" aria-label="Direct link to About Medplum" title="Direct link to About Medplum" translate="no">​</a></h2>
<p>Medplum is an <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">open-source</a> healthcare developer platform built on <a href="https://hl7.org/fhir/" target="_blank" rel="noopener noreferrer" class="">FHIR</a> standards. Medplum provides the <a class="" href="https://www.medplum.com.ar/docs/api">API</a>, <a class="" href="https://www.medplum.com.ar/docs/fhir-datastore">data store</a>, <a class="" href="https://www.medplum.com.ar/docs/auth">authentication</a>, and <a class="" href="https://www.medplum.com.ar/docs/sdk">developer tools</a> that healthcare organizations use to build <a class="" href="https://www.medplum.com.ar/docs/provider">custom EHRs</a>, patient portals, and clinical applications. Medplum is available as a managed service hosted on Amazon Web Services (AWS) and as <a class="" href="https://www.medplum.com.ar/docs/self-hosting">self-hosted software</a> under the <a href="https://github.com/medplum/medplum/blob/main/LICENSE.txt" target="_blank" rel="noopener noreferrer" class="">Apache 2.0 license</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="security" term="security"/>
        <category label="compliance" term="compliance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - May 2026]]></title>
        <id>https://www.medplum.com.ar/blog/may-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/may-2026-update"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[May was a heavy month for Medplum, with 100+ commits from 20+ contributors and four patch releases — v5.1.10 through v5.1.13. Scheduling was the headline: the full appointment operation suite — $find, $hold, $book, $confirm, and $cancel — landed in Alpha. The Provider App also gained medication ordering components, order set import, and operation-based claim submission. On the enterprise side, a new data warehouse export features were enabled, and the platform team shipped passwordless magic-link login, AWS GuardDuty malware protection, and a round of OAuth2 spec-compliance fixes. All of this continues to drive forward our 2026 roadmap priorities.]]></summary>
        <content type="html"><![CDATA[<p>May was a heavy month for Medplum, with 100+ commits from 20+ contributors and four patch releases — v5.1.10 through v5.1.13. <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling</a> was the headline: the full appointment operation suite — <code>$find</code>, <code>$hold</code>, <code>$book</code>, <code>$confirm</code>, and <code>$cancel</code> — landed in Alpha. The <a href="https://provider.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Provider App</a> also gained medication ordering components, order set import, and operation-based claim submission. On the enterprise side, a new data warehouse export features were enabled, and the platform team shipped passwordless magic-link login, AWS GuardDuty malware protection, and a round of OAuth2 spec-compliance fixes. All of this continues to drive forward our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/may-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling">Scheduling<a href="https://www.medplum.com.ar/blog/may-2026-update#scheduling" class="hash-link" aria-label="Direct link to Scheduling" title="Direct link to Scheduling" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>May completed the core scheduling operation suite that the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#scheduling">scheduling roadmap</a> has been building toward. Each step of the booking lifecycle now has a dedicated, spec-aligned FHIR operation:</p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-find"><code>Appointment/$find</code> multi-schedule search</a></strong> — Search for open slots across multiple schedules in a single request, the foundation for self-scheduling across providers and locations</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-hold"><code>$hold</code> operation</a></strong> — Temporarily reserve a slot while a patient completes booking, preventing double-booking during checkout</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-book"><code>$book</code> for proposed appointments</a></strong> — <code>$book</code> now accepts a proposed appointment as input, with test coverage for the patient self-booking path</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-confirm"><code>$confirm</code> operation</a></strong> — New <code>Appointment/:id/$confirm</code> operation to confirm a held or proposed appointment</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-cancel"><code>$cancel</code> operation</a></strong> — New scheduling cancel operation with improved error-path handling throughout the booking flow</li>
<li class=""><strong>Appointment-based Provider flow</strong> — The <a class="" href="https://www.medplum.com.ar/docs/provider/schedule">Provider scheduling calendar</a> now uses the Appointment-based flow, reveals more slots in the schedule page, and is gated behind a scheduling feature flag for controlled rollout</li>
<li class=""><strong>Self-scheduling reference flow</strong> — Foomedical, a sample patient-facing experience, now uses <code>Appointment/$find</code> + <code>$hold</code> to demonstrate the end-to-end patient booking pattern</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-medication-ordering-and-prescribing">Provider App: Medication Ordering and Prescribing<a href="https://www.medplum.com.ar/blog/may-2026-update#provider-app-medication-ordering-and-prescribing" class="hash-link" aria-label="Direct link to Provider App: Medication Ordering and Prescribing" title="Direct link to Provider App: Medication Ordering and Prescribing" translate="no">​</a></h3>
<p><img src="https://github.com/oleg-mp.png" alt="Oleg Rocklin" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/oleg-mp" target="_blank" rel="noopener noreferrer" class="">Oleg Rocklin</a></strong></p>
<p>Medication ordering moved into the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#provider-application">Provider App</a> this month:</p>
<ul>
<li class=""><strong>Meds ordering components</strong> — New React and Provider App components for ordering medications, bringing prescribing into the standard clinical workflow</li>
<li class=""><strong>Batched pharmacy/org searches</strong> — Preferred pharmacies and organizations are now fetched with batched searches during prescribing for faster load times</li>
<li class=""><strong>Resilient draft handling</strong> — Draft <code>MedicationRequest</code> resources are soft-deleted when an order-medication step fails, keeping the chart clean after errors</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-order-sets-and-billing">Provider App: Order Sets and Billing<a href="https://www.medplum.com.ar/blog/may-2026-update#provider-app-order-sets-and-billing" class="hash-link" aria-label="Direct link to Provider App: Order Sets and Billing" title="Direct link to Provider App: Order Sets and Billing" translate="no">​</a></h3>
<p><img src="https://github.com/andystoneman.png" alt="Andy Stoneman" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a></strong> and <img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<ul>
<li class=""><strong>Order set import</strong> — An order set bundle and import button were added to the Provider App, with a sync bot trigger that runs automatically after an example order set is imported</li>
<li class=""><strong>Operation-based claim submission</strong> — Claim submission now uses a server-side FHIR operation instead of a bot, simplifying the <a class="" href="https://www.medplum.com.ar/docs/billing">billing</a> integration and reducing moving parts</li>
<li class=""><strong>Self-pay coverage filtering</strong> — Self-pay coverage is now filtered out of the visit eligibility check and removed from the <code>PatientSummary</code> insurance display, so eligibility reflects only billable payers (<a class="" href="https://www.medplum.com.ar/docs/billing/insurance-eligibility-checks">Insurance Eligibility Checks</a>)</li>
<li class=""><strong><code>ClinicalImpression</code> in the timeline</strong> — Clinical impressions now appear in the patient timeline (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Cancel Visit</strong> — A "Cancel Visit" button and a fixed "Details" link tab round out the encounter workflow (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong>Configurable onboarding</strong> — The Provider App "Get Started" screen can now be hidden via a project setting (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="ai-real-time-clinical-documentation">AI: Real-Time Clinical Documentation<a href="https://www.medplum.com.ar/blog/may-2026-update#ai-real-time-clinical-documentation" class="hash-link" aria-label="Direct link to AI: Real-Time Clinical Documentation" title="Direct link to AI: Real-Time Clinical Documentation" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>AI work this month focused on real-time clinical documentation inside <a class="" href="https://www.medplum.com.ar/docs/provider/spaces">Spaces</a>, the AI-powered chat workspace in the Provider App, as part of the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#ai">AI roadmap</a>:</p>
<ul>
<li class=""><strong>Real-time speech-to-text</strong> — Live speech-to-text in the Provider App for AI-assisted clinical documentation, backed by updates to the <code>$ai-realtime</code> operation</li>
<li class=""><strong>Markdown responses in Spaces</strong> — Spaces now renders markdown in AI responses for clearer, better-formatted output</li>
<li class=""><strong>Whisper hook in <code>react-hooks</code></strong> — The Whisper transcription hook moved into the <code>@medplum/react-hooks</code> package so it can be reused across applications</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="enterprise-data-warehouse-export">Enterprise: Data Warehouse Export<a href="https://www.medplum.com.ar/blog/may-2026-update#enterprise-data-warehouse-export" class="hash-link" aria-label="Direct link to Enterprise: Data Warehouse Export" title="Direct link to Enterprise: Data Warehouse Export" translate="no">​</a></h3>
<p><img src="https://github.com/The-Alchemist.png" alt="Karl Pietrzak" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/The-Alchemist" target="_blank" rel="noopener noreferrer" class="">Karl Pietrzak</a></strong></p>
<p>A major <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#enterprise-scale--infrastructure">Enterprise Scale</a> feature landed: Medplum can now export directly from PostgreSQL into <a href="https://parquet.apache.org/" target="_blank" rel="noopener noreferrer" class="">Apache Parquet</a> and <a href="https://iceberg.apache.org/" target="_blank" rel="noopener noreferrer" class="">Apache Iceberg</a> tables on <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables.html" target="_blank" rel="noopener noreferrer" class="">S3 Tables</a>. This gives data teams an efficient, columnar path into modern lakehouse <a class="" href="https://www.medplum.com.ar/docs/analytics">analytics</a> without standing up a separate ETL pipeline. A new <code>startDate</code> parameter lets exports run incrementally. This is new functionality related to Medplum Enterprise.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="platform-security-and-infrastructure">Platform, Security, and Infrastructure<a href="https://www.medplum.com.ar/blog/may-2026-update#platform-security-and-infrastructure" class="hash-link" aria-label="Direct link to Platform, Security, and Infrastructure" title="Direct link to Platform, Security, and Infrastructure" translate="no">​</a></h3>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong></p>
<ul>
<li class=""><strong>Passwordless magic-link login</strong> — New OAuth2 pre-authorized code flow enables <a class="" href="https://www.medplum.com.ar/docs/auth/pre-authorized-code">magic-link sign-in</a>, with the pre-authorized code lifetime extended to 7 days for email-based flows</li>
<li class=""><strong>Unified external authentication</strong> — Consolidated the external identity-provider paths into a single <a class="" href="https://www.medplum.com.ar/docs/auth/external-identity-providers">unified external auth</a> flow, including Google Cloud Identity Platform userinfo support</li>
<li class=""><strong>AWS GuardDuty Malware Protection</strong> — Added support for <a href="https://docs.aws.amazon.com/guardduty/latest/ug/malware-protection.html" target="_blank" rel="noopener noreferrer" class="">AWS GuardDuty Malware Protection</a> on uploaded files, with graceful handling of images quarantined by the scanner</li>
<li class=""><strong>HTTPS-only subscription URLs</strong> — Rest-hook <a class="" href="https://www.medplum.com.ar/docs/subscriptions"><code>Subscription</code></a> URLs now require HTTPS by default, and a server option can require a verified email address before login</li>
<li class=""><strong>OAuth2 spec-compliance fixes</strong> — A batch of <a class="" href="https://www.medplum.com.ar/docs/api/oauth/token">OAuth2 token endpoint</a> corrections including <code>offline_access</code> handling when <code>refresh_token</code> is in <code>grant_types</code>, <code>www-authenticate: bearer</code> responses, and enforcing login membership before scope</li>
<li class=""><strong><code>log-streaming</code> project feature</strong> — A new <a class="" href="https://www.medplum.com.ar/docs/integration/log-streaming">log-streaming</a> project feature plus a <code>Project.features</code> search parameter for managing it</li>
</ul>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<ul>
<li class=""><strong>Bot Lambda lifecycle management</strong> — Medplum now prunes old <a class="" href="https://www.medplum.com.ar/docs/bots/bots-in-production">bot Lambda</a> versions, deletes the Lambda when a bot is deleted, and removes stale versions, keeping cloud deployments tidy and within service limits</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/agent/stats"><code>Agent/$stats</code> operation</a></strong> — New operation to retrieve statistics for a deployed <a class="" href="https://www.medplum.com.ar/docs/agent">Agent</a>, Medplum's on-premise connectivity service for legacy healthcare systems</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth"><code>User/$rescope</code> operation</a></strong> — New operation to change a user's project scope without re-issuing credentials</li>
<li class=""><strong>Rate-limit reliability</strong> — Optimized Redis key access for <a class="" href="https://www.medplum.com.ar/docs/rate-limits">rate limiting</a>, exposed the <code>RateLimit</code> header for CORS, and improved WebSocket subscription error messages</li>
</ul>
<p><img src="https://github.com/maddyli.png" alt="Maddy Li" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a></strong></p>
<ul>
<li class=""><strong>Rate-limit administration</strong> — A new <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/project-rate-limits">project rate-limits operation</a>, an admin API endpoint for rate-limit utilization status, an active-consumer index, and a Rate Limits tab on the admin page give operators full visibility into <a class="" href="https://www.medplum.com.ar/docs/rate-limits">rate limiting</a></li>
<li class=""><strong>NPI Lookup example bot</strong> — A new example bot for NPI lookups using the <a href="https://npiregistry.cms.hhs.gov/" target="_blank" rel="noopener noreferrer" class="">NPPES API</a></li>
</ul>
<p><img src="https://github.com/mattwiller.png" alt="Matt Willer" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a></strong></p>
<ul>
<li class=""><strong>Range search</strong> — FHIR search now supports range queries with correct overlap and boundary handling</li>
<li class=""><strong>Patient scope hardening</strong> — Patient-scoped tokens are now restricted to their context Patient compartment, and chained search and <code>_include</code> types are validated for safety</li>
<li class=""><strong>Vendored JSON Patch</strong> — The JSON Patch library is now vendored, and FHIR quota-limit computation was unified into a single helper</li>
<li class=""><strong>Larger payload handling</strong> — Oversized request bodies are transformed into a clean HTTP 413 response</li>
</ul>
<p><img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<ul>
<li class=""><strong>Transaction reliability</strong> — Serialized transaction state transitions and more consistent repository connection-state tracking improve <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#enterprise-scale--infrastructure">site reliability</a> under load</li>
<li class=""><strong><code>Project.link</code> search parameter</strong> — New search parameter for navigating linked projects</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/may-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p>May's documentation work spanned self-hosting, compliance, integrations, and the Provider App.</p>
<p><strong>Self-hosting and reliability</strong></p>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/self-hosting/install-on-digital-ocean">Install on DigitalOcean</a></strong> — New guide for self-hosting Medplum on DigitalOcean</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/uptime">Uptime and reliability</a></strong> — New documentation covering Medplum's uptime and site reliability practices</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/bots/bots-in-production">VM context bot security note</a></strong> — Added a security note for VM context bots in production</li>
</ul>
<p><strong>Compliance and scale</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/electronic-prior-auth">Electronic prior authorization testing</a></strong> — Testing documentation for electronic prior authorization, part of the <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4 compliance initiative</a> ahead of the January 2027 enforcement date (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/fhir-datastore/processing-async-bundles">Async batch processing</a></strong> — New documentation for asynchronous batch processing, with a note on how FHIR quotas apply (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>, <a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a>)</li>
</ul>
<p><strong>Integrations</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/health-gorilla/sync-resources-from-health-gorilla">Health Gorilla sync-back resources</a></strong> — Documentation for resources synced back from Health Gorilla (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/dosespot/enroll-user">Self-service prescriber enrollment bot</a></strong> — Documented the self-service prescriber enrollment bot (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
</ul>
<p><strong>Provider App and platform</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/provider/spaces">Spaces feature documentation</a></strong> — Added Spaces feature documentation for the Provider App, including a walkthrough video (<a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/charting">Charting documentation restructure</a></strong> — Restructured the charting documentation with additional decision-guide content (<a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/user-management/project-vs-server-scoped-users">Project vs. server-scoped users</a></strong> and <strong><a class="" href="https://www.medplum.com.ar/docs/auth/direct-external-auth">direct external auth</a></strong> — Clarified user scoping and external auth setup (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/project-rate-limits">Rate limits operation</a></strong> — Documented the new rate-limits operation, plus a clarification on bots with <code>ProjectMembership</code> (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Trust center links</strong> — Updated compliance links to point to the <a href="https://trust.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Medplum Trust Center</a> (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
</ul>
<p><strong>Testing infrastructure</strong></p>
<p><img src="https://github.com/The-Alchemist.png" alt="Karl Pietrzak" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/The-Alchemist" target="_blank" rel="noopener noreferrer" class="">Karl Pietrzak</a></strong></p>
<p>A broad effort migrated many internal packages — including <code>hl7</code>, <code>fhir-router</code>, <code>generator</code>, <code>create-medplum</code>, <code>cdk</code>, <code>ccda</code>, <code>mock</code>, and <code>definitions</code> — from Jest to <a href="https://vitest.dev/" target="_blank" rel="noopener noreferrer" class="">Vitest</a> for faster, more consistent test runs across the monorepo.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/may-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>AWS and CDK</strong></p>
<ul>
<li class="">Fixed handling of complex server configuration, and corrected CDK to send the prefix instead of the bucket name (contributed by <a href="https://github.com/jimfiorato" target="_blank" rel="noopener noreferrer" class="">Jim Fiorato</a>)</li>
</ul>
<p><strong>Authentication</strong></p>
<ul>
<li class="">Serialized cross-tab token refresh using the Web Locks API to prevent race conditions across browser tabs (contributed by <a href="https://github.com/dillonstreator" target="_blank" rel="noopener noreferrer" class="">Dillon Streator</a>)</li>
<li class="">Fixed the <code>RECAPTCHA_SITE_KEY</code> always reverting to the default value (contributed by <a href="https://github.com/TheDarkula" target="_blank" rel="noopener noreferrer" class="">Meade</a>)</li>
<li class="">Added <code>defaultProjectFeatures</code> to the config object keys set (contributed by <a href="https://github.com/nate-watkins" target="_blank" rel="noopener noreferrer" class="">Nate Watkins</a>)</li>
</ul>
<p><strong>FHIR and Agent</strong></p>
<ul>
<li class="">Fixed indexing of fragment <code>CodeSystem</code> resources in the coding table (contributed by <a href="https://github.com/jeffrylooijestijn" target="_blank" rel="noopener noreferrer" class="">Jeffry Looijestijn</a>)</li>
<li class="">The Agent now returns an explicit error when an upgrade artifact is missing (contributed by <a href="https://github.com/galenzo17" target="_blank" rel="noopener noreferrer" class="">Agustin Bereciartua Castillo</a>)</li>
<li class="">Display of <code>onBehalfOf</code> was added to History, Timeline, and Blame views (contributed by <a href="https://github.com/alexanderxlin" target="_blank" rel="noopener noreferrer" class="">Alex Lin</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/may-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.10" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.10</strong></a> — May 1</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.11" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.11</strong></a> — May 6</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.12" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.12</strong></a> — May 17</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.13" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.13</strong></a> — May 20</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/may-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>May brought the scheduling operation suite to completion — <code>$find</code>, <code>$hold</code>, <code>$book</code>, <code>$confirm</code>, and <code>$cancel</code> now cover the full booking lifecycle — and moved the Provider App onto an Appointment-based flow with medication ordering and order set import. Passwordless magic-link login and GuardDuty malware protection strengthen the platform's security posture.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PlumCon 2026 - Agenda]]></title>
        <id>https://www.medplum.com.ar/blog/plumcon-2026</id>
        <link href="https://www.medplum.com.ar/blog/plumcon-2026"/>
        <updated>2026-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[On September 3, 2026 Medplum is hosting our second annual developer conference PlumCon in San Francisco. The conference is by invitation, but please Register Here.]]></summary>
        <content type="html"><![CDATA[<p>On September 3, 2026 Medplum is hosting our second annual <em>developer conference</em> PlumCon in San Francisco. The conference is by invitation, but please <a href="https://luma.com/7xjt6cmh" target="_blank" rel="noopener noreferrer" class="">Register Here</a>.</p>
<p>This year's agenda brings together healthcare builders working across open source infrastructure, AI-enabled operations, Stanford Biodesign, and large-scale healthcare IT.</p>
<p>This agenda is preliminary and subject to change.</p>
<!-- -->
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="morning-session">Morning Session<a href="https://www.medplum.com.ar/blog/plumcon-2026#morning-session" class="hash-link" aria-label="Direct link to Morning Session" title="Direct link to Morning Session" translate="no">​</a></h3>
<table><tbody><tr><td style="white-space:nowrap">9:00 AM</td><td><strong>Breakfast</strong></td><td></td></tr><tr><td style="white-space:nowrap">9:30 AM</td><td><strong>Keynote: Medplum Past, Present and Future</strong></td><td align="center"><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"><p><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></p></td></tr><tr><td style="white-space:nowrap">10:15 AM</td><td><strong>Stanford Biodesign: Vibecoding Healthcare IT</strong></td><td align="center"><img src="https://www.medplum.com.ar/img/avatars/vishnu-ravi.webp" alt="Vishnu Ravi" width="50" height="50" style="border-radius:50%"><img src="https://www.medplum.com.ar/img/avatars/aydin-zahedivash.webp" alt="Aydin Zahedivash" width="50" height="50" style="border-radius:50%"><p><a href="https://med.stanford.edu/profiles/vishnu-ravi" target="_blank" rel="noopener noreferrer" class="">Vishnu Ravi</a>, <a href="https://med.stanford.edu/profiles/aydin-zahedivash" target="_blank" rel="noopener noreferrer" class="">Aydin Zahedivash</a></p></td></tr><tr><td style="white-space:nowrap">11:15 AM</td><td><strong>Coffee Break</strong></td><td></td></tr><tr><td style="white-space:nowrap">11:30 AM</td><td><strong>Scaling to 100M Patients</strong></td><td align="center"><img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"><img src="https://github.com/maddyli.png" alt="Maddy Li" width="50" height="50" style="border-radius:50%"><p><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a>, <a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a></p></td></tr><tr><td style="white-space:nowrap">12:00 PM</td><td><strong>Lunch Break</strong></td><td></td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="afternoon-session">Afternoon Session<a href="https://www.medplum.com.ar/blog/plumcon-2026#afternoon-session" class="hash-link" aria-label="Direct link to Afternoon Session" title="Direct link to Afternoon Session" translate="no">​</a></h3>
<table><tbody><tr><td style="white-space:nowrap">TBD</td><td><strong>Scheduling Agents for Healthcare Operations</strong></td><td align="center"><img src="https://github.com/codyhall.png" alt="Cody Hall" width="50" height="50" style="border-radius:50%"><p><a href="https://github.com/codyhall" target="_blank" rel="noopener noreferrer" class="">Cody Hall</a>, Unity AI</p></td></tr><tr><td style="white-space:nowrap">TBD</td><td><strong>Open Source Impact on Healthcare</strong></td><td align="center"><img src="https://www.medplum.com.ar/img/avatars/stuart.webp" alt="Stuart Parmenter" width="50" height="50" style="border-radius:50%"><p><a href="https://www.linkedin.com/in/stuartparmenter" target="_blank" rel="noopener noreferrer" class="">Stuart Parmenter</a></p></td></tr><tr><td style="white-space:nowrap">TBD</td><td><strong>Community Demos</strong></td><td align="center"><p>Medplum community</p></td></tr><tr><td style="white-space:nowrap">TBD</td><td><strong>Happy Hour</strong></td><td></td></tr></tbody></table>
<p>For recordings, slides, demos, and photos from last year, see <a class="" href="https://www.medplum.com.ar/blog/plumcon-2025-materials">PlumCon 2025 Materials</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="community" term="community"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - April 2026]]></title>
        <id>https://www.medplum.com.ar/blog/april-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/april-2026-update"/>
        <updated>2026-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Medplum stayed active this April, with 130+ commits from 20+ contributors amounting to three patch releases — v5.1.7, v5.1.8, and v5.1.9. The Provider app's billing and coverage workflows took a major step forward with integrated claim submission and live eligibility visibility. Scheduling added support for service line configurations on HealthcareService, aligning with R5/R6 FHIR conventions. Spaces, an AI-powered chat workspace inside the Provider App, now surfaces tool calls and responses directly in the chat so you can see exactly what the AI is doing. Clinical documentation expanded across intake, care plans, diagnostics, authentication, and integrations. All of this continues to drive forward our 2026 roadmap priorities.]]></summary>
        <content type="html"><![CDATA[<p>Medplum stayed active this April, with 130+ commits from 20+ contributors amounting to three patch releases — v5.1.7, v5.1.8, and v5.1.9. The Provider app's billing and coverage workflows took a major step forward with integrated claim submission and live eligibility visibility. <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling</a> added support for service line configurations on <code>HealthcareService</code>, aligning with R5/R6 FHIR conventions. Spaces, an AI-powered chat workspace inside the Provider App, now surfaces tool calls and responses directly in the chat so you can see exactly what the AI is doing. Clinical documentation expanded across intake, care plans, diagnostics, authentication, and integrations. All of this continues to drive forward our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/april-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-spaces-and-ai">Provider App: Spaces and AI<a href="https://www.medplum.com.ar/blog/april-2026-update#provider-app-spaces-and-ai" class="hash-link" aria-label="Direct link to Provider App: Spaces and AI" title="Direct link to Provider App: Spaces and AI" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>April brought three focused Spaces improvements touching the full AI interaction loop — input, reasoning, and execution — as part of the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#ai">AI roadmap</a>:</p>
<ul>
<li class=""><strong>Tool request/response visibility</strong> — Tool calls and responses now surface inside the Spaces chat experience for full transparency into AI agent actions</li>
<li class=""><strong>Improved AI agent loop handling</strong> — More robust multi-step agent execution with a resizable preview panel for inspecting generated output</li>
<li class=""><strong><code>$ai</code> project API key</strong> — The <code>$ai</code> operation now uses the project-scoped API key for consistent model configuration across environments</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-billing-and-coverage">Provider App: Billing and Coverage<a href="https://www.medplum.com.ar/blog/april-2026-update#provider-app-billing-and-coverage" class="hash-link" aria-label="Direct link to Provider App: Billing and Coverage" title="Direct link to Provider App: Billing and Coverage" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>April's biggest Provider app push closed more of the end-to-end <a class="" href="https://www.medplum.com.ar/docs/billing">billing loop</a> — from submitting a claim to understanding why it failed:</p>
<ul>
<li class=""><strong>Claim submission</strong> — Submit claims directly from the Provider app</li>
<li class=""><strong>Submit claim confirm modal</strong> — Confirmation step before claim submission to prevent unintended submissions</li>
<li class=""><strong>Coverage eligibility display</strong> — Coverage eligibility request and response panels in the Provider app, accessible from within encounters</li>
<li class=""><strong>Coverage request component</strong> — Dedicated component for initiating coverage requests (<a class="" href="https://www.medplum.com.ar/docs/billing/insurance-eligibility-checks">Insurance Eligibility Checks</a>)</li>
<li class=""><strong>Error display on claim submission</strong> — Error messages surface clearly when a claim fails to submit</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-prescribing">Provider App: Prescribing<a href="https://www.medplum.com.ar/blog/april-2026-update#provider-app-prescribing" class="hash-link" aria-label="Direct link to Provider App: Prescribing" title="Direct link to Provider App: Prescribing" translate="no">​</a></h3>
<p><img src="https://github.com/oleg-mp.png" alt="Oleg Rocklin" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/oleg-mp" target="_blank" rel="noopener noreferrer" class="">Oleg Rocklin</a></strong></p>
<p>Two long-running prescribing threads landed this month:</p>
<ul>
<li class=""><strong>Drug/Allergy warning enhancement</strong> — Drug/Allergy Warning support brings prescribing safety checks into the Provider app workflow</li>
<li class=""><strong>Provider enrollment React hooks</strong> — React hooks allow a prescriber self-enrollment bot to reduce the integration setup to a few hook calls</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling">Scheduling<a href="https://www.medplum.com.ar/blog/april-2026-update#scheduling" class="hash-link" aria-label="Direct link to Scheduling" title="Direct link to Scheduling" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>The <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#scheduling">scheduling overhaul</a> reached an inflection point in April: <code>HealthcareService</code> is now the authoritative source for scheduling parameters, replacing looser conventions and enabling far more reusable slot configurations:</p>
<ul>
<li class=""><strong><code>HealthcareService</code> scheduling parameters</strong> — Scheduling operations now use parameters defined directly on <code>HealthcareService</code> resources, enabling more expressive and reusable configurations</li>
<li class=""><strong>Explicit <code>HealthcareService</code> references</strong> — Scheduling uses explicit <code>HealthcareService</code> references for unambiguous slot resolution</li>
<li class=""><strong>R5/R6 <code>Availability</code> type alignment</strong> — The scheduling availability subextension is shaped to match the R5/R6 <code>Availability</code> type for forward compatibility, which will help with future-proofing</li>
<li class=""><strong><code>HealthcareService.offeredIn</code> backport</strong> — R5 <code>offeredIn</code> field backported to Medplum's R4 <code>HealthcareService</code> for richer service-location relationships</li>
<li class=""><strong>Scheduling UI consistency</strong> — Provider scheduling UI fixups and month view corrections for a more consistent experience</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/state-by-state-licensure">State-by-state medical licensure scheduling</a></strong> — Scheduling support for state-by-state practitioner licensure requirements (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
<li class=""><strong>Insurance eligibility FHIR operation</strong> — New custom FHIR operation <code>$stedi-check-eligibility</code> for <a href="https://www.medplum.com.ar/docs/integration/stedi/insurance-eligibility/eligibility-checks" target="_blank" rel="noopener noreferrer" class="">insurance eligibility checks</a> (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="platform-and-infrastructure">Platform and Infrastructure<a href="https://www.medplum.com.ar/blog/april-2026-update#platform-and-infrastructure" class="hash-link" aria-label="Direct link to Platform and Infrastructure" title="Direct link to Platform and Infrastructure" translate="no">​</a></h3>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong> and <img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<p>April's platform work covered security hardening, search correctness, and operational reliability — feeding into <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#enterprise-scale--infrastructure">Enterprise Scale</a> and the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap#compliance-h1-2026">H1 compliance</a> track:</p>
<ul>
<li class=""><strong>mTLS passthrough on ALB</strong> — Mutual TLS passthrough at the Application Load Balancer for certificate-based client authentication</li>
<li class=""><strong>Tightened access controls for linked projects</strong> — Stricter permission enforcement and consolidated logic for determining permitted project IDs</li>
<li class=""><strong>Auto-disable subscriptions on failure</strong> — <code>Subscription</code> resources automatically disable after repeated delivery failures, reducing noise and resource waste</li>
<li class=""><strong><code>Patient.$match</code> operation</strong> — Server-side FHIR <code>$match</code> operation for <a class="" href="https://www.medplum.com.ar/blog/patient-deduplication">patient de-duplication</a> and record linkage, which is part of a master patient index pattern</li>
<li class=""><strong>Project-scoped presigned URLs</strong> — Project context is now included in presigned Binary URLs for more secure access</li>
<li class=""><strong>Login rate limiting</strong> — Separate, stricter rate limit on login paths to improve brute-force resistance</li>
<li class=""><strong>JWT <code>jti</code> claim</strong> — The JWT ID (<code>jti</code>) claim is now always set for replay-attack protection</li>
<li class=""><strong>Skip post-deploy migrations in <code>firstBoot</code></strong> — Operators can skip post-deploy migrations during initial boot for faster first-start deployments, which will benefit self-hosted Medplum users</li>
<li class=""><strong>Transaction dead connection management</strong> — Improved handling of dead connections during database transactions</li>
<li class=""><strong>SSE-C encryption for S3 Binary storage</strong> — Server-Side Encryption with Customer-Provided Keys (SSE-C) support for S3 Binary storage (Nicolas Weiß)</li>
</ul>
<p><img src="https://github.com/mattwiller.png" alt="Matt Willer" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a></strong></p>
<ul>
<li class=""><strong>Range search</strong> — Range-based FHIR search correctly handles overlapping ranges and boundary conditions</li>
<li class=""><strong><code>_filter</code> modifier support</strong> — Modifiers in <code>_filter</code> search parameters now work consistently</li>
<li class=""><strong>OTel delta aggregation</strong> — OpenTelemetry metrics use delta aggregation temporality with exponential histogram views for accurate reporting</li>
<li class=""><strong>Rate-limit delay improvement</strong> — Rate-limited requests delay in async context rather than consuming rate-limit tokens for fairer enforcement</li>
</ul>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<ul>
<li class=""><strong>Agent message tracking</strong> — Agent messages are tracked independently of connected clients for more reliable delivery and observability</li>
<li class=""><strong>Load balancer algorithm config</strong> — CDK support for configuring the load balancer routing algorithm via <code>loadBalancerAlgorithm</code></li>
<li class=""><strong>WebSocket handler colocation</strong> — All WebSocket handlers consolidated into a single location for a cleaner server architecture</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="developer-experience">Developer Experience<a href="https://www.medplum.com.ar/blog/april-2026-update#developer-experience" class="hash-link" aria-label="Direct link to Developer Experience" title="Direct link to Developer Experience" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>ResourcesInput</code> component</strong> — New React component to search and select multiple resources, simplifying multi-select UI patterns (<a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a>)</li>
<li class=""><strong><code>MedplumClient</code> streaming support</strong> — <code>MedplumClient</code> now accepts <code>ReadableStream</code> and Node.js <code>Readable</code> for efficient streaming uploads (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Streaming bulk export</strong> — Bulk export uses streaming to handle large datasets without buffering in memory (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong><code>valueSetElementToCoding</code> / <code>codingToValueSetElement</code></strong> — Utility functions now exported from <code>@medplum/react</code> for mapping between value set elements and codings (<a href="https://github.com/deam65" target="_blank" rel="noopener noreferrer" class="">Darren Eam</a>)</li>
<li class=""><strong><code>PatientSummary</code> modular architecture</strong> — Refactored into a config-driven, modular architecture for easier customization per deployment (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong>Tenants tab on Patient page</strong> — Multi-tenancy visibility directly on the Patient detail page (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Admin MFA reset endpoint</strong> — New admin endpoint to reset a user's MFA enrollment (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
<li class=""><strong><code>externalAuthProviders</code> via environment variable</strong> — External auth providers can now be configured via environment variable for simpler deployment (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
<li class=""><strong>Apply markdown rendering to Resource documentation fields</strong> — Resource documentation fields now render markdown for richer display (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong>Two new FHIR search parameters</strong> — Additional search parameters added to expand query capabilities (<a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/april-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p>April saw a concentrated documentation effort on two fronts: filling out the clinical workflow narrative from intake through care plans and diagnostics, and hardening the auth and integrations reference material that production deployments rely on.</p>
<p><strong>Clinical workflows</strong></p>
<p><img src="https://github.com/everett-williams.png" alt="Everett Williams" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/intake">Intake &amp; Registration clinical workflow</a></strong> — End-to-end guide for patient intake and registration flows</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/careplans/longitudinal-patient-case-tracking">Longitudinal patient case tracking with care plans</a></strong> — How to model ongoing patient cases using <code>CarePlan</code> resources</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/labs-imaging">Diagnostic Orders: restructured IA and workflow content</a></strong> — Reorganized Diagnostic Orders section with deeper workflow guidance</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/provider/visits">Visits page: video walkthrough and tutorials</a></strong> — Video walkthrough and tutorial notes added; sidebar reorganized to surface questionnaires more clearly</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/message-editing-and-drafts">Message editing and drafts</a></strong> — Guide for editing messages and managing drafts in the communications system</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/async-encounters">Async encounters with SDK walkthrough</a></strong> — Expanded guide with full SDK code walkthrough for async clinical encounters</li>
<li class=""><strong>Clinical sidebar reorganization</strong> — Care Coordination, Diagnostic Orders, and Clinical Configuration sections reorganized for clearer navigation</li>
</ul>
<p><strong>Authentication and security</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/client-assertion">Client assertion authentication</a></strong> — How to authenticate using signed client assertion JWTs in support of <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">CMS-0057</a> (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/mtls">mTLS authentication</a></strong> — Setup and configuration guide for mutual TLS client certificate authentication (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/external-identity-providers">Direct external auth</a></strong> — Added to the auth sidebar and overview for better discoverability (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/mfa">MFA reset flow</a></strong> — Admin documentation for resetting user MFA enrollment (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
</ul>
<p><strong>Platform and integrations</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/careplans/protocols">Clinical Protocols execution guide</a></strong> — How to execute clinical protocols using Bots and automation (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/health-gorilla/receiving-results">Health Gorilla: receiving flow and migration guide</a></strong> — Lab result receiving flow and migration guidance for Health Gorilla integrations (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/patient-match">Patient <code>$match</code> documentation</a></strong> — Documentation for the new patient matching FHIR operation (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/cds-hooks">CDS Hooks</a></strong> — Basic CDS Hooks integration documentation (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4 / CMS-0057-F update</a></strong> — Compliance documentation updated to include CMS-0057 requirements (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/self-hosting/enabling-rollbacks">Self-hosting: enabling rollbacks</a></strong> — How to enable and execute server rollbacks in self-hosted deployments (<a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/integration/dosespot/enroll-user">Prescriber enrollment statuses</a></strong> — All registration statuses documented for the prescriber enrollment flow (<a href="https://github.com/andystoneman" target="_blank" rel="noopener noreferrer" class="">Andy Stoneman</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/april-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>C-CDA</strong></p>
<ul>
<li class="">Fixed <code>nullFlavor</code> allergy reactions and single translation element handling in C-CDA parsing, preventing import failures on common EHR exports (contributed by <a href="https://github.com/amcgivern" target="_blank" rel="noopener noreferrer" class="">Amanda McGivern</a>)</li>
</ul>
<p><strong>Agent</strong></p>
<ul>
<li class="">Fixed agent channel reload when the endpoint protocol changes, preventing stale connections after a protocol switch (contributed by Adewoye Adegoke)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/april-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.7" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.7</strong></a> — April 8</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.8" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.8</strong></a> — April 14</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.9" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.9</strong></a> — April 23</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/april-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>April deepened the Provider app's billing story — from claim submission to live coverage eligibility display — while Spaces gained speech-to-text for AI-assisted clinical documentation. Scheduling's alignment with <code>HealthcareService</code> parameters makes multi-location and multi-service configurations significantly cleaner. Clinical documentation now spans intake through care plans, diagnostics, and async encounters, giving builders a fuller end-to-end picture of workflow implementation on Medplum.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Andy Stoneman</name>
            <uri>https://github.com/andystoneman</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - March 2026]]></title>
        <id>https://www.medplum.com.ar/blog/march-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/march-2026-update"/>
        <updated>2026-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[March was yet another busy month for Medplum. Three patch releases — v5.1.2, v5.1.3, and v5.1.4 — arrived alongside over 100 commits from 20+ contributors, and the work underneath the surface was just as significant as the new features. Spaces gained richer AI tooling. The communications documentation received a full suite of guides covering everything from the data model to automations. Worker infrastructure got a substantial rethink, and WebSocket subscriptions were hardened across the board. All of it continues to advance our 2026 roadmap priorities.]]></summary>
        <content type="html"><![CDATA[<p>March was yet another busy month for Medplum. Three patch releases — v5.1.2, v5.1.3, and v5.1.4 — arrived alongside over 100 commits from 20+ contributors, and the work underneath the surface was just as significant as the new features. Spaces gained richer AI tooling. The <a class="" href="https://www.medplum.com.ar/docs/communications">communications documentation</a> received a full suite of guides covering everything from the data model to automations. Worker infrastructure got a substantial rethink, and <a class="" href="https://www.medplum.com.ar/docs/subscriptions">WebSocket subscriptions</a> were hardened across the board. All of it continues to advance our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/march-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-spaces-and-ai">Provider App: Spaces and AI<a href="https://www.medplum.com.ar/blog/march-2026-update#provider-app-spaces-and-ai" class="hash-link" aria-label="Direct link to Provider App: Spaces and AI" title="Direct link to Provider App: Spaces and AI" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>Spaces continues to advance our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">AI roadmap initiative</a> and the <a class="" href="https://www.medplum.com.ar/docs/provider">Provider Application roadmap goal</a>:</p>
<ul>
<li class=""><strong>System prompts on <code>Communication</code> resources</strong> — Spaces stores system prompts as <code>Communication</code> resources for clearer modeling and reuse</li>
<li class=""><strong>Component preview, code, and FHIR resources</strong> — Previews and visibility into generated UI, code, and underlying resources in the Spaces chat experience</li>
<li class=""><strong>Translator tool looping</strong> — The translator can iterate until the user's request is satisfied for more reliable multi-step workflows</li>
<li class=""><strong>Updated default language model</strong> — Newer model defaults for improved quality and consistency</li>
<li class=""><strong>Spaces demo bots</strong> — Demo bots for Spaces are easier to discover in development environments</li>
<li class=""><strong>Tab navigation</strong> — Standardized tabs across high-traffic screens (<a href="https://github.com/kevinwadeshaw" target="_blank" rel="noopener noreferrer" class="">Kevin Wadeshaw</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-messaging-scheduling-and-billing">Provider App: Messaging, Scheduling, and Billing<a href="https://www.medplum.com.ar/blog/march-2026-update#provider-app-messaging-scheduling-and-billing" class="hash-link" aria-label="Direct link to Provider App: Messaging, Scheduling, and Billing" title="Direct link to Provider App: Messaging, Scheduling, and Billing" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>The <a href="https://provider.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Provider app</a> gained messaging, calendar, and billing improvements:</p>
<ul>
<li class=""><strong>Communications payload and eFax</strong> — A dedicated payload tab on Communications, eFax integration, and ThreadChat updates (subject on communications, clearer file metadata for uploads and search)</li>
<li class=""><strong>Calendar scheduling</strong> — Switch practitioner schedules from the calendar; more robust Find pane when service types omit a system; visit setup right after <a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-book"><code>$book</code></a>; schedule pickers resolve actors via <code>Schedule:actor</code></li>
<li class=""><strong>Candid billing</strong> — Claim status in the Provider app and use of external identifiers when a Candid encounter id is absent</li>
<li class=""><strong>SMART App Launch</strong> — <code>fhirContext</code> support and respect for an existing <code>login</code> query parameter on launch</li>
<li class=""><strong>Project-scoped Provider access</strong> — Project membership aligns with who can open the Provider experience (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Domain rules for external apps</strong> — <code>DomainConfiguration</code> can target apps hosted outside the core deployment (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Charting and sample data</strong> — Controlled-substance documentation updates (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>) and CPT handling fixes on sample data</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling-operations">Scheduling Operations<a href="https://www.medplum.com.ar/blog/march-2026-update#scheduling-operations" class="hash-link" aria-label="Direct link to Scheduling Operations" title="Direct link to Scheduling Operations" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>Server-side scheduling advances the <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling roadmap initiative</a>:</p>
<ul>
<li class=""><strong><code>$find</code> service type matching</strong> — More accurate matching when resolving available slots</li>
<li class=""><strong>Wildcard availability removed</strong> — Clearer availability semantics and fewer ambiguous slot definitions</li>
<li class=""><strong><a href="https://github.com/medplum/medplum/tree/main/examples/foomedical" target="_blank" rel="noopener noreferrer" class="">FooMedical scheduling demo</a></strong> — Updated patient-facing scheduling showcase</li>
<li class=""><strong>Demo schedules</strong> — Refreshed demo schedule content and calendar examples (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="platform-and-infrastructure">Platform and Infrastructure<a href="https://www.medplum.com.ar/blog/march-2026-update#platform-and-infrastructure" class="hash-link" aria-label="Direct link to Platform and Infrastructure" title="Direct link to Platform and Infrastructure" translate="no">​</a></h3>
<p><img src="https://github.com/codyebberson.png" alt="Cody Ebberson" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a></strong> and <img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<p>This work advances <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">Enterprise Scale &amp; Infrastructure</a>:</p>
<ul>
<li class=""><strong>Workers</strong> — Dispatch worker path, configurable background workers, CDK support for worker-only services, and conditional worker deployment</li>
<li class=""><strong><code>auth/me</code> project features</strong> — Clients read enabled project features from the authenticated session</li>
<li class=""><strong>Marketplace definitions</strong> — Foundation resources for marketplace packages (<a class="" href="https://www.medplum.com.ar/docs/api/fhir/medplum/package">package resource</a>)</li>
<li class=""><strong>Bot <code>$init</code> operation</strong> — Initializes Bot content for repeatable deployments (<a class="" href="https://www.medplum.com.ar/docs/bots">Bots overview</a>)</li>
<li class=""><strong>Auth UI extraction</strong> — Shared React components for sign-in and session flows</li>
</ul>
<p><img src="https://github.com/mattwiller.png" alt="Matt Willer" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a></strong></p>
<ul>
<li class=""><strong>Presigned Binary uploads</strong> — Secure, efficient client-side uploads without routing through the server</li>
<li class=""><strong>Rate-limit caching</strong> — In-memory tracking of heavily rate-limited IPs for faster enforcement</li>
<li class=""><strong>Database tuning</strong> — PostgreSQL transaction idle timeouts and faster login flow</li>
<li class=""><strong>Observability</strong> — Broader FHIR interaction metrics from the system repository; transaction consistency fixes in database reads</li>
</ul>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<ul>
<li class=""><strong>WebSocket subscription hardening</strong> — Subscription token lifecycle, stale subscription detection against user limits, and FHIRcast topic key refresh</li>
<li class=""><strong>HL7 client resilience</strong> — Clients now warn instead of error on unknown message control IDs</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="developer-experience">Developer Experience<a href="https://www.medplum.com.ar/blog/march-2026-update#developer-experience" class="hash-link" aria-label="Direct link to Developer Experience" title="Direct link to Developer Experience" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>ThreadInbox</code> / ThreadChat</strong> — Optional <code>allowPatientSelection</code> for patient-facing apps; prop type exports; QuestionnaireForm fixes for repeated multiple-choice items; questionnaire signature stories (<a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a>, <a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong><code>useSearch</code> typing</strong> — Results use <code>WithId&lt;T&gt;</code> for safer access to server-assigned ids (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong>SMART launch</strong> — Opens in a new tab by default; respects an existing <code>login</code> query parameter on launch (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Reference display fallback</strong> — UUID fallback when a reference has no display string (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong><code>ValueSetAutocomplete</code></strong> — Configurable count behavior (<a href="https://github.com/adityasuri" target="_blank" rel="noopener noreferrer" class="">Aditya Suri</a>)</li>
<li class=""><strong>MedplumClient retry options</strong> — Configurable maximum retry time and default <code>maxRetries</code> (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>, <a href="https://github.com/adityasuri" target="_blank" rel="noopener noreferrer" class="">Aditya Suri</a>)</li>
<li class=""><strong>CLI healthcheck validation</strong> — Custom base URLs are validated against the server healthcheck when configuring profiles (<a class="" href="https://www.medplum.com.ar/docs/cli">Medplum CLI</a>, <a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong><a href="https://github.com/medplum/medplum/tree/main/examples/medplum-smart-on-fhir-demo" target="_blank" rel="noopener noreferrer" class="">SMART on FHIR demo app</a></strong> — New example app for SMART launch and patient context (<a href="https://github.com/alexanderxlin" target="_blank" rel="noopener noreferrer" class="">Alex Lin</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/open-source">Why Open Source</a></strong> — New page on Medplum's open-source philosophy</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/march-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p>March's documentation push emphasizes <strong>communications</strong>, <strong>clinical and scheduling workflows</strong>, and <strong>platform operations</strong> — supporting builders who ship <a class="" href="https://www.medplum.com.ar/docs/provider">workflow-heavy provider experiences</a>.</p>
<p><strong>Communications and messaging</strong></p>
<p><img src="https://github.com/everett-williams.png" alt="Everett Williams" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/thread-lifecycle-participants-access-control">Thread lifecycle, participants, and access control</a></strong> — How threads behave over time, who can see them, and how access policies apply</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/messaging-data-model">Messaging data model</a></strong> — Updated mental model for how conversations are represented and evolve</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/message-response-tracking-and-routing">Task-based message response tracking and routing</a></strong> — Patterns for tying tasks to message workflows</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/searching-and-querying-threads">Searching and querying threads</a></strong> — Practical search patterns for threaded communications</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/sending-messages-and-attachments">Sending messages and attachments</a></strong> — Attachment flows for secure messaging</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/read-receipts-and-message-status">Read receipts and message status</a></strong> — Delivery and read state for auditing and UX</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/communications/messaging-automations">Messaging automations with Bots</a></strong> — Automations that react to messaging events</li>
<li class=""><strong>Example code</strong> — New messaging snippets aligned with the guides</li>
<li class=""><strong>Sidebar reorganization</strong> — Clearer navigation for communications and related topics</li>
</ul>
<p>Additional communications documentation pages are in the works beyond what shipped in March, so expect the <a class="" href="https://www.medplum.com.ar/docs/communications">communications section</a> to keep growing.</p>
<p><strong>Clinical charting and scheduling</strong></p>
<p><img src="https://github.com/deam65.png" alt="Darren Eam" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/deam65" target="_blank" rel="noopener noreferrer" class="">Darren Eam</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/charting/visit-templates">Visit Templates and the SOAP Approach</a></strong> — Visit templates tied to SOAP (structured S/O/P, narrative assessment) in clinical charting</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/timezones">Time zones and timestamps</a></strong> — Scheduling with zones and instants in FHIR and the app (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Scheduling guides</strong> — Broader refresh of scheduling documentation (<a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/scheduling/defining-availability">Defining availability</a></strong> — Clarified alpha labeling (<a href="https://github.com/adityasuri" target="_blank" rel="noopener noreferrer" class="">Aditya Suri</a>)</li>
</ul>
<p><strong>Platform and operations</strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/auth/external-identity-providers">External identity providers</a></strong> — Routing strategies for external IdP integrations (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/access/multi-tenant-access-policy">Multi-tenant access policies</a></strong> — Tenancy guidance in access documentation (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/self-hosting/server-config#maxbatchsize">Server configuration: maxBatchSize</a></strong> — How <code>maxBatchSize</code> interacts with async batches and <code>maxJsonSize</code> (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/blog/events-calendar">Medplum Events Calendar</a></strong> — Updated upcoming events (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
<li class=""><strong>Lab account onboarding</strong> — Revised instructions for requesting a lab account (<a href="https://github.com/reshmakh" target="_blank" rel="noopener noreferrer" class="">Reshma Khilnani</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/march-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>Server</strong></p>
<ul>
<li class="">Return HTTP 400 when PostgreSQL rejects date/time values that overflow field bounds, instead of a generic database error (contributed by Léandre Chamberland-Dozois)</li>
<li class="">Improved patch behavior when JSON patch operations implicitly create arrays</li>
<li class="">Hardened <code>ProjectMembership.invitedBy</code> population for consistent invite attribution</li>
<li class="">Additional edge cases for subscription token expiry and rebinding</li>
<li class="">Fixed basic authentication handling for inactive project memberships</li>
</ul>
<p><strong>Clinical and UI</strong></p>
<ul>
<li class="">Fixed <code>mapReferenceRange</code> so numeric reference ranges map cleanly into FHIR <code>Range</code> for observations (contributed by <a href="https://github.com/amcgivern" target="_blank" rel="noopener noreferrer" class="">Amanda McGivern</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/march-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.2" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.2</strong></a> — March 7</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.3" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.3</strong></a> — March 7</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.4" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.4</strong></a> — March 20</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/march-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>March deepened the Provider app's Spaces, messaging, and scheduling story, while worker and subscription work strengthened the platform's operational backbone. Communications documentation now gives teams a clearer map from threads and tasks to automation — supporting the next wave of patient and clinician-facing workflows.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Everett Williams</name>
            <uri>https://github.com/everett-williams</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Self-Hosted Performance Benchmarks]]></title>
        <id>https://www.medplum.com.ar/blog/medplum-performance-test-2026</id>
        <link href="https://www.medplum.com.ar/blog/medplum-performance-test-2026"/>
        <updated>2026-03-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[One of the most common questions we hear from teams evaluating Medplum is: "Can it handle our scale?" We wanted to answer that question with real data. We recently ran a formal performance evaluation against a self-hosted Medplum deployment that mirrors one of our largest production clusters, and the results speak for themselves - peak throughput exceeding 46,000 requests per second for read-only traffic and nearly 7,000 requests per second for full read/write/search FHIR workflows, with zero HTTP failures across all scenarios.]]></summary>
        <content type="html"><![CDATA[<p>One of the most common questions we hear from teams evaluating Medplum is: <em>"Can it handle our scale?"</em> We wanted to answer that question with real data. We recently ran a formal performance evaluation against a self-hosted Medplum deployment that mirrors one of our largest production clusters, and the results speak for themselves - peak throughput exceeding <strong>46,000 requests per second</strong> for read-only traffic and nearly <strong>7,000 requests per second</strong> for full read/write/search FHIR workflows, with zero HTTP failures across all scenarios.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="executive-summary">Executive Summary<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#executive-summary" class="hash-link" aria-label="Direct link to Executive Summary" title="Direct link to Executive Summary" translate="no">​</a></h2>
<table><thead><tr><th>Scenario</th><th>Description</th><th>Max Throughput</th><th>Avg Response Time</th></tr></thead><tbody><tr><td>1</td><td>Unauthenticated, read-only, no database access</td><td>46,750.67 reqs/s</td><td>18 ms</td></tr><tr><td>2</td><td>Unauthenticated read-only, database access</td><td>14,733.67 reqs/s</td><td>40 ms</td></tr><tr><td>3</td><td>Authenticated, read-only, database access</td><td>20,796.67 reqs/s</td><td>34 ms</td></tr><tr><td>4</td><td>Authenticated, read, write, and search</td><td>6,738.33 reqs/s</td><td>167 ms</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="cluster-configuration">Cluster Configuration<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#cluster-configuration" class="hash-link" aria-label="Direct link to Cluster Configuration" title="Direct link to Cluster Configuration" translate="no">​</a></h2>
<p>The cluster used for this evaluation mirrors one of Medplum's most extensive managed production clusters, making these results grounded in real-world infrastructure rather than a synthetic benchmark environment.</p>
<table><thead><tr><th>Component</th><th>Detail</th></tr></thead><tbody><tr><td><strong>AWS Region</strong></td><td>ca-central-1</td></tr><tr><td><strong>Server Instance Count</strong></td><td>15</td></tr><tr><td><strong>Server Instance Type</strong></td><td>Fargate Linux/X86</td></tr><tr><td><strong>Server CPU</strong></td><td>4096 (4 vCPU)</td></tr><tr><td><strong>Server Memory</strong></td><td>16384 (16 GB)</td></tr><tr><td><strong>Database</strong></td><td>PostgreSQL 16.8, r6gd.4xlarge</td></tr><tr><td><strong>Database vCPU</strong></td><td>16</td></tr><tr><td><strong>Database Memory</strong></td><td>128 GiB</td></tr><tr><td><strong>Database Storage</strong></td><td>950 GiB NVMe SSD</td></tr><tr><td><strong>Database Network</strong></td><td>10 Gbps</td></tr><tr><td><strong>Cache</strong></td><td>Redis 6.2.6, m4.2xlarge</td></tr><tr><td><strong>Cache vCPU</strong></td><td>8</td></tr><tr><td><strong>Cache Memory</strong></td><td>30 GiB</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="testing-methodology">Testing Methodology<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#testing-methodology" class="hash-link" aria-label="Direct link to Testing Methodology" title="Direct link to Testing Methodology" translate="no">​</a></h2>
<p>All tests were run using <a href="https://grafana.com/docs/k6/latest/testing-guides/running-large-tests/" target="_blank" rel="noopener noreferrer" class="">Grafana's hosted k6 testing framework</a>, which is purpose-built for generating massive load through efficient script optimization. Key aspects of the methodology:</p>
<ul>
<li class="">Operating system configurations were adjusted to raise default network and user limits</li>
<li class="">The load generator was monitored continuously to ensure optimal resource utilization</li>
<li class="">Test scripts were crafted to account for k6 scripting nuances, options, and file handling</li>
<li class="">A single k6 instance was configured to utilize all available CPU cores, enabling simulation of thousands of virtual users and hundreds of thousands of HTTP requests per second</li>
</ul>
<p>Each scenario was configured to ramp up to <strong>1,000 virtual users (VUs)</strong> over a <strong>5 minute 30 second</strong> test window.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="scenario-1-unauthenticated-read-only-no-database-access">Scenario 1: Unauthenticated, Read-Only, No Database Access<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#scenario-1-unauthenticated-read-only-no-database-access" class="hash-link" aria-label="Direct link to Scenario 1: Unauthenticated, Read-Only, No Database Access" title="Direct link to Scenario 1: Unauthenticated, Read-Only, No Database Access" translate="no">​</a></h2>
<p><strong>Endpoint:</strong> <code>HTTP GET /</code></p>
<p>This scenario tests the raw serving capacity of the Medplum API tier with no database involvement - reflecting performance for cached or statically resolved responses.</p>
<p><img decoding="async" loading="lazy" alt="Scenario 1 k6 throughput chart" src="https://www.medplum.com.ar/assets/images/scenario-1-chart-f48142ae0c445ab8d9a24456abd73c3a.png" width="2048" height="607" class="img__Ss2"></p>
<p><img decoding="async" loading="lazy" alt="Scenario 1 k6 thresholds" src="https://www.medplum.com.ar/assets/images/scenario-1-stats-1-f2f4afc6b15f35e3fa0edc5c97f1e2f4.png" width="2048" height="223" class="img__Ss2"></p>
<p>A total of <strong>5,767,860 requests</strong> were made with a peak throughput of <strong>46,750.67 reqs/s</strong>. The p95 response time was <strong>30 ms</strong>, and zero HTTP failures were recorded. At steady state, the system handled an average of <strong>16,972 requests/second</strong>.</p>
<p><a href="https://medplum.grafana.net/a/k6-app/runs/7108814" target="_blank" rel="noopener noreferrer" class="">View full run on Grafana k6</a></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="scenario-2-unauthenticated-read-only-database-access">Scenario 2: Unauthenticated, Read-Only, Database Access<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#scenario-2-unauthenticated-read-only-database-access" class="hash-link" aria-label="Direct link to Scenario 2: Unauthenticated, Read-Only, Database Access" title="Direct link to Scenario 2: Unauthenticated, Read-Only, Database Access" translate="no">​</a></h2>
<p><strong>Endpoint:</strong> <code>HTTP GET /healthcheck</code></p>
<p>This scenario introduces database reads into the picture without authentication overhead, testing the throughput of simple DB-backed responses.</p>
<p><img decoding="async" loading="lazy" alt="Scenario 2 k6 throughput chart" src="https://www.medplum.com.ar/assets/images/scenario-2-chart-ce720d11b1050d739760b0b5f401265e.png" width="2048" height="610" class="img__Ss2"></p>
<p><img decoding="async" loading="lazy" alt="Scenario 2 k6 thresholds" src="https://www.medplum.com.ar/assets/images/scenario-2-stats-1-66f45563d9a1aa2dc92e0ab54e56a0ba.png" width="2048" height="220" class="img__Ss2"></p>
<p>A total of <strong>2,916,547 requests</strong> were made with a peak throughput of <strong>14,733.67 reqs/s</strong>. The p95 response time was <strong>89 ms</strong>, and the average request rate was <strong>9,408 requests/second</strong>.</p>
<p><a href="https://medplum.grafana.net/a/k6-app/runs/7108706" target="_blank" rel="noopener noreferrer" class="">View full run on Grafana k6</a></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="scenario-3-authenticated-read-only-database-access">Scenario 3: Authenticated, Read-Only, Database Access<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#scenario-3-authenticated-read-only-database-access" class="hash-link" aria-label="Direct link to Scenario 3: Authenticated, Read-Only, Database Access" title="Direct link to Scenario 3: Authenticated, Read-Only, Database Access" translate="no">​</a></h2>
<p><strong>Endpoint:</strong> <code>HTTP GET /fhir/R4/Patient/{id}</code></p>
<p>This scenario adds JWT authentication to a FHIR read operation, reflecting the typical performance profile for reading a single FHIR resource in a production application.</p>
<p><img decoding="async" loading="lazy" alt="Scenario 3 k6 throughput chart" src="https://www.medplum.com.ar/assets/images/scenario-3-chart-99d8bad29dc7cea984121851d016f787.png" width="2048" height="609" class="img__Ss2"></p>
<p><img decoding="async" loading="lazy" alt="Scenario 3 k6 thresholds" src="https://www.medplum.com.ar/assets/images/scenario-3-stats-1-02e4130f8df166bd8e0abc6983bb5967.png" width="2048" height="218" class="img__Ss2"></p>
<p>A total of <strong>3,641,640 requests</strong> were made with a peak throughput of <strong>20,796.67 reqs/s</strong>. The p95 response time was <strong>57 ms</strong>, and the average request rate was <strong>11,747 requests/second</strong>.</p>
<p><a href="https://medplum.grafana.net/a/k6-app/runs/7108454" target="_blank" rel="noopener noreferrer" class="">View full run on Grafana k6</a></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="scenario-4-authenticated-read-write-and-search">Scenario 4: Authenticated, Read, Write, and Search<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#scenario-4-authenticated-read-write-and-search" class="hash-link" aria-label="Direct link to Scenario 4: Authenticated, Read, Write, and Search" title="Direct link to Scenario 4: Authenticated, Read, Write, and Search" translate="no">​</a></h2>
<p>This is the most realistic scenario - simulating a real-world application workflow that creates, reads, and searches for FHIR Patient resources under load.</p>
<p><strong>Endpoints (executed in sequence per VU):</strong></p>
<ol>
<li class=""><code>HTTP POST /fhir/R4/Patient</code> - CreatePatient</li>
<li class=""><code>HTTP GET /fhir/R4/Patient/{id}</code> - ReadPatient</li>
<li class=""><code>HTTP GET /fhir/R4/Patient?name={name}</code> - SearchPatient</li>
</ol>
<p><img decoding="async" loading="lazy" alt="Scenario 4 k6 throughput chart" src="https://www.medplum.com.ar/assets/images/scenario-4-chart-5e8b5fe93b81e35a9725d740995015e4.png" width="2048" height="758" class="img__Ss2"></p>
<p><img decoding="async" loading="lazy" alt="Scenario 4 k6 thresholds" src="https://www.medplum.com.ar/assets/images/scenario-4-stats-1-e8d93cf46d0e2226b9e591b67a05027c.png" width="2048" height="277" class="img__Ss2"></p>
<p><img decoding="async" loading="lazy" alt="Scenario 4 per-endpoint breakdown" src="https://www.medplum.com.ar/assets/images/scenario-4-stats-2-c1954025d80c0b64b60e4a35fbb288f8.png" width="2048" height="370" class="img__Ss2"></p>
<p>A total of <strong>743,313 requests</strong> were made with a peak throughput of <strong>6,738.33 reqs/s</strong>. The p95 response time was <strong>403 ms</strong>, and the average request rate was <strong>2,398 requests/second</strong>.</p>
<p>Zero HTTP failures were recorded across all three endpoint types.</p>
<p><a href="https://medplum.grafana.net/a/k6-app/runs/7108360" target="_blank" rel="noopener noreferrer" class="">View full run on Grafana k6</a></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="summary">Summary<a href="https://www.medplum.com.ar/blog/medplum-performance-test-2026#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>These results demonstrate that a properly configured self-hosted Medplum deployment can handle demanding production workloads with strong latency characteristics and zero error rates. The cluster configuration used here - 15 Fargate instances backed by a high-memory PostgreSQL node and a Redis cache - represents a realistic mid-to-large production setup.</p>
<p>For teams evaluating Medplum for high-throughput applications, these benchmarks provide a concrete baseline for capacity planning. Questions about sizing, configuration, or performance optimization? Join the conversation on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> or reach out to the Medplum team.</p>]]></content>
        <author>
            <name>Darren Eam</name>
            <uri>https://github.com/deam65</uri>
        </author>
        <category label="self-host" term="self-host"/>
        <category label="fhir-datastore" term="fhir-datastore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - February 2026]]></title>
        <id>https://www.medplum.com.ar/blog/february-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/february-2026-update"/>
        <updated>2026-03-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[February was a productive month for Medplum. We shipped four releases — v5.0.14, v5.0.15, v5.1.0, and v5.1.1, including a minor version bump reflecting the depth of new capabilities — with over 130 commits from 25+ contributors. The biggest themes this month were WebSocket subscription stability and performance improvements, AI-powered provider experiences, scheduling refinements, and revenue cycle tooling — all advancing our 2026 roadmap priorities.]]></summary>
        <content type="html"><![CDATA[<p>February was a productive month for Medplum. We shipped four releases — v5.0.14, v5.0.15, v5.1.0, and v5.1.1, including a minor version bump reflecting the depth of new capabilities — with over 130 commits from 25+ contributors. The biggest themes this month were <strong>WebSocket subscription stability and performance improvements</strong>, <strong>AI-powered provider experiences</strong>, <strong>scheduling refinements</strong>, and <strong>revenue cycle tooling</strong> — all advancing our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/february-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-ai-powered-spaces-and-chat">Provider App: AI-Powered Spaces and Chat<a href="https://www.medplum.com.ar/blog/february-2026-update#provider-app-ai-powered-spaces-and-chat" class="hash-link" aria-label="Direct link to Provider App: AI-Powered Spaces and Chat" title="Direct link to Provider App: AI-Powered Spaces and Chat" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>The <a href="https://provider.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Provider app</a>'s Spaces experience gained significant AI capabilities this month, advancing our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">AI roadmap initiative</a>:</p>
<ul>
<li class=""><strong>LLM components and visualization preview in Spaces</strong> — AI-generated structured components and previews now render inside the chat interface, enabling richer, more interactive AI responses</li>
<li class=""><strong>Attachment support in chat</strong> — Providers can now send and receive file attachments within the base chat component</li>
<li class=""><strong>Updated AI models</strong> — The provider app is configured with the latest available language models</li>
<li class=""><strong><a href="https://storybook.medplum.com.ar/?path=/story/medplum-chat-threadinbox--basic" target="_blank" rel="noopener noreferrer" class="">ThreadInbox</a> as a reusable React component</strong> — Moved to the <code>@medplum/react</code> package, making inbox functionality available to any Medplum-powered application</li>
<li class=""><strong>Navbar alerts and counts</strong> — <a href="https://provider.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Provider app</a> navigation links now support badge icons and resource counts for at-a-glance workflow status</li>
</ul>
<p>The <a href="https://github.com/medplum/medplum/tree/main/examples/foomedical" target="_blank" rel="noopener noreferrer" class="">Foomedical demo</a> — a sample patient-facing experience — was also updated to showcase the latest chat experience.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="aws-lambda-streaming-for-bots">AWS Lambda Streaming for Bots<a href="https://www.medplum.com.ar/blog/february-2026-update#aws-lambda-streaming-for-bots" class="hash-link" aria-label="Direct link to AWS Lambda Streaming for Bots" title="Direct link to AWS Lambda Streaming for Bots" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p><a class="" href="https://www.medplum.com.ar/docs/bots">Bots</a> deployed on AWS Lambda can now stream responses back to callers in real time. This unlocks <a href="https://en.wikipedia.org/wiki/Server-sent_events" target="_blank" rel="noopener noreferrer" class="">Server-Sent Events</a>-style streaming from Lambda-hosted bots — a foundational capability for building AI scribes, copilots, and other latency-sensitive applications. This directly supports the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">AI roadmap initiative</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="websocket-subscriptions-scale-and-observability">WebSocket Subscriptions: Scale and Observability<a href="https://www.medplum.com.ar/blog/february-2026-update#websocket-subscriptions-scale-and-observability" class="hash-link" aria-label="Direct link to WebSocket Subscriptions: Scale and Observability" title="Direct link to WebSocket Subscriptions: Scale and Observability" translate="no">​</a></h3>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<p>February saw a major investment in <a class="" href="https://www.medplum.com.ar/docs/subscriptions">WebSocket subscriptions</a>, improving performance, reliability, and operational visibility at scale — directly advancing the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">Enterprise Scale &amp; Infrastructure roadmap priority</a>:</p>
<ul>
<li class=""><strong>Per-user WebSocket subscription limits</strong> — Prevents runaway connections from any single user from destabilizing the platform</li>
<li class=""><strong>Super admin dashboard for subscription stats</strong> — Real-time visibility into active WebSocket subscriptions, connection counts, and resource utilization across the entire platform (<a class="" href="https://www.medplum.com.ar/docs/self-hosting/super-admin-guide">super admin guide</a>)</li>
<li class=""><strong>Admin operation to clear all WebSocket subscriptions</strong> — Administrative control for operations teams managing large deployments</li>
<li class=""><strong>Multiple performance improvements</strong> — Subscription criteria is now only evaluated when criteria match, access policy decisions are cached in the hot evaluation loop, active subscription lists are partitioned by resource type, Redis key deletion is non-blocking, and a new efficient event payload format reduces latency and CPU load at high subscription volumes</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling-enhancements">Scheduling Enhancements<a href="https://www.medplum.com.ar/blog/february-2026-update#scheduling-enhancements" class="hash-link" aria-label="Direct link to Scheduling Enhancements" title="Direct link to Scheduling Enhancements" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>Building on January's <a class="" href="https://www.medplum.com.ar/docs/scheduling/defining-availability"><code>$find</code> and <code>$book</code></a> foundation, scheduling received several refinements this month:</p>
<ul>
<li class=""><strong>Customizable appointment creation before <a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-book"><code>$book</code></a></strong> — Developers can now inject custom fields and logic into the appointment object before the booking operation executes, enabling clinic-specific workflows</li>
<li class=""><strong><code>_count</code> parameter for <a class="" href="https://www.medplum.com.ar/docs/scheduling/appointment-find"><code>$find</code></a></strong> — Limits the number of available slots returned, improving efficiency for high-volume scheduling queries</li>
<li class=""><strong>Adding a visit now creates a busy slot</strong> — The <a class="" href="https://www.medplum.com.ar/docs/provider/schedule">Provider calendar</a> correctly blocks time when a visit is added, ensuring accurate availability display</li>
<li class=""><strong>Improved UTC/local day discrepancy handling</strong> — Scheduling operations behave correctly when the server's UTC time and the local calendar day differ</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="revenue-cycle-claim-submission-and-eligibility">Revenue Cycle: Claim Submission and Eligibility<a href="https://www.medplum.com.ar/blog/february-2026-update#revenue-cycle-claim-submission-and-eligibility" class="hash-link" aria-label="Direct link to Revenue Cycle: Claim Submission and Eligibility" title="Direct link to Revenue Cycle: Claim Submission and Eligibility" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>Advancing the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">Revenue Cycle &amp; Billing roadmap initiative</a>:</p>
<ul>
<li class=""><strong>Claim submission to Candid</strong> — A proof-of-concept integration for submitting claims directly to Candid Health, enabling automated professional billing workflows from within the Provider app (<a class="" href="https://www.medplum.com.ar/docs/billing">billing overview</a>)</li>
<li class=""><strong>CoverageEligibilityRequest in <code>$extract</code></strong> — The <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/extract">SDC <code>$extract</code> operation</a> now uses the standard <code>CoverageEligibilityRequest</code> resource for insurance eligibility checks, aligning with the FHIR specification</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="pharmacy-components">Pharmacy Components<a href="https://www.medplum.com.ar/blog/february-2026-update#pharmacy-components" class="hash-link" aria-label="Direct link to Pharmacy Components" title="Direct link to Pharmacy Components" translate="no">​</a></h3>
<p><img src="https://github.com/oleg-mp.png" alt="Oleg Rocklin" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/oleg-mp" target="_blank" rel="noopener noreferrer" class="">Oleg Rocklin</a></strong></p>
<p>New React components for <strong>patient preferred pharmacy selection</strong> are now available in <code>@medplum/react</code>. This supports e-prescribing workflows and the <a class="" href="https://www.medplum.com.ar/docs/medications/e-prescibe">ePrescribe integration</a> roadmap initiative.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="multiple-redis-support">Multiple Redis Support<a href="https://www.medplum.com.ar/blog/february-2026-update#multiple-redis-support" class="hash-link" aria-label="Direct link to Multiple Redis Support" title="Direct link to Multiple Redis Support" translate="no">​</a></h3>
<p><img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<p>Medplum server now supports <strong>multiple Redis instances</strong>, enabling more flexible infrastructure topologies including Redis Cluster deployments and failover configurations. This is an important step for enterprise-scale deployments that require high availability for caching and pub/sub. (<a class="" href="https://www.medplum.com.ar/docs/self-hosting">self-hosting guide</a>)</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="instance-level-custom-fhir-operations">Instance-Level Custom FHIR Operations<a href="https://www.medplum.com.ar/blog/february-2026-update#instance-level-custom-fhir-operations" class="hash-link" aria-label="Direct link to Instance-Level Custom FHIR Operations" title="Direct link to Instance-Level Custom FHIR Operations" translate="no">​</a></h3>
<p><img src="https://github.com/rahul1.png" alt="Rahul Agarwal" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a></strong></p>
<p>Developers can now define <a class="" href="https://www.medplum.com.ar/docs/bots/custom-fhir-operations">custom FHIR operations</a> at the instance level with resource input — enabling more granular, resource-specific API extensions. Combined with updated <a class="" href="https://www.medplum.com.ar/docs/bots">bot operation documentation</a>, this gives builders more control over custom workflow APIs. For self-hosters, this is particularly valuable: you can expose clinic- or organization-specific operations directly on your FHIR server without forking Medplum, keeping your customizations cleanly separated from the core platform.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="security-and-authentication">Security and Authentication<a href="https://www.medplum.com.ar/blog/february-2026-update#security-and-authentication" class="hash-link" aria-label="Direct link to Security and Authentication" title="Direct link to Security and Authentication" translate="no">​</a></h3>
<ul>
<li class=""><strong>Public PGP key published</strong> — Medplum now has a published security PGP key for responsible disclosure, listed on the <a class="" href="https://www.medplum.com.ar/docs/compliance">security page</a> (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Sub claim fallback in external auth</strong> — Improved compatibility with external OIDC providers that use non-standard subject claim formats (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
<li class=""><strong>In-memory rate limit tracking for high-volume abuse</strong> — Heavily rate-limited users are now tracked in memory for faster enforcement (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
<li class=""><strong>Access policy search permission explicitly checked</strong> — Tightened enforcement of access control on search operations (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="developer-experience">Developer Experience<a href="https://www.medplum.com.ar/blog/february-2026-update#developer-experience" class="hash-link" aria-label="Direct link to Developer Experience" title="Direct link to Developer Experience" translate="no">​</a></h3>
<ul>
<li class=""><strong>Members tab in project admin</strong> — Users and Patients are now combined into a single Members tab on the project admin page for a cleaner project management experience (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>SMART app launch with patient identifier</strong> — SMART app launch URLs now support patient identifiers, improving interoperability with EHR launch contexts (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Token <code>:text</code> modifier in <a href="https://storybook.medplum.com.ar/?path=/story/medplum-searchcontrol--checkboxes" target="_blank" rel="noopener noreferrer" class="">SearchControl</a></strong> — The <code>SearchControl</code> component now supports the token text modifier for more flexible searches (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Hidden field support in forms</strong> — Form components now support hidden fields for passing context without user input (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Membership label filtering in profile chooser</strong> — The profile selection form can now filter memberships by label, contributed by <a href="https://github.com/jeffrey-peterson-vanna" target="_blank" rel="noopener noreferrer" class="">jeffrey-peterson-vanna</a></li>
<li class=""><strong>Operation to refresh reference display strings</strong> — A new operation allows refreshing cached display strings on resource references, keeping display data current after resource updates (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
<li class=""><strong>Native bcrypt for improved authentication performance</strong> — Switched from the pure-JavaScript <code>bcryptjs</code> library to native bcrypt bindings, significantly improving password hashing throughput (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Configurable CDS services URL</strong> — The Clinical Decision Support (CDS) Hooks service URL is now configurable, enabling integration with custom CDS endpoints. CDS Hooks support is part of Medplum's <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4/CMS-0057-F compliance initiative</a>, which covers payer interoperability requirements ahead of the January 2027 enforcement date. (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/february-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p>February's documentation work was substantial, with a major restoration of SDK docs and expanded coverage of operations, subscriptions, and integrations.</p>
<p><strong>Operations and API</strong></p>
<p><img src="https://github.com/deam65.png" alt="Darren Eam" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/deam65" target="_blank" rel="noopener noreferrer" class="">Darren Eam</a></strong></p>
<ul>
<li class=""><strong>Reorganized FHIR operations sidebar and index</strong> — The <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations">FHIR operations docs</a> are now organized with a cleaner sidebar and index page for faster navigation</li>
<li class=""><strong>New documentation for custom and bot operations</strong> — Full coverage of <a class="" href="https://www.medplum.com.ar/docs/bots/custom-fhir-operations">custom FHIR operations</a>, including instance-level and system-level patterns</li>
<li class=""><strong>Project and system administration operations</strong> — New reference pages for <a class="" href="https://www.medplum.com.ar/docs/self-hosting/super-admin-guide">admin operations</a></li>
<li class=""><strong>Data export and import operations</strong> — Documented the <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/bulk-fhir">Bulk Data Export</a>, <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/ccda-export">C-CDA Export</a>, <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/claim-export">Claim Export</a>, and <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/csv">CSV export</a> API operations</li>
<li class=""><strong>Clinical decision support operations</strong> — New reference for CDS Hooks operations, part of Medplum's <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4/CMS-0057-F compliance initiative</a></li>
</ul>
<p><strong>Subscriptions</strong></p>
<ul>
<li class=""><strong>Subscription extension docs</strong> — Clarified the <a class="" href="https://www.medplum.com.ar/docs/subscriptions/subscription-extensions">subscription extension</a> format for interaction filters and retry policy (<a href="https://github.com/ianplunkett" target="_blank" rel="noopener noreferrer" class="">Ian Plunkett</a>)</li>
<li class=""><strong><code>useSubscription</code> lifecycle hooks</strong> — Added documentation for lifecycle hook callbacks in the <a class="" href="https://www.medplum.com.ar/docs/react/use-subscription"><code>useSubscription</code></a> React hook (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
</ul>
<p><strong>Provider and Clinical</strong></p>
<ul>
<li class=""><strong>DoseSpot notifications</strong> — Updated documentation for <a class="" href="https://www.medplum.com.ar/docs/medications/e-prescibe">DoseSpot</a> notification handling (<a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a>)</li>
<li class=""><strong>Patient login and launch URI clarification</strong> — Improved docs for patient-facing login flows and SMART launch URIs, contributed by <a href="https://github.com/mallikharjunamulpuri" target="_blank" rel="noopener noreferrer" class="">Mallikharjuna Mulpuri</a></li>
<li class=""><strong>Allergy representation</strong> — Clarified allergy status and AllergyIntolerance formatting in the <a class="" href="https://www.medplum.com.ar/docs/charting/chart-data-model#allergies-and-intolerances">chart data model</a>, contributed by <a href="https://github.com/aaronhong" target="_blank" rel="noopener noreferrer" class="">Aaron Hong</a></li>
<li class=""><strong>CareTeam tenancy patterns</strong> — Clarified per-patient CareTeam cardinality and multi-tenancy patterns (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
</ul>
<p><strong>Infrastructure and Security</strong></p>
<ul>
<li class=""><strong>Docker Hardened Images</strong> — Added Docker Hardened Images to the <a class="" href="https://www.medplum.com.ar/docs/compliance">security page</a> (<a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
<li class=""><strong>Medplum Agent solutions page</strong> — Created a dedicated <a class="" href="https://www.medplum.com.ar/docs/agent">Medplum Agent solutions page</a>. The <a class="" href="https://www.medplum.com.ar/docs/agent">Medplum Agent</a> is an application that runs inside your firewall and bridges on-premise devices (HL7/MLLP, ASTM, DICOM) to the cloud via secure WebSocket channels (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Branding guide</strong> — New <a class="" href="https://www.medplum.com.ar/docs/self-hosting/branding">branding documentation</a> explaining how to customize the Medplum logo and application name (<a href="https://github.com/adityasuri" target="_blank" rel="noopener noreferrer" class="">Aditya Suri</a>)</li>
</ul>
<p><strong>Blog</strong></p>
<ul>
<li class=""><strong>Identity Management: A Practical Guide</strong> — New blog post by <a href="https://github.com/everett-williams" target="_blank" rel="noopener noreferrer" class="">Everett Williams</a> on managing digital identities in healthcare applications (<a class="" href="https://www.medplum.com.ar/blog/identity-management">read the post</a>)</li>
<li class=""><strong>Medplum Secures Healthcare Platform on Docker Hardened Images</strong> — Published on the Docker blog, this post by Cody Ebberson and Docker's Ajeet Singh Raina covers how Medplum uses <a href="https://www.docker.com/blog/medplum-healthcare-docker-hardened-images/" target="_blank" rel="noopener noreferrer" class="">Docker Hardened Images</a> to reduce CVE noise, meet HIPAA and SOC 2 requirements, and minimize container security configuration burden</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/february-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>Clinical Data</strong></p>
<ul>
<li class="">Fixed handling of <code>nullFlavor</code> values in CCDA-to-FHIR conversion, improving interoperability with C-CDA documents that contain null-flavored data elements (contributed by <a href="https://github.com/amcgivern" target="_blank" rel="noopener noreferrer" class="">Amanda McGivern</a>)</li>
<li class="">Fixed handling of terminology designations without a language code</li>
</ul>
<p><strong>Scheduling</strong></p>
<ul>
<li class="">Fixed scheduling operations during UTC/local day boundary discrepancies</li>
</ul>
<p><strong>Server and Authentication</strong></p>
<ul>
<li class="">Fixed project-scoped users being properly removed when their project membership is deleted</li>
<li class="">Fixed a string equality check error in the token endpoint</li>
</ul>
<p><strong>Infrastructure</strong></p>
<ul>
<li class="">Fixed the CDK deployment option for retaining RDS instances on stack deletion</li>
<li class="">Fixed basic auth behavior for inactive project memberships</li>
<li class="">Reverted an overly strict date validation change that caused regressions</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/february-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.0.14" target="_blank" rel="noopener noreferrer" class=""><strong>v5.0.14</strong></a> — February 3</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.0.15" target="_blank" rel="noopener noreferrer" class=""><strong>v5.0.15</strong></a> — February 20</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.0" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.0</strong></a> — February 24</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.1.1" target="_blank" rel="noopener noreferrer" class=""><strong>v5.1.1</strong></a> — February 27</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/february-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>February's investments in WebSocket subscription performance and Lambda streaming set the stage for more capable real-time and AI-powered workflows in Q1. The scheduling enhancements continue to push toward a full self-scheduling experience, and the Candid claim submission proof-of-concept marks meaningful progress on revenue cycle automation.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Identity Management - A Practical Guide]]></title>
        <id>https://www.medplum.com.ar/blog/identity-management</id>
        <link href="https://www.medplum.com.ar/blog/identity-management"/>
        <updated>2026-02-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Healthcare applications require careful decisions about user authentication and access control. Whether you're building an EHR, a clinical workflow tool, or a patient portal, getting identity management right from the start will save you from costly architectural mistakes down the road.]]></summary>
        <content type="html"><![CDATA[<p>Healthcare applications require careful decisions about user authentication and access control. Whether you're building an EHR, a clinical workflow tool, or a patient portal, getting identity management right from the start will save you from costly architectural mistakes down the road.</p>
<p>This guide breaks down the key decisions you'll face when integrating with a FHIR-based platform like Medplum, explains the tradeoffs, and recommends approaches that work well for most healthcare organizations.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-basics-authentication-vs-authorization">The Basics: Authentication vs. Authorization<a href="https://www.medplum.com.ar/blog/identity-management#the-basics-authentication-vs-authorization" class="hash-link" aria-label="Direct link to The Basics: Authentication vs. Authorization" title="Direct link to The Basics: Authentication vs. Authorization" translate="no">​</a></h2>
<p>Before diving into architectural decisions, let's clarify two terms that often get confused:</p>
<p><strong>Authentication (AuthN)</strong> answers the question: "Who are you?" It's the process of verifying a user's identity — typically through a username/password combination, single sign-on, or biometric verification.</p>
<p><strong>Authorization (AuthZ)</strong> answers the question: "What can you do?" Once we know who you are, authorization determines which resources you can access and what actions you can perform.</p>
<p>In healthcare, both are critical. You need to know that Dr. Smith is actually Dr. Smith (authentication), and you need to ensure Dr. Smith can only access records for patients in her practice (authorization).</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="decision-1-using-email-address-logins-vs-external-identity-provider-idp">Decision 1: Using Email Address Logins vs. External Identity Provider (IDP)<a href="https://www.medplum.com.ar/blog/identity-management#decision-1-using-email-address-logins-vs-external-identity-provider-idp" class="hash-link" aria-label="Direct link to Decision 1: Using Email Address Logins vs. External Identity Provider (IDP)" title="Direct link to Decision 1: Using Email Address Logins vs. External Identity Provider (IDP)" translate="no">​</a></h2>
<p>The first fundamental decision is how to uniquely identify users in your system. You have two primary options:</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="option-a-email-address">Option A: Email Address<a href="https://www.medplum.com.ar/blog/identity-management#option-a-email-address" class="hash-link" aria-label="Direct link to Option A: Email Address" title="Direct link to Option A: Email Address" translate="no">​</a></h3>
<p>Using email as the unique identifier is simple and intuitive. Users log in with their email, and the system matches them to their account.</p>
<p><strong>Advantages:</strong></p>
<ul>
<li class="">Familiar to users</li>
<li class="">Works with multiple login methods (Google, Microsoft, Okta)</li>
<li class="">No additional services needed</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li class="">Email addresses change (marriage, company rebranding, job changes)</li>
<li class="">When an email changes, you need manual processes to update the account linkage</li>
<li class="">Can create orphaned accounts if not managed carefully</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="option-b-external-id-eg-okta-user-id">Option B: External ID (e.g., Okta User ID)<a href="https://www.medplum.com.ar/blog/identity-management#option-b-external-id-eg-okta-user-id" class="hash-link" aria-label="Direct link to Option B: External ID (e.g., Okta User ID)" title="Direct link to Option B: External ID (e.g., Okta User ID)" translate="no">​</a></h3>
<p>Instead of email, you can use a stable identifier from your identity provider — like an <a href="https://developer.okta.com/docs/api/openapi/okta-management/management/tag/User/" target="_blank" rel="noopener noreferrer" class="">Okta User ID</a> or <a href="https://learn.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0" target="_blank" rel="noopener noreferrer" class="">Azure AD Object ID</a>.</p>
<p><strong>Advantages:</strong></p>
<ul>
<li class="">The ID never changes, regardless of email updates</li>
<li class="">More robust for long-term identity management</li>
<li class="">More flexible for multi-provider scenarios</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li class="">Users are locked to a single identity provider</li>
<li class="">Requires more upfront configuration by admins</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="recommendation">Recommendation<a href="https://www.medplum.com.ar/blog/identity-management#recommendation" class="hash-link" aria-label="Direct link to Recommendation" title="Direct link to Recommendation" translate="no">​</a></h3>
<p>The right choice depends on your organization's size and existing infrastructure.</p>
<p><strong>For smaller organizations</strong> without an existing identity provider, email-based identification is perfectly sufficient. It's simpler to set up, requires no additional infrastructure, and the occasional email change can be handled manually without significant overhead. Medplum supports <a href="https://www.medplum.com.ar/docs/auth/mfa" target="_blank" rel="noopener noreferrer" class="">multi-factor authentication (MFA)</a>, which is required for many regulated scenarios.</p>
<p><strong>For enterprise customers</strong> with existing IDP infrastructure (Okta, Azure AD, etc.), a hybrid approach works best:</p>
<ul>
<li class="">
<p><strong>Use external IDs for your organization's internal staff</strong> (the team building and operating the platform). These users have employer-managed identities through your corporate IDP, and stability matters more than flexibility. When an employee's email changes from <code>jsmith@yourcompany.com</code> to <code>jane.smith@yourcompany.com</code>, their account should continue working seamlessly with your existing SSO.</p>
</li>
<li class="">
<p><strong>Use email for patients and domain-level routing to IDPs for partners</strong> (clinicians or administrators at clinics using your EMR, etc.). This provides flexibility because different customer organizations may use different identity providers - or none at all. Email-based identification allows Medplum to dynamically route users to the appropriate IDP based on their email domain. For example, <code>user@clinic-a.com</code> routes to Clinic A's Okta instance, while <code>user@clinic-b.com</code> routes to Clinic B's Azure AD.</p>
</li>
</ul>
<p>This hybrid approach lets you maintain tight SSO integration for your own team while giving customers the flexibility to use whatever identity infrastructure they have.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="decision-2-identity-provider-strategy">Decision 2: Identity Provider Strategy<a href="https://www.medplum.com.ar/blog/identity-management#decision-2-identity-provider-strategy" class="hash-link" aria-label="Direct link to Decision 2: Identity Provider Strategy" title="Direct link to Decision 2: Identity Provider Strategy" translate="no">​</a></h2>
<p>The next decision is where user credentials are managed. You have three options:</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="option-a-medplum-as-idp">Option A: Medplum as IDP<a href="https://www.medplum.com.ar/blog/identity-management#option-a-medplum-as-idp" class="hash-link" aria-label="Direct link to Option A: Medplum as IDP" title="Direct link to Option A: Medplum as IDP" translate="no">​</a></h3>
<p>Medplum manages credentials directly. Users create accounts with Medplum, which handles password storage, reset flows, and authentication.</p>
<p><strong>Best for:</strong> Smaller deployments, patient-facing applications where you don't have existing identity infrastructure.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="option-b-external-idp-app-based-routing">Option B: External IDP (App-Based Routing)<a href="https://www.medplum.com.ar/blog/identity-management#option-b-external-idp-app-based-routing" class="hash-link" aria-label="Direct link to Option B: External IDP (App-Based Routing)" title="Direct link to Option B: External IDP (App-Based Routing)" translate="no">​</a></h3>
<p>A third-party service (Okta, Azure AD, Auth0) manages credentials, and the routing is determined by the application. You configure a specific IDP for each application (Client ID).</p>
<p><strong>Best for:</strong> Scenarios where all users of a specific app (e.g., "Patient Portal") use the same authentication method (e.g., "Sign in with Google"), regardless of who they are.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="option-c-external-idp-domain-based-routing">Option C: External IDP (Domain-Based Routing)<a href="https://www.medplum.com.ar/blog/identity-management#option-c-external-idp-domain-based-routing" class="hash-link" aria-label="Direct link to Option C: External IDP (Domain-Based Routing)" title="Direct link to Option C: External IDP (Domain-Based Routing)" translate="no">​</a></h3>
<p>A third-party service manages credentials, but routing is determined by the user's email domain. When <code>user@hospital-a.com</code> logs in, they're automatically routed to Hospital A's Okta instance. Medplum supports <a href="https://www.medplum.com.ar/docs/auth/domain-level-identity-providers" target="_blank" rel="noopener noreferrer" class="">domain-level identity providers</a> for this use case.</p>
<p><strong>Best for:</strong> Multi-tenant platforms serving enterprise customers who want to bring their own identity provider (BYOIDP).</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="decision-3-token-flow-architecture">Decision 3: Token Flow Architecture<a href="https://www.medplum.com.ar/blog/identity-management#decision-3-token-flow-architecture" class="hash-link" aria-label="Direct link to Decision 3: Token Flow Architecture" title="Direct link to Decision 3: Token Flow Architecture" translate="no">​</a></h2>
<p>This is where many teams make costly mistakes. Understanding token flows is essential for building a secure, maintainable system.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="whats-a-token">What's a Token?<a href="https://www.medplum.com.ar/blog/identity-management#whats-a-token" class="hash-link" aria-label="Direct link to What's a Token?" title="Direct link to What's a Token?" translate="no">​</a></h3>
<p>A token is a data packet that proves a user's identity for API requests. Think of it like a wristband at a concert - it proves you're allowed to be there without requiring you to show your ID at every interaction.</p>
<p>When integrating with external identity providers, you'll encounter multiple tokens:</p>
<ul>
<li class=""><strong>IDP Token</strong> (from Okta, Azure AD, etc.): Proves the user authenticated with the external IDP</li>
<li class=""><strong>Platform Token</strong> (from Medplum): Required to access the FHIR API</li>
</ul>
<p>The question is: how do you get from an IDP token to a platform token?</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="before-building-custom-infrastructure">Before Building Custom Infrastructure<a href="https://www.medplum.com.ar/blog/identity-management#before-building-custom-infrastructure" class="hash-link" aria-label="Direct link to Before Building Custom Infrastructure" title="Direct link to Before Building Custom Infrastructure" translate="no">​</a></h3>
<p>When evaluating token flows, it's worth asking whether custom middleware or proxy layers are truly necessary. Modern FHIR platforms typically provide robust, standards-compliant authentication out of the box.</p>
<p>Before adding intermediate infrastructure, consider:</p>
<ul>
<li class=""><strong>What specific requirement does it solve?</strong> Make sure there's a documented need that the platform's native authentication can't address.</li>
<li class=""><strong>What's the maintenance burden?</strong> Custom auth layers require ongoing security updates and auditing.</li>
<li class=""><strong>Does it duplicate existing functionality?</strong> Often, the platform already handles what you're trying to build.</li>
</ul>
<p>In most cases, the three-legged OAuth (redirect flow) described below will meet your needs without additional complexity.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="three-legged-oauth-recommended">Three-Legged OAuth (Recommended)<a href="https://www.medplum.com.ar/blog/identity-management#three-legged-oauth-recommended" class="hash-link" aria-label="Direct link to Three-Legged OAuth (Recommended)" title="Direct link to Three-Legged OAuth (Recommended)" translate="no">​</a></h3>
<p><a href="https://www.medplum.com.ar/docs/auth/external-identity-providers" target="_blank" rel="noopener noreferrer" class="">Three legged OAuth</a> is the recommended approach unless your application needs access to other services beyond Medplum:</p>
<ol>
<li class="">User clicks "Login" in your app</li>
<li class="">Browser redirects to Okta</li>
<li class="">User authenticates with Okta</li>
<li class="">Okta redirects back to your app with a code</li>
<li class="">Your app exchanges the code with Medplum</li>
<li class="">Medplum validates with Okta and issues its own token</li>
<li class="">User's browser stores only the Medplum token</li>
</ol>
<p><strong>Result:</strong> User ends up with just a Medplum token. Clean, simple, secure.</p>
<p><strong>Best for:</strong> Applications that only need to access Medplum APIs.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="token-exchange-multi-service-access">Token Exchange (Multi-Service Access)<a href="https://www.medplum.com.ar/blog/identity-management#token-exchange-multi-service-access" class="hash-link" aria-label="Direct link to Token Exchange (Multi-Service Access)" title="Direct link to Token Exchange (Multi-Service Access)" translate="no">​</a></h3>
<p><a href="https://www.medplum.com.ar/docs/auth/token-exchange" target="_blank" rel="noopener noreferrer" class="">Token exchange</a> is useful for multi-service workflows:</p>
<ol>
<li class="">User authenticates with Okta</li>
<li class="">Okta issues a token stored in the user's browser</li>
<li class="">Your app sends the Okta token to Medplum's token exchange endpoint</li>
<li class="">Medplum validates the token and issues its own token</li>
<li class="">User's browser stores both tokens</li>
</ol>
<p><strong>Result:</strong> User has both an Okta token and a Medplum token.</p>
<p><strong>Why this matters:</strong> If your application needs to access other services beyond Medplum (billing systems, other healthcare APIs, etc.), the user still has their Okta token to authenticate with those services. This is common in healthcare, where a single workflow might touch multiple systems.</p>
<div class="language-javascript codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-javascript codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Using the Medplum SDK for token exchange</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> medplum </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">MedplumClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">baseUrl</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">MEDPLUM_BASE_URL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">clientId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">MEDPLUM_CLIENT_ID</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Exchange your external IDP token for a Medplum token</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> medplum</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">exchangeExternalAccessToken</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">OKTA_ACCESS_TOKEN</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Now you can make FHIR API calls</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> patient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> medplum</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">readResource</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Patient'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> patientId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="on-behalf-of-server-side-pattern">On-Behalf-Of (Server-Side Pattern)<a href="https://www.medplum.com.ar/blog/identity-management#on-behalf-of-server-side-pattern" class="hash-link" aria-label="Direct link to On-Behalf-Of (Server-Side Pattern)" title="Direct link to On-Behalf-Of (Server-Side Pattern)" translate="no">​</a></h3>
<p>For server-side applications that act as intermediaries, the <a href="https://www.medplum.com.ar/docs/auth/on-behalf-of" target="_blank" rel="noopener noreferrer" class="">On-Behalf-Of</a> pattern allows a trusted backend to make requests on behalf of specific users:</p>
<ol>
<li class="">Your backend authenticates as a ClientApplication</li>
<li class="">When making requests, include a header specifying which user you're acting for</li>
<li class="">Medplum applies that user's access policies to the request</li>
</ol>
<div class="language-bash codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-bash codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">curl 'https://api.medplum.com.ar/fhir/R4/Patient' \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --user $CLIENT_ID:$CLIENT_SECRET \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -H 'content-type: application/fhir+json' \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -H 'x-medplum: extended' \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -H 'x-medplum-on-behalf-of: ProjectMembership/abc123' \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --data-raw '{"resourceType":"Patient","name":[{"given":["Homer"],"family":"Simpson"}]}'</span><br></div></code></pre></div></div>
<p><strong>Best for:</strong> Architectures where a custom backend mediates all interactions with Medplum. Useful for maintaining audit trails showing both which system made the request and which user it was acting for.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="putting-it-together-recommended-architecture">Putting It Together: Recommended Architecture<a href="https://www.medplum.com.ar/blog/identity-management#putting-it-together-recommended-architecture" class="hash-link" aria-label="Direct link to Putting It Together: Recommended Architecture" title="Direct link to Putting It Together: Recommended Architecture" translate="no">​</a></h2>
<p>For most healthcare organizations building on a FHIR platform, here's the recommended approach:</p>
<ol>
<li class=""><strong>Choose your unique identifiers</strong> - external IDs for your internal staff, email for customers and their users</li>
<li class=""><strong>Use an external IDP</strong> (Okta, Azure AD) for enterprise users, with domain-level routing for multi-tenant scenarios</li>
<li class=""><strong>Implement Three-Legged OAuth</strong> unless your application needs access to other services outside of Medplum</li>
<li class=""><strong>Lean on native platform capabilities</strong> unless you have a specific, documented requirement for custom infrastructure</li>
</ol>
<p>This architecture gives you:</p>
<ul>
<li class="">Centralized user management through your existing IDP</li>
<li class="">Stable user accounts that survive email changes</li>
<li class="">Simplicity of token flow</li>
<li class="">Direct API access without unnecessary intermediaries</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="key-questions-to-ask">Key Questions to Ask<a href="https://www.medplum.com.ar/blog/identity-management#key-questions-to-ask" class="hash-link" aria-label="Direct link to Key Questions to Ask" title="Direct link to Key Questions to Ask" translate="no">​</a></h2>
<p>Before finalizing your identity architecture, ensure you can answer these questions:</p>
<ol>
<li class=""><strong>Who are your user types?</strong> (Staff, clinicians, patients, caregivers)</li>
<li class=""><strong>What identity providers do they use?</strong> (Corporate SSO, social login, self-registration)</li>
<li class=""><strong>What other systems need the IDP token?</strong> (Determines if you need Token Exchange)</li>
<li class=""><strong>How do you handle user offboarding?</strong> (Centralized IDP makes this easier)</li>
<li class=""><strong>What's your multi-tenancy model?</strong> (May require domain-level routing)</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="conclusion">Conclusion<a href="https://www.medplum.com.ar/blog/identity-management#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Identity management doesn't have to be complicated. The key is understanding your requirements before jumping into implementation.</p>
<p>Start with the simplest approach that meets your needs. Three-legged OAuth with an external IDP is the recommended starting point for most healthcare applications. If you later need to access services beyond Medplum, you can adopt token exchange at that point.</p>
<hr>
<p><em>For a complete overview of authentication options, see the <a href="https://www.medplum.com.ar/docs/auth" target="_blank" rel="noopener noreferrer" class="">Medplum Authentication Documentation</a>.</em></p>]]></content>
        <author>
            <name>Everett Williams</name>
            <uri>https://github.com/everett-williams</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Monthly Update - January 2026]]></title>
        <id>https://www.medplum.com.ar/blog/january-2026-update</id>
        <link href="https://www.medplum.com.ar/blog/january-2026-update"/>
        <updated>2026-02-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[January was a packed month for Medplum. We shipped three patch releases (v5.0.11, v5.0.12, v5.0.13), published the 2026 Roadmap, and landed over 100 commits from 20+ contributors. The biggest themes this month were scheduling, the Provider app, and site reliability — all directly advancing our 2026 roadmap priorities.]]></summary>
        <content type="html"><![CDATA[<p>January was a packed month for Medplum. We shipped three patch releases (v5.0.11, v5.0.12, v5.0.13), published the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 Roadmap</a>, and landed over 100 commits from 20+ contributors. The biggest themes this month were <strong>scheduling</strong>, <strong>the Provider app</strong>, and <strong>site reliability</strong> — all directly advancing our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap priorities</a>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="features">Features<a href="https://www.medplum.com.ar/blog/january-2026-update#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-app-spaces-messaging-and-tasks">Provider App: Spaces, Messaging, and Tasks<a href="https://www.medplum.com.ar/blog/january-2026-update#provider-app-spaces-messaging-and-tasks" class="hash-link" aria-label="Direct link to Provider App: Spaces, Messaging, and Tasks" title="Direct link to Provider App: Spaces, Messaging, and Tasks" translate="no">​</a></h3>
<p><img src="https://github.com/techdavidy.png" alt="David Yanez" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/techdavidy" target="_blank" rel="noopener noreferrer" class="">David Yanez</a></strong></p>
<p>The <a href="https://provider.medplum.com.ar/" target="_blank" rel="noopener noreferrer" class="">Provider app</a> saw major improvements across messaging, task management, and the new Spaces experience. This work advances the <a class="" href="https://www.medplum.com.ar/docs/provider">Provider Application roadmap goal</a> of expanding available workflows.</p>
<ul>
<li class=""><strong><a href="https://provider.medplum.com.ar/Spaces/Communication" target="_blank" rel="noopener noreferrer" class="">Spaces</a> streaming and buffered support</strong> — real-time communication with both streaming and buffered message delivery</li>
<li class=""><strong><a href="https://en.wikipedia.org/wiki/Server-sent_events" target="_blank" rel="noopener noreferrer" class="">Server-Sent Events</a> bot implementation</strong> — SSE support for bots, enabling real-time AI-powered interactions</li>
<li class=""><strong><a href="https://provider.medplum.com.ar/Communication" target="_blank" rel="noopener noreferrer" class="">Messaging</a> improvements</strong> — URL support in the inbox, participant filtering, and topic-based threading for Communications</li>
<li class=""><strong><a href="https://provider.medplum.com.ar/Task" target="_blank" rel="noopener noreferrer" class="">Task management</a></strong> — auto-selection when the task list is empty, priority display for better triage</li>
<li class=""><strong>Navbar updates</strong> for both Medplum and Provider apps by <a href="https://github.com/kevinwadeshaw" target="_blank" rel="noopener noreferrer" class="">Kevin Wadeshaw</a>, plus a new <strong>Get Started page</strong></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling-find-and-book-operations">Scheduling: $find and $book Operations<a href="https://www.medplum.com.ar/blog/january-2026-update#scheduling-find-and-book-operations" class="hash-link" aria-label="Direct link to Scheduling: $find and $book Operations" title="Direct link to Scheduling: $find and $book Operations" translate="no">​</a></h3>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<p>The most significant feature work this month was a ground-up buildout of FHIR-native scheduling operations. This directly supports the <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling initiative</a> on our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap</a>, where we committed to self-scheduling, advanced availability management, and resource scheduling.</p>
<ul>
<li class=""><strong><code>$find</code> operation</strong> for querying available slots on a single Schedule resource, now with unique slot identifiers and timezone support (<a class="" href="https://www.medplum.com.ar/docs/scheduling">scheduling docs</a>)</li>
<li class=""><strong><code>$book</code> operation</strong> for creating Appointments through a FHIR operation, with a first pass on the Provider UI booking flow</li>
<li class=""><strong>Provider Calendar refactor</strong> to support the new scheduling operations</li>
<li class=""><strong>Timezone support</strong> in <code>SchedulingParams</code>, enabling scheduling across time zones</li>
<li class="">New <a class="" href="https://www.medplum.com.ar/docs/search/advanced-search-parameters">search parameters</a> for <code>ActivityDefinition.code</code>, <code>Communication.priority</code>, and <code>ProjectMembership.active</code></li>
</ul>
<p>These operations give developers a clean, standards-based API for building patient self-scheduling and staff scheduling workflows — a capability that has been one of our most requested features.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="system-level-custom-fhir-operations">System-Level Custom FHIR Operations<a href="https://www.medplum.com.ar/blog/january-2026-update#system-level-custom-fhir-operations" class="hash-link" aria-label="Direct link to System-Level Custom FHIR Operations" title="Direct link to System-Level Custom FHIR Operations" translate="no">​</a></h3>
<p><img src="https://github.com/monsieurBelbo.png" alt="Gonzalo Bellver" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/monsieurBelbo" target="_blank" rel="noopener noreferrer" class="">Gonzalo Bellver</a></strong></p>
<p>Developers can now define <a class="" href="https://www.medplum.com.ar/docs/bots/custom-fhir-operations">custom FHIR operations</a> at the system level, not just per-resource. This is a key building block for the <a class="" href="https://www.medplum.com.ar/docs/bots">Integrations &amp; Plugins roadmap initiative</a>, enabling more flexible bot-powered workflows and custom API endpoints.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="fhir-operations-and-terminology">FHIR Operations and Terminology<a href="https://www.medplum.com.ar/blog/january-2026-update#fhir-operations-and-terminology" class="hash-link" aria-label="Direct link to FHIR Operations and Terminology" title="Direct link to FHIR Operations and Terminology" translate="no">​</a></h3>
<p><img src="https://github.com/deam65.png" alt="Darren Eam" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/deam65" target="_blank" rel="noopener noreferrer" class="">Darren Eam</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/patient-summary">Patient <code>$summary</code> operation</a></strong> with updated <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/patient-everything"><code>$everything</code> documentation</a></li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/conceptmap-import">ConceptMap import</a></strong> and comprehensive <a class="" href="https://www.medplum.com.ar/docs/terminology">terminology operations documentation</a></li>
<li class="">New <strong><a class="" href="https://www.medplum.com.ar/docs/auth">authentication and security operations</a></strong> and <strong><a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/validate-a-resource">resource validation operations</a></strong></li>
</ul>
<p><img src="https://github.com/mattwiller.png" alt="Matt Willer" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a></strong></p>
<ul>
<li class=""><strong>X-FHIR-Query support in <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/extract">SDC <code>$extract</code></a></strong> — enables dynamic queries in <a class="" href="https://www.medplum.com.ar/docs/questionnaires/parsing-questionnaire-responses">Structured Data Capture</a> extraction, improving form-based data capture workflows</li>
<li class=""><strong>Display language overrides</strong> in <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/valueset-expand"><code>ValueSet/$expand</code></a> and <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/codesystem-validate-code"><code>CodeSystem/$validate-code</code></a> — supports multilingual <a class="" href="https://www.medplum.com.ar/docs/terminology">terminology services</a>, which is important for international deployments</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="site-reliability-and-infrastructure">Site Reliability and Infrastructure<a href="https://www.medplum.com.ar/blog/january-2026-update#site-reliability-and-infrastructure" class="hash-link" aria-label="Direct link to Site Reliability and Infrastructure" title="Direct link to Site Reliability and Infrastructure" translate="no">​</a></h3>
<p>These changes support the <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">Enterprise Scale &amp; Infrastructure roadmap priority</a> of handling growing platform traffic.</p>
<p><img src="https://github.com/mattwiller.png" alt="Matt Willer" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a></strong></p>
<ul>
<li class=""><strong>Reserved database connections for healthcheck</strong> — prevents health checks from being starved during high load</li>
<li class=""><strong>Redis failover error handling</strong> in BullMQ workers — improves resilience during Redis cluster failovers</li>
<li class=""><strong>Skip caching on write for <a class="" href="https://www.medplum.com.ar/docs/api/fhir/resources/auditevent">AuditEvent</a> resources</strong> — reduces memory pressure for high-volume audit logging</li>
<li class=""><strong>Tracing extensions on OperationOutcome</strong> — better observability for debugging production issues</li>
</ul>
<p><img src="https://github.com/mattlong.png" alt="Matt Long" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/mattlong" target="_blank" rel="noopener noreferrer" class="">Matt Long</a></strong></p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/self-hosting/super-admin-guide">ReindexJob</a> configuration enhancements</strong> — more control over reindexing for large datasets</li>
<li class=""><strong>Per-resourceType padding configuration</strong> — fine-grained tuning of array padding for storage optimization</li>
<li class=""><strong>Array padding calculator</strong> — tooling to help determine optimal padding settings</li>
</ul>
<p><img src="https://github.com/noahsilas.png" alt="Noah Silas" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a></strong></p>
<ul>
<li class=""><strong>Automatic pre/post deploy migration generation</strong> — streamlines the database migration workflow for <a class="" href="https://www.medplum.com.ar/docs/self-hosting">self-hosted deployments</a></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="security-and-access-control">Security and Access Control<a href="https://www.medplum.com.ar/blog/january-2026-update#security-and-access-control" class="hash-link" aria-label="Direct link to Security and Access Control" title="Direct link to Security and Access Control" translate="no">​</a></h3>
<ul>
<li class=""><strong>Inactive ProjectMembership disables access tokens</strong> — when a membership is set to inactive, associated tokens are immediately invalidated (<a class="" href="https://www.medplum.com.ar/docs/access/access-policies">access control docs</a>) (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/subscriptions">Subscription</a> Bot execution respects ProjectMembership</strong> — ensures subscriptions run in the correct membership context (<a href="https://github.com/mattwiller" target="_blank" rel="noopener noreferrer" class="">Matt Willer</a>)</li>
<li class=""><strong>On-behalf-of header support</strong> with proper cache disabling (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>, <a href="https://github.com/codyebberson" target="_blank" rel="noopener noreferrer" class="">Cody Ebberson</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="sdk-and-developer-experience">SDK and Developer Experience<a href="https://www.medplum.com.ar/blog/january-2026-update#sdk-and-developer-experience" class="hash-link" aria-label="Direct link to SDK and Developer Experience" title="Direct link to SDK and Developer Experience" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>client.post&lt;T&gt;</code> generic type annotation</strong> for better TypeScript ergonomics (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong>Nested connections in <a class="" href="https://www.medplum.com.ar/docs/graphql">GraphQL</a></strong> (<a href="https://github.com/maddyli" target="_blank" rel="noopener noreferrer" class="">Maddy Li</a>)</li>
<li class=""><strong>Configurable base64 caps</strong> in core (<a href="https://github.com/syp1xd" target="_blank" rel="noopener noreferrer" class="">Sakshum Gadyal</a>)</li>
<li class=""><strong>Abort signal support for <code>sleep</code></strong> to allow request cancellation (<a href="https://github.com/mirza-kapetanovic" target="_blank" rel="noopener noreferrer" class="">Mirza Kapetanovic</a>)</li>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/subscriptions">Subscription</a> AuditEvent destination extension</strong> for routing audit events (<a href="https://github.com/rahul1" target="_blank" rel="noopener noreferrer" class="">Rahul Agarwal</a>)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="ai-and-mcp">AI and MCP<a href="https://www.medplum.com.ar/blog/january-2026-update#ai-and-mcp" class="hash-link" aria-label="Direct link to AI and MCP" title="Direct link to AI and MCP" translate="no">​</a></h3>
<p>Advancing our <a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">AI roadmap initiative</a>:</p>
<ul>
<li class=""><strong><a class="" href="https://www.medplum.com.ar/docs/ai/mcp">MCP server</a> updated</strong> to replace deprecated methods, keeping Medplum's Model Context Protocol support current (<a href="https://github.com/noahsilas" target="_blank" rel="noopener noreferrer" class="">Noah Silas</a>)</li>
<li class=""><strong>AI operation documentation</strong> added (<a class="" href="https://www.medplum.com.ar/docs/ai/ai-operation">AI operation docs</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="documentation">Documentation<a href="https://www.medplum.com.ar/blog/january-2026-update#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation" translate="no">​</a></h2>
<p>A significant documentation effort this month improved coverage across the Provider app, scheduling, self-hosting, the Medplum Agent, and compliance.</p>
<p><strong>Provider</strong></p>
<ul>
<li class="">Provider app docs updated (<a class="" href="https://www.medplum.com.ar/docs/provider">Provider app guide</a>)</li>
<li class="">Updated <a class="" href="https://www.medplum.com.ar/docs/charting">charting documentation</a></li>
</ul>
<p><img src="https://github.com/finnbergquist.png" alt="Finn Bergquist" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/finnbergquist" target="_blank" rel="noopener noreferrer" class="">Finn Bergquist</a></strong></p>
<ul>
<li class=""><strong>Revamped multi-tenancy documentation</strong> (<a class="" href="https://www.medplum.com.ar/docs/auth/domain-level-identity-providers">multi-tenancy identity providers</a>)</li>
<li class=""><strong>Scheduling docs</strong>: availability time zones, <code>$find</code> beta status, <code>SchedulingParameters</code> duration param (<a class="" href="https://www.medplum.com.ar/docs/scheduling">scheduling docs</a>)</li>
<li class=""><strong>DoseSpot enrollment documentation</strong>: how to enroll users with the Enroll Prescriber Bot (<a class="" href="https://www.medplum.com.ar/docs/medications">medications docs</a>)</li>
<li class=""><strong>AccessPolicy requirements for Bulk Export API</strong> (<a class="" href="https://www.medplum.com.ar/docs/api">API docs</a>)</li>
<li class=""><strong>Observation.valueSampledData</strong> documentation</li>
</ul>
<p><strong>Self-Hosting and Operations</strong></p>
<ul>
<li class="">Self-hosting best practices docs (<a class="" href="https://www.medplum.com.ar/docs/self-hosting">self-hosting guide</a>)</li>
<li class="">AWS Lambda bots on localhost guide (<a class="" href="https://www.medplum.com.ar/docs/bots">Bots docs</a>)</li>
<li class="">Node.js version requirement updated to 22+ (<a class="" href="https://www.medplum.com.ar/docs/self-hosting">self-hosting guide</a>)</li>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/self-hosting/running-full-medplum-stack-in-docker">Docker Compose</a> persistence and restart policies improved</li>
</ul>
<p><strong>Medplum Agent</strong></p>
<p><img src="https://github.com/ThatOneBro.png" alt="Derrick Farris" width="50" height="50" style="border-radius:50%"> <strong><a href="https://github.com/ThatOneBro" target="_blank" rel="noopener noreferrer" class="">Derrick Farris</a></strong></p>
<p>The <a class="" href="https://www.medplum.com.ar/docs/agent">Medplum Agent</a> is an application that runs inside your firewall and connects to devices over low-level protocols such as HL7/MLLP, ASTM, and DICOM, bridging them to the cloud via secure HTTPS WebSocket channels. This month the Agent docs received several updates:</p>
<ul>
<li class="">Minimal <a class="" href="https://www.medplum.com.ar/docs/agent/access-policy">access policy for Agent</a> documented</li>
<li class="">Enhanced mode <a class="" href="https://www.medplum.com.ar/docs/agent/acknowledgement-modes"><code>aaMode</code></a> documented</li>
<li class="">Section on deactivating memberships added</li>
</ul>
<p><strong>Additional Docs</strong></p>
<ul>
<li class="">Integration tables organized into logical groups (<a class="" href="https://www.medplum.com.ar/docs/integration">integrations overview</a>)</li>
<li class="">Terminology services: translated display strings documentation (<a class="" href="https://www.medplum.com.ar/docs/terminology">terminology services guide</a>)</li>
<li class="">Compliance documentation and CHPL listing updated for V5 (<a class="" href="https://www.medplum.com.ar/docs/compliance">compliance overview</a>)</li>
<li class="">2026 Roadmap published (<a class="" href="https://www.medplum.com.ar/blog/2026-roadmap">2026 roadmap</a>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="bug-fixes">Bug Fixes<a href="https://www.medplum.com.ar/blog/january-2026-update#bug-fixes" class="hash-link" aria-label="Direct link to Bug Fixes" title="Direct link to Bug Fixes" translate="no">​</a></h2>
<p><strong>Forms and UI</strong></p>
<ul>
<li class="">Fixed repeatable items in <a class="" href="https://www.medplum.com.ar/docs/questionnaires"><code>QuestionnaireForm</code></a></li>
<li class="">Fixed dark mode on the visit details page</li>
<li class="">Fixed color inheritance issue (dark to inherit)</li>
<li class="">Updated diagnoses binding URL in OrderLabsPage</li>
</ul>
<p><strong>Server and API</strong></p>
<ul>
<li class="">Fixed SQL error in date array search parameters</li>
<li class="">Fixed search by POST issue via body-parser update</li>
<li class="">Fixed CCDA timezone offset conversion to FHIR format (<a href="https://github.com/amcgivern" target="_blank" rel="noopener noreferrer" class="">Amanda McGivern</a>)</li>
<li class="">Fixed <code>validateResource</code> argument merging</li>
<li class="">Fixed consistent <code>storageBaseUrl</code> generation with <code>/binary/</code> path (<a href="https://github.com/jfiorato" target="_blank" rel="noopener noreferrer" class="">Jim Fiorato</a>)</li>
<li class="">Fixed out-of-order query results in <code>useSearch</code></li>
<li class="">Fixed too-many-requests error re-wrapping in <code>fetchTokens</code></li>
</ul>
<p><strong>Agent</strong></p>
<ul>
<li class=""><a class="" href="https://www.medplum.com.ar/docs/agent/push"><code>pushToAgent</code></a> now returns on first ACK by default</li>
<li class="">Added logging for <a class="" href="https://www.medplum.com.ar/docs/agent/acknowledgement-modes">enhanced mode</a> acknowledgments</li>
</ul>
<p><strong>Infrastructure</strong></p>
<ul>
<li class="">Fixed <a class="" href="https://www.medplum.com.ar/docs/self-hosting/running-full-medplum-stack-in-docker">Docker Compose</a> full-stack config after hardened images</li>
<li class="">Added persistence to <a class="" href="https://www.medplum.com.ar/docs/self-hosting/running-full-medplum-stack-in-docker">Docker Compose</a> files (<a href="https://github.com/mraspberry-uai" target="_blank" rel="noopener noreferrer" class="">Matthew Raspberry</a>)</li>
<li class="">Fixed database connection release during seeding</li>
<li class="">Fixed Spaces message persistence</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="releases">Releases<a href="https://www.medplum.com.ar/blog/january-2026-update#releases" class="hash-link" aria-label="Direct link to Releases" title="Direct link to Releases" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.0.11" target="_blank" rel="noopener noreferrer" class=""><strong>v5.0.11</strong></a> — January 21</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.0.12" target="_blank" rel="noopener noreferrer" class=""><strong>v5.0.12</strong></a> — January 23</li>
<li class=""><a href="https://github.com/medplum/medplum/releases/tag/v5.0.13" target="_blank" rel="noopener noreferrer" class=""><strong>v5.0.13</strong></a> — January 28</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="looking-ahead">Looking Ahead<a href="https://www.medplum.com.ar/blog/january-2026-update#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>January's scheduling work sets the stage for the self-scheduling and resource scheduling features planned for 2026. The Provider app's Spaces and streaming capabilities are moving us closer to a production-ready provider experience. On the infrastructure side, the Redis failover handling and database connection improvements directly support enterprise-scale deployments.</p>
<p>Join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to share feedback or follow along on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="monthly-update" term="monthly-update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum 2026 Roadmap]]></title>
        <id>https://www.medplum.com.ar/blog/2026-roadmap</id>
        <link href="https://www.medplum.com.ar/blog/2026-roadmap"/>
        <updated>2026-01-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As we kick off 2026, we're excited to share Medplum's vision for the year ahead. Our open-source healthcare development platform has experienced substantial growth throughout 2025:]]></summary>
        <content type="html"><![CDATA[<p>As we kick off 2026, we're excited to share Medplum's vision for the year ahead. Our open-source healthcare development platform has experienced substantial growth throughout 2025:</p>
<!-- -->
<p>As of December 2025:</p>
<ul>
<li class="">500,000+ Docker downloads (up 2x from 2024)</li>
<li class="">161 GitHub contributors (up 40% from 2024)</li>
<li class="">2,100 GitHub stars</li>
</ul>
<p>As informed by our community and customers, we are focusing on the following initiatives in 2026.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="compliance-h1-2026">Compliance (H1 2026)<a href="https://www.medplum.com.ar/blog/2026-roadmap#compliance-h1-2026" class="hash-link" aria-label="Direct link to Compliance (H1 2026)" title="Direct link to Compliance (H1 2026)" translate="no">​</a></h3>
<p>Medplum is pursuing <a class="" href="https://www.medplum.com.ar/docs/compliance/hitrust">HITRUST Certification</a> for our hosted environment. We are also certifying changes related to <a class="" href="https://www.medplum.com.ar/docs/compliance/hti-4">HTI-4/CMS-0057-F</a> to enable both providers and payers to comply with the mandate, with key milestones aligned to the January 2027 enforcement date.</p>
<p>These compliance primitives support hospital and health system connectivity and interoperability. The HTI-4 mandates are also important because they cover prior authorization for medications, professional billing, and facilities billing.</p>
<p><strong>Related Reading:</strong> 📋 <a class="" href="https://www.medplum.com.ar/docs/compliance">Compliance Overview</a>, 🛡️ <a class="" href="https://www.medplum.com.ar/docs/compliance/hitrust">HITRUST</a>, 🔒 <a class="" href="https://www.medplum.com.ar/docs/compliance/soc2">SOC2</a>, 🏥 <a class="" href="https://www.medplum.com.ar/docs/compliance/hipaa">HIPAA</a>, ✅ <a class="" href="https://www.medplum.com.ar/docs/compliance/onc">ONC Certification</a>, 🔗 <a class="" href="https://www.medplum.com.ar/blog/technical-guide-to-tefca">TEFCA Overview</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="enterprise-scale--infrastructure">Enterprise Scale &amp; Infrastructure<a href="https://www.medplum.com.ar/blog/2026-roadmap#enterprise-scale--infrastructure" class="hash-link" aria-label="Direct link to Enterprise Scale &amp; Infrastructure" title="Direct link to Enterprise Scale &amp; Infrastructure" translate="no">​</a></h3>
<p>Platform traffic on Medplum is growing quickly, and we are investing in several initiatives to achieve scale. We are implementing sharding and archiving capabilities to handle larger datasets efficiently. Data warehouse integration via Kafka will support high volume connections. We are also enhancing cross-cloud support for GCP, Azure, and AWS deployments.</p>
<p><strong>Related Reading:</strong> 🏠 <a class="" href="https://www.medplum.com.ar/docs/self-hosting">Self-Hosting Overview</a>, 🗂️ <a href="https://github.com/medplum/medplum/discussions/6026" target="_blank" rel="noopener noreferrer" class="">Sharding Discussion</a>, ☁️ <a class="" href="https://www.medplum.com.ar/docs/self-hosting/install-on-aws">Install on AWS</a>, 🌐 <a class="" href="https://www.medplum.com.ar/docs/self-hosting/install-on-gcp">Install on GCP</a>, 🔷 <a class="" href="https://www.medplum.com.ar/docs/self-hosting/install-on-azure">Install on Azure</a>, 📊 <a class="" href="https://www.medplum.com.ar/docs/analytics">Analytics</a>, 📈 <a class="" href="https://www.medplum.com.ar/docs/self-hosting/aws-athena-guide">AWS Athena Guide</a>, 🎬 <a href="https://youtu.be/0ewuLinTDYQ" target="_blank" rel="noopener noreferrer" class="">PlumCon Scaling to Millions of Patients</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="scheduling">Scheduling<a href="https://www.medplum.com.ar/blog/2026-roadmap#scheduling" class="hash-link" aria-label="Direct link to Scheduling" title="Direct link to Scheduling" translate="no">​</a></h3>
<p>Scheduling is key to healthcare workflows, and we are investing heavily in making it great for a wide variety of use cases. This includes self-scheduling, advanced availability management, facilities scheduling, and resource scheduling.</p>
<p><strong>Related Reading:</strong> 📅 <a class="" href="https://www.medplum.com.ar/docs/scheduling">Scheduling Overview</a>, ⏰ <a class="" href="https://www.medplum.com.ar/docs/scheduling/defining-availability">Defining Availability</a>, 🗓️ <a class="" href="https://www.medplum.com.ar/products/scheduling">Scheduling Product</a>, 🤖 <a class="" href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai">Scheduling Agents for Healthcare Operations</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="provider-application">Provider Application<a href="https://www.medplum.com.ar/blog/2026-roadmap#provider-application" class="hash-link" aria-label="Direct link to Provider Application" title="Direct link to Provider Application" translate="no">​</a></h3>
<p>Medplum has a provider experience that is ONC certified as a base EHR. We will make investments this year to expand the available workflows and integrations. We are also improving the onboarding experience for new practices to get up and running quickly.</p>
<p><strong>Related Reading:</strong> 👨‍⚕️ <a class="" href="https://www.medplum.com.ar/docs/provider">Provider Overview</a>, ⚙️ <a class="" href="https://www.medplum.com.ar/docs/provider/getting-started">Provider Setup</a>, 📝 <a class="" href="https://www.medplum.com.ar/docs/charting">Charting</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="integrations--plugins">Integrations &amp; Plugins<a href="https://www.medplum.com.ar/blog/2026-roadmap#integrations--plugins" class="hash-link" aria-label="Direct link to Integrations &amp; Plugins" title="Direct link to Integrations &amp; Plugins" translate="no">​</a></h3>
<p>We are building a plugin ecosystem to give you access to a wide variety of tools that work with your workflow. We are also enhancing the prescribing experience with improved safety features and HTI-4 compliance.</p>
<p><strong>Related Reading:</strong> 🤖 <a class="" href="https://www.medplum.com.ar/docs/bots">Bots Overview</a>, 📚 <a class="" href="https://www.medplum.com.ar/docs/bots/bot-basics">Bot Basics</a>, 💊 <a class="" href="https://www.medplum.com.ar/docs/medications/e-prescibe">ePrescribe</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="revenue-cycle--billing">Revenue Cycle &amp; Billing<a href="https://www.medplum.com.ar/blog/2026-roadmap#revenue-cycle--billing" class="hash-link" aria-label="Direct link to Revenue Cycle &amp; Billing" title="Direct link to Revenue Cycle &amp; Billing" translate="no">​</a></h3>
<p>We are enabling developers to build high fidelity revenue cycle management solutions. We are also streamlining prior authorization workflows to reduce administrative burden in accordance with the upcoming regulations in HTI-4.</p>
<p><strong>Related Reading:</strong> 💰 <a class="" href="https://www.medplum.com.ar/docs/billing">Billing Overview</a>, 🏦 <a class="" href="https://www.medplum.com.ar/docs/billing/patient-insurance">Patient Insurance</a>, ✅ <a class="" href="https://www.medplum.com.ar/docs/billing/insurance-eligibility-checks">Insurance Eligibility Checks</a>, 📄 <a class="" href="https://www.medplum.com.ar/docs/billing/creating-cms1500">Creating CMS1500</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="ai">AI<a href="https://www.medplum.com.ar/blog/2026-roadmap#ai" class="hash-link" aria-label="Direct link to AI" title="Direct link to AI" translate="no">​</a></h3>
<p>Medplum continues to be a destination for builders who are making incredible AI applications. We will make continued investments to our AI infrastructure such as MCP, SSE, websockets, and composable model configurations that will power the next generation of models, copilots, scribes, and more.</p>
<p><strong>Related Reading:</strong> 🧠 <a class="" href="https://www.medplum.com.ar/docs/ai">AI Overview</a>, 🔌 <a class="" href="https://www.medplum.com.ar/blog/unlocking-healthcare-ai-medplum-support-mcp">MCP Support</a>, 🩻 <a class="" href="https://www.medplum.com.ar/blog/radai-case-study">Rad AI Case Study</a>, 👶 <a class="" href="https://www.medplum.com.ar/blog/summer-case-study">Summer Health Case Study</a>, 📡 <a class="" href="https://www.medplum.com.ar/docs/fhircast">FHIRcast</a>, ⚡ <a class="" href="https://www.medplum.com.ar/docs/bots/consuming-webhooks">Async Bots and SSE</a></p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="key-themes-for-2026">Key Themes for 2026<a href="https://www.medplum.com.ar/blog/2026-roadmap#key-themes-for-2026" class="hash-link" aria-label="Direct link to Key Themes for 2026" title="Direct link to Key Themes for 2026" translate="no">​</a></h3>
<p>To summarize, our 2026 priorities center around three key themes:</p>
<ol>
<li class=""><strong>Regulatory Readiness</strong> - HITRUST certification and HTI-4 compliance to meet upcoming mandates</li>
<li class=""><strong>Scale &amp; Performance</strong> - Infrastructure investments to support enterprise-grade deployments</li>
<li class=""><strong>Developer Experience</strong> - Enhanced scheduling, billing, AI tooling, and plugins to accelerate development</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="join-the-movement">Join the Movement<a href="https://www.medplum.com.ar/blog/2026-roadmap#join-the-movement" class="hash-link" aria-label="Direct link to Join the Movement" title="Direct link to Join the Movement" translate="no">​</a></h3>
<p>2026 will be a transformative year for healthcare technology, and Medplum is leading the charge. Whether you're a developer, healthcare provider, or innovator, there's never been a better time to join our growing community.</p>
<p>Stay tuned for more updates, and join us on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> to be part of the conversation. We share quarterly progress updates and actively incorporate community feedback into our prioritization process. Your input directly shapes where we invest next.</p>]]></content>
        <author>
            <name>Cody Ebberson</name>
            <uri>https://github.com/codyebberson</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum Year in Review 2025]]></title>
        <id>https://www.medplum.com.ar/blog/2025-year-in-review-medplum</id>
        <link href="https://www.medplum.com.ar/blog/2025-year-in-review-medplum"/>
        <updated>2025-12-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[2025 in Review]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="2025 in Review" src="https://www.medplum.com.ar/assets/images/2025-in-review-6d8ddeed047fb6dccdc8cc3d39ee8a11.png" width="2400" height="3936" class="img__Ss2"></p>
<p>An incredible year of growth, innovation, and community. From v5 release to expanding our developer ecosystem, 2025 marked several milestones for Medplum's open-source healthcare platform.</p>
<!-- -->
<p>As we close out 2025, the Medplum team would love to thank our community and customers for joining us on this journey.</p>
<p>We wanted to highlight a few memorable moments and reflect on all that happened during the year. It was a lot of fun, and huge thank you to the team who pushed so hard to make all these things happen.</p>
<p>✅ Released <strong><a class="" href="https://www.medplum.com.ar/blog/v5-release">Medplum v5</a></strong>, our most significant platform modernization to date, featuring full FHIR terminology validation, GraphQL Patch support, and comprehensive dependency upgrades to Node.js 22/24, PostgreSQL 14/18, and React 19</p>
<p>✅ Launched our <strong>new brand identity</strong>, reflecting our evolution as a leading open-source healthcare infrastructure platform.  See the details <a href="https://www.medplum.com.ar/brand" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<p>✅ Hosted our first annual developer conference <strong><a class="" href="https://www.medplum.com.ar/blog/plumcon-2025-materials">PlumCon 2025</a></strong> in San Francisco, bringing together healthcare innovators from around the world</p>
<p>✅ Delivered <strong>many new features and integrations</strong>, including enhanced AI capabilities with <a class="" href="https://www.medplum.com.ar/blog/unlocking-healthcare-ai-medplum-support-mcp">MCP server support</a>, <a class="" href="https://www.medplum.com.ar/blog/custom-fhir-operations">custom FHIR operations</a>, <a class="" href="https://www.medplum.com.ar/blog/ihe-ira-radiology-reporting">IHE IRA radiology reporting certification</a>, and expanded integrations with health information exchange, medications, and revenue cycle.</p>
<p>✅ A special thank you to those who contributed this year - we now have <strong>157 talented contributors</strong> from around the world building the future of healthcare together</p>
<p>✅ Incredible ecosystem growth: <strong>1,462 pull requests</strong>, <strong>55 releases</strong>, <strong>551 issues resolved</strong>, <strong>2.1K GitHub stars</strong>, and <strong>500K+ Docker downloads</strong> powering healthcare applications globally</p>
<p>✅ Added many wonderful customers, and several have made videos of their implementations. See <a href="https://www.medplum.com.ar/case-studies" target="_blank" rel="noopener noreferrer" class="">case studies</a> and <a class="" href="https://www.medplum.com.ar/blog/plumcon-2025-materials#demo-showcase">PlumCon recap</a> for videos.</p>
<p>✅ Organized <strong><a class="" href="https://www.medplum.com.ar/blog/events-calendar">several events</a></strong> throughout this year, including <a class="" href="https://www.medplum.com.ar/blog/fhir-ai-for-life-sciences">FHIR + AI for Life Sciences</a>, <a class="" href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai">Scheduling Agents for Healthcare Operations</a>, and <a href="https://youtu.be/QvC093fAGGU" target="_blank" rel="noopener noreferrer" class="">Visualizing Patient Flow</a>, building our community of healthcare developers</p>
<p>Thank you, dear reader, for being part of our community. See you <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">on Discord</a>.</p>]]></content>
        <author>
            <name>Reshma Khilnani</name>
            <uri>https://github.com/reshmakh</uri>
        </author>
        <category label="integration" term="integration"/>
        <category label="fhir-datastore" term="fhir-datastore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Terminology Service Updates in Medplum v5]]></title>
        <id>https://www.medplum.com.ar/blog/v5-terminology</id>
        <link href="https://www.medplum.com.ar/blog/v5-terminology"/>
        <updated>2025-11-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As part of the Medplum v5 release, we've been hard at work delivering several key improvements to our]]></summary>
        <content type="html"><![CDATA[<p>As part of the <a class="" href="https://www.medplum.com.ar/blog/v5-release">Medplum v5 release</a>, we've been hard at work delivering several key improvements to our
<a href="https://hl7.org/fhir/R4/terminology-service.html" target="_blank" rel="noopener noreferrer" class="">FHIR Terminology Services</a>, which power Medplum's rich features for handling coded values:</p>
<ul>
<li class=""><a href="https://github.com/medplum/medplum/pull/7151" target="_blank" rel="noopener noreferrer" class="">Supporting synonyms</a> in <code>ValueSet/$expand</code>, allowing users to find codes by a number of different search terms</li>
<li class=""><a href="https://github.com/medplum/medplum/pull/7579" target="_blank" rel="noopener noreferrer" class="">Scaling our implementation</a> of the <code>ConceptMap/$translate</code> operation to handle maps with over a million entries</li>
<li class="">Updating our library of UMLS code systems with their <a href="https://www.nlm.nih.gov/research/umls/knowledge_sources/metathesaurus/release/notes.html" target="_blank" rel="noopener noreferrer" class="">latest release</a>, including several new code
systems around medications and supplements and a mapping between related code systems and RxNorm</li>
<li class="">A collection of <a href="https://github.com/medplum/medplum/pull/7010" target="_blank" rel="noopener noreferrer" class="">performance enhancements</a> that <a href="https://github.com/medplum/medplum/pull/7570" target="_blank" rel="noopener noreferrer" class="">speed up ValueSet expansion</a> and
<a href="https://github.com/medplum/medplum/pull/7571" target="_blank" rel="noopener noreferrer" class="">code validation</a> by a significant margin</li>
<li class="">(In beta) The option to <a href="https://github.com/medplum/medplum/pull/7666" target="_blank" rel="noopener noreferrer" class="">validate all required terminology bindings</a> in resources on write</li>
</ul>
<p>Below we'll discuss each of these changes in more detail and give examples of the features available in
Medplum's Terminology Services today.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="coding-synonyms">Coding Synonyms<a href="https://www.medplum.com.ar/blog/v5-terminology#coding-synonyms" class="hash-link" aria-label="Direct link to Coding Synonyms" title="Direct link to Coding Synonyms" translate="no">​</a></h2>
<p>Many codes are known by multiple different related names or terms, and users may use different search terms in different
contexts when trying to find the right code for a clinical concept. For example, consider a provider populating
information about a patient allergy, who wants to fill in the <a href="https://hl7.org/fhir/R4/allergyintolerance-definitions.html#AllergyIntolerance.reaction.manifestation" target="_blank" rel="noopener noreferrer" class=""><code>AllergyIntolerance.reaction.manifestation</code> field</a>
with the SNOMED CT® code for hives using the <a href="https://hl7.org/fhir/R4/valueset-clinical-findings.html" target="_blank" rel="noopener noreferrer" class="">Clinical Findings ValueSet</a>. The relevant code in
SNOMED is <code>247472004</code>, but its display string is "Wheal (finding)" — not "hives"! If the user doesn't know the more
technical term, finding the correct code would be difficult.</p>
<p>Fortunately, most code systems record multiple names (synonyms) for their codes. These are stored as metadata properties
on the coding, which can be seen by <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/codesystem-lookup">looking up the code</a>:</p>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"resourceType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Parameters"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"parameter"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"name"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SNOMED CT (US Edition)"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"display"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Wheal (finding)"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"property"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hives"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"property"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Urticarial rash"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"property"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Welt"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"property"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Weal"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"property"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueString"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Nettle rash"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Medplum now supports searching against these synonyms in addition to the primary display string when searching with the
<code>filter</code> parameter of the <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/valueset-expand"><code>ValueSet/$expand</code> operation</a>. Specifically, any coding properties with a
special <a href="https://hl7.org/fhir/R4/codesystem-definitions.html#CodeSystem.property.uri" target="_blank" rel="noopener noreferrer" class=""><code>uri</code> value</a> of <code>http://hl7.org/fhir/concept-properties#synonym</code> will be indexed for search as a
synonym for the given code. The <code>SY</code> property shown above is defined in the corresponding <code>CodeSystem</code> resource:</p>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SY"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"description"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Designated synonym"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Properties with this `uri` will have their values included when searching for codes</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"uri"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://hl7.org/fhir/concept-properties#synonym"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>You can see the feature working as intended below, using Medplum's <a href="https://storybook.medplum.com.ar/?path=/story/medplum-codeableconceptinput--basic" target="_blank" rel="noopener noreferrer" class=""><code>&lt;CodeableConceptInput&gt;</code> React component</a>:</p>
<p><img decoding="async" loading="lazy" alt="A user types &amp;quot;hives&amp;quot; into a search field, and the corresponding SNOMED code is displayed" src="https://www.medplum.com.ar/assets/images/hives-synonym-34d2fa076706ddb778416f1619ca017f.gif" width="1854" height="894" class="img__Ss2"></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="scalable-concept-mapping">Scalable Concept Mapping<a href="https://www.medplum.com.ar/blog/v5-terminology#scalable-concept-mapping" class="hash-link" aria-label="Direct link to Scalable Concept Mapping" title="Direct link to Scalable Concept Mapping" translate="no">​</a></h2>
<p>Some of the largest code systems in common clinical use contain hundreds of thousands of different codes, and mappings
between them also operate on that scale. Our existing implementation of the <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/conceptmap-translate"><code>ConceptMap/$translate</code></a>
operation relied on the data present inside the <code>ConceptMap</code> JSON, which limited the number of mappings that could
be supported to the amount that would fit in a single resource.</p>
<p>To enable large mappings between complex code systems, we rebuilt our system for handling <code>ConceptMap</code> resources from
the ground up. Existing mappings contained in the resource JSON were indexed into an optimized lookup table, and we
added a new <code>ConceptMap/$import</code> endpoint similar to the <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/codesystem-import">one for CodeSystems</a> to facilitate loading
maps with a million entries or more into the system.</p>
<p>For example, we can query a large map of drugs from many different code systems to get their corresponding RxNorm code:</p>
<div class="language-bash codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-bash codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token plain">$ curl -H "Authorization: Bearer $ACCESS_TOKEN" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  'https://api.medplum.com.ar/fhir/R4/ConceptMap/$translate?url=$RXNORM&amp;system=http://snomed.info/sct&amp;code=9500005'</span><br></div></code></pre></div></div>
<div class="language-json codeBlockContainer_ZGJx theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_kX1v"><pre tabindex="0" class="prism-code language-json codeBlock_TAPP thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AdAo"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"resourceType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Parameters"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"parameter"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"result"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueBoolean"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"match"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"part"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"equivalence"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"valueCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"equivalent"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"concept"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token property" style="color:#36acaa">"valueCoding"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"system"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://www.nlm.nih.gov/research/umls/rxnorm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"code"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8123"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Our Postgres database is able to serve translations like this robustly, with a typical request executing in just
10 – 50 ms on our server! The ability to convert codes efficiently from one system to another is expected to be a
foundational capability for supporting cross-coding and partner integrations at scale in the future.</p>
<p>This development paves the way for us to support complex mappings between large, commonly-used code systems. Next on our
roadmap for this feature is to ingest the entire <a href="https://www.nlm.nih.gov/research/umls/mapping_projects/snomedct_to_icd10cm.html" target="_blank" rel="noopener noreferrer" class="">SNOMED to ICD-10</a> mapping and make it available to
customers for testing. This map is both large (~250,000 entries) and complex, containing dependency requirements and
descriptive notes that ensure codes are mapped correctly in context.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="updated-umls-library-with-2025aa-release">Updated UMLS Library with 2025AA Release<a href="https://www.medplum.com.ar/blog/v5-terminology#updated-umls-library-with-2025aa-release" class="hash-link" aria-label="Direct link to Updated UMLS Library with 2025AA Release" title="Direct link to Updated UMLS Library with 2025AA Release" translate="no">​</a></h2>
<p>Medplum maintains a library of full code systems imported from the semiannual <a href="https://www.nlm.nih.gov/research/umls/knowledge_sources/metathesaurus/release/notes.html" target="_blank" rel="noopener noreferrer" class="">UMLS releases</a>, which
includes several widely-used systems like SNOMED CT, ICD-10, and LOINC. We've created an updated version of the library
from the latest release (2025AA), containing over 10,000 new codes and several new code systems:</p>
<ul>
<li class=""><a href="http://www.fdbhealth.com/fdb-medknowledge/" target="_blank" rel="noopener noreferrer" class="">FDB MedKnowledge</a></li>
<li class=""><a href="https://www.elsevier.com/solutions/drug-database" target="_blank" rel="noopener noreferrer" class="">Gold Standard Drug Database</a></li>
<li class=""><a href="http://www.fda.gov/ForIndustry/DataStandards/StructuredProductLabeling/default.htm" target="_blank" rel="noopener noreferrer" class="">FDA Structured Product Labels</a> for drugs and active substances</li>
<li class=""><a href="https://www2a.cdc.gov/vaccines/iis/iisstandards/vaccines.asp?rpt=mvx" target="_blank" rel="noopener noreferrer" class="">Manufacturers of Vaccines</a></li>
<li class=""><a href="https://www.nlm.nih.gov/mesh/" target="_blank" rel="noopener noreferrer" class="">Medical Subject Headings (MeSH)</a></li>
</ul>
<p>In tandem with the updates to scale <code>ConceptMap/$translate</code> described above, the mapping of several
<a href="https://www.nlm.nih.gov/research/umls/rxnorm/docs/techdoc.html#s3_1" target="_blank" rel="noopener noreferrer" class="">medication terminologies to RxNorm</a> was extracted from the UMLS data set. This ConceptMap,
containing about a quarter million mappings, was used as the foundation of our testing for the changes to <code>ConceptMap</code>.
The following code systems are currently mapped in whole or part to RxNorm via this resource:</p>
<ul>
<li class="">CVX (vaccines)</li>
<li class="">Gold Standard (drugs)</li>
<li class="">MeSH (drugs and substances subset)</li>
<li class="">FDA Structured Product Labels (drugs)</li>
<li class="">FDB MedKnowledge (drugs)</li>
<li class="">SNOMED CT (drugs subset)</li>
</ul>
<p>Contact <a href="mailto:support@medplum.com.ar" target="_blank" rel="noopener noreferrer" class="">support@medplum.com.ar</a> for access to the updated 2025AA release resources, in either
our hosted cluster or your own self-hosted install.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="valueset-performance-improvements">ValueSet Performance Improvements<a href="https://www.medplum.com.ar/blog/v5-terminology#valueset-performance-improvements" class="hash-link" aria-label="Direct link to ValueSet Performance Improvements" title="Direct link to ValueSet Performance Improvements" translate="no">​</a></h2>
<p>Expanding a ValueSet to find matching codes is the most common terminology operation on Medplum: every time a user
uses an autocomplete to fill in a coded value, the relevant ValueSet definition is being queried and filtered to provide
them with a list of matching options. However, the database queries to power the autocomplete expansion can and often
do contain complicated recursive joins in combination with text filters to find all the correct codes. While working on
some of the other features listed here, we noticed a few ways to improve the relevant SQL queries. We were able to
significantly boost performance across multiple terminology operations by combining a few different optimizations:</p>
<ol>
<li class="">Improving index usage for text filters</li>
<li class="">Updating indexes on coding properties</li>
<li class="">Preloading property IDs to eliminate a JOIN</li>
</ol>
<p>By replacing conditions of the form <code>LOWER(display) LIKE '%filtertext%'</code> with the equivalent <code>display ILIKE '%filtertext%'</code>,
we enabled better use of existing indexes in our lookup tables and made text search in <code>ValueSet/$expand</code> more efficient.</p>
<p>Since many terminology queries also involve property metadata (for example, to determine whether one code is a child of
another), optimizing that part of our database queries had the potential to impact multiple different operations including
code validation. With a combination of minor changes to our query structure, and updates to our lookup table indexes,
we were able to make these queries up to 20x faster!</p>
<p>The effect these changes had was dramatic: the median latency for our <code>ValueSet/$expand</code> operation improved by 95%, as
shown below (endpoint latency in milliseconds):</p>
<p><strong>Before</strong></p>
<p><img decoding="async" loading="lazy" alt="Graph of endpoint latency with values around 450 ms" src="https://www.medplum.com.ar/assets/images/vs-expand-before-dc6fd8ee12e69bf12f0883afefc0d0dc.png" width="1636" height="822" class="img__Ss2"></p>
<p><strong>After</strong></p>
<p><img decoding="async" loading="lazy" alt="Graph of endpoint latency with values under 50 ms" src="https://www.medplum.com.ar/assets/images/vs-expand-after-288cc484d905600a31d45e4c02fd882b.png" width="1596" height="816" class="img__Ss2"></p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="terminology-validation">Terminology Validation<a href="https://www.medplum.com.ar/blog/v5-terminology#terminology-validation" class="hash-link" aria-label="Direct link to Terminology Validation" title="Direct link to Terminology Validation" translate="no">​</a></h2>
<p>Last but not least, we've finally unlocked a long-requested feature: validating all terminology requirements for
FHIR resources on write. Most resources contain some coded values, and the FHIR specification or a custom resource
profile can require that those values are drawn from a specific allowed set. Medplum server now includes the option to
check that any <code>required</code> <a href="https://hl7.org/fhir/R4/terminologies.html#binding" target="_blank" rel="noopener noreferrer" class="">terminology bindings</a> are satisfied in resources being written to the
server. Since this involves potentially tens of <a class="" href="https://www.medplum.com.ar/docs/api/fhir/operations/valueset-validate-code">validation queries</a> to the terminology service per
resource, all the performance work we did over the past few months was instrumental in making it possible.</p>
<p>By enabling the <code>validate-terminology</code> feature for your Project, you can opt into the new validation process. It
provides assurance that your data is fully compliant with the FHIR specification, and maximizes the interoperability of
data stored in Medplum. This does come with a small performance cost to perform the validation, but we will be
continuing to monitor and optimize this functionality in the coming months.</p>
<p>If you're interested in helping us test out terminology validation in your development or staging Project, contact
<a href="mailto:support@medplum.com.ar" target="_blank" rel="noopener noreferrer" class="">support@medplum.com.ar</a> to have the feature enabled. If you operate a self-hosted cluster,
you will need to upgrade to Medplum v5 before the feature will be available.</p>]]></content>
        <author>
            <name>Matt Willer</name>
            <uri>https://github.com/mattwiller</uri>
        </author>
        <category label="fhir-datastore" term="fhir-datastore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Scheduling Agents for Healthcare Operations: A Deep Dive with Unity AI]]></title>
        <id>https://www.medplum.com.ar/blog/scheduling-agents-unity-ai</id>
        <link href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai"/>
        <updated>2025-11-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Slideshow: View Presentation]]></summary>
        <content type="html"><![CDATA[<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo" title="Scheduling Agents for Healthcare Operations: A Deep Dive with Unity AI" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><em>Slideshow: <a href="https://drive.google.com/file/d/1t4h8IthpimQlayRz6j5lyOuuMpYFHT0b/view?usp=sharing" target="_blank" rel="noopener noreferrer" class="">View Presentation</a></em></p>
<p>This is a transcript summary of the October 2025 webinar with Medplum and Unity AI.  Medplum CEO Reshma Khilnani interviews Unity AI CTO <a href="https://www.unityai.co/about/our-team" target="_blank" rel="noopener noreferrer" class="">Cody Hall</a>.</p>
<p><strong>Reshma:</strong> We recently hosted a webinar exploring the intersection of AI, healthcare operations, and open-source infrastructure. I was joined by Cody Hall, CTO and Co-Founder of Unity AI, to discuss how his team is solving one of healthcare's <strong>most persistent bottlenecks</strong>: scheduling, using AI Agents.</p>
<!-- -->
<p><strong>Reshma:</strong> At Medplum, we often talk about the "terrible choice" healthcare developers face: invest heavily to build from scratch or fight with rigid, off-the-shelf software. Unity AI demonstrates <strong>a third path</strong>—building exceptional products on top of pre-built primitives. Here is a recap of how Unity AI is using Medplum and <code>FHIR</code> to coordinate scarce resources.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-core-problem-coordination-and-scarcity">The Core Problem: Coordination and Scarcity<a href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai#the-core-problem-coordination-and-scarcity" class="hash-link" aria-label="Direct link to The Core Problem: Coordination and Scarcity" title="Direct link to The Core Problem: Coordination and Scarcity" translate="no">​</a></h2>
<p><strong>Cody:</strong> Healthcare operations are fundamentally about <strong>the coordination of scarce resources</strong>—staff, equipment time, and physical space. While clinical algorithms for treatment are well-established, the logistics of getting the right patient to the right place at the right time remains a massive challenge.</p>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo?start=740" title="Complex Scheduling Solutions" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><strong>Cody:</strong> Currently, this coordination is driven by <strong>human-to-human negotiation</strong>. A scheduler might make ten phone calls to confirm a single appointment. If a patient doesn't pick up, that scheduler rarely has the time to immediately find a backfill. The result is unused capacity, lost revenue for the clinic, and, most importantly, delayed care for patients.</p>
<p><strong>Cody:</strong> Our thesis is that voice agents represent a solution to this communication constraint. Unlike humans, AI agents are <strong>infinitely scalable</strong>. They can react instantly to cancellations, reach more people simultaneously, and continuously work to fill schedule gaps.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-role-of-data-standardization-fhir">The Role of Data Standardization (FHIR)<a href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai#the-role-of-data-standardization-fhir" class="hash-link" aria-label="Direct link to The Role of Data Standardization (FHIR)" title="Direct link to The Role of Data Standardization (FHIR)" translate="no">​</a></h2>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo?start=430" title="Data Standardization in Healthcare" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><strong>Cody:</strong> Automation requires <strong>a high-fidelity representation of reality</strong>. Dr. Herbert Simon once said that decision-makers can "satisfice" by finding optimum solutions for a simplified world or satisfactory solutions for a more realistic world. <code>FHIR</code> allows us to find solutions for the realistic world because it lets us model complex relationships without oversimplifying.</p>
<p><strong>Cody:</strong> A practical example of this is the <code>RelatedPerson</code> resource in <code>FHIR</code>. In a pediatric context, the patient is rarely the person coordinating the appointment. For example, if a parent is scheduling dental cleanings for two children, do you treat this as two separate tasks and call the parent twice? Or do you query the <code>RelatedPerson</code> resource, identify that one contact manages both appointments, and <strong>consolidate the communication</strong>?</p>
<p><strong>Reshma:</strong> This is a really subtle but important point. At Medplum, we see this constantly with pediatrics and elder care on the platform. Noting down the <code>RelatedPerson</code> is critical for caregiver access. It is excellent to see an agent that actually <strong>respects this data model</strong> to reduce friction for the family.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="architecture-systems-of-action">Architecture: Systems of Action<a href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai#architecture-systems-of-action" class="hash-link" aria-label="Direct link to Architecture: Systems of Action" title="Direct link to Architecture: Systems of Action" translate="no">​</a></h2>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo?start=900" title="Technical Architecture &amp; Tools" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><strong>Cody:</strong> We use Medplum not just as a data store, but as a foundation for <strong>a "system of action."</strong> We model a confirmation request as a <code>FHIR</code> <code>Bundle</code> containing the <code>Appointment</code>, <code>Patient</code>, and <code>Organization</code>.</p>
<p><strong>Cody:</strong> Once that bundle hits our API, a subscription in Medplum triggers our application. We use a durable workflow engine to spin up a voice agent. That agent calls the patient, verifies identity (like checking Date of Birth), and confirms the slot. The agent then <strong>updates the <code>Task</code> and <code>Appointment</code> status in Medplum in real-time</strong>.</p>
<p><strong>Cody:</strong> Because Medplum handles the identity management and event-driven architecture, we can <strong>focus entirely on the logic of the scheduling agents</strong> rather than building boilerplate infrastructure.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-future-the-distributed-ehr">The Future: The Distributed EHR<a href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai#the-future-the-distributed-ehr" class="hash-link" aria-label="Direct link to The Future: The Distributed EHR" title="Direct link to The Future: The Distributed EHR" translate="no">​</a></h2>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo?start=1150" title="Future of EHRs &amp; Scheduling" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><strong>Cody:</strong> Historically, EHRs were monolithic systems like Magic MUMPS. If you needed a specific feature, you hoped your vendor built it. Today, we are moving toward composability. I see a future of <strong>"Distributed EHRs,"</strong> where Medplum acts as a headless backend allowing specialized vertical applications—like Unity AI for scheduling—to sit on top of a shared data layer.</p>
<p><strong>Reshma:</strong> We agree completely. We believe customization is required to be successful, and monolithic systems often fail to yield to specific workflows like infusion or complex radiology. The composability of this architecture allows for <strong>"best-of-breed" solutions</strong> to work together seamlessly through standard APIs.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="community-qa-highlights">Community Q&amp;A Highlights<a href="https://www.medplum.com.ar/blog/scheduling-agents-unity-ai#community-qa-highlights" class="hash-link" aria-label="Direct link to Community Q&amp;A Highlights" title="Direct link to Community Q&amp;A Highlights" translate="no">​</a></h2>
<div class="responsive-iframe-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/pbiJRr1GxDo?start=1920" title="Q&amp;A" session="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div>
<p><strong>Cody:</strong> During the Q&amp;A, we discussed how referrals are handled. In our system, referrals are modeled as a <code>ServiceRequest</code>. We pick up that request and generate the downstream communication workflows to ensure the patient is scheduled, <strong>closing the loop between providers</strong>.</p>
<p><strong>Reshma:</strong> We also discussed the role of Bots. In Medplum, <strong>Bots effectively act as server-side functions</strong>. Whether verifying insurance with a partner like Stedi or triggering a custom workflow, Bots provide the logic layer that connects static data to active processes.</p>
<p><strong>Cody:</strong> Finally, regarding data storage, the consensus is to <strong>keep data in <code>FHIR</code> whenever possible</strong>. While there is always a temptation to use a separate SQL database for app-specific config, keeping data in <code>FHIR</code> ensures interoperability and allows for powerful graph queries via <code>GraphQL</code> across the entire patient context.</p>
<hr>
<p><em>To learn more about Unity AI, visit <a href="https://unityai.com/" target="_blank" rel="noopener noreferrer" class="">UnityAI.com</a>.</em></p>]]></content>
        <author>
            <name>Cody Hall</name>
            <uri>https://github.com/codyhall</uri>
        </author>
        <category label="community" term="community"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Medplum v5 is Released]]></title>
        <id>https://www.medplum.com.ar/blog/v5-release</id>
        <link href="https://www.medplum.com.ar/blog/v5-release"/>
        <updated>2025-10-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We are pleased to announce the Release of Medplum v5, the next major version of the open source healthcare developer platform.]]></summary>
        <content type="html"><![CDATA[<p>We are pleased to announce the <strong>Release of Medplum v5</strong>, the next major version of the open source healthcare developer platform.</p>
<p>As outlined in our <a class="" href="https://www.medplum.com.ar/blog/preparing-for-v5">preparatory post in May</a>, Medplum v5 represents a comprehensive and necessary modernization of our core stack. This release ensures our platform maintains the highest standards of <strong>performance, security, and developer experience</strong> by aligning with the latest stable versions of our critical runtime and tooling dependencies.</p>
<!-- -->
<p>As with all major releases, our goal is to provide a <strong>stable, predictable, and future-proof</strong> platform for building healthcare solutions.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="core-platform-modernization">Core Platform Modernization<a href="https://www.medplum.com.ar/blog/v5-release#core-platform-modernization" class="hash-link" aria-label="Direct link to Core Platform Modernization" title="Direct link to Core Platform Modernization" translate="no">​</a></h2>
<p>The bulk of the work in v5 involved essential dependency upgrades and technical debt reduction.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="runtime-and-infrastructure">Runtime and Infrastructure<a href="https://www.medplum.com.ar/blog/v5-release#runtime-and-infrastructure" class="hash-link" aria-label="Direct link to Runtime and Infrastructure" title="Direct link to Runtime and Infrastructure" translate="no">​</a></h3>
<p>Medplum v5 now requires and is rigorously tested against modern runtime environments:</p>
<ul>
<li class=""><strong>Node.js</strong>: We have deprecated Node 20 and now continuously test on <strong>Node 22 and 24</strong>. This upgrade enables access to the latest JavaScript features and performance improvements, including Node 22's Maglev compiler.</li>
<li class=""><strong>PostgreSQL</strong>: We have ended support for Postgres 13 and now continuously test on <strong>Postgres 14 and 18</strong>. Users benefit from major database performance features, such as Postgres 18's asynchronous I/O subsystem.</li>
<li class=""><strong>Redis</strong>: Support for Redis 6 has been dropped; we now continuously test on <strong>Redis 7</strong>.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="new-capabilities">New Capabilities<a href="https://www.medplum.com.ar/blog/v5-release#new-capabilities" class="hash-link" aria-label="Direct link to New Capabilities" title="Direct link to New Capabilities" translate="no">​</a></h2>
<p>We are excited to release several major new features in Medplum v5:</p>
<ol>
<li class=""><strong>Full FHIR Terminology Validation</strong>. Medplum now includes comprehensive, built-in terminology support covering major code systems like <strong>SNOMED, ICD, CPT, and others</strong>. Crucially, this functionality also includes <strong>hierarchy support</strong> (e.g., "descendant of"). This advanced validation logic contributes directly to better <strong>data hygiene</strong>, improves <strong>data quality</strong>, and increases confidence in the integrity of the data managed by the Medplum platform.</li>
<li class=""><strong>FHIR GraphQL Patch support</strong>. The Medplum GraphQL API now supports <strong>FHIR Patch operations</strong>, enabling more efficient and flexible updates to FHIR resources via GraphQL mutations. This enhancement allows developers to perform partial updates, reducing payload sizes and improving performance for applications that require frequent resource modifications.</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="frontend-and-developer-tooling">Frontend and Developer Tooling<a href="https://www.medplum.com.ar/blog/v5-release#frontend-and-developer-tooling" class="hash-link" aria-label="Direct link to Frontend and Developer Tooling" title="Direct link to Frontend and Developer Tooling" translate="no">​</a></h3>
<p>We have streamlined the frontend stack to improve build times, component quality, and overall developer experience:</p>
<ul>
<li class=""><strong>React</strong>: We've dropped support for React 18 and <strong>now require React 19</strong>, which simplifies our component maintenance moving forward.</li>
<li class=""><strong>UI Components</strong>: Upgraded all usage from <strong>Mantine v7 to v8</strong>, which features improved date handling and enhanced TypeScript support.</li>
<li class=""><strong>Core Frameworks</strong>: Successfully upgraded <strong>Express from v4 to v5</strong> and <strong>Storybook from v8 to v9</strong>.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="strategic-update-esm-by-default">Strategic Update: ESM by Default<a href="https://www.medplum.com.ar/blog/v5-release#strategic-update-esm-by-default" class="hash-link" aria-label="Direct link to Strategic Update: ESM by Default" title="Direct link to Strategic Update: ESM by Default" translate="no">​</a></h2>
<p>A key architectural shift in v5 is the move to <strong>ES Modules (ESM) by default</strong>.</p>
<p>This aligns Medplum with the modern JavaScript module standard, offering benefits like improved tree-shaking and better future compatibility. For a smooth transition, we will <strong>dual-publish certain SDK packages as CJS+ESM</strong>. We strongly recommend that all custom applications migrate to ESM for optimal compatibility and performance moving forward.</p>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="planning-your-migration-breaking-changes">Planning Your Migration (Breaking Changes)<a href="https://www.medplum.com.ar/blog/v5-release#planning-your-migration-breaking-changes" class="hash-link" aria-label="Direct link to Planning Your Migration (Breaking Changes)" title="Direct link to Planning Your Migration (Breaking Changes)" translate="no">​</a></h2>
<p>Medplum v5 includes a few minor breaking changes, primarily involving the deprecation of long-standing features and updates to API signatures for better consistency and modern patterns.</p>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="api-and-sdk-changes">API and SDK Changes<a href="https://www.medplum.com.ar/blog/v5-release#api-and-sdk-changes" class="hash-link" aria-label="Direct link to API and SDK Changes" title="Direct link to API and SDK Changes" translate="no">​</a></h3>
<table><thead><tr><th>Old Feature/Component</th><th>New Feature/Component</th><th>Note</th></tr></thead><tbody><tr><td>Non-standard usage of <code>?param:in=...</code> and <code>?param:not-in=...</code></td><td><strong>Strict FHIR compliance</strong></td><td>Invalid usage of the <code>:in</code> and <code>:not-in</code> search modifiers now <strong>throws an error</strong>. For simple inclusion checks, <strong>remove the modifier</strong>: <code>Patient?_id=uuid1,uuid2</code>.</td></tr><tr><td><code>PasswordChangeRequest</code> resource</td><td><code>UserSecurityRequest</code> resource</td><td><code>PasswordChangeRequest</code> was deprecated for over a year; <code>UserSecurityRequest</code> is a superset of its functionality.</td></tr><tr><td><code>Hl7Server.start</code> and <code>Hl7Server.stop</code> methods</td><td>Same methods, now <strong>async</strong></td><td>These methods must now be used with <code>await</code> or promise chains.</td></tr><tr><td><code>ProjectSecret</code> type definition</td><td><code>ProjectSetting</code> type</td><td>Use the <code>ProjectSetting</code> type instead.</td></tr><tr><td><code>MemoizedSearchControl</code> React component</td><td><code>SearchControl</code> React component</td><td>Use the standard component directly.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_SAay" id="infrastructure-changes">Infrastructure Changes<a href="https://www.medplum.com.ar/blog/v5-release#infrastructure-changes" class="hash-link" aria-label="Direct link to Infrastructure Changes" title="Direct link to Infrastructure Changes" translate="no">​</a></h3>
<ul>
<li class=""><strong>AWS Container Insights</strong>: Updated from v1 to <strong>Container Insights v2</strong>.</li>
<li class=""><strong>CloudWatch Logs for Audit Events</strong>: Audit logging now utilizes <strong>AWS FireLens log routing</strong> for improved log management.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="the-value-of-upgrading">The Value of Upgrading<a href="https://www.medplum.com.ar/blog/v5-release#the-value-of-upgrading" class="hash-link" aria-label="Direct link to The Value of Upgrading" title="Direct link to The Value of Upgrading" translate="no">​</a></h2>
<p>While a major version upgrade requires planning, Medplum v5 delivers concrete benefits that justify the effort:</p>
<ul>
<li class=""><strong>Performance</strong>: Immediate and substantial performance gains across the stack, from the database and runtime to frontend tooling.</li>
<li class=""><strong>Security</strong>: Access to the latest security features and patches across all dependencies.</li>
<li class=""><strong>Future-Proofing</strong>: Setting your healthcare solutions on a stable, supported platform that is aligned with industry best practices.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SAay" id="next-steps-for-self-hosted-customers">Next Steps for Self-Hosted Customers<a href="https://www.medplum.com.ar/blog/v5-release#next-steps-for-self-hosted-customers" class="hash-link" aria-label="Direct link to Next Steps for Self-Hosted Customers" title="Direct link to Next Steps for Self-Hosted Customers" translate="no">​</a></h2>
<p>We encourage self-hosted customers to begin planning their upgrade immediately.</p>
<ul>
<li class="">Consult our detailed <strong>migration guides</strong> on the documentation site.</li>
<li class="">Schedule <strong>database and runtime environment upgrades</strong> with your DevOps team.</li>
<li class="">Review your custom application codebase for compatibility with newer dependencies and the breaking changes listed above.</li>
</ul>
<p>For technical questions or feedback, please join the conversation on <a href="https://discord.gg/medplum" target="_blank" rel="noopener noreferrer" class="">Discord</a> or submit issues on <a href="https://github.com/medplum/medplum" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<p>Medplum v5 is ready to power your next generation of healthcare applications.</p>]]></content>
        <author>
            <name>Cody Ebberson</name>
            <uri>https://github.com/codyebberson</uri>
        </author>
        <category label="release" term="release"/>
        <category label="self-host" term="self-host"/>
        <category label="fhir-datastore" term="fhir-datastore"/>
        <category label="integration" term="integration"/>
        <category label="compliance" term="compliance"/>
        <category label="auth" term="auth"/>
        <category label="community" term="community"/>
        <category label="performance" term="performance"/>
    </entry>
</feed>