Hospitalização

Uma hospitalização é a internação do paciente numa instituição — quando ela começou, quando terminou, onde, com qual profissional e por qual diagnóstico. Não é um atendimento do prontuário: é um evento que aparece na linha do tempo do paciente, ao lado do pronto atendimento, e serve para a equipe saber o que aconteceu com o paciente fora do cuidado que ela presta.

No FHIR ela é um Encounter com class.code IMP, e é esse código que faz a Nilo criar uma hospitalização em vez de um atendimento. No NiloCare o registro aparece em Eventos, com Evento: Hospitalização.

As regras desta página valem igualmente para o pronto atendimento — os dois são eventos e só se distinguem pelo class.code. Elas são bem diferentes das dos atendimentos VR e AMB: aqui o identifier é obrigatório, o status é calculado pela plataforma, e nenhum agendamento é criado.

Campos

CampoObrigatórioO que significaNo NiloCare
identifiersimChaves do evento. É por aqui que a API decide entre criar e atualizar
classsimTem de ser IMP. É o que distingue a hospitalizaçãoEvento: Hospitalização
statussim pelo FHIRAceito e descartado: a plataforma calcula o estado a partir de period.end
subjectsimO paciente internado, por um identificador dele já cadastrado
period.startsimData de entradaData de entrada / Data entrada
period.endnãoData de saída. Ausente, a internação é tratada como em andamentoData de saída / Data saída
participant[].individualnãoO profissional, por um identificador dele. type tem de ser PractitionerProfissional
location[0].location.displaynãoOnde a internação aconteceu, como texto livreLocal
diagnosis[].conditionnãoCondições já cadastradas a vincular ao eventoDiagnóstico
idnãoSó resposta: o identificador Nilo FHIR do recurso
metanãoSó resposta: metadados da gravação

Campos que a Nilo não usa

participant[].type, appointment, length e as extensões de origem, canal e desfecho não são lidos num evento — são campos dos atendimentos. O Encounter canônico traz ainda type, serviceType, priority, episodeOfCare, basedOn, reasonCode, reasonReference, account, hospitalization, serviceProvider, partOf, classHistory e statusHistory, nenhum deles lido nem gravado. Enviá-los não é recusado — o valor fica no recurso FHIR e volta nas leituras —, mas nada no NiloCare passa a exibi-los.

O campo Referido por da tela de eventos não tem representação FHIR. Toda hospitalização escrita por esta API entra como Outros, e uma atualização redefine o valor que a equipe tiver marcado na tela.

Cadastrar ou atualizar

Não há endpoint separado para criar e atualizar. O mesmo POST faz os dois, e quem decide é o identifier.

POST
/fhir/resources/Encounter
1curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Encounter \
2 -H "x-api-key: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "class": {
6 "code": "IMP",
7 "display": "inpatient encounter",
8 "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
9 },
10 "period": {
11 "start": "2026-01-17T16:00:00+00:00",
12 "end": "2026-01-20T11:30:00+00:00"
13 },
14 "resourceType": "Encounter",
15 "status": "finished",
16 "subject": {
17 "identifier": {
18 "system": "https://www.acmesaude.com.br/integracao/paciente/",
19 "value": "507823709",
20 "use": "usual"
21 },
22 "type": "Patient"
23 },
24 "identifier": [
25 {
26 "system": "https://www.acmesaude.com.br/integracao/evento/",
27 "value": "1126",
28 "use": "usual"
29 }
30 ],
31 "location": [
32 {
33 "location": {
34 "display": "Hospital Municipal de Exemplo"
35 }
36 }
37 ],
38 "participant": [
39 {
40 "individual": {
41 "identifier": {
42 "system": "https://www.acmesaude.com.br/integracao/profissional/",
43 "value": "5032932",
44 "use": "usual"
45 },
46 "type": "Practitioner"
47 }
48 }
49 ]
50}'

A resposta devolve o recurso como ficou gravado:

