Atendimentos
API completa de agendamento integrada ao chat. Gerencie profissionais, servicos, lembretes automaticos e agenda multi-canal.
Feature Flag
Este modulo requer a feature appointments_module habilitada na conta. Disponivel em todos os planos pagos.
Base URL
Todos os endpoints usam o prefixo /api/v1/accounts/{account_id}
Visao Geral
O modulo de Atendimentos expoe a mesma logica de negocio em 4 canais de consumo:
- Dashboard NooviChat — operadores criam e gerenciam atendimentos pelo chat
- n8n workflows — automacao server-to-server via
api_access_token - Widget publico — clientes agendam online via iframe (requer
appointments_public_widget) - Captain AI — bot 24/7 agenda conversacionalmente (requer
appointments_captain_booking)
Ao criar um atendimento, lembretes automaticos sao materializados com base nos templates configurados no servico. Os lembretes sao enviados via WhatsApp no tempo certo.
/api/v1/accounts/{account_id}/appointmentsRetorna lista paginada de atendimentos com filtros opcionais por data, profissional, status e contato.
Parametros de Query
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
from(query) | string (date-time) | Nao | Inicio do intervalo (ISO 8601 UTC). Ex: 2026-06-01T00:00:00Z |
to(query) | string (date-time) | Nao | Fim do intervalo (ISO 8601 UTC) |
professional_id(query) | integer | Nao | Filtrar por profissional |
service_id(query) | integer | Nao | Filtrar por servico |
status(query) | string | Nao | scheduled | confirmed | completed | cancelled | no_show |
contact_id(query) | integer | Nao | Filtrar por contato |
pipeline_card_id(query) | integer | Nao | Filtrar atendimentos vinculados a um card especifico do Pipeline Pro (Feature C) |
page(query) | integer | Nao | Pagina (padrao 1) — 50 registros por pagina (fixo, BACK-011) |
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments?from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z&status=scheduled" \
-H "api_access_token: YOUR_TOKEN" | jq .{
"data": [
{
"id": 42,
"public_id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": 101,
"contact": { "id": 101, "name": "Maria Silva" },
"professional_id": 3,
"professional": { "id": 3, "name": "Dr. Santos" },
"service_id": 7,
"service": { "id": 7, "name": "Limpeza Dental", "duration_minutes": 60 },
"scheduled_at": "2026-06-15T10:00:00Z",
"ends_at": "2026-06-15T11:00:00Z",
"status": "scheduled",
"price_cents": 20000,
"currency": "BRL",
"created_at": "2026-06-01T09:30:00Z"
}
],
"meta": {
"total_count": 38,
"page": 1
}
}/api/v1/accounts/{account_id}/appointmentsCria novo atendimento e materializa lembretes automaticos a partir dos templates do servico.
Body (appointment)
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
contact_id | integer | Sim | ID do contato (paciente/cliente) |
professional_id | integer | Sim | ID do profissional |
service_id | integer | Sim | ID do servico |
scheduled_at | string (date-time) | Sim | Data/hora de inicio (ISO 8601 UTC) |
partner_id | integer | Nao | ID do convenio/plano de saude |
ends_at | string (date-time) | Nao | Data/hora de fim. Se omitido, calculado automaticamente. |
notes | string | Nao | Observacoes do atendimento |
conversation_display_id | integer | Nao | Vincular a conversa existente (display_id da conta) |
price_cents | integer | Nao | Override do preco do servico em centavos |
create_pipeline_card | boolean | Nao | Criar card no Pipeline Pro (default false) |
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments" \
-H "api_access_token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"appointment": {
"contact_id": 101,
"professional_id": 3,
"service_id": 7,
"scheduled_at": "2026-06-15T10:00:00Z",
"notes": "Primeira consulta"
}
}'{
"data": {
"id": 42,
"public_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "scheduled",
"scheduled_at": "2026-06-15T10:00:00Z",
"ends_at": "2026-06-15T11:00:00Z",
"price_cents": 20000,
"currency": "BRL",
"reminders": [
{
"id": 88,
"send_at": "2026-06-14T10:00:00Z",
"status": "pending",
"body": "Ola Maria, lembrando da sua Limpeza Dental amanha as 10:00."
}
]
}
}// Data no passado (BACK-003):
{
"errors": {
"scheduled_at": ["must be in the future"]
}
}
// Conflito de horario:
{
"errors": {
"slot": ["conflito de horario"]
}
}
// Conflito com atendimento existente:
{
"errors": {
"scheduled_at": ["conflicts with an existing appointment for this professional"]
}
}/api/v1/accounts/{account_id}/appointments/{appointment_id}Retorna detalhes completos de um atendimento especifico, incluindo lembretes.
Parametros de Path
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
account_id(path) | integer | Sim | ID da conta |
appointment_id(path) | integer | Sim | ID do atendimento |
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments/42" \
-H "api_access_token: YOUR_TOKEN" | jq .{
"data": {
"id": 42,
"public_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "confirmed",
"contact": { "id": 101, "name": "Maria Silva", "phone_number": "+5511999990000" },
"professional": { "id": 3, "name": "Dr. Santos", "specialty": "Odontologia" },
"service": { "id": 7, "name": "Limpeza Dental", "duration_minutes": 60 },
"scheduled_at": "2026-06-15T10:00:00Z",
"ends_at": "2026-06-15T11:00:00Z",
"price_cents": 20000,
"currency": "BRL",
"reminders": [
{ "id": 88, "status": "sent", "sent_at": "2026-06-14T10:00:00Z" }
]
}
}/api/v1/accounts/{account_id}/appointments/{appointment_id}Atualiza campos do atendimento. Para mudar status use os endpoints de acao (confirm, complete, no_show).
Body (appointment)
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
scheduled_at | string (date-time) | Nao | Reagendar — dispara webhook appointment.rescheduled |
professional_id | integer | Nao | Trocar profissional |
partner_id | integer | Nao | Trocar convenio |
notes | string | Nao | Atualizar observacoes |
price_cents | integer | Nao | Ajustar preco |
curl -X PATCH "https://chat.seudominio.com/api/v1/accounts/1/appointments/42" \
-H "api_access_token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "appointment": { "scheduled_at": "2026-06-16T14:00:00Z", "notes": "Reagendado a pedido da paciente" } }'/api/v1/accounts/{account_id}/appointments/{appointment_id}Cancela o atendimento (soft-delete — status muda para cancelled). O registro e preservado para historico.
Body (opcional)
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
cancellation_reason | string | Nao | Motivo do cancelamento |
curl -X DELETE "https://chat.seudominio.com/api/v1/accounts/1/appointments/42" \
-H "api_access_token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "cancellation_reason": "Paciente solicitou via WhatsApp" }'/api/v1/accounts/{account_id}/appointments/{appointment_id}/confirmConfirma o atendimento (scheduled → confirmed). Dispara webhook appointment.confirmed.
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/42/confirm" \
-H "api_access_token: YOUR_TOKEN"{ "data": { "id": 42, "status": "confirmed" } }/api/v1/accounts/{account_id}/appointments/{appointment_id}/completeMarca o atendimento como concluido. Dispara webhook appointment.completed.
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/42/complete" \
-H "api_access_token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "notes": "Limpeza realizada com sucesso." }'/api/v1/accounts/{account_id}/appointments/{appointment_id}/no_showRegistra no-show (paciente nao compareceu). Dispara webhook appointment.no_show.
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/42/no_show" \
-H "api_access_token: YOUR_TOKEN"/api/v1/accounts/{account_id}/appointments/availabilityRetorna slots disponiveis para um profissional em uma data, considerando horario de trabalho, buffer e consultas existentes.
Parametros de Query
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
date(query) | string (date) | Sim | Data a verificar (YYYY-MM-DD) |
professional_id(query) | integer | Nao | Filtrar por profissional especifico |
service_id(query) | integer | Nao | Servico para calcular duracao dos slots |
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments/availability?date=2026-06-15&professional_id=3&service_id=7" \
-H "api_access_token: YOUR_TOKEN" | jq .{
"data": [
{
"professional_id": 3,
"professional_name": "Dr. Santos",
"slots": [
{ "start": "2026-06-15T08:00:00Z", "end": "2026-06-15T09:00:00Z", "available": true },
{ "start": "2026-06-15T09:00:00Z", "end": "2026-06-15T10:00:00Z", "available": false },
{ "start": "2026-06-15T10:00:00Z", "end": "2026-06-15T11:00:00Z", "available": true }
]
}
]
}/api/v1/accounts/{account_id}/appointments/metricsRetorna metricas agregadas de atendimentos para um intervalo de datas. Usado pela aba Relatorios no dashboard.
BACK-002 — Validacao de data
Passar uma string de data invalida (ex: from=invalid) agora retorna 422 em vez de 200 com dados vazios.
Parametros de Query
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
from(query) | string (date-time) | Nao | Inicio do periodo (ISO 8601 UTC). Padrao: 30 dias atras. Deve ser uma data valida — invalido retorna 422. |
to(query) | string (date-time) | Nao | Fim do periodo (ISO 8601 UTC). Padrao: hoje. Deve ser uma data valida — invalido retorna 422. |
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments/metrics?from=2026-04-01T00:00:00Z&to=2026-04-30T23:59:59Z" \
-H "api_access_token: YOUR_TOKEN" | jq .{
"data": {
"total": 142,
"completed": 87,
"cancelled": 12,
"no_show": 8,
"confirmed": 35,
"revenue_cents": 2180000,
"currency": "BRL"
}
}{ "error": "argument out of range" }/api/v1/accounts/{account_id}/appointments/bulk_actionAplica uma acao de status a multiplos atendimentos simultaneamente. Apenas administradores.
Body
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
ids | array[integer] | Sim | IDs dos atendimentos |
action | string | Sim | confirm | cancel | no_show | complete |
cancellation_reason | string | Nao | Obrigatorio se action=cancel |
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/bulk_action" \
-H "api_access_token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ids": [42, 43, 44], "action": "confirm" }'{
"succeeded": [42, 43],
"failed": [
{ "id": 44, "error": "Cannot confirm a cancelled appointment" }
]
}/api/v1/accounts/{account_id}/appointments/exportExporta atendimentos em formato CSV com resumo financeiro. Apenas administradores.
Parametros de Query
| Nome | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
from(query) | string (date-time) | Sim | Inicio do intervalo |
to(query) | string (date-time) | Sim | Fim do intervalo |
professional_id(query) | integer | Nao | Filtrar por profissional |
status(query) | string | Nao | Filtrar por status |
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments/export?from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z" \
-H "api_access_token: YOUR_TOKEN" -o atendimentos.csvid,contact_name,contact_phone,professional_name,service_name,scheduled_at,ends_at,status,price_cents,currency
42,Maria Silva,+5511999990000,Dr. Santos,Limpeza Dental,2026-06-15T10:00:00Z,2026-06-15T11:00:00Z,completed,20000,BRLTransicoes de Status (BACK-010)
O modelo Appointment implementa um guard de transicao de status. Apenas as transicoes listadas abaixo sao permitidas. Qualquer outra tentativa retorna 422 com:
| Status atual | Pode transicionar para |
|---|---|
scheduled | confirmed, cancelled, no_show, completed |
confirmed | completed, cancelled, no_show |
completed | — (terminal) |
cancelled | — (terminal) |
no_show | — (terminal) |
Endpoints de acao
Use os endpoints dedicados /confirm, /complete, /no_show para transicionar status. O endpoint PATCH so atualiza campos de dados (scheduled_at, notes, partner_id, custom_attributes).
Auditoria de Mudancas (Feature E)
O modelo Appointment utiliza a gem Audited para registrar automaticamente todas as mudancas nos campos criticos.
| Campo auditado | Descricao |
|---|---|
status | Toda transicao de status e registrada com timestamp e user_id |
scheduled_at | Reagendamentos — valor anterior e novo |
ends_at | Alteracao de horario de fim |
notes | Edicoes nas observacoes |
price_cents | Ajustes de preco |
cancellation_reason | Motivo de cancelamento |
cancelled_by_id | Quem cancelou (user ID) |
pipeline_card_id | Vinculacao/desvinculacao de card Pipeline Pro |
O historico de auditoria pode ser consultado internamente via Rails console:
# Listar todas as mudancas de um atendimento
appt = Appointment.find(42)
appt.audits.order(:created_at).each do |audit|
puts "#{audit.created_at} — #{audit.user_id} — #{audit.audited_changes}"
end
# Filtrar apenas mudancas de status
appt.audits.select { |a| a.audited_changes.key?('status') }API de auditoria
Nao existe endpoint REST publico para consultar audits de atendimentos nesta versao. O log esta disponivel apenas via Rails console ou integracao direta com o banco de dados (tabela audits).