Use ServiceRequest as the referral order and Task resources to track fulfillment, then synchronize status between the two with explicit event rules rather than manual updates. US Core requires servers to support ServiceRequest.reasonCode or reasonReference, and reasonReference is the better choice whenever a Condition or Observation is available. For transport, favor a RESTful API with Subscriptions where the target supports them, and fall back to polling or batch queries when it does not.
TL;DR:
- Referrals should rely on ServiceRequest and Task resources, with explicit event rules for synchronization and lifecycle management.
- Support for reasonReference referencing Conditions or Observations is preferred for better structured data and automation.
- FHIR referral variants depend on whether both systems host FHIR servers or if intermediaries clone or proxy resources, affecting implementation approach.
- Keep Task status and businessStatus separate to ensure proper automation and user interface updates, with periodic polling as a fallback.
- Confirm support for core search parameters, resource references, and FHIR profiles before going live to avoid costly redesigns.
Table of Contents
- How a referral moves through the system
- Canonical FHIR resources and how to link them
- Direct, indirect, and light referral variants
- Keeping ServiceRequest and Task in sync
- Building the integration layer: transport, scopes, and TEFCA
- A developer checklist for shipping referral workflows
- Common pitfalls and how referral workflows scale
- What this pattern looks like in practice
- Where Smart Admissions fits into your referral workflow
- Sources
- FAQ
How a referral moves through the system
A FHIR-based referral follows a predictable sequence, and your architecture should mirror it exactly rather than invent shortcuts. The referral source completes a clinical assessment, then creates a ServiceRequest with intent set to order. That ServiceRequest triggers a Task, which notifies the target organization or provider that action is needed. The target accepts or assigns the Task, performs the work, and records the outcome in a Procedure, DiagnosticReport, or DocumentReference. Once that fulfillment resource exists, the Task closes and the ServiceRequest itself moves to completed.
Several actors touch this sequence, and your integration plan needs to name each one explicitly:
- The referral source: the ordering clinician or facility system that generates the ServiceRequest.
- The referral target: the receiving provider, specialist, or facility that fulfills the order.
- An intermediary layer: a health information exchange, coordination platform, or clearinghouse that may clone or proxy resources between source and target.
- A care navigator or coordinator: a human role responsible for chasing down stalled Tasks.
- System components: the EMR, a referral management system, and the exchange layer connecting them.
Attachments and consent deserve early design attention rather than being bolted on later. When a referral needs supporting documentation, attach it through DocumentReference rather than embedding text in notes, and link the relevant Condition or Encounter so the receiving system has clinical context without a phone call. Consent handling varies by jurisdiction and data-sharing agreement, so confirm what the target system expects before you assume a bare ServiceRequest is enough to authorize disclosure. Getting this sequence and its attachments right the first time avoids a costly redesign once real referrals start flowing between systems that were never tested against each other. The HL7 workflow guidance frames this entire sequence as a state machine, not a document handoff, which matters for how you build the next layer.
Canonical FHIR resources and how to link them
ServiceRequest is the referral order, and its fields carry the clinical intent that everything downstream depends on. Set intent to order, use code to specify what is being requested, and set priority when urgency matters. The performer or performerType fields identify who should act, and basedOn links a ServiceRequest to any prior request it fulfills. The field that most affects downstream automation is reasonCode versus reasonReference: the US Core ServiceRequest profile requires support for one of the two, but a reference to a Condition or Observation gives the receiving system structured data it can act on, while a bare code gives it a string to interpret.
Task carries the fulfillment lifecycle, and four fields do most of the work: status for the underlying state machine, businessStatus for the human-readable label, requester and owner to identify who asked and who is acting, and focus to point back at the ServiceRequest being fulfilled. When a referral spans multiple approval stages, use partOf to link sub-Tasks to a parent Task rather than creating flat, unrelated Task resources that lose the relationship.
A handful of supporting resources round out a complete referral:
- CommunicationRequest for structured messages between referral parties.
- DocumentReference for attachments such as scanned forms or clinical summaries.
- Procedure or DiagnosticReport to record what fulfillment actually produced.
- Condition or Observation as the clinical justification referenced from ServiceRequest.
Keep reference chains shallow and stable. A ServiceRequest that references a Condition, which is referenced again from a Task’s focus, works fine as long as every system resolves the same identifiers consistently. Problems show up when an intermediary re-creates resources with new IDs instead of preserving the originals, breaking the chain every downstream consumer expects to follow.
Pro Tip: Store the original ServiceRequest identifier as an external identifier on any cloned resource so you can always trace a copy back to its source.
Direct, indirect, and light referral variants
Referral workflows split into four patterns depending on what both systems can host, and picking the wrong one for your integration partner causes most early implementation failures.
- Direct: both the source and target run their own FHIR-capable servers, so the source POSTs a Task directly to the target’s API and both sides can subscribe to updates for near-real-time status changes.
- Direct-light: the target has no FHIR server of its own, so a client application or lightweight intermediary handles the exchange, with the target pulling data through a portal or posting results back through a narrow, token-scoped interface.
- Indirect: an intermediary, often a health information exchange, clones or proxies the referenced resources on the target’s behalf, creating filler-order ServiceRequests and Tasks that must stay synchronized with the originals through subscription or polling.
- Indirect-light: a mixed-capability scenario where one side has full FHIR support and the other does not, requiring the same synchronization discipline as the indirect pattern plus clear documentation of which system owns the canonical copy of each resource.
The decision between these four comes down to two questions: does the target run a FHIR server, and does a trusted intermediary sit between the parties. Get the answer wrong and you either build subscription infrastructure the target can never use, or you skip reconciliation logic that an indirect pattern absolutely requires. The SDOH Clinical Care referral workflow guide documents these four variants with example resources for each, and it is worth reviewing before you commit to an architecture.
Keeping ServiceRequest and Task in sync
Task.status tracks the underlying workflow state that every FHIR-conformant system understands, while Task.businessStatus carries the human-readable label your staff actually see, such as “awaiting insurance verification” or “pending clinical review.” Keep the two separate: status drives automation, businessStatus drives your user interface, and conflating them produces a system that either confuses staff or breaks automated triggers.
A small event table keeps both resources consistent without ad hoc logic scattered across your codebase:
| Trigger event | Effect on Task | Effect on ServiceRequest |
|---|---|---|
| ServiceRequest set to active | Create approval Task with status requested | Status remains active |
| ServiceRequest revoked | Set all open Tasks to status cancelled | Status set to revoked |
| Final approval Task completed | Task status set to completed | Status set to completed |
| Target rejects referral | Task status set to rejected | Status set to revoked or reset per policy |
For multi-stage approvals, model each stage as a sub-Task linked with partOf to the parent Task, and only mark the parent completed once every sub-Task resolves. When you poll for status rather than relying on push notifications, query Task?based-on=ServiceRequest/[id]&status=requested,accepted,in-progress on a fixed interval and apply exponential backoff when a target system returns repeated timeouts. The FHIR R5 workflow management page walks through this exact lifecycle, including how no-show handling propagates back to the original ServiceRequest.
Building the integration layer: transport, scopes, and TEFCA
A typical referral exchange looks like a short, predictable sequence of REST calls once you strip away the surrounding infrastructure:
- POST a new ServiceRequest with status active and intent order to the target’s ServiceRequest endpoint.
- POST a corresponding Task with focus pointing at that ServiceRequest and owner set to the target organization.
- PATCH or PUT the Task as its status changes, using conditional updates or ETags to avoid race conditions when both systems can write.
- Query or fetch the resulting Procedure, DiagnosticReport, or DocumentReference once fulfillment is recorded.
Subscriptions give you push-based updates and are the right choice whenever the target supports them, since they eliminate the latency and load of constant polling. When a target does not support Subscriptions, fall back to polling with backoff, and batch your queries across multiple referrals rather than issuing one request per patient every cycle. Scopes matter as much as transport: request granular, resource-level SMART scopes for ServiceRequest and Task rather than broad patient-level access, and declare exactly what your system supports in its CapabilityStatement so partners know what to expect before they integrate.
TEFCA changes the discovery picture for anyone exchanging referrals across a broader network rather than a single point-to-point connection. ONC’s roadmap for facilitated FHIR anticipates FHIR exchange through Qualified Health Information Networks, with endpoint discovery mediated by QHIN interactions rather than a static partner list. Design your referral system to tolerate variable discovery models rather than hardcoding endpoints, since a QHIN-mediated flow may resolve a target’s address differently than a direct bilateral agreement.
A developer checklist for shipping referral workflows
Before a referral workflow goes live, run through a short set of conformance and testing steps that catch most integration failures early.
- Confirm your ServiceRequest implementation supports the US Core profile’s requirement for reasonCode or reasonReference, and default to reasonReference whenever a Condition or Observation exists.
- Implement and test the core search parameters your partners will rely on: ServiceRequest?patient=, ServiceRequest?patient=&category=, and Task?based-on=ServiceRequest/[id].
- Declare every supported resource, search parameter, Subscription capability, and SMART scope in your CapabilityStatement so integration partners can verify compatibility without a manual conversation.
- Write unit tests for every Task state transition, not just the happy path, including rejection, cancellation, and timeout scenarios.
- Run end-to-end integration tests against sample resources that mimic a real referral, and keep a small conformance test harness other teams can reuse.
Error handling deserves its own attention rather than an afterthought bolted onto the happy path. Build retry logic with idempotency keys so a dropped connection never creates a duplicate Task, and log every state transition with enough context to reconstruct what happened when a referral stalls. A partner integration that silently drops updates is far harder to debug after the fact than one that fails loudly and immediately.
Pro Tip: Keep a library of sample ServiceRequest and Task resources on hand for every use-case variant, direct, direct-light, indirect, and indirect-light, so new integration partners can test against realistic examples before their first live referral.
Common pitfalls and how referral workflows scale
The most common mistake in referral implementations is treating the referral as a document transfer instead of a stateful workflow. Teams that model a referral as a PDF attached to a message lose the ability to track status, trigger automation, or reconcile discrepancies when a target system falls behind. The HL7 workflow guidance is explicit that referrals need coordinated interactions and shared state, not a one-time handoff.

