https://app.clinplus.com.br/api/pub/v1 REST · JSON · v1

API de Integração

API REST pública pra conectar sistemas parceiros — bots de WhatsApp, CRMs e afins — à sua clínica.

Base URL
https://app.clinplus.com.br/api/pub/v1
Autenticação

Toda chamada precisa do header Authorization: Bearer <token>. O token é criado pela clínica em Configurações → API / Integrações, com os escopos (módulos) que ele pode acessar.

curl https://app.clinplus.com.br/api/pub/v1/ping \
  -H "Authorization: Bearer SEU_TOKEN"
Escopos disponíveis
agendamentos:ler— Consultar agendamentos e horários disponíveis
agendamentos:criar— Criar agendamentos
agendamentos:cancelar— Cancelar agendamentos
pacientes:ler— Buscar e consultar pacientes
pacientes:criar— Cadastrar pacientes
lembretes:ler— Listar agendamentos pendentes de lembrete
lembretes:enviar— Disparar lembretes por WhatsApp
catalogos:ler— Ler catálogos (médicos, especialidades, convênios, unidades)
crm:ler— Consultar leads e estágios do CRM
crm:criar— Criar e atualizar leads do CRM
financeiro:ler— Consultar saldo, entradas e saídas do dia
financeiro:criar— Lançar despesas/receitas por WhatsApp (via Flagy)

Feito pra IA / Agentes

Conecte seu bot/assistente em minutos: os endpoints são orientados a intenção e a API é auto-descritível.

Artefatos prontos
GET /tools.json— esquemas de function-calling (Anthropic/OpenAI) — cole no seu agente
GET /openapi.json— spec OpenAPI 3.0 (gera SDK/tools automático)
GET /postman.json— coleção Postman (importe e teste)
Atalhos semânticos (o jeito que a IA pensa)
GET /disponibilidade/proximo— próximo horário livre por especialidade
POST /agendamentos/rapido— resolve/cria paciente por telefone + agenda em 1 chamada
GET /pacientes/por-telefone— o bot já tem o número do paciente
Conector nativo (MCP)
POST /mcp— Servidor Model Context Protocol (JSON-RPC): plugue Claude/ChatGPT/agents direto. Auth: mesmo Bearer token.
Webhooks (nós → você)

Cadastre uma URL em Configurações → API e receba POST assinado quando um agendamento muda (agendamento.criado, .confirmado, .cancelado, .concluido). Valide com X-ClinPlus-Signature: sha256=<hmac>.

Retry sem duplicar

Mande o header Idempotency-Key: <único> nos POST — se o agente repetir a chamada, devolvemos o mesmo resultado (não cria dois agendamentos). Em conflito de horário, o erro já traz os proximos_horarios livres.

Catálogos

GET /catalogos/profissionais?especialidade=cardiologia escopo catalogos:ler

Lista os médicos/profissionais ativos (filtra por especialidade).

Resposta 200
{
  "data": [
    { "id": 36, "nome": "Dr. Roberto Lima", "especialidade": "cardiologia", "crm": "41023 SP" }
  ],
  "meta": { "request_id": "…", "version": "v1" }
}
GET /catalogos/especialidades escopo catalogos:ler

Lista as especialidades.

Resposta 200
{
  "data": [ { "id": 4, "titulo": "Cardiologia", "cbo": "2251-21" } ],
  "meta": { "request_id": "…", "version": "v1" }
}
GET /catalogos/convenios escopo catalogos:ler

Lista os convênios.

Resposta 200
{
  "data": [ { "id": 29, "titulo": "Bradesco Saúde", "registro_ans": "005711" } ],
  "meta": { "request_id": "…", "version": "v1" }
}
GET /catalogos/procedimentos?q=ultra&tipo=exame escopo catalogos:ler

Catálogo de procedimentos (serviços/exames) com preparo e valor particular. Filtre por nome/TUSS (q=) e por tipo (servico|exame). Também em /catalogos/procedimentos/pesquisa?q=.

Resposta 200
{
  "data": [
    {
      "id": 181, "nome": "Ultrassom Abdominal", "tipo": "exame",
      "tuss_codigo": "40901114", "tuss_tabela": "22",
      "preparo": "Jejum de 8 horas. Beber 1L de água 1h antes.",
      "valor_particular": 150.00, "duracao_min": 30, "descricao": null
    }
  ],
  "meta": { "request_id": "…", "version": "v1" }
}
POST /catalogos/convenios/validar escopo catalogos:ler

Diz se um convênio/plano cobre um procedimento (há tabela de preço cadastrada). convenio aceita id ou nome; procedimento aceita código TUSS ou nome.

