API da agenda

Para parceiros e sistemas da clínica lerem a agenda do Trilio e do Órbita, verem os horários livres, marcarem, cancelarem e remarcarem consultas, e receberem um aviso quando a agenda muda. Versão v1.

Disponível no plano Clínica em diante. Quem administra a clínica gera a chave em Configurações › Conexões e saúde › Para desenvolvedores, com o que ela pode fazer: ler a agenda (agenda:leitura) e marcar na agenda (agenda:escrita).

Autenticação

Toda chamada leva a chave no cabeçalho. A chave aparece uma vez, quando é criada; a clínica pode revogá-la a qualquer momento.

curl https://api.quatrouno.com.br/v1/compromissos?inicio=2026-11-09&fim=2026-11-13 \
  -H "Authorization: Bearer qu_live_..."

Limite: 120 chamadas por minuto por chave. Toda chamada fica registrada para a clínica.

Rotas

RotaDevolve
GET /v1/compromissos?inicio&fimO que ocupa a agenda na janela (até 62 dias). Filtros opcionais: profissional (id) e atualizado_desde (data e hora com fuso).
GET /v1/compromissos/{id}Um compromisso.
GET /v1/profissionaisMédicos e técnicos com agenda: id, nome, tipo.
GET /v1/procedimentosid, nome, duracao_minutos, cirurgico.
GET /v1/locaisid, nome.

As respostas vêm em {"dados": ...}.

Marcar na agenda

Precisa de uma chave com agenda:escrita. O parceiro marca como a recepção da clínica marcaria: em qualquer horário livre da agenda, não só nos que aparecem no link de agendamento.

RotaFaz
GET /v1/disponibilidade?procedimentos&inicio&fimOs horários livres para 1 a 5 procedimentos (ids separados por vírgula), numa janela de até 31 dias. Filtro opcional: profissional. Serve a chaves de leitura ou de escrita.
POST /v1/agendamentosMarca. Exige o cabeçalho Idempotency-Key. Responde 201.
POST /v1/agendamentos/{id}/remarcarMuda data, hora, duração ou profissional de uma marcação feita por esta chave. O id continua o mesmo.
POST /v1/agendamentos/{id}/cancelarCancela uma marcação feita por esta chave. Corpo opcional: {"motivo": "..."}.

{id} é o agendamento_id ou o id do compromisso (ag:...). A chave só cancela e remarca o que ela mesma marcou; o resto responde 404.

Horário livre

{ "data": "2026-11-20", "hora": "09:20",
  "inicio": "2026-11-20T09:20:00-03:00", "fim": "2026-11-20T09:40:00-03:00",
  "duracao_minutos": 20,          // o bloco da agenda
  "duracao_referencia": 40,       // quanto os procedimentos somam com este profissional
  "profissional_id": "…" }

Marcar

curl -X POST https://api.quatrouno.com.br/v1/agendamentos \
  -H "Authorization: Bearer qu_live_..." \
  -H "Idempotency-Key: 6f1c2d4e-…" \
  -H "Content-Type: application/json" \
  -d '{
    "paciente": { "nome": "Maria da Silva", "telefone": "21987654321", "nascimento": "1980-01-31" },
    "profissional_id": "…", "procedimento_ids": ["…"],
    "data": "2026-11-20", "hora": "09:20"
  }'

Se a assinatura da clínica estiver com pagamento atrasado há mais de 7 dias, marcar e remarcar respondem 403 acesso_suspenso; ler e cancelar continuam.

Compromisso

{
  "id": "ag:5b1c...",            // ag:, dia:, exc: ou blc:<id>:<AAAAMMDD>
  "tipo": "consulta",            // consulta, exame, dia_cirurgico, bloqueio
  "modulo": "trilio",
  "origem": "interna",           // interna, diagy, api, google_calendar, ics, sistema_externo
  "somente_leitura": false,      // verdadeiro quando veio de outro sistema
  "inicio": "2026-11-10T12:00:00+00:00",
  "fim": "2026-11-10T12:20:00+00:00",
  "dia_inteiro": false,
  "profissional_id": "…", "recurso_tecnico_id": null, "local_id": null, "local_nome": null,
  "status": "booked",            // pending, booked, fulfilled, noshow
  "paciente_nome": "J.S.",       // conforme o nível da chave
  "servico": "Retorno",
  "observacao": null,
  "itens": null,                 // no dia cirúrgico, as cirurgias do dia
  "atualizado_em": "2026-11-07T18:31:02+00:00"
}

O que sai do paciente depende do nível escolhido pela clínica para a chave: só ocupado (sem paciente e sem serviço), tipo (sem paciente), iniciais ou nome completo (com paciente_id). Prontuário nunca sai.

Webhooks

A clínica cadastra uma URL https e recebe um POST quando um compromisso é criado, alterado ou cancelado.

POST https://seu-sistema/webhook
X-Event-Id: ev_123
X-Timestamp: 1762540000
X-Signature: <hex de HMAC-SHA256(segredo, X-Timestamp + "." + corpo)>

{
  "eventId": "ev_123",
  "eventType": "compromisso.alterado",
  "eventVersion": 1,
  "clinicId": "…",
  "versao": 123,
  "occurredAt": "2026-11-07T18:31:02+00:00",
  "payload": { "ref": "ag:5b1c...", "compromissos": [ { …estado atual… } ] }
}
// Node: conferir a assinatura
import crypto from "node:crypto";
const esperada = crypto.createHmac("sha256", segredo).update(`${timestamp}.${corpoCru}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(assinatura));

Erros

Sempre {"erro": {"codigo", "mensagem"}}, com a mensagem em português.

StatusCódigo
400parametro_invalido, periodo_invalido, idempotencia_ausente
401chave_ausente, chave_invalida, chave_revogada
402plano
403escopo_insuficiente, acesso_suspenso
404nao_encontrado
405metodo_nao_permitido
409horario_ocupado, aparelho_ocupado, profissional_de_folga, clinica_fechada, agendamento_encerrado, limite_agendas, idempotencia_conflito
422parametro_invalido (campo do corpo), paciente_invalido, profissional_invalido, procedimento_invalido, convenio_invalido, horario_passado, fora_da_grade, aparelho_inexistente
429limite (com Retry-After)
500erro_interno