Mensagem enviada

Uma mensagem enviada é o que a equipe e o paciente trocaram na conversa: o texto, o anexo, quando saiu e quando chegou.

No FHIR o recurso é a Communication.

Este recurso é somente leitura. Não existe POST /fhir/resources/Communication — não há como enviar mensagem a um paciente por esta API.

Campos

Todos os campos são de resposta — nenhum deles é enviado por você.

CampoSempre presenteO que significa
resourceTypesimConstante Communication
identifiersimIdentificador Nilo da mensagem
statussimSituação de entrega — veja abaixo
medium[0]simConstante REMOTE, com display e text iguais a remote presence
sentquase sempreQuando a mensagem foi enviada
receivednãoQuando foi entregue
senderquase sempreQuem enviou: um Practitioner nas mensagens da equipe, um Patient nas do paciente. Ausente quando a mensagem da equipe não registrou autor
recipient[]nãoOs pacientes da conversa — só nas mensagens da equipe
payload[]nãoO texto e o anexo
id · metasimIdentificador Nilo FHIR do recurso e metadados da gravação

status é entrega, não leitura

ValorO que aconteceu
preparationA mensagem está na fila
in-progressEstá saindo
completedFoi enviada, entregue ou lida
not-doneFalhou

completed junta três coisas diferentes. Enviada, entregue e lida colapsam no mesmo valor: não há como saber, por este campo, se o paciente leu a mensagem.

O que dá alguma pista é o received, que só aparece quando a entrega foi confirmada — mas leitura não tem campo nenhum.

Quem enviou e quem recebeu

Mensagem do paciente vem sem destinatário. Só as mensagens enviadas pela equipe trazem recipient[]. Numa mensagem recebida, o campo simplesmente não vem — a plataforma não registra para quem, dentro da equipe, ela foi.

E uma mensagem da equipe também pode vir sem recipient: quando a conversa não resolve nenhum paciente, a lista sai vazia e some da resposta. Ausência de recipient não distingue, sozinha, quem enviou — para isso, olhe o type do sender.

Numa mensagem do paciente, o sender é o primeiro paciente da conversa, não necessariamente quem escreveu. Numa conversa com mais de um paciente — o que acontece em conversas familiares —, isso pode apontar para a pessoa errada.

Não use o sender de uma mensagem recebida para atribuir autoria.

Uma conversa resolve no máximo 50 pacientes. Acima disso, os destinatários excedentes são omitidos em silêncio do recipient[]. Numa conversa grande, a lista que você recebe é incompleta e não há sinal disso na resposta.

O conteúdo

payload[] traz até dois itens: um com contentString, para o texto, e outro com contentAttachment, para o anexo.

Uma mensagem só com anexo vem com um item só; uma mensagem sem texto e sem anexo vem sem payload. E o anexo é uma referência ao arquivo, não o conteúdo dele.

Campos que a Nilo não usa

A Communication canônica traz muito mais: basedOn, partOf, inResponseTo, category, priority, subject, topic, about, encounter, reasonCode, reasonReference e note. Nenhum deles é lido.

Repare em inResponseTo e em partOf: não há como reconstruir a thread da conversa por esta API. As mensagens vêm soltas, e a única forma de agrupá-las é pelo par de participantes e pela ordem de sent.

E repare em subject: numa mensagem da equipe, o paciente está em recipient; numa do paciente, em sender. Não há um campo único que diga “de quem é esta conversa”.

Buscar

GET
/fhir/resources/Communication
1curl -G https://landing-zone-api.nilo.services/fhir/resources/Communication \
2 -H "x-api-key: <apiKey>" \
3 -d _count=50 \
4 -d _lastUpdated=eq2013-01-14 \
5 --data-urlencode _page_token=Cjj3YopYuf%2F%2F%2F%2F%2BABd%2BbgE0m...dSANQAFoLCUSM7w9VYUqaEANglLWUugQ%3D \
6 --data-urlencode identifier=https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/parrot-api--whats-app-message|9911204 \
7 -d received=ge2026-07-01 \
8 --data-urlencode recipient=Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4 \
9 --data-urlencode recipient:identifier=https://www.acmesaude.com.br/integracao/paciente/|507823709 \
10 --data-urlencode sender=Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19 \
11 --data-urlencode sender:identifier=https://www.acmesaude.com.br/integracao/profissional/|5032932 \
12 -d sent=ge2026-07-01 \
13 -d status=completed

A resposta é sempre um Bundle do tipo searchset:

