Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Cómo importar resultados de laboratorio a un registro FHIR
Tutorial: importar un informe de laboratorio como CSV y como HL7 v2 ORU^R01 a Observaciones FHIR R4 con códigos LOINC y rangos de referencia, manejar marcadores no mapeados e informes reenviados, y rastrear cada resultado a su laboratorio.
Este tutorial toma un informe de laboratorio como archivo CSV y como mensaje HL7 v2 ORU^R01, lo importa a un registro HL7 FHIR R4 de un paciente en una solicitud cada uno, y muestra lo que se obtiene a cambio: recursos de laboratorio Observation con códigos LOINC, rangos de referencia y procedencia. También cubre los dos problemas con los que se encuentra toda integración de laboratorio: marcadores que no se pueden mapear automáticamente e informes que se envían dos veces. Todo se ejecuta en el sandbox gratuito con un paciente sintético.
Por qué los resultados de laboratorio son difíciles de almacenar
Un informe de laboratorio parece simple: un marcador, un valor, una unidad, un rango de referencia, una fecha. En la práctica, cada laboratorio nombra los marcadores a su manera ("Hemoglobina glicozilada", "HbA1c", "Glycated haemoglobin"), usa comas o puntos para los decimales, escribe rangos como 4,0-5,6, <5 o >3.5, y reenvía el mismo informe cuando algo falla. Almacenados como texto libre, esos resultados no se pueden comparar a lo largo del tiempo, graficar, compartir con otra aplicación o entregar a un modelo de IA con confianza.
Un registro FHIR almacena cada resultado como un Observation con un código LOINC, una unidad UCUM, un valor, un rango de referencia y una fecha, y mantiene quién lo envió en un recurso Provenance. El conector de laboratorio realiza esa conversión por usted.
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
Antes de empezar
Necesitas una clave de sandbox (sk_test_…) de platform.anpheros.com/dashboard (Obtener una clave de sandbox). Los ejemplos utilizan curl; los SDKs tienen las mismas llamadas (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')
Paso 1: importar un informe CSV
Así es como un laboratorio rumano podría exportar un informe: punto y coma, comas decimales, nombres de columna rumanos y fechas como DD.MM.YYYY. El conector reconoce nombres de columna rumanos e ingleses.
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 respuesta (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, glucosa y TSH se mapearon a LOINC a partir de sus nombres. Las comas decimales se convirtieron en números y los rangos se convirtieron en referenceRange. Una fila regresó en unmapped. Todavía se almacena, bajo el código propio del laboratorio (urn:anpheros:lab-code) con el texto exacto del informe, por lo que no se pierde nada.
Paso 2: Manejar marcadores no mapeados
Algunos nombres requieren una decisión. "Glicemie" (glucosa en sangre) es un buen ejemplo: LOINC tiene un código para la glucosa en suero o plasma (2345-7, una muestra venosa tomada en un laboratorio) y otro para la glucosa en sangre total (2339-0, por ejemplo, una punción digital). En un informe de laboratorio, un "Glicemie" sin más se mapea a suero o plasma. Un nombre que diga "capilar", "capillary" o "sânge integral" se mapea a sangre total:
{"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"}]}
Para los marcadores que el conector no reconoce, busque el código:
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}
Luego, envíe el código en una columna LOINC. Un código en el informe siempre prevalece sobre el nombre. Mantenga ese mapeo por laboratorio de su lado y agregue la columna a cada informe de ese laboratorio:
Analiza;Rezultat;UM;Interval de referinta;Data;LOINC
Glicemie;99;mg/dL;70-100;04.10.2026;2339-0
Los marcadores que LOINC no cubre en absoluto, como el inventado "Marker foarte rar", pueden permanecer bajo el código del laboratorio. Se muestran al paciente y se incluyen en el registro. No se pueden comparar con los resultados de otros laboratorios.
Paso 3: enviar el mismo informe dos veces
Los laboratorios reenvían informes. Cada fila obtiene un identificador estable construido a partir del ID del informe, el código, la fecha y el valor, por lo que una segunda importación del mismo informe no crea nada:
{"created": 0, "skipped": 4, "unmapped": ["Marker foarte rar"], "warnings": [], "observations": []}
Las filas que cambiaron, un valor corregido por ejemplo, se importan como nuevos resultados. La cabecera Idempotency-Key añade una segunda garantía: un reintento de red con la misma clave devuelve la primera respuesta sin cambios.
Paso 4: importar un mensaje HL7 v2 ORU^R01
La mayoría de los sistemas de información de laboratorio utilizan HL7 v2. Envíe el mensaje tal como está (texto ER7, segmentos separados por 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 el sistema de codificación LN se utiliza directamente como LOINC. OBX-7 se convierte en el rango de referencia y OBX-8 (H, N) la interpretación. OBR-3 (R-77) se mantiene como el ID del informe en la procedencia. El paciente es el de la URL: el segmento PID no se utiliza para encontrar un paciente, por lo que un PID incorrecto no puede adjuntar resultados a otra persona.
¿Ya tiene resultados analizados? Envíe JSON: {"date": "2026-10-01", "origin": "report-77", "items": [{"marker": "Ferritin", "value": 38, "unit": "ng/mL", "ref_low": 15, "ref_high": 150}]}. La ferritina se mapea a LOINC 2276-4.
Paso 5: leer los resultados como FHIR
curl "$BASE/fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date&_count=1" \
-H "Authorization: Bearer $KEY"
El HbA1c importado, tal como se almacena:
{
"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": "%"}}]
}
El LOINC display es el nombre estándar en inglés. code.text conserva la redacción propia del laboratorio, por lo que el paciente sigue viendo lo que estaba en el informe en papel. Para más información sobre recursos y búsquedas, consulte la guía de la plataforma FHIR y los sistemas de códigos FHIR.
Paso 6: Comprobar quién lo envió
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 y source_system: labx permanecen con el valor. Cuando una aplicación de IA lea posteriormente este resultado a través de la API de contexto, se etiquetará como [import/labx], de modo que el modelo pueda distinguir un resultado de laboratorio de un valor introducido por el paciente.
Qué sucede a continuación
- El paciente ve los resultados en su aplicación. Cualquier aplicación a la que haya dado su consentimiento puede leerlos, dentro de sus ámbitos (modelo de consentimiento y acceso).
- Se activa un webhook
resource.createdpor cada Observation, de modo que un panel de control de la clínica o un resumen de IA pueda actualizarse sin sondeos. POST /fhir/R4/Observation/$validate?profile=eu-labinforma cómo una medición de un resultado se compara con el perfil de informe de laboratorio de HL7 Europe.- Hasta 500 filas por solicitud; los límites se enumeran en Límites y límites de velocidad.
Preguntas frecuentes
¿Qué formatos de informes de laboratorio se pueden importar a FHIR?
CSV con una fila de encabezado (se aceptan coma, punto y coma o tabulación, coma decimal), mensajes HL7 v2 ORU^R01 y JSON. Los informes PDF se pueden almacenar como documentos; los valores extraídos de ellos apuntan de vuelta al documento.
¿Qué sucede con los marcadores sin código LOINC?
Se almacenan bajo el código propio del laboratorio con el texto exacto del informe y se listan en unmapped. Agregue una columna LOINC para ese laboratorio y se mapearán. Un código en el informe siempre tiene prioridad sobre el nombre.
¿Es seguro reenviar un informe?
Sí. Cada fila tiene un identificador estable construido a partir del informe, código, fecha y valor, por lo que las filas ya importadas se omiten; las filas modificadas se importan como nuevos resultados.
¿Puede un laboratorio importar resultados para cualquier paciente?
No. Un laboratorio importa en los pacientes creados por su proyecto o cuyos registros la persona compartió con él a través de OAuth. Otros pacientes no existen para él (404).
Relacionado
- API de resultados de laboratorio: HL7 v2 y FHIR lado a lado, y qué debe contener un resultado
- Conector de laboratorio: cada nombre de columna, campo HL7 y campo de respuesta
- Interoperabilidad de datos de salud: por qué los códigos y la procedencia hacen que los datos intercambiados sean utilizables
- Integraciones de salud: clínicas, laboratorios, dispositivos y aplicaciones de terceros
- API de datos médicos: escritura de observaciones únicas, condiciones y medicamentos
- Cómo crear una aplicación de salud con IA con un backend FHIR: uso de estos resultados en una respuesta de IA
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card