Versões e mudanças

Versão atual da especificação: 1.18.0 · prefixo /api/public/v1

Política de compatibilidade

  • Mudanças compatíveis (campos opcionais novos, novos códigos de erro, novos endpoints) entram na v1 sem aviso prévio de quebra — trate campos desconhecidos de forma tolerante.
  • Mudanças incompatíveis ganham um novo prefixo de versão (/api/public/v2/...); a versão anterior segue disponível durante a transição.
  • Códigos de erro só são removidos em uma nova versão maior.
  • Trate qualquer resposta 5xx como transitória e repita a chamada com o mesmo idempotency_key.

Histórico

  1. v1.18.0

    • POST /api/public/v1/lab-results/upload e POST /api/public/v1/documents passam a devolver o 202 como JSON curto e completo, encerrando a resposta na hora. Antes o corpo ficava aberto (streaming) enquanto o exame era lido, e quem desligava a conexão interrompia a leitura.
    • A leitura do exame agora roda em segundo plano no servidor, independente da conexão do chamador. Nada muda nos campos da resposta (document_id, status, batch_id, queued) nem no acompanhamento por GET /status?document_id=…
    • A varredura interna de recuperação passou de 5 minutos para 1 minuto, reduzindo a espera quando uma leitura precisa ser retomada.
  2. v1.17.0

    • GET /api/public/v1/family-members passa a responder 200 com exists=false, multiple=false e members vazio quando o telefone não tem conta — antes essa situação vinha como 404.
    • Quem tratava o 404 como "sem conta" precisa passar a olhar o campo exists. As chamadas POST, PATCH e DELETE de familiares continuam respondendo 404 not_found quando não existe conta para o telefone.
  3. v1.16.0

    • GET /api/public/v1/patients passa a responder 200 com exists=false quando o telefone é válido e ainda não tem cadastro — antes essa situação vinha como 404. O corpo é o mesmo (exists, profile_complete e missing).
    • Quem tratava o 404 como "não cadastrado" precisa passar a olhar o campo exists. Telefone impossível continua em 400 invalid_phone, e os demais endpoints seguem usando patient_not_found (404).
  4. v1.15.1

    • POST /api/public/v1/patients aceita cadastro progressivo de verdade: campo enviado em branco ("" ou null) passa a significar "ainda não informado" e não recusa mais a chamada com invalid_payload. Só o telefone é obrigatório.
    • CPF continua sendo validado quando enviado com conteúdo, e deve ir sempre como texto — enviado como número, perde o zero à esquerda e é recusado como CPF inválido.
  5. v1.15.0

    • Novo POST /api/public/v1/cron/review-maintenance (interno, Bearer próprio): com mode refresh recalcula as sugestões de todas as pessoas com exame ativo e com mode packets agrupa em pacotes as sugestões abertas que estavam sem pacote. Percorre a base por cursor e não devolve dado clínico.
    • A fila do médico passa a ser agrupada por pessoa, com a contagem separada de exames e de encaminhamentos; ao abrir a pessoa, a lista vem ordenada por prioridade e cada item pode ser aceito, editado ou rejeitado com justificativa.
    • Sugestão rejeitada continua visível na aba Prescrições do paciente como revisada e considerada desnecessária pelo médico, com nome, registro profissional, data e motivo.
    • Nenhuma mudança de contrato nos endpoints usados pelo agente do WhatsApp.
  6. v1.14.0

    • Sugestões de exames e encaminhamentos passam por revisão médica antes de valer como documento: cada exame gera um pacote na fila dos médicos do Vital, que mantêm, ajustam ou recusam item por item.
    • Aprovado o pacote, o documento consolidado é assinado eletronicamente na DocuSign e fica disponível ao paciente na aba Prescrições.
    • Novo POST /api/public/docusign/webhook: recebe os avisos de envelope da DocuSign, valida o HMAC dos cabeçalhos x-docusign-signature-1 a -5 sobre o corpo bruto e guarda o documento assinado. Assinatura inválida responde 401; integração não configurada responde 503. A resposta nunca traz dado de paciente.
    • A conexão com a DocuSign é configurada em Administração › Integrações › Assinatura eletrônica. Chave privada e segredo do webhook ficam cifrados e não voltam para a tela.
    • Segregação de sigilo: a fila de revisão é exclusiva do perfil Clínico. Admin e Gestão veem apenas números agregados, a configuração técnica e a auditoria, sem nome, exame ou resultado.
  7. v1.13.0

    • Novo POST /lab-results/upload-batch: até 10 arquivos no mesmo corpo, dentro de um batch_id. Cada arquivo é baixado, deduplicado e lido em execução própria — nenhum espera o outro.
    • A resposta é sempre 207 com results[] na ordem dos itens: item aceito traz document_id, item recusado traz error/reason e o mesmo status que a chamada de arquivo único devolveria. Reenvie somente os itens com ok: false.
    • Cada item precisa da sua própria idempotency_key. member_id pode vir no lote (vale para todos) e/ou por item.
    • Limites: 10 itens e 100 MB somados por chamada (25 MB pelo proxy do GPT Maker). Soma acima do limite responde 413 batch_too_large.
    • A rota v1/lab-results/upload-batch foi liberada no proxy /api/public/gpt.
    • No app, o envio de vários arquivos passa de 3 para 5 arquivos ao mesmo tempo.
  8. v1.12.0

    • Primeiro acesso sem código: ao criar o cadastro, POST /patients já devolve o bloco access com uma senha provisória (7 dias) e o endereço de entrada, para o agente enviar na conversa. Nenhuma chamada extra é necessária.
    • A entrada do paciente no painel passa a ser só celular + senha, sem código de 6 dígitos. Quem entra com a senha provisória cai direto na tela de criar a senha definitiva e segue para a home.
    • Se a emissão cair no limite de 1 por minuto, a resposta traz access_pending em vez de falhar o cadastro — reemita por /patients/access.
    • Recuperação de senha continua com código de 6 dígitos no WhatsApp.
  9. v1.11.1

    • Correção: dois exames diferentes enviados na mesma conversa com a mesma idempotency_key (o mesmo wamid reaproveitado pelo agente) não são mais confundidos — a chave só devolve duplicidade quando o arquivo é idêntico.
    • Arquivo diferente com chave repetida é aceito como exame novo e entra na leitura normalmente.
  10. v1.11.0

    • Encaminhamentos médicos agora geram uma carta em PDF que o paciente baixa na aba Prescrições e entrega ao especialista, com identificação, especialidade, prazo, motivo detalhado, os resultados que motivaram a sugestão, a evolução do marcador, outros achados alterados do mesmo exame e a diretriz de base.
    • Nova regra de encaminhamento: fosfatase alcalina muito elevada sugere avaliação em gastroenterologia/hepatologia (protocolo de encaminhamento TelessaúdeRS-UFRGS).
    • A carta nunca contém diagnóstico fechado, medicamento, dose ou tratamento, e cada download fica registrado na auditoria.
  11. v1.10.1

    • Motor de prescrições: leucócitos e plaquetas passam a ser comparados na mesma escala, independentemente da unidade do laudo (10³/uL ou /mm³), eliminando alertas indevidos.
    • Resultados com rótulo trocado (hemoglobina glicada gravada como hemoglobina) são descartados pelo motor e o histórico foi corrigido.
    • Rotina interna de reavaliação agora percorre todas as pessoas com exames, sem depender de limite de leitura, e registra quem já foi avaliado.
  12. v1.10.0

    • Motor de prescrições: ao fim da leitura de cada exame, a plataforma passa a gerar sugestões de exames a repetir/complementar e de consultas por especialidade, com prazo, valor que motivou e a diretriz de base (SBD, SBC, SBEM, INCA, Ministério da Saúde). Nunca indica medicamento, dose ou diagnóstico.
    • Nova aba Prescrições no painel do paciente, com a lista de cada pessoa da conta e os botões Já fiz, Agendado e Não quero agora.
    • Nova rotina interna POST /api/public/v1/cron/prescriptions: avalia em lotes o histórico já enviado. Autenticação por token interno.
    • Nova rotina interna POST /api/public/v1/cron/reminders: resumo diário dos cuidados pendentes no WhatsApp, em horário comercial de São Paulo, com no máximo 5 itens por mensagem e desligamento pelo paciente. Itens urgentes avisam no momento da leitura.
  13. v1.9.3

    • Correção do reenvio: o código da mensagem do WhatsApp (wamid/idempotency_key) deixa de ser único no sistema inteiro e passa a ser único por pessoa + lote. Antes, reenviar um arquivo com o mesmo wamid em outro lote quebrava a gravação e a API respondia 500 ingestion_failed.
    • Conflito de chave dentro do mesmo lote passa a responder 200 duplicated:true com reason: idempotency_key_reused e orientação de usar uma chave diferente por arquivo — em vez de erro 500.
    • Falhas internas passam a registrar código e mensagem técnica do banco no log de recusa, no lugar do genérico unknown_error.
  14. v1.9.2

    • Correção: a chave de idempotência (idempotency_key/wamid) agora só vale dentro do mesmo batch_id. Antes, quando o agente reaproveitava o mesmo wamid da conversa em um envio novo, o exame era tratado como duplicado — a resposta vinha 200 duplicated:true, o arquivo nem era baixado e o exame nunca aparecia no painel.
    • A resposta de duplicidade passa a dizer o motivo: reason: idempotency_key_reused (mesma chave no mesmo lote) ou reason: duplicate_content (arquivo idêntico já recebido).
    • Descarte por conteúdo idêntico e falha 500 passam a ficar registrados com motivo técnico curto, para permitir diagnóstico posterior.
  15. v1.9.1

    • A leitura do exame passa a acontecer dentro da própria chamada de envio (resposta 202 sai na hora, com o document_id, e a requisição segue viva até o exame ficar pronto). Isso encerra os casos de arquivo recebido que nunca era lido.
    • Nova rede de segurança automática a cada 5 minutos: qualquer envio cuja leitura tenha sido interrompida volta a ser lido, inclusive documento que ficou sem registro na fila. A varredura prioriza os envios mais recentes e ignora exames já concluídos.
    • Novo endpoint interno POST /api/public/v1/cron/process, usado só pelo agendador do próprio Vital (Bearer interno). Não deve ser chamado pelo agente do WhatsApp.
  16. v1.9.0

    • /documents e /lab-results/upload passam a aceitar o arquivo em bytes crus no corpo, com os metadados na query string (?phone=...&mime=...&filename=...&batch_id=...). Nesse formato a assinatura cobre {timestamp}. seguido dos bytes — caminho recomendado quando a URL de mídia do WhatsApp pode já ter expirado.
    • Toda recusa de recebimento passa a ficar registrada de forma permanente (motivo, status, lote, tamanho, host e caminho da mídia — nunca a query com token), o que permite responder dias depois por que um envio falhou.
    • Leitura que ficou pela metade é retomada automaticamente: cada novo envio e cada consulta de status recoloca na fila os documentos parados há mais de 90 segundos, com no máximo 3 tentativas por documento.
  17. v1.8.4

    • Telefone brasileiro sem o DDI (ex.: 11922522354) passa a ser normalizado com o 55 automaticamente, em todos os endpoints.
    • Número impossível (DDD fora de 11–99, celular sem o nono dígito, número curto sem DDI) responde 400 invalid_phone em vez de 404 exists:false — evita o agente cadastrar duplicado.
    • CPF e telefone enviados como número JSON são convertidos para texto: notação científica (5.3866792018E10) e zero à esquerda deixam de corromper o CPF. O formato recomendado continua sendo texto.
  18. v1.8.3

    • Download da mídia passa a tentar até 3 vezes com espera crescente quando a falha é transitória (timeout ou rede); motivos definitivos, como link expirado, não são repetidos.
    • Cada tentativa é registrada com motivo, status HTTP, tempo e tamanho (host e caminho apenas, nunca a query com token), e o sucesso registra bytes e duração.
    • Reenvio de um arquivo que já existia mas falhou deixa de ficar preso na deduplicação: responde 202 com duplicated: true e reprocessing: true e recoloca a leitura na fila.
    • Envio acima do limite do proxy responde 413 media_too_large com reason=too_large e limit_bytes, em vez de erro genérico; formato não aceito responde 415 com reason=unsupported_mime.
  19. v1.8.2

    • Falha ao baixar a mídia deixa de ser 502 genérico: agora responde 422 media_unreachable com reason (expired_url, forbidden, not_found, timeout, network_error, viewer_page, empty), detail e message pronta para o agente.
    • URLs de mídia do WhatsApp Cloud API passam a ser baixadas com token: media.access_token no corpo ou WHATSAPP_TOKEN no servidor; metadados de graph.facebook.com são resolvidos automaticamente até o arquivo.
    • Download com tempo máximo de 30 segundos e limite de tamanho conferido antes de ler o arquivo; o servidor registra host, caminho e status da falha, nunca a query com token.
  20. v1.8.1

    • O caminho /family-members passa a ser aceito também pelo proxy com Bearer (/api/public/gpt/v1/family-members), nos métodos GET, POST, PATCH e DELETE. Antes o proxy respondia 404 endpoint_not_allowed.
    • Nenhuma mudança de contrato: corpos, respostas e erros seguem iguais aos do caminho direto assinado.
  21. v1.8.0

    • Novo recurso de família: cada pessoa da conta tem ficha própria, vinculada ao telefone do titular. Só o titular acessa o painel.
    • GET /v1/family-members?phone=… devolve as pessoas da conta já numeradas, para o agente perguntar de quem é o exame; POST, PATCH e DELETE /v1/family-members cadastram, editam e removem um parente.
    • POST /v1/documents e POST /v1/lab-results/upload aceitam member_id. Com mais de uma pessoa na conta e sem member_id, a resposta passa a ser 409 member_required com a lista de pessoas; member_not_found indica id de outra conta.
    • Contas com uma única pessoa não mudam: o contrato anterior continua válido sem member_id.
  22. v1.7.0

    • Corrigido o processamento de arquivos enviados pelo WhatsApp: a leitura agora permanece na mesma execução do recebimento pelo proxy, evitando que uma sub-requisição encerrada pelo ambiente deixe o documento parado em received.
    • O formato real do arquivo passa a ser identificado pela assinatura binária; PDFs rotulados pelo WhatsApp como image/jpeg deixam de falhar na leitura multimodal.
    • O GPT Maker continua recebendo HTTP 202 e document_id imediatamente; o contrato dos corpos e respostas não mudou.
    • POST /v1/process permanece como rede de segurança para recuperação manual ou agendada.
  23. v1.6.0

    • Leitura pelo WhatsApp tão rápida quanto pelo app: o arquivo recebido em POST /v1/documents e POST /v1/lab-results/upload passa a ser lido em uma execução própria disparada no ato do envio, em vez de depender de uma tarefa solta que podia ser encerrada antes de começar (envios ficavam parados em received).
    • POST /v1/process aceita { "document_id": "<uuid>" } para ler um documento específico na hora; a resposta é enviada em streaming e fecha quando a leitura termina.
    • POST /v1/process (modo fila) recupera jobs presos em execução há mais de 10 minutos, além de pendentes e falhos.
    • Nenhuma mudança nos contratos existentes de ingestão, consentimento, cadastro ou status.
  24. v1.5.1

    • Desempenho da leitura: POST /v1/documents e POST /v1/lab-results/upload iniciam o processamento imediatamente ao receber o arquivo (antes o envio esperava a próxima passada de /v1/process). A resposta continua 202 na hora.
    • Motor de leitura mais rápido: modelo multimodal de última geração com fila de prioridade, laudos do mesmo arquivo lidos em paralelo e gravações agrupadas. Se a leitura rápida não encontrar conteúdo, o arquivo é relido no modelo forte — sem perda de qualidade.
    • Nenhuma mudança de contrato: caminhos, corpos e códigos de erro seguem iguais.
  25. v1.5.0

    • GET /status passa a aceitar ?document_id=<uuid> como alternativa a ?phone=, devolvendo o estado daquele envio (received, triaging, extracting, normalizing, interpreting, ready, rejected, failed) e o batch_id.
    • O parâmetro phone deixa de ser obrigatório: informe phone OU document_id.
    • Novos códigos de erro: invalid_document_id (400) e document_not_found (404).
    • Fluxo completo do agente validado pelo proxy /api/public/gpt/v1: termo vigente, aceite, cadastro, link de acesso, abertura de lote, upload e acompanhamento.
  26. v1.4.0

    • Novo proxy assinado em /api/public/gpt/v1/<endpoint> para agentes que não calculam HMAC (caso do GPTMaker): autentica com Authorization: Bearer <token do proxy>, calcula a assinatura e repassa para /api/public/v1/<endpoint>, devolvendo status e corpo originais.
    • O proxy aceita apenas a lista fechada de endpoints v1 já publicados, com limite de 120 chamadas por minuto e 25 MB por arquivo.
    • Novos códigos de erro exclusivos do proxy: unauthorized, endpoint_not_allowed, method_not_allowed, rate_limited, payload_too_large e proxy_not_configured.
    • As rotas /api/public/v1/* seguem inalteradas para parceiros que assinam as chamadas.
  27. v1.3.0

    • Novo endpoint GET /consents/current: devolve versão, título, resumo, hash e link público do termo vigente (o texto integral fica no link). Com ?phone=… informa se o titular já aceitou essa versão.
    • Novos endpoints POST /consents/acceptance e POST /consents/refusal: mesma regra de /consents, com a decisão implícita no caminho — não é preciso enviar accepted.
    • O aceite agora grava o horário real da mensagem quando enviado em evidence.accepted_at, marca o telefone como verificado no canal WhatsApp e encerra aceites anteriores em caso de recusa ou revogação.
    • Novos endpoints POST /lab-results/start (abre lote e confere consentimento, devolve batch_id) e POST /lab-results/upload (envio de arquivo com batch_id obrigatório). /documents continua válido para envio sem lote.
    • Termo de consentimento passou a ser versionado no sistema e editável pelo administrador; cada versão publicada tem link público estável em /termo/{versao}.
    • Novos códigos de erro: missing_decision, missing_batch_id e batch_start_failed.
  28. v1.2.0

    • Novo endpoint POST /patients/access: entrega o acesso do titular pelo WhatsApp — senha provisória forte devolvida uma única vez (7 dias, troca obrigatória no primeiro acesso) ou código de 6 dígitos com mode: "code".
    • POST /auth-code documentado na especificação: confirma se há código de verificação ativo para um número, com expiração e status de entrega.
    • Novos códigos de erro: rate_limited (429) e not_found.
  29. v1.1.0

    • Novo endpoint POST /patients: cria ou atualiza o cadastro do titular (nome completo, nome preferido, data de nascimento, CPF, sexo biológico e e-mail), aceitando envio parcial.
    • Novo endpoint GET /patients?phone=…: devolve o cadastro, o estado do consentimento e a lista de campos que ainda faltam. O CPF volta apenas com os 4 últimos dígitos.
    • Novos códigos de erro: invalid_birth_date e email_in_use.
  30. v1.0.0

    • Publicação da API v1: /consents, /documents, /status, /process, /magic-link e /erasure.
    • Assinatura HMAC-SHA256 obrigatória em todos os endpoints, com janela de 5 minutos.
    • Idempotência por idempotency_key e deduplicação por hash do arquivo.
    • Especificação OpenAPI 3.1 publicada em /api/public/v1/openapi.json.