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
Registre o consentimento
Apresente o termo ao titular e envie o aceite em POST /consents. Sem aceite ativo, nenhum arquivo é aceito.
- 2
Envie o exame
POST /documents com o arquivo por URL, base64 ou texto. Use idempotency_key para evitar duplicidade em reentregas.
- 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
Entregue o painel
POST /magic-link gera um link de uso único, válido por 15 minutos, para o titular abrir o painel.
- 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çalho | Conteúdo |
|---|---|
| x-vital-timestamp | Epoch em segundos. Tolerância de 5 minutos. |
| x-vital-signature | HMAC-SHA256 de timestamp.corpo em hexadecimal minúsculo. |
| content-type | application/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 aceitos | PDF, JPEG, PNG, WEBP, HEIC e texto puro |
|---|---|
| Tamanho máximo por arquivo | 100 MB |
| Janela de tolerância da assinatura | 5 minutos |
| Idempotência | idempotency_key (use o id da mensagem) + deduplicação por hash do arquivo |
| Documentos por chamada de /process | até 3 |
| Cadência recomendada de /process | 1 chamada por minuto |
| Validade do magic link | 15 minutos, uso único |
| Carência da eliminação de dados | 7 dias, cancelável |
Códigos de erro
Erros vêm sempre como { "error": "codigo" }.
| Código | HTTP | Significado |
|---|---|---|
| missing_signature | 401 | Faltou `x-vital-signature` ou `x-vital-timestamp`. |
| invalid_signature | 401 | A assinatura não corresponde ao corpo enviado. |
| stale_timestamp | 401 | Timestamp fora da janela de 5 minutos. |
| invalid_payload | 400 | O corpo não passou na validação do schema. |
| invalid_phone | 400 | Telefone não normalizável para E.164. |
| invalid_cpf | 400 | CPF informado não é válido. |
| missing_media | 400 | Nenhum de `url`, `base64` ou `text` foi informado. |
| empty_media | 400 | O arquivo chegou vazio. |
| consent_required | 403 | Sem aceite ativo do termo para este titular. |
| patient_not_found | 404 | Nenhum titular com esse telefone. |
| media_too_large | 413 | Arquivo acima de 100 MB. |
| unsupported_media_type | 415 | Formato de arquivo não aceito. |
| media_download_failed | 502 | Nã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.