# Laudos estruturados (Precisa Saúde)

HTML: https://docs.precisa-saude.com.br/api/

## Visão geral

Extração de laudo laboratorial em PDF, JPEG ou PNG para FHIR R4.

Você envia um laudo em PDF, JPEG ou PNG e recebe um Bundle FHIR R4 com o paciente, um `DiagnosticReport` e uma `Observation` por marcador lido. Cada `Observation` traz o código LOINC quando o marcador tem um, ao lado do nome como o laudo o imprimiu.

### Como um laudo vira Bundle

A âncora (03) define quais códigos podem aparecer no resultado, e a conferência (05) descarta o que o modelo devolveu fora disso. Um valor sem trecho correspondente na página não chega ao Bundle.

1. **Envio**: o documento e a finalidade, pelo `POST /v1/extractions`
2. **Texto**: a camada de texto do PDF, ou OCR quando ela não existe
3. **Âncora**: quais marcadores do catálogo a página nomeia
4. **Modelo**: valor, unidade e o trecho de onde cada um saiu
5. **Conferência**: descarta código fora da âncora e trecho que a página não tem
6. **FHIR R4**: o Bundle, com LOINC e faixa, na ordem do laudo
7. **Resultado**: `GET /v1/extractions/{id}`, ou o aviso por webhook

#### O que roda do nosso lado

- **Texto**: camada de texto; OCR só em laudo digitalizado
- **Âncora**: busca pelos nomes impressos, sem modelo
- **Modelo**: no Amazon Bedrock, em sa-east-1, e o texto não sai da região
- **Conferência**: o trecho citado está na página, e o código foi ancorado
- **FHIR R4**: LOINC, faixa de referência e `confidence` por documento

#### E o que fica com a sua integração

- **Envio**: o arquivo, e a finalidade em `purpose`
- **Resultado**: consulta pelo id, ou aviso por webhook
- **Leitura do Bundle**: com a biblioteca FHIR da sua stack
- **Sua regra**: o que fazer com `partial` e com confiança baixa, como mandar para revisão

### Modelo assíncrono

O envio responde `202` com um identificador. O resultado sai por `GET /v1/extractions/{id}`, e opcionalmente por webhook, que carrega apenas o identificador e o nome do evento. Dado clínico sai por um caminho autenticado só.

### Aviso por webhook

Com webhook na chave, o fim de cada trabalho gera um `POST` para a sua URL com `{"id", "state"}`, assinado com HMAC-SHA256 sobre `{timestamp}.{body}` (o instante, um ponto e o corpo) no cabeçalho `X-Precisa-Signature`, com o instante em `X-Precisa-Timestamp`. Responda 2xx em até 5 segundos. Qualquer outra resposta, ou nenhuma, faz o aviso ser repetido com intervalo exponencial: 10 segundos depois, e então 20, 40, 80, 160 e 300, com variação de 20% para mais ou para menos, enquanto o prazo de 15 minutos do trabalho durar. O registro das tentativas fica no nosso armazenamento, e não na memória do processo, então o aviso sobrevive a uma reinicialização do serviço dentro desse prazo.

O corpo e o cabeçalho `X-Precisa-Delivery-Id` são os mesmos em todas as tentativas, e `X-Precisa-Delivery-Attempt` conta a partir de 1. Use o `X-Precisa-Delivery-Id` para descartar repetição: a mesma entrega pode chegar mais de uma vez. O estado do aviso sai em `webhook` no `GET /v1/extractions/{id}`, e `failed` ali quer dizer que não haverá outra tentativa. O aviso nunca é o único caminho: o `GET` responde o mesmo estado.

### Retenção

O serviço não retém dado clínico de forma durável. O documento enviado e o resultado gerado ficam cifrados em armazenamento temporário. O PDF é apagado ao fim da extração. O resultado fica disponível para leituras repetidas até `expiresAt`, fixado em 15 minutos após o envio. `DELETE /v1/extractions/{id}` apaga o conteúdo antes disso. A partir de `expiresAt`, a API bloqueia o acesso ao resultado, mesmo que a exclusão física ainda esteja pendente.

Após `DELETE`, o `GET` em JSON ainda pode responder `200` com os metadados do trabalho, sem `bundle`, até `expiresAt`.

A exclusão física é programada para o vencimento e repetida por varreduras periódicas. Interrupções do serviço ou falhas no armazenamento podem atrasá-la. Não há cópia em backup, snapshot ou outra região. O que persiste é o registro do trabalho, sem conteúdo clínico: identificador, tenant, finalidade declarada, estado e carimbos de tempo.

### Reenvio seguro

Quem perde a resposta do envio por falha de rede não sabe se o trabalho existe. Mande o cabeçalho `Idempotency-Key` com um UUID novo por documento e reenvie com a mesma chave: dentro dos 15 minutos do trabalho, o reenvio devolve o mesmo `202`, com o mesmo `id` e o mesmo `expiresAt`, não cria trabalho, não conta na cota e não é cobrado. A resposta repetida traz `Idempotent-Replayed: true`. Depois dos 15 minutos a chave deixa de valer e o mesmo valor cria trabalho novo.

A mesma chave com outro documento, ou com outros campos, responde `422` `idempotency_key_reused`. O serviço guarda o hash da chave e um hash do pedido, nunca o valor da chave nem o documento, e apaga os dois quando o trabalho vence.

### Limites

Até 20 MB e 30 páginas por documento. Os dois números estão em `components.schemas.Limits`, para validar antes de enviar sem precisar ler esta frase.

O envio aceita PDF, JPEG e PNG estático. Cada foto conta como uma página. Imagens têm teto de 16000000 pixels e 8192 pixels por lado; a orientação EXIF do JPEG é respeitada. HEIC e PNG animado não são aceitos.

Os limites de arquivo e as cotas são tetos de admissão, não garantia de vazão sustentada ou de tempo de conclusão. O tempo depende do número de páginas, da necessidade de OCR e dos trabalhos em curso. Para o piloto, envie um trabalho por vez e confira os resultados de PDFs escaneados.

### Qualidade da captura

Prefira scans a 300 DPI ou fotos com foco, página inteira, boa iluminação e sem sombras, reflexos ou compressão de aplicativos de mensagem. Ampliar uma imagem pequena não recupera detalhes. A avaliação `inputQuality` é anterior ao modelo e traz política versionada, métricas e motivos por página. `passed` significa apenas que os sinais medidos passaram pelo piso de entrada; não garante acurácia nem completude. Todo OCR continua com `needsManualReview=true`.

Na política `scan-quality-v1`, uma página com ao menos dez palavras é recusada quando combina resolução efetiva inferior a 150 DPI, confiança média do OCR inferior a 90 e ao menos 5% das palavras com confiança inferior a 60. Também é recusada quando a média fica abaixo de 65 e ao menos 35% das palavras ficam abaixo de 60, independentemente do DPI. Documento sem texto reconhecido é recusado. DPI isolado não causa recusa. A resolução é calculada pelos pixels originais e pelo tamanho de exibição da imagem dominante no PDF, antes da ampliação para OCR. Em JPEG/PNG, é relativa à página normalizada pelo serviço, não ao DPI EXIF da câmera. Quando não pode ser medida, o motivo é `resolution_unknown`.