A second frequent failure is skipping structured justification. A ServiceRequest with only a free-text reasonCode forces the receiving team to read and interpret prose before triage, while a reasonReference to a Condition or Observation lets automated systems route and prioritize the referral immediately.
Scaling introduces its own set of concerns:
- Subscription limits: most FHIR servers cap the number of active subscriptions per client, so batch related referrals under fewer subscription topics where possible.
- Polling efficiency: query in batches rather than one request per patient, and apply backoff when a target repeatedly times out.
- Idempotency: every status update should be safe to retry without creating duplicate Task or ServiceRequest resources.
- Reconciliation: schedule periodic checks that compare cloned or proxied resources against their source to catch silent sync failures.
Operational teams typically track referral acceptance time, time to first appointment, referral close rate, missed-referral rate, and Task update latency as the core signals that a workflow is healthy. Set up alerting on any Task that sits in a requested state past an expected threshold, since a stalled Task is usually the earliest sign of a referral at risk of leaking out of the pipeline entirely. Reviewing referral prioritization strategies alongside these KPIs helps teams decide which stalled referrals need the most urgent attention.
What this pattern looks like in practice
Building referral workflows against real production systems tends to expose gaps that the specification alone never mentions, things like inconsistent identifier handling across EMRs or a target system that acknowledges a Task but never updates businessStatus. The pattern described here, ServiceRequest for intent, Task for lifecycle, reasonReference for justification, holds up across the direct, direct-light, indirect, and indirect-light variants precisely because it separates what is being asked from how it is being tracked.
Some platforms apply this same separation by integrating with existing EMR and insurance portal connections to pull real-time eligibility data and clinical assessments into the admissions workflow rather than treating referrals as static paperwork. That integration approach mirrors the reasonReference and Task-tracking patterns covered above, applied specifically to skilled nursing, rehabilitation, and post-acute referral intake.
— Harry
Where Smart Admissions fits into your referral workflow
If your facility is building or evaluating FHIR referral workflows but does not want to staff a full integration team, some platforms offer an automation layer that does not require admissions coordinators to write ServiceRequest or Task handling code. Such platforms can integrate with existing EMR and insurance portal systems to verify eligibility in real time, manage clinical assessments, and keep documentation organized as referrals move through review.

