API v1 · chamadas assinadas

Integre seu agente à plataforma Vital

O Vital recebe exames em qualquer formato — PDF, foto, print ou texto — registra o consentimento do titular, lê e normaliza os resultados e devolve ao paciente um painel com evolução dos marcadores e orientação de qual especialidade procurar. Esta é a documentação pública do contrato de integração.

Fluxo da integração

  1. 1

    Registre o consentimento

    Apresente o termo ao titular e envie o aceite em POST /consents. Sem aceite ativo, nenhum arquivo é aceito.

  2. 2

    Envie o exame

    POST /documents com o arquivo por URL, base64 ou texto. Use idempotency_key para evitar duplicidade em reentregas.

  3. 3

    Acompanhe a fila

    POST /process executa o pipeline (chame de minuto a minuto) e GET /status devolve as contagens para você responder ao titular.

  4. 4

    Entregue o painel

    POST /magic-link gera um link de uso único, válido por 15 minutos, para o titular abrir o painel.

  5. 5

    Atenda os direitos do titular

    POST /erasure cobre portabilidade e eliminação; a revogação usa /consents com accepted: false.

Autenticação

Toda chamada leva dois cabeçalhos. A assinatura é o HMAC-SHA256, em hexadecimal minúsculo, de timestamp.corpo, calculado com o segredo compartilhado com o parceiro. Em requisições GET, o "corpo" é a query string incluindo o ?. Assine sempre o corpo exatamente como ele vai no fio — serialize uma única vez.

CabeçalhoConteúdo
x-vital-timestampEpoch em segundos. Tolerância de 5 minutos.
x-vital-signatureHMAC-SHA256 de timestamp.corpo em hexadecimal minúsculo.
content-typeapplication/json nos métodos com corpo.
import crypto from "node:crypto";

const BASE = "https://sua-instancia-vital.example";
const SECRET = process.env.VITAL_INGEST_SECRET; // entregue ao parceiro; nunca versione

async function callVital(path, payload) {
  const body = JSON.stringify(payload);
  const ts = Math.floor(Date.now() / 1000);
  const signature = crypto
    .createHmac("sha256", SECRET)
    .update(`${ts}.${body}`)
    .digest("hex");

  const res = await fetch(BASE + path, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "x-vital-timestamp": String(ts),
      "x-vital-signature": signature,
    },
    body,
  });
  return { status: res.status, data: await res.json() };
}

await callVital("/api/public/v1/consents", {
  patient: { phone: "+5511999998888", full_name: "Maria Souza" },
  accepted: true,
  term_version: "v1.0",
  channel: "whatsapp",
});

O segredo de assinatura é entregue individualmente a cada parceiro e não aparece em nenhum lugar desta documentação. Mantenha-o apenas no servidor, nunca no navegador, no app ou no repositório.

Limites e regras

Formatos aceitosPDF, JPEG, PNG, WEBP, HEIC e texto puro
Tamanho máximo por arquivo100 MB
Janela de tolerância da assinatura5 minutos
Idempotênciaidempotency_key (use o id da mensagem) + deduplicação por hash do arquivo
Documentos por chamada de /processaté 3
Cadência recomendada de /process1 chamada por minuto
Validade do magic link15 minutos, uso único
Carência da eliminação de dados7 dias, cancelável

Códigos de erro

Erros vêm sempre como { "error": "codigo" }.

CódigoHTTPSignificado
missing_signature401Faltou `x-vital-signature` ou `x-vital-timestamp`.
invalid_signature401A assinatura não corresponde ao corpo enviado.
stale_timestamp401Timestamp fora da janela de 5 minutos.
invalid_payload400O corpo não passou na validação do schema.
invalid_phone400Telefone não normalizável para E.164.
invalid_cpf400CPF informado não é válido.
missing_media400Nenhum de `url`, `base64` ou `text` foi informado.
empty_media400O arquivo chegou vazio.
consent_required403Sem aceite ativo do termo para este titular.
patient_not_found404Nenhum titular com esse telefone.
media_too_large413Arquivo acima de 100 MB.
unsupported_media_type415Formato de arquivo não aceito.
media_download_failed502Não foi possível baixar a URL informada (pode ter expirado).

Conformidade obrigatória do integrador

  • Consentimento antes de tudo. Apresente o termo de uso de dados sensíveis de saúde e registre o aceite antes de enviar qualquer arquivo.
  • Sem diagnóstico. Nem o Vital nem o agente podem afirmar diagnóstico ou indicar tratamento e medicamento. Toda interpretação devolvida traz a fonte do protocolo aplicado e o aviso de não-diagnóstico — reproduza-os junto ao conteúdo.
  • Minimização. Envie apenas o necessário; não armazene o conteúdo clínico no seu lado além do tempo da entrega.
  • Direitos do titular. Os comandos MEUS DADOS, APAGAR, CANCELAR e REVOGAR precisam funcionar a qualquer momento na conversa.