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.

GET/api/v1/accounts/{account_id}/appointments

Retorna lista paginada de atendimentos com filtros opcionais por data, profissional, status e contato.

Parametros de Query

NomeTipoObrigatorioDescricao
from(query)string (date-time)NaoInicio do intervalo (ISO 8601 UTC). Ex: 2026-06-01T00:00:00Z
to(query)string (date-time)NaoFim do intervalo (ISO 8601 UTC)
professional_id(query)integerNaoFiltrar por profissional
service_id(query)integerNaoFiltrar por servico
status(query)stringNaoscheduled | confirmed | completed | cancelled | no_show
contact_id(query)integerNaoFiltrar por contato
pipeline_card_id(query)integerNaoFiltrar atendimentos vinculados a um card especifico do Pipeline Pro (Feature C)
page(query)integerNaoPagina (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 .
200Lista de atendimentos paginada
json
{
  "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
  }
}
POST/api/v1/accounts/{account_id}/appointments

Cria novo atendimento e materializa lembretes automaticos a partir dos templates do servico.

Body (appointment)

NomeTipoObrigatorioDescricao
contact_idintegerSimID do contato (paciente/cliente)
professional_idintegerSimID do profissional
service_idintegerSimID do servico
scheduled_atstring (date-time)SimData/hora de inicio (ISO 8601 UTC)
partner_idintegerNaoID do convenio/plano de saude
ends_atstring (date-time)NaoData/hora de fim. Se omitido, calculado automaticamente.
notesstringNaoObservacoes do atendimento
conversation_display_idintegerNaoVincular a conversa existente (display_id da conta)
price_centsintegerNaoOverride do preco do servico em centavos
create_pipeline_cardbooleanNaoCriar 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"
    }
  }'
201Atendimento criado com lembretes materializados
json
{
  "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."
      }
    ]
  }
}
422Conflito de horario, erro de validacao ou data no passado (BACK-003)
json
// 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"]
  }
}
GET/api/v1/accounts/{account_id}/appointments/{appointment_id}

Retorna detalhes completos de um atendimento especifico, incluindo lembretes.

Parametros de Path

NomeTipoObrigatorioDescricao
account_id(path)integerSimID da conta
appointment_id(path)integerSimID do atendimento
bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/appointments/42" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Detalhes completos do atendimento
json
{
  "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" }
    ]
  }
}
PATCH/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)

NomeTipoObrigatorioDescricao
scheduled_atstring (date-time)NaoReagendar — dispara webhook appointment.rescheduled
professional_idintegerNaoTrocar profissional
partner_idintegerNaoTrocar convenio
notesstringNaoAtualizar observacoes
price_centsintegerNaoAjustar preco
bash
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" } }'
DELETE/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)

NomeTipoObrigatorioDescricao
cancellation_reasonstringNaoMotivo do cancelamento
bash
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" }'
POST/api/v1/accounts/{account_id}/appointments/{appointment_id}/confirm

Confirma o atendimento (scheduled → confirmed). Dispara webhook appointment.confirmed.

bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/42/confirm" \
  -H "api_access_token: YOUR_TOKEN"
200Atendimento confirmado
json
{ "data": { "id": 42, "status": "confirmed" } }
POST/api/v1/accounts/{account_id}/appointments/{appointment_id}/complete

Marca o atendimento como concluido. Dispara webhook appointment.completed.

bash
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." }'
POST/api/v1/accounts/{account_id}/appointments/{appointment_id}/no_show

Registra no-show (paciente nao compareceu). Dispara webhook appointment.no_show.

bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/appointments/42/no_show" \
  -H "api_access_token: YOUR_TOKEN"
GET/api/v1/accounts/{account_id}/appointments/availability

Retorna slots disponiveis para um profissional em uma data, considerando horario de trabalho, buffer e consultas existentes.

Parametros de Query

NomeTipoObrigatorioDescricao
date(query)string (date)SimData a verificar (YYYY-MM-DD)
professional_id(query)integerNaoFiltrar por profissional especifico
service_id(query)integerNaoServico para calcular duracao dos slots
bash
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 .
200Slots disponiveis
json
{
  "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 }
      ]
    }
  ]
}
GET/api/v1/accounts/{account_id}/appointments/metrics

Retorna 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

NomeTipoObrigatorioDescricao
from(query)string (date-time)NaoInicio do periodo (ISO 8601 UTC). Padrao: 30 dias atras. Deve ser uma data valida — invalido retorna 422.
to(query)string (date-time)NaoFim do periodo (ISO 8601 UTC). Padrao: hoje. Deve ser uma data valida — invalido retorna 422.
bash
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 .
200Metricas agregadas do periodo
json
{
  "data": {
    "total": 142,
    "completed": 87,
    "cancelled": 12,
    "no_show": 8,
    "confirmed": 35,
    "revenue_cents": 2180000,
    "currency": "BRL"
  }
}
422String de data invalida (BACK-002)
json
{ "error": "argument out of range" }
POST/api/v1/accounts/{account_id}/appointments/bulk_action

Aplica uma acao de status a multiplos atendimentos simultaneamente. Apenas administradores.

Body

NomeTipoObrigatorioDescricao
idsarray[integer]SimIDs dos atendimentos
actionstringSimconfirm | cancel | no_show | complete
cancellation_reasonstringNaoObrigatorio se action=cancel
bash
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" }'
200Resultado da acao em massa
json
{
  "succeeded": [42, 43],
  "failed": [
    { "id": 44, "error": "Cannot confirm a cancelled appointment" }
  ]
}
GET/api/v1/accounts/{account_id}/appointments/export

Exporta atendimentos em formato CSV com resumo financeiro. Apenas administradores.

Parametros de Query

NomeTipoObrigatorioDescricao
from(query)string (date-time)SimInicio do intervalo
to(query)string (date-time)SimFim do intervalo
professional_id(query)integerNaoFiltrar por profissional
status(query)stringNaoFiltrar por status
bash
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.csv
200Arquivo CSV (text/csv)
json
id,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,BRL

Transicoes 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:

{{"errors":{"status":["cannot transition from X to Y"]}}}
Status atualPode transicionar para
scheduledconfirmed, cancelled, no_show, completed
confirmedcompleted, 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 auditadoDescricao
statusToda transicao de status e registrada com timestamp e user_id
scheduled_atReagendamentos — valor anterior e novo
ends_atAlteracao de horario de fim
notesEdicoes nas observacoes
price_centsAjustes de preco
cancellation_reasonMotivo de cancelamento
cancelled_by_idQuem cancelou (user ID)
pipeline_card_idVinculacao/desvinculacao de card Pipeline Pro

O historico de auditoria pode ser consultado internamente via Rails console:

ruby
# 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).