Corpo (request)
{"convenio":"Bradesco Saúde","plano":"Top Nacional","procedimento":"Consulta"}
Resposta 200
{
  "data": {
    "aceito": true,
    "motivo": "Procedimento coberto — há tabela de preço cadastrada para este convênio/plano.",
    "convenio": { "id": 29, "titulo": "Bradesco Saúde" },
    "plano": "Top Nacional",
    "procedimento": "Consulta em consultório",
    "tuss": "10101012",
    "valor": 120.00
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// aceito=false quando não há tabela de preço; motivo explica (convênio inativo, sem tabela, etc.).
GET /catalogos/unidades escopo catalogos:ler

Lista as unidades/clínicas.

Resposta 200
{
  "data": [ { "id": 1, "nome": "Clínica Viver Bem — Matriz", "sigla": "MATRIZ", "cidade": null, "uf": null } ],
  "meta": { "request_id": "…", "version": "v1" }
}

Agendamentos

GET /agendamentos?data=YYYY-MM-DD&profissional_id=&status= escopo agendamentos:ler

Agendamentos de um dia.

Resposta 200
{
  "data": {
    "data": "2026-08-28",
    "agendamentos": [
      {
        "id": 917,
        "inicio": "2026-08-28T09:15:00-03:00",
        "fim": "2026-08-28T09:45:00-03:00",
        "status": "concluido",
        "titulo": "Consulta cardiológica",
        "descricao": null,
        "paciente": {
          "id": 2056, "nome": "Maria Silva", "telefone": "11900000001",
          "cpf": null, "nascimento": null, "email": "maria@ex.com", "sexo": "feminino"
        },
        "profissional": {
          "id": 36, "nome": "Dr. Roberto Lima", "conselho": "41023/SP", "especialidade": "cardiologia"
        },
        "convenio": { "id": 29, "nome": "Bradesco Saúde" },
        "procedimentos": [
          {
            "item_id": 181, "nome": "Ultrassom Abdominal", "tipo": "exame",
            "tuss_codigo": "40901114", "tuss_tabela": "22", "quantidade": 1,
            "preparo": "Jejum de 8 horas. Beber 1L de água 1h antes."
          }
        ],
        "preparo": "Jejum de 8 horas. Beber 1L de água 1h antes."
      }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /disponibilidade?profissional_id=36&data=YYYY-MM-DD escopo agendamentos:ler

Horários livres de um profissional num dia.

Resposta 200
{
  "data": {
    "data": "2026-09-01",
    "slots": [
      { "hora": "07:00", "disponivel": true, "motivo": null },
      { "hora": "07:45", "disponivel": false, "motivo": "ocupado" }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /disponibilidade/dias?profissional_id=36&limite=14 escopo agendamentos:ler

Próximos dias com vaga.

Resposta 200
{
  "data": {
    "dias": [
      { "data": "2026-08-29", "dia_semana": 6, "disponiveis": 16 },
      { "data": "2026-08-30", "dia_semana": 0, "disponiveis": 16 }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /disponibilidade/proximo?especialidade=cardiologia&dias=14 escopo agendamentos:ler

PRÓXIMO horário livre — varre os profissionais (por especialidade ou todos). Ideal pra IA.

Resposta 200
{
  "data": {
    "disponivel": true,
    "proximo": {
      "data": "2026-08-28", "hora": "17:30", "inicio": "2026-08-28T17:30:00-03:00",
      "profissional": { "id": 36, "nome": "Dr. Roberto Lima" }
    }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /disponibilidade/busca-elastica?especialidades=cardiologia,endocrinologia&dias_semana=4,5&turno=manha&dias=14&limite=20 escopo agendamentos:ler

Busca horários por vários critérios de uma vez: especialidades (csv), dias_semana (0=dom…6=sáb, csv), turno (manha|tarde|noite), de e dias. Reduz o nº de chamadas.

Resposta 200
{
  "data": {
    "total": 2,
    "resultados": [
      {
        "data": "2026-09-02", "hora": "07:00", "inicio": "2026-09-02T07:00:00-03:00",
        "profissional": { "id": 36, "nome": "Dr. Roberto Lima", "especialidade": "cardiologia" }
      },
      {
        "data": "2026-09-02", "hora": "07:45", "inicio": "2026-09-02T07:45:00-03:00",
        "profissional": { "id": 36, "nome": "Dr. Roberto Lima", "especialidade": "cardiologia" }
      }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /agendamentos/{id} escopo agendamentos:ler

Detalhe de um agendamento.

Resposta 200
{
  "data": {
    "id": 917,
    "inicio": "2026-08-28T09:15:00-03:00",
    "fim": "2026-08-28T09:45:00-03:00",
    "status": "concluido",
    "titulo": "Consulta cardiológica",
    "descricao": null,
    "paciente": { "id": 2056, "nome": "Maria Silva", "telefone": "11900000001", "cpf": null, "nascimento": null, "email": null, "sexo": "feminino" },
    "profissional": { "id": 36, "nome": "Dr. Roberto Lima", "conselho": "41023/SP", "especialidade": "cardiologia" },
    "convenio": { "id": 29, "nome": "Bradesco Saúde" },
    "procedimentos": [ { "item_id": 181, "nome": "Ultrassom Abdominal", "tipo": "exame", "tuss_codigo": "40901114", "tuss_tabela": "22", "quantidade": 1, "preparo": "Jejum de 8 horas." } ],
    "preparo": "Jejum de 8 horas."
  },
  "meta": { "request_id": "…", "version": "v1" }
}
POST /agendamentos escopo agendamentos:criar

Cria um agendamento. convenio_id ausente/null = PARTICULAR. tipo_atendimento = consulta|retorno. procedimentos = ids do catálogo (ou {item_id,qtd}).

Corpo (request)
{"cliente_id":193,"profissional_id":36,"titulo":"Consulta","inicio":"2026-08-28T14:00:00","fim":null,"tipo_atendimento":"consulta","convenio_id":null,"procedimentos":[181],"descricao":null,"notificar":true}
Resposta 200
{
  "data": {
    "id": 940, "status": "agendado", "inicio": "2026-08-28T14:00:00-03:00", "fim": "2026-08-28T15:00:00-03:00",
    "paciente": { "id": 193, "nome": "Maria Silva" }, "profissional": { "id": 36, "nome": "Dr. Roberto Lima" }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// HTTP 201. Em conflito de horário: HTTP 409 com error.details.proximos_horarios[].
POST /agendamentos/rapido escopo agendamentos:criar

RESOLVE-ou-CRIA o paciente (telefone/CPF) e agenda numa tacada. Ideal pra bot de WhatsApp.

Corpo (request)
{"telefone":"11999998888","nome":"Maria Silva","profissional_id":36,"titulo":"Consulta","inicio":"2026-08-28T14:00:00"}
Resposta 200
{
  "data": {
    "id": 941, "status": "agendado", "inicio": "2026-08-28T14:00:00-03:00",
    "paciente": { "id": 2058, "nome": "Maria Silva", "ja_existia": false }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// HTTP 201. Resolve-ou-cria o paciente pelo telefone/CPF e agenda.
POST /agendamentos/{id}/reagendar escopo agendamentos:criar

Reagendamento ATÔMICO: move a mesma reserva para outro horário; só muda se a nova vaga estiver livre (senão 409 e o original fica intacto). fim é opcional (mantém a duração).

Corpo (request)
{"inicio":"2026-08-29T15:00:00","fim":null}
Resposta 200
{
  "data": {
    "id": 917, "status": "agendado",
    "inicio": "2026-08-29T15:00:00-03:00", "fim": "2026-08-29T16:00:00-03:00",
    "tipo_atendimento": "retorno",
    "paciente": { "id": 2056, "nome": "Maria Silva" },
    "profissional": { "id": 36, "nome": "Dr. Roberto Lima" }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// HTTP 409 se a nova vaga estiver ocupada (o agendamento original permanece intacto).
POST /agendamentos/{id}/cancelar escopo agendamentos:cancelar

Cancela um agendamento.

Corpo (request)
{"motivo":"Paciente remarcou"}
Resposta 200
{
  "data": { "id": 917, "status": "cancelado" },
  "meta": { "request_id": "…", "version": "v1" }
}

Pacientes

GET /pacientes?q=maria&limit=20 escopo pacientes:ler

Busca pacientes por nome, telefone ou CPF.

Resposta 200
{
  "data": [
    { "id": 2056, "nome": "Maria Silva", "telefone": "11900000001", "cpf": null, "nascimento": null, "sexo": "feminino", "email": null, "pre_cadastro": false }
  ],
  "meta": { "request_id": "…", "version": "v1" }
}
GET /pacientes/por-telefone?telefone=11999998888 escopo pacientes:ler

Acha o paciente pelo telefone (o bot já tem o número).

Resposta 200
{
  "data": { "id": 2057, "nome": "Maria Silva", "telefone": "11900000002", "cpf": null, "nascimento": null, "sexo": "feminino", "email": "maria@ex.com", "pre_cadastro": false },
  "meta": { "request_id": "…", "version": "v1" }
}
// HTTP 404 quando não encontra.
GET /pacientes/por-cpf?cpf=12345678900 escopo pacientes:ler

Acha o paciente pelo CPF.

Resposta 200
{
  "data": { "id": 2057, "nome": "Maria Silva", "telefone": "11900000002", "cpf": "12345678900", "nascimento": "1985-10-01", "sexo": "feminino", "email": null, "pre_cadastro": false },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /pacientes/contexto?telefone=11999998888 escopo pacientes:ler

Paciente + próximos agendamentos numa única chamada (por telefone). Economiza 2 requisições.

Resposta 200
{
  "data": {
    "paciente": { "id": 2057, "nome": "Maria Silva", "telefone": "11999998888", "cpf": null, "nascimento": null, "sexo": "feminino", "email": null, "pre_cadastro": false },
    "proximos_agendamentos": [
      { "id": 918, "inicio": "2026-08-29T09:00:00-03:00", "fim": "2026-08-29T09:30:00-03:00", "status": "agendado", "titulo": "Retorno", "tipo_atendimento": "retorno", "profissional": "Dr. Roberto Lima" }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /pacientes/{id} escopo pacientes:ler

Detalhe de um paciente.

Resposta 200
{
  "data": { "id": 2057, "nome": "Maria Silva", "telefone": "11900000002", "cpf": null, "nascimento": null, "sexo": "feminino", "email": null, "pre_cadastro": false },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /pacientes/{id}/agendamentos escopo pacientes:ler

Agendamentos de um paciente.

Resposta 200
{
  "data": {
    "agendamentos": [
      { "id": 918, "inicio": "2026-08-28T09:20:00-03:00", "fim": "2026-08-28T09:50:00-03:00", "status": "concluido", "titulo": "Retorno", "profissional": "Dr. Roberto Lima" }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
POST /pacientes escopo pacientes:criar

Cadastra um paciente.

Corpo (request)
{"nome":"Maria Silva","telefone":"11999998888","cpf":null,"nascimento":null,"sexo":"feminino","whatsapp":true}
Resposta 200
{
  "data": { "id": 2058, "nome": "Maria Silva", "telefone": "11955554444", "cpf": null, "nascimento": null, "sexo": "feminino", "email": null, "pre_cadastro": true, "ja_existia": false },
  "meta": { "request_id": "…", "version": "v1" }
}
// ja_existia=true quando o telefone/CPF já era de um paciente (não duplica).

Lembretes

GET /lembretes/pendentes?horas=24 escopo lembretes:ler

Agendamentos que ainda precisam de lembrete.

Resposta 200
{
  "data": {
    "janela_horas": 24,
    "total": 1,
    "pendentes": [
      { "agendamento_id": 918, "paciente": "Maria Silva", "telefone": "11900000002", "inicio": "2026-08-29T09:00:00-03:00", "profissional": "Dr. Roberto Lima" }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
POST /lembretes/{id}/enviar escopo lembretes:enviar

Dispara o lembrete por WhatsApp.

Resposta 200
{
  "data": { "agendamento_id": 918, "enviado": true, "canal": "whatsapp" },
  "meta": { "request_id": "…", "version": "v1" }
}

Financeiro (WhatsApp/Flagy)

GET /financeiro/resumo?data=2026-09-18 escopo financeiro:ler

Saldo do dia, entradas e saídas (para responder "quanto entrou hoje?"). Opcional data=YYYY-MM-DD.

Resposta 200
{
  "data": {
    "data": "2026-09-18", "entradas_dia": 1850.00, "saidas_dia": 420.50,
    "saldo_dia": 1429.50, "saldo_total": 38210.75
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /financeiro/briefing?dias=7 escopo financeiro:ler

Resumo proativo pronto pra enviar (saldo + contas a vencer/vencidas + inadimplência + insight de IA). Traz um campo "mensagem" já formatado. Agende no Flagy (ex.: 19h).

GET /financeiro/aprovacoes escopo financeiro:ler

Lançamentos acima do limite aguardando aprovação de um admin.

POST /financeiro/lancamentos/aprovar escopo financeiro:criar

Aprova (grava) ou rejeita um lançamento que ficou acima do limite.

Corpo (request)
{"token":"<do preview>","aprovado":true}
POST /financeiro/lancamentos/preview-comprovante escopo financeiro:criar

Comprovante por foto: a IA lê a imagem (imagem_url hospedada pelo Flagy), extrai a despesa e devolve o resumo pra confirmar (mesmo /confirmar).

Corpo (request)
{"telefone":"11999998888","imagem_url":"https://.../nota.jpg"}
GET /financeiro/relatorio?tipo=dre&mes=2026-09 escopo financeiro:ler

Gera um relatório em PDF sob demanda (hoje: DRE do mês) e devolve um link efêmero pra enviar como documento.

POST /financeiro/lancamentos/preview escopo financeiro:criar

Passo 1: confere a whitelist do número, a IA interpreta o texto e devolve o resumo pra confirmar (ou opções quando o paciente é ambíguo). NÃO grava ainda.

Corpo (request)
{"telefone":"11999998888","texto":"lançar despesa de cartucho de impressora, 45 reais","sid":"wamid-123"}
Resposta 200
{
  "data": {
    "status": "confirmar",
    "token": "4d7b7f1adeb1aba22c9779205a80d4d2",
    "resumo": "Vou lançar SAÍDA de R$ 45,00 — Cartucho de impressora · categoria Materiais. Confirma? Responda SIM.",
    "lancamento": { "tipo": "saida", "valor": 45, "descricao": "Cartucho de impressora", "data": "2026-09-18" }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// status pode ser: confirmar | ambiguo (traz opcoes[] de pacientes) | incompleto (pergunta) | limite | sem_permissao.
POST /financeiro/lancamentos/confirmar escopo financeiro:criar

Passo 2: com o token do preview (e opcao_id se houver ambiguidade de paciente), grava o lançamento em entradas/saídas.

Corpo (request)
{"token":"<do preview>","opcao_id":null}
Resposta 200
{
  "data": {
    "status": "lancado",
    "comprovante": "✅ Saída de R$ 45,00 lançada — Cartucho de impressora. (a revisar no sistema)",
    "lancamento_id": 12488
  },
  "meta": { "request_id": "…", "version": "v1" }
}
POST /financeiro/lancamentos/cancelar escopo financeiro:criar

Cancela um lançamento pendente (resposta NÃO).

Corpo (request)
{"token":"<do preview>"}

CRM / Leads

GET /crm/estagios escopo crm:ler

Colunas do funil (id/nome/categoria) — use pra mapear o estágio.

Resposta 200
{
  "data": {
    "estagios": [
      { "id": 12, "nome": "Novo", "cor": "#2563eb", "ordem": 1, "categoria": "inicial" },
      { "id": 13, "nome": "Em contato", "cor": "#f59e0b", "ordem": 2, "categoria": "andamento" },
      { "id": 16, "nome": "Fechado (ganho)", "cor": "#10b981", "ordem": 5, "categoria": "ganho" }
    ]
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /crm/leads?q=maria&estagio_id=&origem=&limit=50 escopo crm:ler

Lista leads do funil. Filtre por texto (q=), estágio ou origem.

GET /crm/leads/por-telefone?telefone=11999998888 escopo crm:ler

Acha o lead mais recente pelo telefone (dedup).

Resposta 200
{
  "data": {
    "id": 842, "nome": "Maria Silva", "telefone": "11999998888",
    "origem": "campanha", "score": 65, "ref_externa": "flagy-lead-8842",
    "estagio": { "id": 12, "nome": "Novo", "categoria": "inicial" }
  },
  "meta": { "request_id": "…", "version": "v1" }
}
GET /crm/leads/{id} escopo crm:ler

Detalhe de um lead.

POST /crm/leads escopo crm:criar

Cria OU atualiza (upsert) um lead capturado. Casa por ref_externa (id da sua ferramenta) ou telefone; senão cria. Idempotente. Dispara o webhook lead.criado.

Corpo (request)
{"nome":"Maria Silva","telefone":"11999998888","email":null,"origem":"campanha","interesse":"Ortodontia","valor_estimado":1500,"ref_externa":"flagy-lead-8842"}
Resposta 200
{
  "data": {
    "id": 842, "nome": "Maria Silva", "telefone": "11999998888", "email": null,
    "origem": "campanha", "interesse": "Ortodontia", "valor_estimado": 1500.00, "score": 65,
    "ref_externa": "flagy-lead-8842", "cliente_id": null, "convertido_em": null,
    "estagio": { "id": 12, "nome": "Novo", "categoria": "inicial" },
    "ja_existia": false
  },
  "meta": { "request_id": "…", "version": "v1" }
}
// ja_existia=true (HTTP 200) quando casou por ref_externa ou telefone e atualizou o lead existente.

Utilitário

GET /ping escopo (qualquer)

Testa o token e devolve os escopos dele.

Resposta 200
{
  "data": {
    "ok": true,
    "clinica": "Clínica Viver Bem",
    "token": "Bot WhatsApp",
    "escopos": ["agendamentos:ler", "pacientes:ler", "lembretes:enviar"],
    "agora": "2026-08-28T17:12:34-03:00"
  }
}
Playground