Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Como importar resultados de laboratório para um registo FHIR
Tutorial: importe um relatório de laboratório como CSV e como HL7 v2 ORU^R01 para Observações FHIR R4 com códigos LOINC e intervalos de referência, lide com marcadores não mapeados e relatórios reenviados, e rastreie cada resultado ao seu laboratório.
Este tutorial pega num relatório de laboratório como ficheiro CSV e como mensagem HL7 v2 ORU^R01, importa-o para o registo HL7 FHIR R4 de um paciente num pedido cada, e mostra o que recebe de volta: recursos Observation de laboratório com códigos LOINC, intervalos de referência e proveniência. Cobre também os dois problemas que toda a integração de laboratório encontra: marcadores que não podem ser mapeados automaticamente e relatórios que são enviados duas vezes. Tudo corre na sandbox gratuita com um paciente sintético.
Porquê os resultados de laboratório são difíceis de armazenar
Um relatório de laboratório parece simples: um marcador, um valor, uma unidade, um intervalo de referência, uma data. Na prática, cada laboratório nomeia os marcadores à sua maneira ("Hemoglobina glicozilata", "HbA1c", "Glycated haemoglobin"), utiliza vírgulas ou pontos para decimais, escreve intervalos como 4,0-5,6, <5 ou >3.5, e reenvia o mesmo relatório quando algo falha. Armazenados como texto livre, esses resultados não podem ser comparados ao longo do tempo, graficados, partilhados com outra aplicação ou fornecidos a um modelo de IA com confiança.
Um registo FHIR armazena cada resultado como um Observation com um código LOINC, uma unidade UCUM, um valor, um intervalo de referência e uma data, e mantém quem o enviou num recurso Provenance. O conector de laboratório faz essa conversão por si.
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 começar
Precisa de uma chave de sandbox (sk_test_…) em platform.anpheros.com/dashboard (Obter uma chave de sandbox). Os exemplos utilizam curl; os SDKs têm as mesmas chamadas (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')
Passo 1: importar um relatório CSV
É assim que um laboratório romeno pode exportar um relatório: ponto e vírgula, vírgulas decimais, nomes de colunas romenos e datas como DD.MM.YYYY. O conector reconhece nomes de colunas romenos 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
A resposta (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, glucose e TSH foram mapeados para LOINC a partir dos seus nomes. As vírgulas decimais tornaram-se números e os intervalos tornaram-se referenceRange. Uma linha voltou em unmapped. Continua armazenada, sob o código próprio do laboratório (urn:anpheros:lab-code) com o texto exato do relatório, para que nada se perca.
Passo 2: tratar marcadores não mapeados
Alguns nomes necessitam de uma decisão. "Glicemia" é um bom exemplo: o LOINC tem um código para glicose em soro ou plasma (2345-7, uma amostra venosa recolhida em laboratório) e outro para glicose em sangue total (2339-0, por exemplo, uma picada no dedo). Num relatório de laboratório, uma "Glicemia" simples é mapeada para soro ou plasma. Um nome que diga "capilar" ou "sangue integral" é mapeado para sangue 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 marcadores que o conector não reconhece, procure o 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}
Em seguida, envie o código numa coluna LOINC. Um código no relatório tem sempre precedência sobre o nome. Mantenha esse mapeamento por laboratório do seu lado e adicione a coluna a todos os relatórios desse laboratório:
Analiza;Rezultat;UM;Interval de referinta;Data;LOINC
Glicemie;99;mg/dL;70-100;04.10.2026;2339-0
Marcadores que o LOINC não cobre de todo, como o inventado "Marker foarte rar", podem permanecer sob o código do laboratório. São mostrados ao paciente e incluídos no registo. Não podem ser comparados com os resultados de outros laboratórios.
Passo 3: enviar o mesmo relatório duas vezes
Os laboratórios reenviaram relatórios. Cada linha recebe um identificador estável construído a partir do ID do relatório, do código, da data e do valor, pelo que uma segunda importação do mesmo relatório não cria nada:
{"created": 0, "skipped": 4, "unmapped": ["Marker foarte rar"], "warnings": [], "observations": []}
As linhas que foram alteradas, um valor corrigido por exemplo, são importadas como novos resultados. O cabeçalho Idempotency-Key adiciona uma segunda garantia: uma nova tentativa de rede com a mesma chave devolve a primeira resposta inalterada.
Passo 4: importar uma mensagem HL7 v2 ORU^R01
A maioria dos sistemas de informação laboratorial utiliza HL7 v2. Envie a mensagem como está (texto ER7, segmentos separados por CR ou 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 com o sistema de codificação LN é usado diretamente como LOINC. OBX-7 torna-se o intervalo de referência e OBX-8 (H, N) a interpretação. OBR-3 (R-77) é mantido como o ID do relatório na proveniência. O paciente é aquele no URL: o segmento PID não é usado para encontrar um paciente, portanto, um PID incorreto não pode anexar resultados a outra pessoa.
Já possui resultados analisados? Envie JSON: {"date": "2026-10-01", "origin": "report-77", "items": [{"marker": "Ferritin", "value": 38, "unit": "ng/mL", "ref_low": 15, "ref_high": 150}]}. A Ferritina é mapeada para LOINC 2276-4.
Passo 5: ler os resultados como FHIR
curl "$BASE/fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date&_count=1" \
-H "Authorization: Bearer $KEY"
O HbA1c importado, conforme armazenado:
{
"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": "%"}}]
}
O LOINC display é o nome padrão em inglês. code.text mantém a própria terminologia do laboratório, para que o paciente ainda veja o que estava no relatório em papel. Para mais informações sobre recursos e pesquisa, consulte o guia Plataforma FHIR e Sistemas de código FHIR.
Passo 6: verificar quem enviou
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 mantêm o valor. Quando uma aplicação de IA ler posteriormente este resultado através da API de contexto, será rotulado como [import/labx], permitindo que o modelo distinga um resultado de laboratório de um valor introduzido pelo paciente.
O que acontece a seguir
- O paciente vê os resultados na sua aplicação. Qualquer aplicação à qual tenha dado consentimento pode lê-los, dentro dos seus âmbitos (modelo de consentimento e acesso).
- Um
resource.createdwebhook é acionado para cada Observation, para que um painel de controlo da clínica ou um resumo de IA possa ser atualizado sem polling. POST /fhir/R4/Observation/$validate?profile=eu-labreporta como um resultado se compara ao perfil de relatório de laboratório HL7 Europe.- Até 500 linhas por pedido; os limites estão listados em Limites e limites de taxa.
Perguntas Frequentes
Que formatos de relatório de laboratório podem ser importados para o FHIR?
CSV com uma linha de cabeçalho (vírgula, ponto e vírgula ou tabulação, vírgula decimal aceite), mensagens HL7 v2 ORU^R01 e JSON. Relatórios em PDF podem ser armazenados como documentos; os valores extraídos deles apontam de volta para o documento.
O que acontece com marcadores sem código LOINC?
São armazenados sob o código próprio do laboratório com o texto exato do relatório e listados em unmapped. Adicione uma coluna LOINC para esse laboratório e eles serão mapeados. Um código num relatório tem sempre prioridade sobre o nome.
É seguro reenviar um relatório?
Sim. Cada linha tem um identificador estável construído a partir do relatório, código, data e valor, pelo que as linhas já importadas são ignoradas; as linhas alteradas são importadas como novos resultados.
Um laboratório pode importar resultados para qualquer paciente?
Não. Um laboratório importa para pacientes que criou no seu projeto ou cujos registos a pessoa partilhou com ele através de OAuth. Outros pacientes não existem para ele (404).
Relacionado
- API de resultados laboratoriais: HL7 v2 e FHIR lado a lado, e o que um resultado deve conter
- Conector de laboratório: cada nome de coluna, campo HL7 e campo de resposta
- Interoperabilidade de dados de saúde: por que códigos e proveniência tornam os dados trocados utilizáveis
- Integrações de saúde: clínicas, laboratórios, dispositivos e aplicações de terceiros
- API de dados médicos: escrever observações únicas, condições e medicamentos
- Como criar uma aplicação de saúde com IA com um backend FHIR: utilizando estes resultados numa resposta de IA
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card