Cadastrar
| Endpoint | POST /fhir/resources/Media |
|---|---|
| Autenticação | 🔓 Chave de API |
| Status | Implementado |
- O campo
identifieré obrigatório e deve ser novo e único a cada arquivo: não existe atualização deMedia. - O campo
subjecté obrigatório, e osubject.identifiertambém: é por ele que o paciente é resolvido. Enviar apenas osubject.referenceresulta em erro. - Envie o arquivo por
content.urlou porcontent.data(base64). Ocontent.urltem precedência quando os dois são enviados. - O
content.titlesó é preservado como nome do arquivo no envio em base64. No envio por URL o nome é definido pelo NiloCare. - Somente
application/pdf, com limite de 10 MiB (10485760 bytes). - Não há
PUTnemDELETEpara este recurso.
Modelagem da API - Request
- Headers
- Body
| Opção | Tipo | Requerido | Descrição | Exemplo | |||||
|---|---|---|---|---|---|---|---|---|---|
| x-api-key | string | Sim | Chave de autenticação do cliente, fornecida durante a configuração do ambiente. | ||||||
| Content-Type | string | Sim | application/json | ||||||
| resourceType required | any Value: "Media" |
| id | string (id) ^[A-Za-z0-9\-\.]{{1,64}}$ Qualquer combinação de letras, números, "-" e ".", com um limite de 64 caracteres. (Pode ser um número inteiro, um OID não prefixado, UUID ou qualquer outro padrão de identificador que atenda a essas restrições.) Os IDs não diferenciam maiúsculas de minúsculas. |
object (Meta) Os metadados sobre um recurso. Este conteúdo do recurso é normalmente mantido pelo sistema gestor do registro. | |
required | Array of objects (Identifier) non-empty Identificador do arquivo no sistema de origem. Obrigatório e deve ser novo e único a cada arquivo: não há atualização de Media. |
| status required | any Obrigatório pela especificação FHIR, porém ignorado na escrita: o NiloCare não armazena o status do arquivo. A consulta sempre retorna Value: "completed" |
required | object Paciente ao qual o arquivo será associado. A resolução usa exclusivamente o |
required | Envio por URL (object) or Envio em base64 (object) Conteúdo do arquivo. Informe |
{- "resourceType": "Media",
- "id": "903dAAe9-c57f-4eb3-bd1c-65XXd41exx81",
- "meta": {
- "lastUpdated": "2022-05-25T18:42:06.551129+00:00",
- "versionId": "903dAAe9-c57f-4eb3-bd1c-65XXd41exx81"
}, - "identifier": [
- {
- "system": "{host}/fhir/resources/NamingSystem/hippocrates-api--model-name",
- "use": "usual",
- "value": "12345"
}
], - "status": "completed",
- "subject": {
- "type": "Patient"
}, - "content": {
- "contentType": "application/pdf",
- "data": "JVBERi0xLjQKJeLjz9MK...",
- "title": "Laudo do exame",
- "size": 20481,
- "hash": "string"
}
}Envio por URL
O NiloCare baixa o arquivo a partir da URL informada em content.url. Use esse fluxo para arquivos
grandes ou que já estejam publicados em um endereço acessível.
Nesse fluxo o nome do arquivo é definido pelo NiloCare a partir do paciente — o content.title
não é preservado como nome do arquivo. Para controlar o nome, use o envio em base64.
curl --request POST \
--url https://landing-zone-api.nilo.services/fhir/resources/Media \
--header 'Content-Type: application/json' \
--header 'x-api-key: <inserir API Key aqui>' \
--data '{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77001"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77001.pdf",
"title": "Laudo do exame"
}
}'
Envio do conteúdo em base64
O conteúdo enviado em content.data é decodificado, validado e armazenado pelo NiloCare, preservando o
nome derivado de content.title. Nesse fluxo o content.contentType é obrigatório.
curl --request POST \
--url https://landing-zone-api.nilo.services/fhir/resources/Media \
--header 'Content-Type: application/json' \
--header 'x-api-key: <inserir API Key aqui>' \
--data '{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77002"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"title": "Laudo do exame",
"data": "JVBERi0xLjQKMSAwIG9iajw8L1R5cGUvQ2F0YWxvZy9QYWdlcyAyIDAgUj4+ZW5kb2JqCjIgMCBvYmo8PC9UeXBlL1BhZ2VzL0tpZHNbMyAwIFJdL0NvdW50IDE+PmVuZG9iagozIDAgb2JqPDwvVHlwZS9QYWdlL1BhcmVudCAyIDAgUi9NZWRpYUJveFswIDAgNTk1IDg0Ml0+PmVuZG9iagp4cmVmCjAgNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDkgMDAwMDAgbiAKMDAwMDAwMDA1MiAwMDAwMCBuIAowMDAwMDAwMTAxIDAwMDAwIG4gCnRyYWlsZXI8PC9TaXplIDQvUm9vdCAxIDAgUj4+CnN0YXJ0eHJlZgoxNjQKJSVFT0YK"
}
}'
O content.data do exemplo acima é um PDF mínimo válido — uma única página em branco — para manter a
requisição legível.
Nome do arquivo (content.title)
As regras abaixo valem apenas para o envio em base64 — é o único fluxo em que o content.title é
preservado. Nele, o nome do arquivo é derivado do content.title da seguinte forma:
- acentos são transliterados (
ó→o); - caracteres que não sejam letras, números,
.,_ou-são substituídos por_; - uma extensão
.pdfjá presente no título não é duplicada; - o nome é truncado em 100 caracteres;
.,_e-nas extremidades são removidos;- sem
content.title, o arquivo é nomeadodocument.pdf.
content.title enviado | Nome do arquivo no NiloCare |
|---|---|
"Laudo do exame" | Laudo_do_exame.pdf |
"Relatório Médico.pdf" | Relatorio_Medico.pdf |
"../../etc/Relatório Médico.pdf" | etc_Relatorio_Medico.pdf |
| ausente | document.pdf |
O arquivo é limitado a 10 MiB (10485760 bytes).
Modelagem da API - Response
- ✔ 200
- ✘ 400
- ✘ 500
| resourceType required | any Value: "Media" |
| id | string (id) ^[A-Za-z0-9\-\.]{{1,64}}$ Qualquer combinação de letras, números, "-" e ".", com um limite de 64 caracteres. (Pode ser um número inteiro, um OID não prefixado, UUID ou qualquer outro padrão de identificador que atenda a essas restrições.) Os IDs não diferenciam maiúsculas de minúsculas. |
object (Meta) Os metadados sobre um recurso. Este conteúdo do recurso é normalmente mantido pelo sistema gestor do registro. | |
required | Array of objects (Identifier) non-empty Identificador do arquivo no sistema de origem. Obrigatório e deve ser novo e único a cada arquivo: não há atualização de Media. |
| status required | any Obrigatório pela especificação FHIR, porém ignorado na escrita: o NiloCare não armazena o status do arquivo. A consulta sempre retorna Value: "completed" |
required | object Paciente ao qual o arquivo será associado. A resolução usa exclusivamente o |
required | Envio por URL (object) or Envio em base64 (object) Conteúdo do arquivo. Informe |
{- "resourceType": "Media",
- "id": "903dAAe9-c57f-4eb3-bd1c-65XXd41exx81",
- "meta": {
- "lastUpdated": "2022-05-25T18:42:06.551129+00:00",
- "versionId": "903dAAe9-c57f-4eb3-bd1c-65XXd41exx81"
}, - "identifier": [
- {
- "system": "{host}/fhir/resources/NamingSystem/hippocrates-api--model-name",
- "use": "usual",
- "value": "12345"
}
], - "status": "completed",
- "subject": {
- "type": "Patient"
}, - "content": {
- "contentType": "application/pdf",
- "data": "JVBERi0xLjQKJeLjz9MK...",
- "title": "Laudo do exame",
- "size": 20481,
- "hash": "string"
}
}required | Array of objects Uma coleção de mensagens de erro, aviso ou informação que resultado de uma ação do sistema. |
| resourceType required | string Default: "OperationOutcome" Indica o tipo do recurso transacionado. |
{- "issue": [
- {
- "code": "exception",
- "details": {
- "text": "Parâmetro enviado inválido"
}, - "severity": "error"
}
], - "resourceType": "OperationOutcome"
}Possíveis Erros
identifier não informado
O identifier é obrigatório e é usado para verificar se o arquivo já existe.
Erro retornado
{
"issue": [
{
"code": "required",
"details": {
"text": "Field is required"
},
"expression": [
"Media.identifier"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77001.pdf",
"title": "Laudo do exame"
}
}
identifier já utilizado (atualização não permitida)
Se qualquer um dos identifier enviados corresponder a um arquivo já existente, a requisição é
rejeitada — Media não pode ser atualizado. Envie sempre um identifier novo a cada arquivo.
Pré-condição do exemplo abaixo: já existe um
Mediacom oidentifierinformado.
Erro retornado
{
"issue": [
{
"code": "exception",
"details": {
"text": "PermissionDenied: Update Media is not allowed."
},
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77001"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77002.pdf",
"title": "Outro laudo"
}
}
subject não informado
O paciente é obrigatório e é resolvido antes de qualquer processamento do arquivo.
Erro retornado
{
"issue": [
{
"code": "required",
"details": {
"text": "Field is required"
},
"expression": [
"Media.subject"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77003"
}
],
"status": "completed",
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77003.pdf",
"title": "Laudo do exame"
}
}
subject sem identifier
O paciente é resolvido exclusivamente pelo subject.identifier. Enviar apenas o subject.reference
— ainda que ele aponte para um Patient existente no store — não é suficiente, e o erro retornado é
genérico (sem expression).
Erro retornado
{
"issue": [
{
"code": "exception",
"details": {
"text": "FieldRequiredError: ['Field reference.identifier is required']"
},
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77010"
}
],
"status": "completed",
"subject": {
"reference": "Patient/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77003.pdf",
"title": "Laudo do exame"
}
}
Paciente do subject não existe
O paciente informado no subject.identifier não foi encontrado no NiloCare. Cadastre o paciente antes
de enviar o arquivo.
Erro retornado
{
"issue": [
{
"code": "not-found",
"details": {
"text": "Patient does not exist"
},
"expression": [
"Media.subject"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77004"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "999999999"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"url": "https://arquivos.acmesaude.com.br/laudos/laudo-77004.pdf",
"title": "Laudo do exame"
}
}
Nem content.url nem content.data informados
É preciso informar uma das duas formas de envio do arquivo.
Erro retornado
{
"issue": [
{
"code": "required",
"details": {
"text": "Either content.url or content.data is required"
},
"expression": [
"Media.content"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77005"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "application/pdf",
"title": "Laudo do exame"
}
}
contentType não suportado
No envio em base64, somente application/pdf é aceito.
Erro retornado
{
"issue": [
{
"code": "not-supported",
"details": {
"text": "The contentType 'image/png' is not supported. Only 'application/pdf' is supported."
},
"expression": [
"Media.content.contentType"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
}
Exemplo de payload que gera o erro
{
"resourceType": "Media",
"identifier": [
{
"system": "https://www.acmesaude.com.br/integracao/arquivo",
"use": "usual",
"value": "77006"
}
],
"status": "completed",
"subject": {
"identifier": {
"system": "https://www.acmesaude.com.br/integracao/paciente",
"value": "456"
},
"type": "Patient"
},
"content": {
"contentType": "image/png",
"title": "Exame de imagem",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGP6DwABAgEAX9TQMQAAAABJRU5ErkJggg=="
}
}
Demais validações do conteúdo em base64
As validações abaixo são aplicadas nesta ordem, todas com severity: "error" e no formato
OperationOutcome. Como os payloads diferem apenas no valor de content.data / content.size, os
cenários estão resumidos na tabela:
| Cenário | code | details.text | expression |
|---|---|---|---|
content.contentType não informado | required | Field is required | Media.content.contentType |
content.data não é base64 válido | invalid | Field is not a valid base64-encoded content | Media.content.data |
content.data decodifica para conteúdo vazio | required | Field is required | Media.content.data |
| Conteúdo acima do limite | too-long | Field exceeds the maximum allowed size of 10485760 bytes | Media.content.data |
content.size divergente | invalid | Field does not match the content size of 20481 bytes | Media.content.size |
| Conteúdo não é um PDF | invalid | Field content is not a valid PDF file | Media.content.data |
- Espaços e quebras de linha no
content.datasão tolerados — payloads base64 quebrados em 76 colunas funcionam normalmente. - O
content.hashé aceito, mas não é validado. - Na mensagem do erro de
content.size, o valor20481é substituído pelo tamanho real do conteúdo decodificado.