ChatSynap · Integração de sistemas
Especificação dos endpoints que o sistema de prontuário expõe para que o ChatSynap consulte horários, crie e cancele agendamentos diretamente na agenda da clínica.
O ChatSynap é a plataforma de atendimento da clínica no WhatsApp: um agente de IA conversa com o paciente, qualifica, agenda consultas e conduz a régua de lembretes e confirmação. Nesta integração, o agendamento passa a ser feito diretamente na agenda do prontuário.
O modelo é o ChatSynap chama a API do prontuário (não o contrário). O ChatSynap mantém um registro local de cada consulta — para lembretes e confirmação — usando o id retornado pelo prontuário como chave; por isso ele precisa ser estável e único.
| Momento da conversa | Chamada |
|---|---|
| Paciente pede horários | GET /availability |
| Paciente escolhe um horário | GET /patients → POST /appointments |
| Paciente desiste ou remarca | POST /appointments/{id}/cancel (remarcação = cancelar + criar) |
| Agente precisa de contexto | GET /appointments, GET /patients |
A clínica cadastra a integração no painel do ChatSynap informando dois dados fornecidos pelo prontuário:
base_url — URL base da API (ex.: https://api.seuprontuario.com.br/chatsynap/v1). Precisa ser HTTPS com hostname público — endereços internos e IPs privados são bloqueados pela nossa camada de segurança.api_key — chave secreta emitida pelo prontuário para essa clínica.As chamadas partem de infraestrutura em nuvem (IPs de datacenter, não fixos). A autorização deve ser feita pela chave, não por IP.
Toda requisição do ChatSynap envia:
Authorization: Bearer {api_key}
Content-Type: application/json
Chave ausente ou inválida → responder HTTP 401 com { "error": "unauthorized" }.
Convenções que valem para todos:
2026-09-01T14:00:00-03:00);id;Localiza o cadastro do paciente antes de agendar.
Query params (ao menos um)
phone (dígitos com DDI/DDD, ex.: 5579999998888) · cpf (só dígitos) · name
Resposta 200
{
"patients": [
{
"id": "12345",
"name": "Maria Souza",
"phone": "5579999998888",
"cpf": "00000000000",
"email": "maria@example.com",
"birth_date": "1990-05-10"
}
]
}
Nenhum resultado → 200 com "patients": [] (não usar 404).
Consulta a agenda existente.
Query params (opcionais, combináveis)
date (YYYY-MM-DD) · patient_id
Resposta 200
{
"appointments": [
{
"id": "ag-9876",
"patient_id": "12345",
"professional_id": "dr-01",
"start": "2026-09-01T14:00:00-03:00",
"end": "2026-09-01T14:30:00-03:00",
"status": "confirmed"
}
]
}
status ∈ confirmed | tentative | cancelled.
Horários livres que o agente oferecerá ao paciente.
Query params
start e end (janela em ISO 8601, obrigatórios) · professional_id (opcional)
Resposta 200
{
"timezone": "America/Fortaleza",
"slots": [
{ "start": "2026-09-01T14:00:00-03:00", "end": "2026-09-01T14:30:00-03:00", "professional_id": "dr-01" },
{ "start": "2026-09-01T14:30:00-03:00", "end": "2026-09-01T15:00:00-03:00", "professional_id": "dr-01" }
]
}
Sem disponibilidade → 200 com "slots": []. Os slots devem já refletir as regras da clínica (horário de funcionamento, bloqueios, antecedência mínima): o ChatSynap oferece ao paciente exatamente o que vier aqui.
Cria o agendamento na agenda do prontuário.
Body
{
"patient": {
"id": "12345",
"name": "Maria Souza",
"phone": "5579999998888",
"cpf": "00000000000"
},
"start": "2026-09-01T14:00:00-03:00",
"end": "2026-09-01T14:30:00-03:00",
"professional_id": "dr-01",
"notes": "Agendado via ChatSynap (WhatsApp)",
"source": "chatsynap"
}
patient.id vem preenchido quando o paciente foi localizado via GET /patients; caso contrário vêm name + phone (e cpf quando o paciente informou). Recomendação: localizar por telefone/CPF e, se não existir, criar o cadastro — devolver patient_not_found só se a política da clínica exigir cadastro prévio.end pode ser omitido; usar então a duração padrão do procedimento/agenda.Resposta 201
{
"id": "ag-9877",
"status": "confirmed",
"start": "2026-09-01T14:00:00-03:00",
"end": "2026-09-01T14:30:00-03:00",
"patient_id": "12345"
}
O id retornado é a chave que o ChatSynap gravará e usará em qualquer cancelamento futuro.
Conflito de horário — resposta 409
{ "error": "slot_conflict", "message": "Horário não está mais disponível" }
O agente então reconsulta a disponibilidade e oferece alternativas ao paciente.
Cancela um agendamento criado pelo ChatSynap.
Body (opcional)
{ "reason": "Paciente solicitou pelo WhatsApp" }
Resposta 200
{ "id": "ag-9877", "status": "cancelled" }
200 normalmente.id desconhecido → 404 com { "error": "not_found" }.Remarcação não tem endpoint próprio: o ChatSynap cancela e cria um novo agendamento.
Formato padrão: { "error": "<código>", "message": "<texto para log>" }.
| HTTP | error | Quando |
|---|---|---|
| 401 | unauthorized | api_key ausente ou inválida |
| 400 | invalid_request | parâmetro obrigatório ausente ou data malformada |
| 404 | not_found | agendamento inexistente (cancelamento) |
| 409 | slot_conflict | horário ocupado na criação |
| 422 | patient_not_found | política exige cadastro prévio e o paciente não existe |
| 5xx | — | erro interno; o ChatSynap informa ao paciente que houve instabilidade |
Erros de negócio previsíveis (conflito, paciente não encontrado) devem usar os códigos acima — é o que permite ao agente reagir corretamente na conversa em vez de tratar a resposta como falha técnica.
GET /availability.Idempotency-Key (UUID) no POST /appointments; armazenando a chave por 24 h e devolvendo a mesma resposta para repetições, elimina-se o risco de consulta duplicada em retry de rede.timezone em /availability informa o fuso da agenda.A fase 2 prevê um webhook no sentido inverso: o prontuário faz POST em um endpoint do ChatSynap a cada consulta criada, remarcada ou cancelada (payload com id, status, start, patient.phone; autenticação por credenciais por instância, no mesmo padrão da integração de documentos já existente). Escopo e ativação serão combinados na homologação — se o prontuário já tiver mecanismo de webhook, sinalizar: isso antecipa a fase 2.
Independente da agenda, o ChatSynap já oferece um endpoint para o prontuário enviar documentos (PDF) ao WhatsApp do paciente — receitas, atestados, laudos, resultados de exame:
POST https://ecymkwllrmjejuzfilzp.supabase.co/functions/v1/medical-pdf-webhook
Autenticação: headers x-instance-id + x-instance-token, fornecidos no painel da clínica (Instâncias → “Integração Prontuário API”).
phone + pdfUrl (URL pública do PDF), com opcionais name, caption, fileName, documentType, professionalName, externalRef;application/pdf de até 10 MB;documentType ∈ receita | renovacao_receita | relatorio | atestado | exames | laudo | outro.Exemplos completos de payload e respostas estão na tela de configuração da instância no painel.
Para iniciar, precisamos receber do fornecedor:
base_url de sandbox + api_key de teste;GET /patients por telefone, com e sem resultadoGET /availability em janela com e sem horáriosPOST /appointments com paciente existente e com paciente novoPOST /appointments em horário ocupado → 409 slot_conflictPOST /appointments/{id}/cancel, incluindo repetição idempotente