Uma página recusada impede a extração do documento inteiro, sem chamada de modelo. O envio ainda responde `202`; a consulta em JSON responde `200`, com `state=failed`, `error.code=input_quality_too_low`, `inputQuality.action=retake_or_rescan` e as páginas afetadas. Não há Bundle. Refaça a captura e envie o novo arquivo com outra `Idempotency-Key`. Casos limítrofes seguem com `review_required`, motivos por página e revisão humana obrigatória. `not_assessed` indica ausência de avaliação, inclusive documentos com camada de texto. Essa recusa não devolve a cota de documentos reservada no envio.

### Ler o Bundle na sua stack

O Bundle é FHIR R4, e as extensões que ele carrega são do IG do fhir-brasil, com `url` publicada. Não há SDK nosso para instalar: a biblioteca FHIR da sua linguagem já sabe ler.

- [Firely SDK](https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/) para .NET
- [HAPI FHIR](https://hapifhir.io/) para Java
- [fhir.resources](https://pypi.org/project/fhir.resources/) para Python

## Primeira chamada

O sandbox não pede chave e responde com laudos sintéticos, de conteúdo e resultado fixos: nove em formatos de laboratório brasileiro e cinco em formatos americanos, um por formato e dois do laudo de laboratório (o próprio laudo e a impressão de portal). Os 34 laudos americanos completos estão no download de laudos sintéticos, mais abaixo. Serve para escrever a integração e o teste dela antes de qualquer contrato. Os botões "Experimente" da referência abaixo chamam o mesmo sandbox.

### 1. Escolha um laudo

Liste os laudos de exemplo. Cada um traz o PDF e o Bundle FHIR esperado, para a sua integração comparar com o que recebe. O campo `region` (`BR` ou `US`) separa os formatos brasileiros dos americanos, e nos americanos o `layout` diz qual dos cinco formatos é. Nos americanos, o Bundle esperado é o que o serviço devolve quando lê o laudo sem erro: o valor na unidade do serviço, com o impresso na extensão `as-printed`, e os valores derivados (VLDL, glicose média estimada). No envio pelo sandbox, a faixa que o catálogo completou vem em `catalogRanges`, fora do Bundle, como no `/v1`.

```bash
curl https://laudos.precisa-saude.com.br/sandbox/v1/fixtures
```

### 2. Envie

A resposta é `202` com o `id` do trabalho e o instante em que ele expira.

```bash
curl -X POST https://laudos.precisa-saude.com.br/sandbox/v1/extractions \
  -H "Content-Type: application/json" \
  -d '{"fixtureId":"hemograma"}'
```

### 3. Consulte

Repita até o `state` sair de `queued` e `running`. `succeeded` e `partial` trazem o Bundle; `failed` traz `error` com um código da lista de erros.

```bash
curl https://laudos.precisa-saude.com.br/sandbox/v1/extractions/$JOB_ID
```

### 4. Busque o Bundle

O Bundle FHIR sozinho, em JSON ou XML conforme o `Accept`.

```bash
curl https://laudos.precisa-saude.com.br/sandbox/v1/extractions/$JOB_ID/bundle \
  -H "Accept: application/fhir+json"
```

### Para o seu cliente de API

- [OpenAPI (openapi.json)](https://docs.precisa-saude.com.br/api/openapi.json). A especificação completa, gerada do mesmo código que valida as requisições. Importe no Postman, no Insomnia ou no Bruno, ou gere um cliente com NSwag (.NET) ou OpenAPI Generator (Java).
- [Coleção do Bruno (.zip)](https://docs.precisa-saude.com.br/api/downloads/precisa-laudos-bruno.zip). As chamadas prontas, incluindo o percurso do sandbox sem chave e um laudo sintético para o envio. Extraia e abra a pasta no Bruno; a chave fica como variável secreta, fora dos arquivos, e a variável `lang` do ambiente escolhe a língua das mensagens de erro.
- [Laudos sintéticos, formatos americanos (.zip)](https://docs.precisa-saude.com.br/api/downloads/precisa-laudos-sinteticos-eua.zip). Trinta e quatro laudos sintéticos em cinco formatos de laboratório americano: laudo monoespaçado, laudo em colunas, impressão de portal, página de portal de prontuário e densitometria de corpo inteiro. De 18 a 85 anos, nos dois sexos, de uma a cinco páginas, com resultado alterado, valor com sinal (`<1`), resultado em texto, coluna de resultado anterior, tabela de evolução e páginas densas. Cada um vem com o PDF, o gabarito do gerador e o resultado esperado: o Bundle FHIR que o serviço devolve quando lê o laudo sem erro, com o valor na unidade do serviço e o impresso em `as-printed`, os derivados, e as `catalogRanges` à parte. Laboratório, paciente e médico são inventados, e toda página traz a marca de amostra sintética. Cinco deles, um de cada formato, também respondem no sandbox.

### Em produção

Troque `/sandbox/v1` por `/v1`, envie PDF, JPEG ou PNG como `multipart/form-data` com o campo `purpose`, e mande a chave no cabeçalho `X-API-Key`. O resto do percurso é o mesmo.

Para poder reenviar sem criar trabalho duplicado, mande também `Idempotency-Key` com um UUID novo por documento. O comportamento está em "Reenvio seguro", na visão geral.

### Câmera e fototeca

O aplicativo web ou nativo deve permitir fotografar e enviar sem conversão manual. Solicite ou exporte JPEG automaticamente, aplique a orientação e redimensione somente para caber nos limites publicados, preservando texto pequeno. O iPhone pode gerar HEIC/HEIF; esses arquivos sem conversão não são aceitos pela API. Clientes nativos podem solicitar JPEG; clientes web precisam conferir a saída do seletor e converter imagens compatíveis para JPEG antes do envio. Teste câmera e seleção de foto existente separadamente no Safari do iOS, Chrome do Android e nos aplicativos nativos. Não dependa apenas da conversão implícita do navegador. Informe o tipo de mídia correspondente na parte do arquivo do multipart. Para texto ilegível, ofereça prévia e nova captura.

A chave de produção é emitida pela Precisa. Peça pelo [formulário de contato](https://precisa-saude.com.br/laudos#contato).

### Codificação

Toda resposta sai em UTF-8: `charset=utf-8` no `Content-Type` do JSON e do XML, e `encoding="UTF-8"` na declaração do XML. Nome de exame em português tem acento em quase toda linha, e um cliente que decodifica como Latin-1 mostra `HematÃ³crito` no lugar de `Hematócrito`.

## Layouts de laudos sintéticos (104)

Laudos fictícios em português brasileiro e inglês, gerados por lab-report-fixtures. Explore PDFs digitais e scans simulados com caixas por campo. Os gabaritos descrevem o conteúdo impresso, não a acurácia medida da extração. A galeria não chama modelos; o sandbox abaixo devolve respostas predefinidas. Use as amostras para avaliar PDFs digitais e escaneados nos dois idiomas. Resultados de OCR exigem conferência contra o original; a galeria não comprova acurácia da extração.

[lab-report-fixtures · MIT](https://github.com/Precisa-Saude/lab-report-fixtures)

[Manifesto completo do corpus](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/manifest.json)

| Laudo | Idioma do laudo | Layout | Qualidade | Página | Baixar PDF | Anotações dos campos | Gabarito |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ruled-529000-digital | en-US | ruled | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-digital.expected.json) |
| ruled-529000-clean | en-US | ruled | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-clean.expected.json) |
| ruled-529000-typical | en-US | ruled | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-typical.expected.json) |
| ruled-529000-difficult | en-US | ruled | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529000-difficult.expected.json) |
| ruled-529001-digital | en-US | ruled | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-digital.expected.json) |
| ruled-529001-clean | en-US | ruled | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-clean.expected.json) |
| ruled-529001-typical | en-US | ruled | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-typical.expected.json) |
| ruled-529001-difficult | en-US | ruled | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/ruled-529001-difficult.expected.json) |
| borderless-529010-digital | en-US | borderless | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-digital.expected.json) |
| borderless-529010-clean | en-US | borderless | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-clean.expected.json) |
| borderless-529010-typical | en-US | borderless | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-typical.expected.json) |
| borderless-529010-difficult | en-US | borderless | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529010-difficult.expected.json) |
| borderless-529011-digital | en-US | borderless | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-digital.expected.json) |
| borderless-529011-clean | en-US | borderless | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-clean.expected.json) |
| borderless-529011-typical | en-US | borderless | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-typical.expected.json) |
| borderless-529011-difficult | en-US | borderless | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/borderless-529011-difficult.expected.json) |
| wrapped-529020-digital | en-US | wrapped | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-digital.expected.json) |
| wrapped-529020-clean | en-US | wrapped | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-clean.expected.json) |
| wrapped-529020-typical | en-US | wrapped | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-typical.expected.json) |
| wrapped-529020-difficult | en-US | wrapped | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529020-difficult.expected.json) |
| wrapped-529021-digital | en-US | wrapped | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-digital.expected.json) |
| wrapped-529021-clean | en-US | wrapped | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-clean.expected.json) |
| wrapped-529021-typical | en-US | wrapped | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-typical.expected.json) |
| wrapped-529021-difficult | en-US | wrapped | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/wrapped-529021-difficult.expected.json) |
| range-below-529030-digital | en-US | range-below | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-digital.expected.json) |
| range-below-529030-clean | en-US | range-below | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-clean.expected.json) |
| range-below-529030-typical | en-US | range-below | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-typical.expected.json) |
| range-below-529030-difficult | en-US | range-below | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529030-difficult.expected.json) |
| range-below-529031-digital | en-US | range-below | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-digital.expected.json) |
| range-below-529031-clean | en-US | range-below | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-clean.expected.json) |
| range-below-529031-typical | en-US | range-below | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-typical.expected.json) |
| range-below-529031-difficult | en-US | range-below | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/range-below-529031-difficult.expected.json) |
| history-529040-digital | en-US | history | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-digital.expected.json) |
| history-529040-clean | en-US | history | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-clean.expected.json) |
| history-529040-typical | en-US | history | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-typical.expected.json) |
| history-529040-difficult | en-US | history | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529040-difficult.expected.json) |
| history-529041-digital | en-US | history | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-digital.expected.json) |
| history-529041-clean | en-US | history | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-clean.expected.json) |
| history-529041-typical | en-US | history | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-typical.expected.json) |
| history-529041-difficult | en-US | history | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/history-529041-difficult.expected.json) |
| continued-529050-digital | en-US | continued | Digital | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-digital.expected.json) |
| continued-529050-clean | en-US | continued | Scan · 300 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-clean.expected.json) |
| continued-529050-typical | en-US | continued | Scan · 170 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-typical.expected.json) |
| continued-529050-difficult | en-US | continued | Scan · 110 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529050-difficult.expected.json) |
| continued-529051-digital | en-US | continued | Digital | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-digital.expected.json) |
| continued-529051-clean | en-US | continued | Scan · 300 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-clean.expected.json) |
| continued-529051-typical | en-US | continued | Scan · 170 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-typical.expected.json) |
| continued-529051-difficult | en-US | continued | Scan · 110 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529051-difficult.expected.json) |
| br-ruled-529000-digital | pt-BR | ruled | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-digital.expected.json) |
| br-ruled-529000-clean | pt-BR | ruled | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-clean.expected.json) |
| br-ruled-529000-typical | pt-BR | ruled | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-typical.expected.json) |
| br-ruled-529000-difficult | pt-BR | ruled | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529000-difficult.expected.json) |
| br-ruled-529001-digital | pt-BR | ruled | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-digital.expected.json) |
| br-ruled-529001-clean | pt-BR | ruled | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-clean.expected.json) |
| br-ruled-529001-typical | pt-BR | ruled | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-typical.expected.json) |
| br-ruled-529001-difficult | pt-BR | ruled | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-ruled-529001-difficult.expected.json) |
| br-borderless-529010-digital | pt-BR | borderless | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-digital.expected.json) |
| br-borderless-529010-clean | pt-BR | borderless | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-clean.expected.json) |
| br-borderless-529010-typical | pt-BR | borderless | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-typical.expected.json) |
| br-borderless-529010-difficult | pt-BR | borderless | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529010-difficult.expected.json) |
| br-borderless-529011-digital | pt-BR | borderless | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-digital.expected.json) |
| br-borderless-529011-clean | pt-BR | borderless | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-clean.expected.json) |
| br-borderless-529011-typical | pt-BR | borderless | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-typical.expected.json) |
| br-borderless-529011-difficult | pt-BR | borderless | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-borderless-529011-difficult.expected.json) |
| br-wrapped-529020-digital | pt-BR | wrapped | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-digital.expected.json) |
| br-wrapped-529020-clean | pt-BR | wrapped | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-clean.expected.json) |
| br-wrapped-529020-typical | pt-BR | wrapped | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-typical.expected.json) |
| br-wrapped-529020-difficult | pt-BR | wrapped | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529020-difficult.expected.json) |
| br-wrapped-529021-digital | pt-BR | wrapped | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-digital.expected.json) |
| br-wrapped-529021-clean | pt-BR | wrapped | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-clean.expected.json) |
| br-wrapped-529021-typical | pt-BR | wrapped | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-typical.expected.json) |
| br-wrapped-529021-difficult | pt-BR | wrapped | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-wrapped-529021-difficult.expected.json) |
| br-range-below-529030-digital | pt-BR | range-below | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-digital.expected.json) |
| br-range-below-529030-clean | pt-BR | range-below | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-clean.expected.json) |
| br-range-below-529030-typical | pt-BR | range-below | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-typical.expected.json) |
| br-range-below-529030-difficult | pt-BR | range-below | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529030-difficult.expected.json) |
| br-range-below-529031-digital | pt-BR | range-below | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-digital.expected.json) |
| br-range-below-529031-clean | pt-BR | range-below | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-clean.expected.json) |
| br-range-below-529031-typical | pt-BR | range-below | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-typical.expected.json) |
| br-range-below-529031-difficult | pt-BR | range-below | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-range-below-529031-difficult.expected.json) |
| br-history-529040-digital | pt-BR | history | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-digital.expected.json) |
| br-history-529040-clean | pt-BR | history | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-clean.expected.json) |
| br-history-529040-typical | pt-BR | history | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-typical.expected.json) |
| br-history-529040-difficult | pt-BR | history | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529040-difficult.expected.json) |
| br-history-529041-digital | pt-BR | history | Digital | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-digital.expected.json) |
| br-history-529041-clean | pt-BR | history | Scan · 300 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-clean.expected.json) |
| br-history-529041-typical | pt-BR | history | Scan · 170 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-typical.expected.json) |
| br-history-529041-difficult | pt-BR | history | Scan · 110 DPI | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-history-529041-difficult.expected.json) |
| br-continued-529050-digital | pt-BR | continued | Digital | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-digital.expected.json) |
| br-continued-529050-clean | pt-BR | continued | Scan · 300 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-clean.expected.json) |
| br-continued-529050-typical | pt-BR | continued | Scan · 170 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-typical.expected.json) |
| br-continued-529050-difficult | pt-BR | continued | Scan · 110 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529050-difficult.expected.json) |
| br-continued-529051-digital | pt-BR | continued | Digital | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-digital.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-digital.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-digital.expected.json) |
| br-continued-529051-clean | pt-BR | continued | Scan · 300 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-clean.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-clean.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-clean.expected.json) |
| br-continued-529051-typical | pt-BR | continued | Scan · 170 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-typical.expected.json) |
| br-continued-529051-difficult | pt-BR | continued | Scan · 110 DPI | 2 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-difficult.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-difficult.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529051-difficult.expected.json) |
| continued-529800-mixed | en-US | continued | Digital + scan | 6 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529800-mixed.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529800-mixed.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529800-mixed.expected.json) |
| continued-529815-typical | en-US | continued | Scan · 170 DPI | 15 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529815-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529815-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529815-typical.expected.json) |
| continued-529830-typical | en-US | continued | Scan · 170 DPI | 30 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529830-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529830-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/continued-529830-typical.expected.json) |
| unreadable-529999-unreadable | en-US | borderless | Ilegível | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/unreadable-529999-unreadable.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/unreadable-529999-unreadable.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/unreadable-529999-unreadable.expected.json) |
| br-continued-529800-mixed | pt-BR | continued | Digital + scan | 6 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529800-mixed.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529800-mixed.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529800-mixed.expected.json) |
| br-continued-529815-typical | pt-BR | continued | Scan · 170 DPI | 15 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529815-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529815-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529815-typical.expected.json) |
| br-continued-529830-typical | pt-BR | continued | Scan · 170 DPI | 30 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529830-typical.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529830-typical.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-continued-529830-typical.expected.json) |
| br-unreadable-529999-unreadable | pt-BR | borderless | Ilegível | 1 | [PDF](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-unreadable-529999-unreadable.pdf) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-unreadable-529999-unreadable.fields.json) | [JSON](https://docs.precisa-saude.com.br/api/downloads/lab-report-fixtures/br-unreadable-529999-unreadable.expected.json) |

## Gere seu cliente

A Precisa não publica SDK. O contrato é o OpenAPI, e o cliente da sua linguagem sai dele, com o gerador que a sua equipe já usa e na versão do contrato que você baixou. Os comandos abaixo são os que a nossa CI roda a cada mudança no contrato: ela gera os clientes .NET e Java, confere o nome de cada operação e compila os dois.

Baixe o contrato na pasta onde o cliente vai ser gerado:

```bash
curl -O https://docs.precisa-saude.com.br/api/openapi.json
```

### .NET: NSwag 14.7.1

Gera uma classe só, `PrecisaLaudosClient`, que usa `System.Text.Json` e compila num projeto .NET 8 sem pacote extra.

```bash
dotnet tool install --global NSwag.ConsoleCore --version 14.7.1
nswag openapi2csclient /input:openapi.json /output:PrecisaLaudosClient.cs \
  /namespace:Precisa.Laudos /className:PrecisaLaudosClient /jsonLibrary:SystemTextJson
```

### Java: OpenAPI Generator 7.25.0

Gera um projeto Maven, com a classe `ExtractionsApi` e um modelo por schema do contrato. A CI compila com `mvn package`.

```bash
docker run --rm -v "$PWD:/local" openapitools/openapi-generator-cli:v7.25.0 generate \
  -i /local/openapi.json -g java -o /local/precisa-laudos-client \
  --group-id br.com.precisasaude --artifact-id precisa-laudos-client \
  --api-package br.com.precisasaude.laudos.api \
  --model-package br.com.precisasaude.laudos.model \
  --invoker-package br.com.precisasaude.laudos.client
```

Os nomes que o seu código vai usar saem do contrato:

- Operações: `getHealth`, `createExtraction`, `getExtraction`, `deleteExtraction`, `getExtractionBundle`
- Modelos: `CatalogRange`, `Confidence`, `Error`, `ErrorCode`, `ErrorDetail`, `Extension`, `ExtractionAccepted`, `ExtractionDeleted`, `ExtractionResult`, `Health`, `JobState`, `Limits`, `Progress`, `Purpose`, `SkippedBiomarker`, `SkippedPage`, `Versions`, `WebhookDelivery`

O Bundle sai como objeto livre no cliente gerado (`Object` em Java, `object` em .NET), porque a forma dele é a do FHIR R4. Leia com a biblioteca FHIR da sua linguagem, citada na visão geral.

O documento é OpenAPI 3.0.3. Antes de gerar os clientes, a CI confere o documento com o validador do OpenAPI Generator.

## De onde vem cada valor

Cada `Observation` diz onde o valor está no documento e quanto dá para confiar nele. É o que deixa sua equipe conferir um valor contra o PDF sem procurar página por página, e rotear para revisão o que merece olho humano.

As extensões ficam em `Observation.extension`, e o `url` de cada uma é o prefixo abaixo seguido do nome. As que têm partes levam as partes num `extension` aninhado, com o nome da parte no `url`.

```
https://fhir-brasil.dev.br/ig/StructureDefinition/
```

- `extraction-source`: As páginas em que o exame aparece, a do trecho citado primeiro, e o trecho como o documento imprime. Em documento digitalizado, também a caixa do trecho na página, em fração dela (de 0 a 1, origem no canto superior esquerdo), para você destacar o valor no PDF. Não vem em valor calculado, porque ele não está impresso em lugar nenhum.
- `extraction-confidence`: `reading` diz se os caracteres foram lidos certo: 1 quando o documento tem camada de texto, e a confiança do OCR nos números do trecho quando é digitalizado. `interpretation` diz se o valor foi atribuído ao exame, à unidade e à faixa certos. Os dois falham por motivos diferentes, e por isso não viram um número só.
- `as-printed`: O valor e a faixa como o documento imprime, quando a `Observation` traz o valor convertido para outra unidade. Só aparece quando houve conversão.
- `derived-from-ocr`: O valor saiu de documento digitalizado. Serve para você aplicar a esse dado o limiar que quiser.
- `superseded`: O valor está impresso, mas o próprio laudo o substitui por outro. Hoje é a filtração glomerular por equação estratificada por etnia, publicada ao lado da equação sem etnia. Mostre o outro valor.

### Nos campos do próprio R4

- `derivedFrom`: O valor foi calculado, e não lido: VLDL dos triglicerídeos, glicose média estimada da hemoglobina glicada. Aponta para as observações de que ele saiu. Valor calculado não traz `extraction-source`, porque não há trecho para citar.
- `valueQuantity.comparator`: O laudo publica um limite em vez de uma medida: `<` em "inferior a 0,5", `>` em "superior a 90".
- `referenceRange`: A faixa que o laudo imprime, e só ela. Faixa com um limite só ("inferior a 190") sai com um lado. Referência qualitativa confirmada na página, como "NEGATIVO", sai em `referenceRange[].text`, com a grafia impressa. Quando o laudo não imprime faixa nenhuma, o campo não vem, e a faixa do catálogo da Precisa para o exame vai em `catalogRanges`, no envelope.
- `interpretation`: `H` e `L` para fora da faixa, e `HH` e `LL` quando o laudo marca o valor como crítico. Sem faixa impressa, a comparação é contra a do catálogo que está em `catalogRanges`.

### No envelope

O `GET` resume o documento, para você decidir sem percorrer o Bundle. `confidence` traz a média e o mínimo dos dois eixos; o mínimo é o que importa, porque dezoito valores bons e um ilegível dão média alta. `needsManualReview` é o sinal da própria extração (documento lido por OCR, página que falhou, exame que ficou de fora, valor com confiança baixa), e para onde o laudo vai continua sendo decisão sua.

`inputQuality` avalia a captura antes do modelo, com motivos e métricas por página. `input_quality_too_low` significa que é preciso refazer a captura, com foco e boa iluminação, preferencialmente a 300 DPI. O trabalho fica `failed`, sem Bundle, e `inputQuality.action` é `retake_or_rescan`. Envie o novo arquivo com outra `Idempotency-Key`; a recusa não devolve a cota reservada no envio. `review_required` pede conferência. `passed` não garante acurácia nem completude; todo OCR continua exigindo revisão humana.

`failedPages` lista as páginas que o modelo não conseguiu ler, que são as que fazem o `partial`, e `skippedPages` todas as que não produziram resultado, cada uma com o motivo. `skippedBiomarkers` traz os exames que o laudo imprimia e não viraram `Observation`, também com o motivo. `catalogRanges` traz a faixa do catálogo da Precisa para cada `Observation` cujo laudo não imprimiu faixa, pelo `id` dela; ela fica fora do `referenceRange` porque não foi o laboratório que a publicou. `degradedOcr` diz que o documento é digitalizado e a leitura saiu rala demais para confiar sem conferir. Enquanto o trabalho roda, `progress` diz a fase e, na leitura, quantas páginas já foram.

## Extensões

Há passos que nem todo contrato quer pagar, e eles ficam desligados até você pedir. Ligue no envio, repetindo o campo `extensions` ou mandando a lista separada por vírgula. Nome fora da lista recusa o envio com `400`, em vez de ser ignorado.

As extensões são mantidas pela Precisa, e código seu não roda dentro do serviço. Para lógica própria, construa em cima do Bundle.

**Envio com extensões**

```bash
curl -X POST https://laudos.precisa-saude.com.br/v1/extractions \
  -H "X-API-Key: $PRECISA_API_KEY" \
  -F purpose=care_coordination \
  -F extensions=history \
  -F extensions=lab-name-vision \
  -F heightCm=175 \
  -F file=@laudo.pdf
```

- `document-patient`: Devolve em `documentPatient` o nome do paciente como o documento imprime, para você conferir se o laudo é de quem você acha que é. Desligada, o serviço não devolve nada do paciente que você não mandou. O nome some junto com o Bundle, e não fica no registro do trabalho. Sem custo de modelo: o nome já sai da leitura do laudo.
- `history`: Lê as tabelas de acompanhamento (a mesma medida em datas anteriores) e devolve um `DiagnosticReport` por data, com a extensão `reprinted-in` apontando para o laudo. A data do próprio laudo não se repete: ela completa o laudo principal. Custa uma chamada de modelo por página com tabela.
- `lab-name-vision`: Quando o texto do laudo não traz o nome do laboratório (há laudos em que ele só aparece como logotipo), lê a primeira página como imagem. Não roda em scan degradado. Custa uma chamada de visão, só nos documentos que chegarem sem nome.

### Altura do paciente

Mande `heightCm`, em centímetros, quando tiver. Alguns marcadores calculados dependem dela, como o IMC e o índice de massa muscular. A altura vale só para aquela extração e não fica guardada no registro do trabalho.

## Tratamento de dados

Esta seção pode ser enviada sozinha ao time de segurança e ao encarregado de dados. O link direto é `docs.precisa-saude.com.br/api/#tratamento-de-dados`.

### Retenção

O serviço não retém dado clínico de forma durável. O documento enviado e o resultado gerado ficam cifrados em armazenamento temporário. O PDF é apagado ao fim da extração. O resultado fica disponível para leituras repetidas até `expiresAt`, fixado em 15 minutos após o envio. `DELETE /v1/extractions/{id}` apaga o conteúdo antes disso. A partir de `expiresAt`, a API bloqueia o acesso ao resultado, mesmo que a exclusão física ainda esteja pendente.

Após `DELETE`, o `GET` em JSON ainda pode responder `200` com os metadados do trabalho, sem `bundle`, até `expiresAt`.

A exclusão física é programada para o vencimento e repetida por varreduras periódicas. Interrupções do serviço ou falhas no armazenamento podem atrasá-la. Não há cópia em backup, snapshot ou outra região. O que persiste é o registro do trabalho, sem conteúdo clínico: identificador, tenant, finalidade declarada, estado e carimbos de tempo.

### Onde o dado é processado

Na AWS em São Paulo (`sa-east-1`): o serviço, o armazenamento temporário e o modelo que faz a extração. O documento não sai da região para ser processado.

### Cifra em repouso

Documento e resultado ficam no S3 cifrados com AES-256. O registro do trabalho fica no DynamoDB, cifrado com KMS.

### Sem cópia

As tabelas não têm recuperação de ponto no tempo nem réplica em outra região, o bucket não tem replicação, e nada disso entra em plano de backup.

### Finalidade

Todo envio declara `purpose`, de uma lista fechada: `care_coordination`, `member_self_service`, `clinical_quality`, `research`. Valor fora da lista é recusado com `400`, e a finalidade fica no registro do trabalho.

### Logs

O serviço registra contagem, código e duração, nunca o conteúdo do laudo. Os logs ficam 30 dias.

### Papel na LGPD

O parceiro é o controlador do dado, e a Precisa trata o documento como operadora, na finalidade que o envio declara.

### Dados administrativos

O serviço devolve a parte clínica do laudo, e a parte administrativa fica com você: CPF ou CNS do paciente, CNES do laboratório executante e a referência do `performer`. Quem tem esses dados é você, que autorizou o exame. O `Patient` do Bundle leva um nome genérico e um `id`, que é o seu quando você manda o cabeçalho `x-subject-id` (letras, dígitos, ponto e hífen, até 64 caracteres), e o `performer` do `DiagnosticReport` leva o nome do laboratório como o laudo imprime, sem CNES. O serviço não devolve CPF ou CNS extraídos do PDF. Com a extensão `document-patient`, o nome impresso no laudo é devolvido em `documentPatient` para conferência e apagado junto com o resultado.

## Erros

Toda resposta fora de `2xx` tem o mesmo corpo. Ramifique por `code`, que vem de uma lista fechada; o `message` é para gente e pode mudar.

Parte dos erros só aparece depois do `202`, porque a extração acontece depois de o envio ser aceito. Esses chegam no campo `error` do `GET`, com o trabalho em `failed`.

O `message` sai em português, ou em inglês com `Accept-Language: en`. Sem o cabeçalho, vale a língua definida no contrato da chave. O `code` é o mesmo nas duas, e a resposta diz a língua em `Content-Language`.

**Corpo de erro**

```json
{
  "error": {
    "code": "invalid_input",
    "message": "Envie o documento no campo `file`, como multipart."
  }
}
```

- `document_cap_reached`: `403` no envio. A chave usou todos os documentos do teto do contrato, como o de um período de avaliação. Repetir não adianta: o teto só é ampliado pela Precisa, na mesma chave. O trabalho não foi criado e nada foi contado.
  Mensagem: Esta chave já usou os N documentos do período de avaliação. Para continuar, escreva para contato@precisa-saude.com.br e o limite é ampliado na mesma chave.
- `expired`: `410`, ou em `error` no `GET`. O prazo de 15 minutos passou, ou o resultado foi apagado por `DELETE`. Definitivo: só reenviando o documento.
  Mensagem: O resultado expirou e deixou de existir.
- `file_too_large`: `413` no envio. O documento passa de `maxBytes`, ou a imagem excede `maxImagePixels` ou `maxImageSide`, antes de o trabalho entrar na fila.
  Mensagem: O documento passa de 20971520 bytes.
- `idempotency_key_reused`: `422` no envio. A `Idempotency-Key` já foi usada, dentro dos 15 minutos, com outro documento ou outros campos. O trabalho antigo não é devolvido: gere uma chave nova para o envio novo.
  Mensagem: Esta `Idempotency-Key` já foi usada com outro documento ou outros campos. Use uma chave nova.
- `image_only_pdf`: Em `error` no `GET`, ou `422` quando se pede o Bundle (rota `/bundle`, ou `GET` com `Accept` de XML). O PDF não tem camada de texto e o OCR não conseguiu lê-lo. Repetir o mesmo arquivo falha igual.
  Mensagem: O PDF não tem camada de texto e o OCR não conseguiu lê-lo.
- `input_quality_too_low`: Em `error` no `GET`, ou `422` ao pedir o Bundle. A qualidade da captura ficou abaixo da política de entrada. Consulte `inputQuality.pages` e envie uma nova captura, com nova Idempotency-Key. Nenhuma chamada de modelo nem Bundle foi produzido.
  Mensagem: A qualidade da captura é insuficiente para extração. Consulte inputQuality.pages e refaça a foto ou o scan com foco, sem sombras ou compressão, preferencialmente a 300 DPI. Envie o novo arquivo com uma nova Idempotency-Key.
- `invalid_input`: `400` no envio. Requisição malformada, campo obrigatório ausente ou `purpose` fora da lista. Também o `404` de trabalho inexistente e o `406` de `Accept` ou `_format` que nenhum tipo servido atende. Corrija antes de repetir.
  Mensagem: Envie o documento no campo `file`, como multipart.
- `missing_collection_date`: Em `error` no `GET`, ou `422` quando se pede o Bundle. O laudo foi lido, mas não traz data de coleta, que é obrigatória no Bundle. Repetir igual não resolve: reenvie com `collectionDate`, que só vale para laudo sem data.
  Mensagem: O laudo não traz data de coleta, e ela é obrigatória no Bundle.
- `not_a_lab_report`: Em `error` no `GET`, ou `422` quando se pede o Bundle. O documento foi lido e não parece laudo laboratorial.
  Mensagem: O documento não parece um laudo laboratorial.
- `not_ready`: `409` quando se pede o Bundle (rota `/bundle`, ou `GET` com `Accept` de XML) e a extração ainda está em curso, ou no envio, quando o envio anterior com a mesma `Idempotency-Key` ainda está sendo registrado. Volte depois do `Retry-After`. Diferente do `expired`, este passa sozinho.
  Mensagem: A extração ainda está em curso. Tente de novo em instantes.
- `processing_error`: Em `error` no `GET` (ou `422` quando se pede o Bundle), ou `500` e `503` quando a falha é na própria requisição (o `503` traz `Retry-After`). Falha do nosso lado, inclusive documento com cara de laudo do qual nenhum marcador saiu. Quando o modelo não leu nenhuma página nem depois das retentativas, o trabalho traz `failedPages`, e reenviar resolve.
  Mensagem: Falha ao processar o documento.
- `rate_limited`: `429` no envio. Cota ou concorrência do tenant excedida. Traz `Retry-After` em segundos.
  Mensagem: Requisições por minuto no limite do contrato.
- `too_many_pages`: `413` no envio. O documento passa de `maxPages`, conferido antes de o trabalho entrar na fila.
  Mensagem: O documento tem 31 páginas, e o limite é 30.
- `unauthorized`: `401`. Chave ausente, inexistente ou revogada. O problema é a credencial, não o corpo da requisição.
  Mensagem: Chave inválida ou revogada.
- `unsupported_media_type`: `415` no envio. Envie PDF, JPEG ou PNG estático válido, com o tipo declarado correspondente.
  Mensagem: Envie `application/pdf`, `image/jpeg` ou `image/png`.

## Versões e mudanças

A versão do contrato está no caminho, `/v1`. Toda resposta do `GET` do trabalho traz `versions`, que diz o que produziu aquele resultado:

- `api`: Versão do contrato, por exemplo `v1`.
- `catalog`: Versão do catálogo da Precisa (o pacote `@precisa-saude/fhir`) de onde saíram os códigos, as faixas e o mapeamento para LOINC, por exemplo `0.41.2`.
- `loinc`: Release do LOINC contra a qual o catálogo foi conferido, por exemplo `2.83`. `unknown` quando o catálogo não a declara.
- `model`: Modelo que produziu a extração.
- `prompt`: Versão do prompt de extração.

### Mudanças

As mudanças do contrato `/v1`, da mais recente para a mais antiga.

- 2026-10-09: Trabalho aceito cuja instância do serviço para no meio da extração é retomado por outra a partir do documento guardado, e termina em resultado. Quando sobra pouco prazo para retomar, ele falha com `processing_error` e uma mensagem que manda reenviar, onde ficava em `running` até vencer. Enquanto uma instância encerra, o `GET /health` e o `POST /v1/extractions` respondem `503` com `Retry-After`.
- 2026-10-09: O `DELETE /v1/extractions/{id}` também para a extração em curso, em até 5 segundos: depois disso nenhuma chamada nova ao modelo começa, e o trabalho termina `failed` com `expired`, como quando os 15 minutos vencem no meio do processamento. O reenvio com `Idempotency-Key` que já tem dono tem limite próprio por minuto e de simultâneos, com os números do contrato e separado dos envios; acima dele, `429 rate_limited` com `Retry-After`. O reenvio cujo tamanho de corpo não pode ser o do documento original recebe `422 idempotency_key_reused` antes de o upload terminar.
- 2026-10-09: Em `versions`, `catalog` traz a versão do catálogo que produziu o resultado (`0.41.2` hoje) e `loinc` a release do LOINC contra a qual ele foi conferido (`2.83` hoje), onde os dois diziam `local`.
- 2026-10-09: O aviso por webhook que não recebe 2xx em 5 segundos é repetido com intervalo exponencial (10 segundos, e então 20, 40, 80, 160 e 300, com variação de 20%) enquanto durar o prazo do trabalho, e sobrevive a uma reinicialização do serviço. Toda tentativa leva `X-Precisa-Delivery-Id`, igual entre as tentativas, e `X-Precisa-Delivery-Attempt`. O `GET /v1/extractions/{id}` traz o estado do aviso em `webhook`.
- 2026-10-09: Resultado em texto com resposta LOINC conferida ("Negativo", "Não reagente", "++") passa a vir em `valueCodeableConcept`, com os códigos LOINC e SNOMED CT e o impresso em `text`; texto sem resposta conferida continua em `valueString`. Trabalho em que o modelo não leu nenhuma página, nem depois das retentativas, falha com `processing_error`, lista as páginas em `failedPages` e diz para reenviar, onde falhava como documento sem marcador. Códigos novos para a densidade óssea por região da densitometria de corpo inteiro (`BMD_Arms` a `BMD_Trunk`, sete regiões, sem LOINC), e em laudo de composição corporal a faixa do catálogo segue o sexo e a idade impressos. A unidade perde a marca "(calc)", "% of total Hgb" vira `%`, e "Thousand/uL" e "Million/uL" ganham o código UCUM. No sandbox, o resultado esperado dos laudos americanos é o que o serviço devolve, e o envelope do trabalho traz `catalogRanges`.
- 2026-10-09: O `GET /health` responde `503` com `{"status":"unavailable"}` quando o serviço não pode atender o `/v1`. No `POST /v1/extractions`, a cota por minuto, os simultâneos e o teto de documentos são conferidos antes de o arquivo ser lido, e o envio recusado depois pelo formulário também conta na cota por minuto. O sandbox limita cada endereço a 300 requisições por minuto e 200 trabalhos abertos, com `429 rate_limited` e `Retry-After`.
- 2026-10-09: O contrato passa a sair em OpenAPI 3.0.3, e não em 3.1. Constante de um valor vira `enum` de um item, e a descrição ao lado de um `$ref` sai, porque o 3.0 a ignora. Requisições e respostas não mudam.
- 2026-10-09: O contrato declara o `GET /health`, que não pede chave e responde `{"status":"ok"}`.
- 2026-10-09: O contrato declara o cabeçalho opcional `x-subject-id` no `POST /v1/extractions`, com `maxLength` e `pattern`. Valor que não casa é aceito e ignorado, e o id do trabalho vira o id do `Patient`.
- 2026-10-09: Consultar o trabalho ou o Bundle depois do `DELETE` ou do prazo responde `410 expired`, como a documentação diz, onde podia responder `503 processing_error`.
- 2026-10-09: Teto de documentos por chave, para períodos de avaliação: envio acima do teto responde `403` com o código novo `document_cap_reached`.
- 2026-10-09: Cada operação ganha `operationId` (`createExtraction`, `getExtraction`, `deleteExtraction`, `getExtractionBundle`) e a tag `Extractions`, e os schemas repetidos viram componentes com nome, para o cliente gerado ter nomes estáveis. Envio e resposta não mudam.
- 2026-10-09: `GET /v1/extractions/{id}` entrega o Bundle em XML com `Accept: application/fhir+xml` ou `application/xml`, e o parâmetro `_format` do R4 passa a valer, à frente do `Accept`. Pedir o Bundle de trabalho que falhou responde `422` com o código da falha, onde antes respondia `410`.
- 2026-10-09: O `message` dos erros em português ou inglês, escolhido pelo `Accept-Language` ou pela língua do contrato da chave, com `Content-Language` na resposta; o `code` não muda. O contrato declara `Accept-Language`, `Content-Language` e a frase padrão de cada código em `x-error-messages`.
- 2026-10-09: Cabeçalho `Idempotency-Key` no envio, código novo `idempotency_key_reused` (`422`), e `409 not_ready` no envio repetido enquanto o primeiro ainda é registrado.
- 2026-10-06: `skippedBiomarkers` ganha o motivo `specimen-mismatch` e o campo `detail`.
- 2026-10-06: `catalogRanges` no envelope. A faixa do catálogo da Precisa sai do `referenceRange` do Bundle, que passa a trazer só a faixa impressa no laudo.
- 2026-09-29: Campo `collectionDate` no envio, a data de coleta de reserva para laudo sem data.
- 2026-09-28: Extensão `document-patient` e campo `documentPatient`, mais `degradedOcr`. `skippedPages` passa de lista de números de página para lista de objetos com `pageNumber` e `reason`, mudança incompatível.
- 2026-09-28: Campo `extensions` no envio (`history`, `lab-name-vision`), e `heightCm`.
- 2026-09-28: Proveniência e confiança em dois eixos em cada `Observation`. No envelope, `progress`, `failedPages`, `needsManualReview`, `resultDeliveredAt` e `skippedBiomarkers`; `confidence.reading` passa a opcional.
- 2026-09-23: O cabeçalho `Idempotency-Key` sai do contrato, porque nada no serviço o lia ainda.
- 2026-09-23: `/v1` no ar: envio com a chave em `X-API-Key`, limites de tamanho e de páginas, consulta, rota do Bundle e exclusão.

## Referência

### Confere se o serviço está pronto

`GET /health`

Responde `200` com `{"status":"ok"}` quando o serviço está pronto para atender o `/v1`, e `503` com `{"status":"unavailable"}` quando não está. Não pede chave e não diz mais nada: versão e estado de dependência ficam de fora de propósito, para a rota não servir de reconhecimento a quem varre. Serve para conferir rede, DNS e TLS antes do primeiro envio; a chave se confere com uma chamada ao `/v1`, que responde `401` quando ela não vale.

- `200`: O serviço está pronto para atender.
- `503`: O serviço está no ar, mas não pode atender o `/v1`.

**Exemplo**

```bash
curl https://laudos.precisa-saude.com.br/health
```

### Envia um laudo para extração

`POST /v1/extractions`

Envia um documento. Responde 202 com o identificador do trabalho; o resultado sai pelo GET.

- `202`: Trabalho aceito. Com `Idempotency-Key` já usada no mesmo pedido, dentro da janela, é o `202` do primeiro envio repetido, sem trabalho novo. (`Idempotent-Replayed`)
- `400`: Entrada inválida: PDF protegido por senha, `purpose` fora da lista, extensão desconhecida, `heightCm` fora do intervalo, `collectionDate` fora do formato ou `Idempotency-Key` vazia, longa demais ou fora de ASCII. `invalid_input`. (`Content-Language`)
- `403`: A chave usou todos os documentos do teto do contrato, como o de um período de avaliação. Conferido depois da validação e da cota, e só em chave com teto. Não traz `Retry-After`: repetir não adianta. `document_cap_reached`. (`Content-Language`)
- `409`: Dois envios simultâneos com a mesma `Idempotency-Key`: o primeiro ainda está sendo registrado. Traz `Retry-After`; o reenvio depois dele recebe o `202` do primeiro. `not_ready`. (`Retry-After`, `Content-Language`)
- `413`: Documento acima de `maxBytes` ou de `maxPages`, conferidos antes de o trabalho entrar na fila. `file_too_large` ou `too_many_pages`. (`Content-Language`)
- `415`: Formato inválido ou diferente de PDF, JPEG e PNG estático. `unsupported_media_type`. (`Content-Language`)
- `422`: A `Idempotency-Key` já foi usada, dentro da janela, com outro documento ou outros campos. O trabalho antigo não é devolvido. `idempotency_key_reused`. (`Content-Language`)
- `429`: Cota ou concorrência excedida, conferidas antes de o arquivo ser lido. Traz `Retry-After` em segundos. `rate_limited`. (`Retry-After`, `Content-Language`)

**Exemplo**

```bash
curl -X POST https://laudos.precisa-saude.com.br/v1/extractions \
  -H "X-API-Key: $PRECISA_API_KEY" \
  -F "purpose=care_coordination" \
  -F "file=@laudo.pdf;type=application/pdf"
```

### Consulta um trabalho

`GET /v1/extractions/{id}`

Estado do trabalho, com o Bundle embutido em `bundle` quando houver. Com `Accept` de XML (`application/fhir+xml` ou `application/xml`), ou `_format` de XML, a resposta é o próprio Bundle em XML, igual ao de `/v1/extractions/{id}/bundle`: o envelope é JSON nosso e não tem forma em XML. Nesse caso, trabalho em curso responde `409` com `Retry-After`, e trabalho que falhou responde `422` com o código da falha, do mesmo jeito que a rota do Bundle.

- `200`: Em JSON, o estado do trabalho, com o Bundle quando houver. A extração acontece **depois** do `202`, então todo erro dela chega aqui, em `error`, e nunca como status do `POST`: `image_only_pdf`, `input_quality_too_low`, `not_a_lab_report`, `missing_collection_date` e `processing_error`. O estado `partial` traz Bundle e indica página não lida. Em XML, o Bundle FHIR R4 sozinho. (`Content-Language`)
- `404`: Não existe, ou é de outro tenant. A resposta é a mesma nos dois. (`Content-Language`)
- `406`: O `Accept`, ou o `_format`, não casa com nenhum tipo servido. (`Content-Language`)
- `409`: Só com `Accept` de XML: a extração ainda está em curso, e o envelope de estado não tem forma em XML. Traz `Retry-After`. `not_ready`. Em JSON o mesmo trabalho responde `200` com `state` `queued` ou `running`. (`Retry-After`, `Content-Language`)
- `410`: Expirado. O resultado deixou de existir após os 15 minutos. `expired`. (`Content-Language`)
- `422`: A extração falhou, e não há Bundle. O código é o mesmo que o envelope traria em `error`: `image_only_pdf`, `input_quality_too_low`, `not_a_lab_report`, `missing_collection_date` ou `processing_error`. Definitivo para este trabalho. (`Content-Language`)

**Exemplo**

```bash
curl https://laudos.precisa-saude.com.br/v1/extractions/$JOB_ID \
  -H "X-API-Key: $PRECISA_API_KEY"
```

### Apaga um resultado antes do prazo

`DELETE /v1/extractions/{id}`

Apaga documento e resultado antes do prazo e para a extração em curso, em até 5 segundos: depois disso nenhuma chamada nova ao modelo começa, e o trabalho termina `failed` com `expired`. A leitura não consome, então esta é a forma de encerrar na hora em vez de esperar os 15 minutos. Idempotente.

- `200`: Apagado, ou já não existia. O corpo traz o estado final.
- `404`: Não existe, ou é de outro tenant. A resposta é a mesma nos dois. (`Content-Language`)

**Exemplo**

```bash
curl -X DELETE https://laudos.precisa-saude.com.br/v1/extractions/$JOB_ID \
  -H "X-API-Key: $PRECISA_API_KEY"
```

### Busca o Bundle FHIR

`GET /v1/extractions/{id}/bundle`

O Bundle FHIR R4 sozinho. `Accept` escolhe o tipo, e o padrão é `application/fhir+json`. `application/json` e `application/xml` são aceitos como apelido, e a resposta volta rotulada com o tipo pedido, não com o `fhir+` equivalente. O parâmetro `_format` do R4 ganha do `Accept` quando vem. Tipo fora da lista responde 406, e não JSON em silêncio.

- `200`: O Bundle, no tipo de mídia negociado.
- `404`: Não existe, ou é de outro tenant. A resposta é a mesma nos dois. (`Content-Language`)
- `406`: O `Accept`, ou o `_format`, não casa com nenhum tipo servido. (`Content-Language`)
- `409`: A extração ainda está em curso. Traz `Retry-After`. `not_ready`. Distinto do `410`, que é definitivo. (`Retry-After`, `Content-Language`)
- `410`: Expirado, ou apagado por `DELETE`. Definitivo: não adianta repetir. `expired`. (`Content-Language`)
- `422`: A extração falhou, e não há Bundle. O código é o mesmo que o envelope traria em `error`: `image_only_pdf`, `input_quality_too_low`, `not_a_lab_report`, `missing_collection_date` ou `processing_error`. Definitivo para este trabalho. (`Content-Language`)

**Exemplo**

```bash
curl https://laudos.precisa-saude.com.br/v1/extractions/$JOB_ID/bundle \
  -H "X-API-Key: $PRECISA_API_KEY" \
  -H "Accept: application/fhir+json"
```
