# How to integrate clinic systems with a FHIR backend

> Tutorial: connect a clinic EMR to patients' FHIR R4 records — directory of doctors, matching by record number, a visit as one transaction with the doctor as author, lab reports, other providers' data and webhooks.

Source: https://developers.anpheros.com/guides/integrate-clinic-systems-fhir

**This tutorial connects a clinic's software (an EMR, a practice management system or a booking tool) to patients' HL7 FHIR R4 records in Anpheros: the clinic and its doctors are registered in the directory, patients are matched by the clinic's record number, a visit is written as one transaction with the doctor named as author, and the clinic learns about data other providers add.** Every request is `curl` against the free sandbox, and the responses are the platform's own.

The integration runs on the clinic's server, with a project API key for the patients the clinic registers and, for people who already have an Anpheros record, an OAuth grant they approve.

## What maps to what

| In the clinic system | In FHIR R4 |
|---|---|
| the clinic, its departments | `Organization` |
| a doctor or nurse | `Practitioner` |
| that person working at that clinic, with a specialty | `PractitionerRole` |
| the patient file and its number | `Patient` with an `identifier` in the clinic's system |
| a visit | `Encounter` |
| vital signs, results measured during the visit | `Observation` linked to the `Encounter` |
| a diagnosis | `Condition` (ICD-10), with `verificationStatus` provisional or confirmed |
| a prescription, current treatment | `MedicationStatement` (ATC) |
| a letter, a discharge summary, a scan | `DocumentReference` with the file |
| lab results | the [lab connector](https://developers.anpheros.com/guides/lab-connector), into `Observation` |

## Step 1: register the clinic and its doctors

Directory resources have no patient. Other projects in the same environment can read them, so a patient's other providers see who wrote what, but only your project can change them.

```bash
export BASE=https://platform.anpheros.com/fhir/R4
export KEY=sk_test_…
H=(-H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json")

curl -X POST $BASE/Organization "${H[@]}" -d '{"resourceType": "Organization", "active": true, "name": "Clinica Cardio Nord",
  "identifier": [{"system": "https://clinic.example/org", "value": "CCN"}]}'

curl -X POST $BASE/Practitioner "${H[@]}" -d '{"resourceType": "Practitioner", "active": true,
  "name": [{"family": "Popescu", "given": ["Ana"], "prefix": ["Dr."]}]}'

curl -X POST $BASE/PractitionerRole "${H[@]}" -d '{"resourceType": "PractitionerRole", "active": true,
  "practitioner": {"reference": "Practitioner/'$PRACTITIONER'"},
  "organization": {"reference": "Organization/'$ORG'"},
  "code": [{"text": "Cardiologist"}]}'
```

Keep the returned ids next to your staff records. When someone leaves, set their `PractitionerRole` to `"active": false`; their past writes keep their name, and they can no longer act through your system.

## Step 2: match patients

For patients the clinic registers, create the `Patient` with the clinic's record number as an identifier:

```bash
curl -X POST $BASE/Patient "${H[@]}" -d '{"resourceType": "Patient",
  "identifier": [{"system": "https://clinic.example/mrn", "value": "MRN-20981"}],
  "name": [{"family": "Dinu", "given": ["Andrei"]}], "gender": "male", "birthDate": "1968-11-05"}'
```

From then on, find the patient by that number, never by name and birth date:

```bash
curl "$BASE/Patient?identifier=https://clinic.example/mrn|MRN-20981" -H "Authorization: Bearer $KEY"
```

**When the person already has an Anpheros record**, from their own app or another provider, the clinic does not create a second one. It asks the person for access with OAuth, from a tablet at the reception desk or a link sent before the visit, using a **confidential** application (the clinic's server keeps the secret). The person chooses their record and how long the clinic may access it. The steps are in [How to implement patient consent with SMART on FHIR](https://developers.anpheros.com/guides/smart-on-fhir-backend); the token's `patient` field is the id to store with your file.

## Step 3: write a visit as one transaction

A visit produces several resources that belong together. Send them in a `transaction` so they are stored all at once or not at all, and say who is working: `X-Anpheros-Acting-As` names the doctor's role. It becomes the author in Provenance, is written to the access log, and is shown to the patient by name.

```bash
curl -X POST $BASE "${H[@]}" \
  -H "X-Anpheros-Acting-As: PractitionerRole/$ROLE" \
  -H "X-Anpheros-Author-Type: practitioner" \
  -H "X-Anpheros-Source-System: ccn-emr" -d '{
  "resourceType": "Bundle", "type": "transaction",
  "entry": [
    {"fullUrl": "urn:uuid:aa000000-0000-4000-8000-000000000001",
     "resource": {"resourceType": "Encounter", "status": "finished",
       "class": {"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB", "display": "ambulatory"},
       "subject": {"reference": "Patient/'$PID'"},
       "serviceProvider": {"reference": "Organization/'$ORG'"},
       "participant": [{"individual": {"reference": "PractitionerRole/'$ROLE'"}}],
       "period": {"start": "2026-10-09T10:00:00Z", "end": "2026-10-09T10:30:00Z"}},
     "request": {"method": "POST", "url": "Encounter"}},
    {"resource": {"resourceType": "Observation", "status": "final",
       "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs"}]}],
       "code": {"coding": [{"system": "http://loinc.org", "code": "8867-4", "display": "Heart rate"}]},
       "subject": {"reference": "Patient/'$PID'"},
       "encounter": {"reference": "urn:uuid:aa000000-0000-4000-8000-000000000001"},
       "effectiveDateTime": "2026-10-09T10:10:00Z",
       "valueQuantity": {"value": 92, "unit": "/min", "system": "http://unitsofmeasure.org", "code": "/min"}},
     "request": {"method": "POST", "url": "Observation"}},
    {"resource": {"resourceType": "Condition",
       "subject": {"reference": "Patient/'$PID'"},
       "encounter": {"reference": "urn:uuid:aa000000-0000-4000-8000-000000000001"},
       "clinicalStatus": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active"}]},
       "verificationStatus": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", "code": "provisional"}]},
       "code": {"coding": [{"system": "http://hl7.org/fhir/sid/icd-10", "code": "I48.0", "display": "Paroxysmal atrial fibrillation"}]}},
     "request": {"method": "POST", "url": "Condition"}}
  ]}'
```

The `transaction-response` has `201 Created` for the Encounter, the Observation and the Condition. The Observation and the Condition now point to the real `Encounter/0ca25459-…`. The Provenance of each names the doctor's role, the clinic and the source system:

```json
"agent": [{"who": {"reference": "PractitionerRole/e6d8c227-…",
                   "identifier": {"system": "https://anpheros.com/fhir/CodeSystem/author-type", "value": "practitioner"}},
           "onBehalfOf": {"reference": "Organization/c3a56a4b-…", "display": "Clinica Cardio Nord"}}],
"entity": [{"role": "source", "what": {"identifier": {"system": "ccn-emr"}}}]
```

The diagnosis is `provisional` until it is confirmed. Update it to `confirmed` later, and the history keeps both. What each field means is explained in [Medical data provenance explained](https://developers.anpheros.com/guides/medical-data-provenance).

## Step 4: laboratory results and documents

Results from the clinic's own laboratory, or reports the patient brings, go through the lab connector in one request per report:

```bash
curl -X POST "https://platform.anpheros.com/v1/patients/$PID/labs/import" -H "Authorization: Bearer $KEY" \
     -H "Content-Type: x-application/hl7-v2+er7" -H "X-Anpheros-Source-System: ccn-lab" --data-binary @oru.hl7
```

Letters and discharge summaries are documents: create a `DocumentReference` through `/v1/patients/{id}/documents` and upload the PDF. The original file is never modified, and values extracted from it point back to it. See [How to import laboratory results into a FHIR record](https://developers.anpheros.com/guides/import-lab-results-fhir) and [Medical data API](https://developers.anpheros.com/guides/medical-data-api).

## Step 5: read what other providers wrote, and stay in your lane

With the patient's consent, the clinic reads the whole record within its scopes, including what other clinics, laboratories and the patient added. It can change only what it wrote itself. An update or deletion of another organisation's resource answers `403`, and the original stays as it was. To correct something another provider wrote, write your own resource (for example a new `Condition` with your assessment) and let the record show both, each with its author.

Before a visit, `GET $BASE/Patient/$PID/$summary` gives the International Patient Summary of the record: problems, medications, allergies and recent vital signs, from every source.

## Step 6: hear about new data

Register a webhook once for the clinic's project:

```bash
curl -X POST https://platform.anpheros.com/v1/webhooks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
     -d '{"url": "https://ccn.example/anpheros/hook", "events": ["resource.created", "resource.updated", "consent.revoked"]}'
```

When another project writes into a record your clinic can access, the event says so with `data.external: true` and the source, so your EMR can show "new results from another laboratory" without polling. A `consent.revoked` event means the person has withdrawn the clinic's access: stop syncing that record. Signatures, retries and payloads are covered in [Webhooks](https://developers.anpheros.com/guides/webhooks).

## What the patient sees

The patient sees the visit, the heart rate and the provisional diagnosis in their record, each marked as added by Dr. Ana Popescu at Clinica Cardio Nord. In their connections, the clinic's application lists every access, by name when a practitioner was acting. That transparency is what makes patients willing to grant access to the next clinic.

## Checklist for going live

- [ ] Organization, Practitioners and PractitionerRoles registered; leavers set to inactive
- [ ] Patients matched by the clinic's identifier, never by name
- [ ] Existing records reached through OAuth consent, not duplicated
- [ ] Every request from clinical staff carries `X-Anpheros-Acting-As`
- [ ] Visits written as transactions; diagnoses with the right verification status
- [ ] Source system set on every write; lab reports through the connector
- [ ] Webhook endpoint verifying signatures; `consent.revoked` handled
- [ ] Production project with a signed DPA (`sk_live_…` keys); see [Pricing](https://developers.anpheros.com/guides/pricing)

## Frequently asked questions

### Does Anpheros have a ready-made connector for my EMR?
No. There are no ready-made connectors to specific EMRs or laboratory systems; the integration is built against the FHIR R4 and REST APIs, usually as a small service next to the EMR. HL7 v2 lab messages are accepted as they are.

### Can a doctor work for two clinics?
Yes. One `Practitioner` can have a `PractitionerRole` at each organisation. The role named in `X-Anpheros-Acting-As` decides which clinic each write is recorded for.

### What happens when the patient revokes the clinic's access?
The clinic's calls for that record answer `401`, and a `consent.revoked` webhook is sent. What the clinic wrote stays in the patient's record with its provenance; the clinic just can no longer read or change it.

## Related

- [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations): all integration patterns at a glance
- [Medical data provenance explained](https://developers.anpheros.com/guides/medical-data-provenance)
- [How to implement patient consent with SMART on FHIR](https://developers.anpheros.com/guides/smart-on-fhir-backend)
- [How to import laboratory results into a FHIR record](https://developers.anpheros.com/guides/import-lab-results-fhir)
- [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability)
