# Як імпортувати лабораторні результати до запису FHIR

> Посібник: імпортуйте лабораторний звіт у форматі CSV та HL7 v2 ORU^R01 до FHIR R4 Observations з кодами LOINC та референтними діапазонами, обробляйте невідповідні маркери та повторно надіслані звіти, а також відстежуйте кожен результат до його лабораторії.

Source: https://developers.anpheros.com/uk/guides/import-lab-results-fhir

**Цей посібник розглядає лабораторний звіт у файлі CSV та як повідомлення HL7 v2 ORU^R01, імпортує його до запису HL7 FHIR R4 пацієнта одним запитом для кожного, і показує, що ви отримаєте у відповідь: лабораторні `Observation` ресурси з кодами LOINC, референтними діапазонами та походженням.** Він також охоплює дві проблеми, з якими стикається кожна інтеграція лабораторії: маркери, які не можуть бути автоматично зіставлені, та звіти, які надсилаються двічі. Все працює на безкоштовному пісочниці з синтетичним пацієнтом.

## Чому лабораторні результати важко зберігати

Лабораторний звіт виглядає просто: маркер, значення, одиниця вимірювання, референтний діапазон, дата. На практиці кожна лабораторія називає маркери по-своєму ("Глікозильований гемоглобін", "HbA1c", "Glycated haemoglobin"), використовує коми або крапки для десяткових знаків, пише діапазони як `4,0-5,6`, `<5` або `>3.5`, і повторно надсилає той самий звіт, коли щось йде не так. Збережені як вільний текст, ці результати неможливо порівняти з часом, відобразити на графіку, надати іншій програмі або впевнено передати моделі штучного інтелекту.