Response
1{
2 "class": {
3 "code": "IMP",
4 "display": "inpatient encounter",
5 "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
6 },
7 "period": {
8 "start": "2026-01-17T16:00:00+00:00",
9 "end": "2026-01-20T11:30:00+00:00"
10 },
11 "resourceType": "Encounter",
12 "status": "finished",
13 "subject": {
14 "identifier": {
15 "system": "https://www.acmesaude.com.br/integracao/paciente/",
16 "value": "507823709",
17 "use": "usual"
18 },
19 "type": "Patient",
20 "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
21 },
22 "id": "1268435b-5ae5-499c-bd75-635252d67901",
23 "meta": {
24 "lastUpdated": "2026-01-20T11:31:04.902000Z",
25 "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
26 },
27 "identifier": [
28 {
29 "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/hippocrates-api--hospitalization",
30 "value": "4821",
31 "use": "usual"
32 },
33 {
34 "system": "https://www.acmesaude.com.br/integracao/evento/",
35 "value": "1126",
36 "use": "usual"
37 }
38 ],
39 "location": [
40 {
41 "location": {
42 "display": "Hospital Municipal de Exemplo"
43 }
44 }
45 ],
46 "participant": [
47 {
48 "individual": {
49 "identifier": {
50 "system": "https://www.acmesaude.com.br/integracao/profissional/",
51 "value": "5032932",
52 "use": "usual"
53 },
54 "type": "Practitioner",
55 "reference": "Practitioner/1a9c7f52-64b8-4a3e-8d21-9f0b7c4e6d38"
56 }
57 }
58 ]
59}

Guarde o id: é por ele que se faz a leitura direta. A resposta traz também o identificador Nilo da hospitalização ao lado do seu, no system:

{host}/fhir/resources/NamingSystem/hippocrates-api--hospitalization

O identifier é obrigatório e a escrita é recusada sem ele.

Use um namespace de identificador só para eventos. Reaproveitar num evento um system + value já usado noutro tipo de registro faz a atualização falhar com Could not find … identifier for Encounter, porque a API acha o recurso mas não o evento.

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

A atualização substitui, não complementa. Um campo omitido não preserva o valor atual: omitir location apaga o local, omitir participant apaga o profissional, omitir period.end volta a internação para em andamento. Para mudar um campo só, reenvie o evento inteiro com o valor novo.

A exceção é diagnosis, que só adiciona — veja Diagnósticos.

Entrada, saída e estado

period.start é a data de entrada e é obrigatório. period.end é a data de saída, opcional, e quando enviado tem de ser maior que period.start.

O status funciona de forma diferente dos atendimentos: o FHIR R4 exige o campo, mas o valor que você envia é descartado. A plataforma calcula o estado a partir de period.end:

period.endstatus nas leituras
ausente, ou no futuroin-progress
no passadofinished

Uma internação em andamento, portanto, é simplesmente uma sem data de saída:

POST
/fhir/resources/Encounter
1curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Encounter \
2 -H "x-api-key: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "class": {
6 "code": "IMP",
7 "display": "inpatient encounter",
8 "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
9 },
10 "period": {
11 "start": "2026-01-17T16:00:00+00:00"
12 },
13 "resourceType": "Encounter",
14 "status": "in-progress",
15 "subject": {
16 "identifier": {
17 "system": "https://www.acmesaude.com.br/integracao/paciente/",
18 "value": "507823709",
19 "use": "usual"
20 },
21 "type": "Patient"
22 },
23 "identifier": [
24 {
25 "system": "https://www.acmesaude.com.br/integracao/evento/",
26 "value": "1128",
27 "use": "usual"
28 }
29 ],
30 "location": [
31 {
32 "location": {
33 "display": "Hospital Municipal de Exemplo"
34 }
35 }
36 ]
37}'

Para dar alta, reenvie o mesmo identifier com o period.end preenchido.

O status que você enviou continua no recurso FHIR e volta na leitura imediatamente seguinte — inclusive um cancelled ou um planned, que não têm significado aqui. O valor calculado pela plataforma só aparece na próxima vez que o evento mudar por lá, e aí substitui o seu. Reler o recurso logo depois do POST não confirma o estado real: use a tabela acima.

Profissional

O profissional vai em participant[].individual, e a referência precisa ter type: "Practitioner":

1{
2 "participant": [
3 {
4 "individual": {
5 "type": "Practitioner",
6 "identifier": { "system": "", "value": "" }
7 }
8 }
9 ]
10}

