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
- Il paziente visualizza i risultati nella propria app. Qualsiasi applicazione a cui ha acconsentito può leggerli, nei limiti dei propri scope (modello di consenso e accesso).
- Un webhook
resource.createdviene attivato per ogni Observation, in modo che una dashboard clinica o un riepilogo AI possa aggiornarsi senza polling. POST /fhir/R4/Observation/$validate?profile=eu-labriporta come un risultato si confronta con il profilo del report di laboratorio HL7 Europe.- Fino a 500 righe per richiesta; i limiti sono elencati in Limiti e rate limits.
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
- API per i risultati di laboratorio: HL7 v2 e FHIR affiancati, e cosa deve contenere un risultato
- Connettore di laboratorio: ogni nome di colonna, campo HL7 e campo di risposta
- Interoperabilità dei dati sanitari: perché codici e provenienza rendono utilizzabili i dati scambiati
- Integrazioni sanitarie: cliniche, laboratori, dispositivi e app di terze parti
- API per dati medici: scrittura di singole osservazioni, condizioni e farmaci
- Come creare un'app sanitaria AI con un backend FHIR: utilizzo di questi risultati in una risposta AI
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card