Запис FHIR зберігає кожен результат як `Observation` з кодом LOINC, одиницею UCUM, значенням, референтним діапазоном та датою, а також зберігає інформацію про відправника в ресурсі `Provenance`. [Лабораторний конектор](https://developers.anpheros.com/uk/guides/lab-connector) виконує це перетворення для вас.

```
 lab report (CSV, HL7 v2, JSON)
        │  POST /v1/patients/{id}/labs/import
        ▼
 ┌──────────────────────────────────────────────┐
 │ parse rows → map marker to LOINC → parse     │
 │ value, unit, range → stable id per row       │
 └──────────────────────────────────────────────┘
        │
        ▼
 Observation (category laboratory) + Provenance (author_type import, source system, report id)
        │
        ├─► the patient's app and every app they consented to
        └─► webhooks: resource.created per Observation
```

## Перед початком роботи

Вам потрібен ключ для пісочниці (`sk_test_…`) з [platform.anpheros.com/dashboard](https://platform.anpheros.com/dashboard/) (**Отримати ключ для пісочниці**). У прикладах використовується `curl`; [SDK](https://developers.anpheros.com/uk/guides/sdks) мають ті ж виклики (`labs.importCsv`, `labs.importHl7`, `labs.importItems`).

```bash
export BASE=https://platform.anpheros.com
export KEY=sk_test_…
# Elena Ionescu, a synthetic patient with type 2 diabetes
export PID=$(curl -s "$BASE/fhir/R4/Patient?identifier=https://anpheros.com/fhir/sid/sandbox-persona|p02" \
  -H "Authorization: Bearer $KEY" | jq -r '.entry[0].resource.id')
```

## Крок 1: імпорт CSV-звіту

Ось як румунська лабораторія може експортувати звіт: крапки з комою, десяткові коми, румунські назви стовпців та дати як `DD.MM.YYYY`. Конектор розпізнає румунські та англійські назви стовпців.

```bash
cat > report.csv <<'EOF'
Analiza;Rezultat;UM;Interval de referinta;Data
Hemoglobina glicozilata (HbA1c);6,9;%;4,0-5,6;01.10.2026
Glicemie;131;mg/dL;70-100;01.10.2026
TSH;2,1;mUI/L;0,4-4,0;01.10.2026
Marker foarte rar;12;U/L;0-20;01.10.2026
EOF

curl -X POST "$BASE/v1/patients/$PID/labs/import" -H "Authorization: Bearer $KEY" \
     -H "Content-Type: text/csv" -H "X-Anpheros-Source-System: labx" \
     -H "Idempotency-Key: report-2026-10-01-elena" --data-binary @report.csv
```

Відповідь (`201`):

```json
{"created": 4, "skipped": 0, "unmapped": ["Marker foarte rar"], "warnings": [],
 "observations": [
  {"id": "ff0bbb44-…", "marker": "Hemoglobina glicozilata (HbA1c)", "code": "4548-4", "system": "http://loinc.org", "value": 6.9, "unit": "%", "date": "2026-10-01"},
  {"id": "ebe5522f-…", "marker": "Glicemie", "code": "2345-7", "system": "http://loinc.org", "value": 131.0, "unit": "mg/dL", "date": "2026-10-01"},
  {"id": "bace44a8-…", "marker": "TSH", "code": "3016-3", "system": "http://loinc.org", "value": 2.1, "unit": "mUI/L", "date": "2026-10-01"},
  {"id": "26fd2270-…", "marker": "Marker foarte rar", "code": "marker_foarte_rar", "system": "urn:anpheros:lab-code", "value": 12.0, "unit": "U/L", "date": "2026-10-01"}]}
```

HbA1c, глюкоза та TSH були зіставлені з LOINC за їхніми назвами. Десяткові коми перетворилися на числа, а діапазони стали `referenceRange`. Один рядок повернувся в `unmapped`. Він все ще зберігається під власним кодом лабораторії (`urn:anpheros:lab-code`) з точним текстом зі звіту, тому нічого не втрачено.

## Крок 2: обробка невідповідних маркерів

Деякі назви потребують рішення. "Glicemie" (рівень глюкози в крові) є гарним прикладом: LOINC має один код для глюкози в сироватці або плазмі (`2345-7`, венозний зразок, взятий у лабораторії) та інший для глюкози в цільній крові (`2339-0`, наприклад, при проколюванні пальця). У лабораторному звіті проста назва "Glicemie" зіставляється з сироваткою або плазмою. Назва, що містить "capilar", "capillary" або "sânge integral", зіставляється з цільною кров'ю:

```json
{"created": 1, "skipped": 0, "unmapped": [], "warnings": [],
 "observations": [{"id": "00480a6d-…", "marker": "Glicemie capilara", "code": "2339-0", "system": "http://loinc.org", "value": 140.0, "unit": "mg/dL", "date": "2026-10-02"}]}
```

Для маркерів, які конектор не розпізнає, знайдіть код:

```bash
curl "$BASE/v1/terminology/loinc?q=glucose" -H "Authorization: Bearer $KEY"
```

```json
{"data": [
  {"system": "http://loinc.org", "code": "2339-0", "display": "Glucose [Mass/volume] in Blood", "display_ro": "Glicemie (sânge)", "category": "laboratory", "unit": "mg/dL"},
  {"system": "http://loinc.org", "code": "2345-7", "display": "Glucose [Mass/volume] in Serum or Plasma", "display_ro": "Glicemie (ser)", "category": "laboratory", "unit": "mg/dL"}],
 "total": 2}
```

Потім надішліть код у стовпці `LOINC`. Код у звіті завжди має перевагу над назвою. Зберігайте це зіставлення для кожної лабораторії на своїй стороні та додавайте стовпець до кожного звіту з неї:

```
Analiza;Rezultat;UM;Interval de referinta;Data;LOINC
Glicemie;99;mg/dL;70-100;04.10.2026;2339-0
```

Маркери, які LOINC взагалі не охоплює, як-от вигаданий "Marker foarte rar", можуть залишатися під кодом лабораторії. Вони відображаються пацієнту та включаються до запису. Їх не можна порівнювати з результатами інших лабораторій.

## Крок 3: надсилання одного й того ж звіту двічі

Лабораторії повторно надсилають звіти. Кожен рядок отримує стабільний ідентифікатор, створений з ідентифікатора звіту, коду, дати та значення, тому другий імпорт того самого звіту нічого не створює:

```json
{"created": 0, "skipped": 4, "unmapped": ["Marker foarte rar"], "warnings": [], "observations": []}
```

Рядки, що змінилися, наприклад, виправлене значення, імпортуються як нові результати. Заголовок `Idempotency-Key` додає другу гарантію: повторна спроба мережі з тим самим ключем повертає першу відповідь без змін.

## Крок 4: імпорт повідомлення HL7 v2 ORU^R01

Більшість лабораторних інформаційних систем використовують HL7 v2. Надішліть повідомлення як є (текст ER7, сегменти розділені CR або LF):

```
MSH|^~\&|LABX|LAB1|ANPHEROS|EHR|202610010930||ORU^R01|MSG00077|P|2.5.1
PID|1||12345||Ionescu^Elena||19850903|F
OBR|1||R-77|24331-1^Lipid panel^LN|||202610010800
OBX|1|NM|2093-3^Cholesterol [Mass/volume] in Serum or Plasma^LN||212|mg/dL|<200|H|||F|||202610010800
OBX|2|NM|2085-9^HDL Cholesterol^LN||52|mg/dL|>40|N|||F|||202610010800
```

```bash
curl -X POST "$BASE/v1/patients/$PID/labs/import" -H "Authorization: Bearer $KEY" \
     -H "Content-Type: x-application/hl7-v2+er7" --data-binary @oru.hl7
```

```json
{"created": 2, "skipped": 0, "unmapped": [], "warnings": [],
 "observations": [
  {"id": "b562045b-…", "marker": "Cholesterol [Mass/volume] in Serum or Plasma", "code": "2093-3", "system": "http://loinc.org", "value": 212.0, "unit": "mg/dL", "date": "2026-10-01T08:00:00Z"},
  {"id": "9b3274e4-…", "marker": "HDL Cholesterol", "code": "2085-9", "system": "http://loinc.org", "value": 52.0, "unit": "mg/dL", "date": "2026-10-01T08:00:00Z"}]}
```

`OBX-3` з кодовою системою `LN` використовується безпосередньо як LOINC. `OBX-7` стає референсним діапазоном, а `OBX-8` (`H`, `N`) — інтерпретацією. `OBR-3` (`R-77`) зберігається як ідентифікатор звіту в provenance. Пацієнт — це той, що в URL: сегмент `PID` не використовується для пошуку пацієнта, тому неправильний `PID` не може прикріпити результати до іншої особи.

Вже маєте розпарсені результати? Надішліть JSON: `{"date": "2026-10-01", "origin": "report-77", "items": [{"marker": "Ferritin", "value": 38, "unit": "ng/mL", "ref_low": 15, "ref_high": 150}]}`. Ферритин відображається на LOINC `2276-4`.

## Крок 5: Читання результатів як FHIR

```bash
curl "$BASE/fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date&_count=1" \
     -H "Authorization: Bearer $KEY"
```

Імпортований HbA1c, як збережено:

```json
{
  "resourceType": "Observation",
  "id": "62b1b0c0-…",
  "meta": {"versionId": "1", "lastUpdated": "2026-10-12T20:05:57.011Z"},
  "identifier": [{"system": "urn:anpheros:lab-import", "value": "c52d3cd6449291d34f6bef1516d0ac05"}],
  "status": "final",
  "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "laboratory"}]}],
  "code": {"coding": [{"system": "http://loinc.org", "code": "4548-4", "display": "Hemoglobin A1c/Hemoglobin.total in Blood"}],
           "text": "Hemoglobina glicozilata (HbA1c)"},
  "subject": {"reference": "Patient/…"},
  "effectiveDateTime": "2026-10-01",
  "valueQuantity": {"value": 6.9, "unit": "%"},
  "referenceRange": [{"low": {"value": 4.0, "unit": "%"}, "high": {"value": 5.6, "unit": "%"}}]
}
```

LOINC display — це стандартна англійська назва. `code.text` зберігає власне формулювання лабораторії, тому пацієнт все ще бачить те, що було в паперовому звіті. Щоб дізнатися більше про ресурси та пошук, дивіться посібник [FHIR platform](https://developers.anpheros.com/uk/guides/fhir) та [FHIR code systems](https://developers.anpheros.com/uk/guides/fhir-code-systems).

## Крок 6: перевірка відправника

```bash
curl "$BASE/v1/patients/$PID/provenance/Observation/62b1b0c0-…" -H "Authorization: Bearer $KEY"
```

```json
{"data": [{"version": 1, "activity": "CREATE", "recorded": "2026-10-12T20:05:57.011000Z",
           "author_type": "import", "author": "proj_…", "source_system": "labx", "origin_id": null,
           "fhir": "Provenance/f15c4fee-…"}], "total": 1}
```

`author_type: import` та `source_system: labx` залишаються зі значенням. Коли ШІ-додаток пізніше читає цей результат через [context API](https://developers.anpheros.com/uk/guides/llm-healthcare-data), він позначається як `[import/labx]`, щоб модель могла відрізнити лабораторний результат від значення, введеного пацієнтом.

## Що відбувається далі

- Пацієнт бачить результати у своєму додатку. Будь-який додаток, на доступ до якого він надав згоду, може їх прочитати в межах своїх областей дії ([модель згоди та доступу](https://developers.anpheros.com/uk/guides/consent)).
- Для кожного Observation спрацьовує [вебхук](https://developers.anpheros.com/uk/guides/webhooks) `resource.created`, щоб інформаційна панель клініки або зведення ШІ могли оновитися без опитування.
- `POST /fhir/R4/Observation/$validate?profile=eu-lab` звітує, як результат співвідноситься з профілем лабораторного звіту HL7 Europe.
- До 500 рядків на запит; обмеження перелічені в розділі [Обмеження та ліміти швидкості](https://developers.anpheros.com/uk/guides/limits).

## Часті запитання

### Які формати лабораторних звітів можна імпортувати у FHIR?
CSV з рядком заголовка (приймаються коми, крапки з комою або табуляція, десяткова кома), повідомлення HL7 v2 ORU^R01 та JSON. Звіти у форматі PDF можуть зберігатися як документи; витягнуті з них значення посилаються назад на документ.

### Що відбувається з маркерами без коду LOINC?
Вони зберігаються під власним кодом лабораторії з точним текстом зі звіту та перелічені у `unmapped`. Додайте стовпець LOINC для цієї лабораторії, і вони будуть відображені. Код у звіті завжди має пріоритет над назвою.

### Чи безпечно повторно надсилати звіт?
Так. Кожен рядок має стабільний ідентифікатор, створений зі звіту, коду, дати та значення, тому рядки, які вже були імпортовані, пропускаються; змінені рядки імпортуються як нові результати.

### Чи може лабораторія імпортувати результати для будь-якого пацієнта?
Ні. Лабораторія імпортує дані для пацієнтів, для яких її проєкт був створений, або чиї записи особа надала їй через OAuth. Інші пацієнти для неї не існують (`404`).

## Пов'язане

- [API лабораторних результатів](https://developers.anpheros.com/uk/guides/lab-results-api): HL7 v2 та FHIR поруч, і що повинен містити один результат
- [Лабораторний конектор](https://developers.anpheros.com/uk/guides/lab-connector): кожна назва стовпця, поле HL7 та поле відповіді
- [Інтероперабельність медичних даних](https://developers.anpheros.com/uk/guides/interoperability): чому коди та походження роблять обмінені дані придатними для використання
- [Медичні інтеграції](https://developers.anpheros.com/uk/guides/healthcare-integrations): клініки, лабораторії, пристрої та сторонні додатки
- [API медичних даних](https://developers.anpheros.com/uk/guides/medical-data-api): запис окремих спостережень, станів та медикаментів
- [Як створити медичний додаток зі штучним інтелектом з бекендом FHIR](https://developers.anpheros.com/uk/guides/build-ai-healthcare-app): використання цих результатів у відповіді ШІ