O participant[].type — o CodeableConcept do papel, com ATNDnão é lido num evento. Mandá-lo não é erro, só não tem efeito.

Um profissional que não casa com nenhum cadastro é descartado em silêncio: o evento é gravado sem profissional e a chamada responde 200. Diferente dos atendimentos, aqui não há erro. Confira o identificador do profissional antes de uma carga de eventos — a resposta não avisa.

Um item de participant sem individual, ou com individual.type diferente de Practitioner, também não é lido — e o primeiro caso faz a escrita falhar com um erro genérico. Não mande participant vazio.

Local

O local é texto livre, em location[0].location.display. Apenas o primeiro item da lista é lido — e, ao contrário do procedimento, aqui ele é opcional:

1{ "location": [ { "location": { "display": "Hospital Municipal de Exemplo" } } ] }

Por compatibilidade, um location[0].location.identifier apontando para um local de atendimento já cadastrado também é aceito, e o nome daquele local é gravado como texto. Não há vínculo: alterar o local depois não muda o que ficou no evento. Prefira display.

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

location é opcional, mas um location[0].location vazio — sem display e sem identifier — faz a escrita falhar com um erro genérico. Ou mande o campo preenchido, ou não mande location.

Diagnósticos

diagnosis vincula à internação condições que já existem. Cada item aponta para uma Condição por um identificador dela — este campo não a cria:

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

Para criar a condição e a hospitalização na mesma chamada, mande os dois num Bundle do tipo transaction e referencie a condição pelo fullUrl da entrada dela.

Uma condição pertence a um evento. Referenciar uma condição já vinculada a outro evento é recusado — e a recusa chega depois de a hospitalização ter sido criada na plataforma.

O resultado é uma escrita parcial ruim: a hospitalização existe na Nilo, mas o recurso FHIR não foi criado, então o seu identifier não encontra nada no store. Um reenvio do mesmo payload não atualiza o evento — cria uma segunda hospitalização. Trate este 400 como duplicação a resolver, não como retry seguro: confira o vínculo da condição e o evento já criado antes de reenviar.

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

diagnosis só adiciona. Remover um item do payload não desfaz o vínculo da condição com o evento, e reenviar uma condição já vinculada àquela mesma hospitalização não é erro — é uma operação sem efeito.

Paciente

subject é obrigatório, e o paciente tem de existir no cadastro:

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

Um evento não cria paciente. Cadastre o Paciente primeiro.

Buscar

GET
/fhir/resources/Encounter
1curl -G https://landing-zone-api.nilo.services/fhir/resources/Encounter \
2 -H "x-api-key: <apiKey>" \
3 -d _lastUpdated=eq2013-01-14 \
4 --data-urlencode _page_token=Cjj3YopYuf%2F%2F%2F%2F%2BABd%2BbgE0m...dSANQAFoLCUSM7w9VYUqaEANglLWUugQ%3D \
5 --data-urlencode class=http://terminology.hl7.org/CodeSystem/v3-ActCode|VR \
6 -d date=ge2026-04-01 \
7 --data-urlencode diagnosis=Condition/c61b5f58-32b0-477b-b75a-54e306952082 \
8 --data-urlencode identifier=https://www.acmesaude.com.br/integracao/atendimento/|55162 \
9 --data-urlencode participant=Practitioner/1a9c7f52-64b8-4a3e-8d21-9f0b7c4e6d38 \
10 --data-urlencode participant-type=http://terminology.hl7.org/CodeSystem/v3-ParticipationType|ATND \
11 --data-urlencode patient=Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4 \
12 --data-urlencode patient:identifier=https://www.acmesaude.com.br/integracao/paciente/|507823709 \
13 --data-urlencode practitioner=Practitioner/1a9c7f52-64b8-4a3e-8d21-9f0b7c4e6d38 \
14 -d status=finished \
15 --data-urlencode subject=Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4

A busca é a mesma para atendimentos e eventos, porque os quatro tipos são o mesmo recurso FHIR. Para trazer só as hospitalizações de um paciente, filtre por class:

$curl --request GET \
> --url 'https://landing-zone-api.nilo.services/fhir/resources/Encounter?patient:identifier=https://www.acmesaude.com.br/integracao/paciente/|507823709&class=IMP' \
> --header 'x-api-key: SUA_API_KEY'

A resposta é sempre um Bundle do tipo searchset. Busca sem resultados volta 200 com um Bundle cujo entry é uma lista vazia, não 404.

Parâmetros de busca suportados

NomeTipoDescriçãoExpressão
identifiertokenIdentificador do evento, em system|valueEncounter.identifier
patient:identifierreferencePaciente internado, pelo identificador deleEncounter.subject.identifier
patientreferencePaciente internado, pelo id Nilo FHIREncounter.subject
classtokenIMP para hospitalizaçõesEncounter.class
statustokenin-progress ou finishedEncounter.status
datedatePeríodo da internação, com os prefixos eq, ge, leEncounter.period
practitionerreferenceProfissional do evento. Aceita :identifierEncounter.participant.individual
diagnosisreferenceCondição vinculada. Aceita :identifierEncounter.diagnosis.condition

O parâmetro canônico location não encontra nada, apesar de o evento ter local: a Nilo grava o local como texto, e esse parâmetro casa por referência. Filtrar por local não é possível.

E participant-type também não: o papel do participante não é gravado nos eventos.

Ler por ID

GET
/fhir/resources/Encounter/:id
1curl https://landing-zone-api.nilo.services/fhir/resources/Encounter/id \
2 -H "x-api-key: <apiKey>"

A leitura por ID responde 404 quando o id não existe.

Diferente da busca, esta leitura não devolve um Bundle — mas também não devolve o recurso nu. A resposta é um envelope com fullUrl, search e resource, e o evento está em resource. Ler status ou identifier na raiz da resposta não encontra nada.

Valores aceitos

class.code tem de ser IMP, no system http://terminology.hl7.org/CodeSystem/v3-ActCode, com display inpatient encounter. É o código do vocabulário v3-ActEncounterCode para internação.

Os outros códigos aceitos pela API são EMER (pronto atendimento) e VR/AMB (atendimentos). Qualquer outro é recusado:

Response
1{
2 "errors": "Encounter class SS is not supported"
3}

status aceita os nove códigos do FHIR R4 no envio, e nenhum tem efeito. Nas leituras só in-progress e finished aparecem.

Efeitos colaterais

Vincular uma condição por diagnosis altera a condição: ela passa a pertencer a esta hospitalização, e esta API não desfaz o vínculo. Isso é visível na página da Condição.

Uma condição já vinculada a outro evento cria a hospitalização sem gravar o recurso FHIR. Veja Diagnósticos.

Nenhum agendamento é criado. Esse efeito é exclusivo dos atendimentos VR e AMB.

Este endpoint não remove eventos: a escrita nunca responde 204. A remoção acontece do lado da plataforma e é propagada para o store FHIR pela sincronização.

Erros

Recusa é 400, e o outro código que este endpoint devolve é 429, quando o limite de escrita do tipo de recurso é atingido.

Nos eventos as validações chegam sem expression e com o code genérico exception, e o details.text traz um prefixo técnico (ValueError: …). Trate esses erros pela menção no texto, não pelo code nem pelo expression.

E a mesma condição sai com mensagens diferentes conforme o tipo: o paciente não encontrado é Could not find Patient in subject aqui e Patient with identifier … does not exist or is not active nos atendimentos.

MensagemO que significa
Identifier is mandatoryO payload não trouxe identifier
Could not find Patient in subjectO identificador de subject não casou com nenhum paciente
Could not find Locationlocation[0].location veio só com identifier, e ele não resolveu
Could not find Condition … in FHIR storeA condição de diagnosis não existe
Condition … already linked to another …A condição pertence a outro evento. A mensagem termina com um nome de tipo interno, que não é contrato estável — case pelo already linked to another
Could not find … identifier for EncounterOs identificadores casaram com um recurso que não é esta hospitalização

O que a integração não cobre

Não há como, por esta API: filtrar eventos por local, registrar mais de um profissional num evento, desvincular uma condição de um evento, ou definir o Referido por. Também não é possível informar origem, canal ou desfecho — essas extensões valem só para os atendimentos.