Facilities that want the technical patterns in this guide operationalized without building them in house can see exactly how the integration works on the how Smart Admissions works page. Plans are available Monthly and annual plans available, and teams evaluating staffing alongside referral volume may also want to review telehealth staffing options for virtual care coverage. Visit the pricing page to compare plans and start a trial.
Sources
- ServiceRequest – FHIR R5
- Workflow – FHIR Implementation Guidance
- FHIR roadmap for TEFCA exchange v2 – ONC blog
FAQ
What are the four types of referrals?
FHIR referral implementations typically define four variants: direct, direct-light, indirect, and indirect-light, distinguished by whether each system hosts its own FHIR server and whether an intermediary clones or proxies resources between them. The SDOH Clinical Care referral workflow guide documents example resources for each variant.
What does the 80/20 rule mean in FHIR?
There is no defined “80/20 rule” within the FHIR specification or US Core implementation guides covered here, so any reference to one likely comes from a specific organization’s internal shorthand rather than a normative standard. Implementers should rely on the ServiceRequest and Task patterns and US Core profile requirements described in this article instead.
What are the steps of the referral process?
A referral begins with a clinical assessment, followed by creation of a ServiceRequest with intent set to order, then a Task to notify the target system. The target accepts and fulfills the request, records the outcome in a Procedure, DiagnosticReport, or DocumentReference, and both the Task and ServiceRequest close once fulfillment is confirmed.
How do I keep track of referrals across systems?
Track referrals by monitoring Task.status and Task.businessStatus continuously, using Subscriptions for push updates where supported and polling with backoff where they are not. Facilities using a dedicated platform like Smart Admissions can monitor referral status, eligibility, and documentation in one place instead of building custom tracking logic.
Why should ServiceRequest reference a Condition instead of using a text code?
Referencing a Condition or Observation through reasonReference gives the receiving system structured, machine-readable justification instead of a plain text string, which supports faster automated triage. The US Core ServiceRequest profile requires support for reasonCode or reasonReference, and reasonReference is the recommended choice whenever structured data is available.