AnpherosAnpheros PlatformDevelopers

Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card

Come importare referti di laboratorio in un fascicolo FHIR

Tutorial: importa un referto di laboratorio come CSV e come HL7 v2 ORU^R01 in Osservazioni FHIR R4 con codici LOINC e intervalli di riferimento, gestisci marcatori non mappati e referti inviati nuovamente, e traccia ogni risultato al suo laboratorio.

Questo tutorial prende un referto di laboratorio come file CSV e come messaggio HL7 v2 ORU^R01, lo importa nel record HL7 FHIR R4 di un paziente con una richiesta ciascuno, e mostra cosa si ottiene: risorse di laboratorio Observation con codici LOINC, intervalli di riferimento e provenienza. Copre anche i due problemi che ogni integrazione di laboratorio incontra: marcatori che non possono essere mappati automaticamente e referti che vengono inviati due volte. Tutto funziona sulla sandbox gratuita con un paziente sintetico.

Perché i risultati di laboratorio sono difficili da archiviare

Un referto di laboratorio sembra semplice: un marcatore, un valore, un'unità, un intervallo di riferimento, una data. In pratica, ogni laboratorio nomina i marcatori a modo suo ("Emoglobina glicosilata", "HbA1c", "Glycated haemoglobin"), utilizza virgole o punti per i decimali, scrive gli intervalli come 4,0-5,6, <5 o >3.5 e reinvia lo stesso referto quando qualcosa non funziona. Archiviati come testo libero, questi risultati non possono essere confrontati nel tempo, graficati, condivisi con un'altra applicazione o forniti con sicurezza a un modello di intelligenza artificiale.

Un record FHIR archivia ogni risultato come un Observation con un codice LOINC, un'unità UCUM, un valore, un intervallo di riferimento e una data, e conserva chi lo ha inviato in una risorsa Provenance. Il connettore di laboratorio esegue questa conversione per te.

 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

Prima di iniziare

È necessaria una chiave sandbox (sk_test_…) da platform.anpheros.com/dashboard (Ottieni una chiave sandbox). Gli esempi utilizzano curl; gli SDK hanno le stesse chiamate (labs.importCsv, labs.importHl7, labs.importItems).

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')

Passaggio 1: importare un report CSV

Ecco come un laboratorio rumeno potrebbe esportare un report: punti e virgola, virgole decimali, nomi di colonna rumeni e date come DD.MM.YYYY. Il connettore riconosce i nomi di colonna rumeni e inglesi.

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

La risposta (201):

{"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, glucosio e TSH sono stati mappati a LOINC dai loro nomi. Le virgole decimali sono diventate numeri e gli intervalli sono diventati referenceRange. Una riga è tornata in unmapped. È ancora memorizzata, sotto il codice del laboratorio (urn:anpheros:lab-code) con il testo esatto del report, quindi nulla è andato perso.

Passaggio 2: gestione dei marcatori non mappati

Alcuni nomi richiedono una decisione. "Glicemie" è un buon esempio: LOINC ha un codice per il glucosio nel siero o nel plasma (2345-7, un campione venoso prelevato in laboratorio) e un altro per il glucosio nel sangue intero (2339-0, ad esempio un prelievo capillare). Su un referto di laboratorio, un semplice "Glicemie" viene mappato a siero o plasma. Un nome che dice "capilar", "capillary" o "sânge integral" viene mappato a sangue intero:

{"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"}]}

Per i marcatori che il connettore non riconosce, cercare il codice:

curl "$BASE/v1/terminology/loinc?q=glucose" -H "Authorization: Bearer $KEY"
{"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}

Quindi inviare il codice in una colonna LOINC. Un codice nel referto ha sempre la precedenza sul nome. Mantenere quella mappatura per laboratorio dalla propria parte e aggiungere la colonna a ogni referto proveniente da esso:

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

I marcatori che LOINC non copre affatto, come il fittizio "Marker foarte rar", possono rimanere sotto il codice del laboratorio. Vengono mostrati al paziente e inclusi nel referto. Non possono essere confrontati con i risultati di altri laboratori.

Passaggio 3: inviare lo stesso report due volte

I laboratori inviano nuovamente i report. Ogni riga ottiene un identificatore stabile costruito dall'ID del report, dal codice, dalla data e dal valore, quindi una seconda importazione dello stesso report non crea nulla:

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

Le righe che sono cambiate, ad esempio un valore corretto, vengono importate come nuovi risultati. L'intestazione Idempotency-Key aggiunge una seconda garanzia: un nuovo tentativo di rete con la stessa chiave restituisce la prima risposta invariata.

Passaggio 4: importare un messaggio HL7 v2 ORU^R01

La maggior parte dei sistemi informativi di laboratorio utilizza HL7 v2. Inviare il messaggio così com'è (testo ER7, segmenti separati da CR o 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
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
{"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 con il sistema di codifica LN viene utilizzato direttamente come LOINC. OBX-7 diventa l'intervallo di riferimento e OBX-8 (H, N) l'interpretazione. OBR-3 (R-77) viene mantenuto come ID del report nella provenienza. Il paziente è quello nell'URL: il segmento PID non viene utilizzato per trovare un paziente, quindi un PID errato non può allegare risultati a qualcun altro.

Si possiedono già risultati analizzati? Inviare JSON: {"date": "2026-10-01", "origin": "report-77", "items": [{"marker": "Ferritin", "value": 38, "unit": "ng/mL", "ref_low": 15, "ref_high": 150}]}. La ferritina viene mappata a LOINC 2276-4.

Passaggio 5: leggere i risultati come FHIR

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

L'HbA1c importato, come memorizzato:

{
  "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": "%"}}]
}

Il display LOINC è il nome standard in inglese. code.text mantiene la dicitura del laboratorio, in modo che il paziente veda ancora ciò che era sul referto cartaceo. Per ulteriori informazioni su risorse e ricerca, consultare la guida FHIR platform e FHIR code systems.

Step 6: verifica chi l'ha inviato

curl "$BASE/v1/patients/$PID/provenance/Observation/62b1b0c0-…" -H "Authorization: Bearer $KEY"
{"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 e source_system: labx rimangono con il valore. Quando un'applicazione AI leggerà successivamente questo risultato tramite la context API, sarà etichettato [import/labx], in modo che il modello possa distinguere un risultato di laboratorio da un valore inserito dal paziente.

Cosa succede dopo

Domande frequenti

Quali formati di referti di laboratorio possono essere importati in FHIR?

CSV con una riga di intestazione (virgola, punto e virgola o tabulazione, virgola decimale accettata), messaggi HL7 v2 ORU^R01 e JSON. I referti PDF possono essere archiviati come documenti; i valori estratti da essi puntano al documento.

Cosa succede ai marcatori senza codice LOINC?

Vengono archiviati sotto il codice del laboratorio stesso con il testo esatto dal referto e elencati in unmapped. Aggiungere una colonna LOINC per quel laboratorio e verranno mappati. Un codice nel referto ha sempre la precedenza sul nome.

È sicuro reinviare un referto?

Sì. Ogni riga ha un identificatore stabile costruito dal referto, codice, data e valore, quindi le righe già importate vengono saltate; le righe modificate vengono importate come nuovi risultati.

Un laboratorio può importare risultati per qualsiasi paziente?

No. Un laboratorio importa nei pazienti il cui progetto ha creato o i cui record la persona ha condiviso con esso tramite OAuth. Altri pazienti non esistono per esso (404).

Correlati

Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card

Product updates by email

New features, guides and the end of the beta. One email a month at most.

Send me occasional Anpheros Platform updates by email (new features, API changes, guides). I'll confirm by email and can unsubscribe in one click from any email. Privacy