Response
1{
2 "resourceType": "Bundle",
3 "type": "searchset",
4 "entry": [
5 {
6 "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Communication/a3f802d6-71b4-4e59-9c07-52d148ba3e91",
7 "resource": {
8 "resourceType": "Communication",
9 "identifier": [
10 {
11 "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/parrot-api--whats-app-message",
12 "value": "9911204",
13 "use": "usual"
14 }
15 ],
16 "status": "completed",
17 "id": "a3f802d6-71b4-4e59-9c07-52d148ba3e91",
18 "meta": {
19 "lastUpdated": "2026-07-02T14:31:13.004000Z",
20 "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
21 },
22 "medium": [
23 {
24 "coding": [
25 {
26 "code": "REMOTE",
27 "display": "remote presence",
28 "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationMode"
29 }
30 ],
31 "text": "remote presence"
32 }
33 ],
34 "sent": "2026-07-02T14:31:08+00:00",
35 "received": "2026-07-02T14:31:12+00:00",
36 "sender": {
37 "identifier": {
38 "system": "https://www.acmesaude.com.br/integracao/profissional/",
39 "value": "5032932",
40 "use": "usual"
41 },
42 "type": "Practitioner",
43 "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
44 },
45 "recipient": [
46 {
47 "identifier": {
48 "system": "https://www.acmesaude.com.br/integracao/paciente/",
49 "value": "507823709",
50 "use": "usual"
51 },
52 "type": "Patient",
53 "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
54 }
55 ],
56 "payload": [
57 {
58 "contentString": "Bom dia! Sua consulta é amanhã às 14h."
59 }
60 ]
61 },
62 "search": {
63 "mode": "match"
64 }
65 },
66 {
67 "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Communication/7e40b915-c2d8-4a63-81f7-06e93a2c5478",
68 "resource": {
69 "resourceType": "Communication",
70 "identifier": [
71 {
72 "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/parrot-api--whats-app-message",
73 "value": "9911207",
74 "use": "usual"
75 }
76 ],
77 "status": "completed",
78 "id": "7e40b915-c2d8-4a63-81f7-06e93a2c5478",
79 "meta": {
80 "lastUpdated": "2026-07-02T14:40:55.318000Z",
81 "versionId": "MTc4NjAyMTQ1MjkwNTAwMDQwMg"
82 },
83 "medium": [
84 {
85 "coding": [
86 {
87 "code": "REMOTE",
88 "display": "remote presence",
89 "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationMode"
90 }
91 ],
92 "text": "remote presence"
93 }
94 ],
95 "sent": "2026-07-02T14:40:51+00:00",
96 "sender": {
97 "identifier": {
98 "system": "https://www.acmesaude.com.br/integracao/paciente/",
99 "value": "507823709",
100 "use": "usual"
101 },
102 "type": "Patient",
103 "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
104 },
105 "payload": [
106 {
107 "contentString": "Confirmado, obrigada!"
108 }
109 ]
110 },
111 "search": {
112 "mode": "match"
113 }
114 }
115 ],
116 "link": []
117}

Busca sem resultados não é erro: volta 200 com um Bundle cujo entry é uma lista vazia.

Response
1{
2 "resourceType": "Bundle",
3 "type": "searchset",
4 "entry": [],
5 "link": []
6}

Parâmetros de busca suportados

NomeTipoDescriçãoExpressão
identifiertokenIdentificador da mensagem, em system|valueCommunication.identifier
sender · sender:identifierreferenceQuem enviouCommunication.sender
recipient · recipient:identifierreferenceQuem recebeuCommunication.recipient
statustokenSituação de entregaCommunication.status
sentdateData de envio, com os prefixos eq, ge, leCommunication.sent
receiveddateData de entrega, com os mesmos prefixosCommunication.received
mediumtokenAceito, e inútil: toda mensagem é REMOTECommunication.medium
_lastUpdateddateData da última gravação no store, com os mesmos prefixos

Para listar as mensagens de um paciente, você precisa das duas buscas. As que ele recebeu estão em recipient; as que ele enviou, em sender. Não há um parâmetro que cubra os dois.

Os demais parâmetros canônicos da Communication existem e não encontram nada, porque a plataforma não preenche o campo correspondente: based-on, category, encounter, instantiates-canonical, instantiates-uri, part-of, patient e subject.

Repare em patient: o parâmetro canônico procura em Communication.subject, que a Nilo não preenche — use recipient e sender.

Qual identificador as referências de sender e recipient carregam depende da sua implantação. Na configuração que usa identificadores externos, cada referência sai com o identificador do seu sistema; sem ela, vem o identificador Nilo. Confira numa resposta de leitura antes de montar a busca em volume.

A paginação é por _count e _page_token; havendo página seguinte, o Bundle traz a URL pronta em link.

Ler por ID

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

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 a mensagem está em resource.

Response
1{
2 "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Communication/a3f802d6-71b4-4e59-9c07-52d148ba3e91",
3 "resource": {
4 "resourceType": "Communication",
5 "identifier": [
6 {
7 "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/parrot-api--whats-app-message",
8 "value": "9911204",
9 "use": "usual"
10 }
11 ],
12 "status": "completed",
13 "id": "a3f802d6-71b4-4e59-9c07-52d148ba3e91",
14 "meta": {
15 "lastUpdated": "2026-07-02T14:31:13.004000Z",
16 "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
17 },
18 "medium": [
19 {
20 "coding": [
21 {
22 "code": "REMOTE",
23 "display": "remote presence",
24 "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationMode"
25 }
26 ],
27 "text": "remote presence"
28 }
29 ],
30 "sent": "2026-07-02T14:31:08+00:00",
31 "received": "2026-07-02T14:31:12+00:00",
32 "sender": {
33 "identifier": {
34 "system": "https://www.acmesaude.com.br/integracao/profissional/",
35 "value": "5032932",
36 "use": "usual"
37 },
38 "type": "Practitioner",
39 "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
40 },
41 "payload": [
42 {
43 "contentString": "Bom dia! Sua consulta é amanhã às 14h."
44 }
45 ]
46 },
47 "search": {
48 "mode": "match"
49 }
50}

Cadastrar ou atualizar

Não existe. Este recurso não tem caminho de escrita nesta API.

Um POST /fhir/resources/Communication não é uma operação suportada e não devolve um erro de validação tratável: a chamada falha com erro inesperado do servidor (500). Não escreva tratamento em cima desse comportamento — ele não é contrato, e nada é gravado.

O que a integração não cobre

  • enviar mensagem a um paciente;
  • a thread da conversa — não há inResponseTo nem partOf;
  • se o paciente leu a mensagem;
  • o destinatário de uma mensagem recebida;
  • os pacientes além do quinquagésimo numa conversa grande;
  • o conteúdo do anexo — só a referência a ele.

Para as mensagens que a plataforma vai enviar, veja Mensagem programada.