Profissionais

Gerencie os profissionais que prestam serviços na sua clínica ou estabelecimento. Profissionais são entidades independentes de agentes NooviChat — podem existir sem acesso ao sistema.

Licença e permissão

Profissionais é uma funcionalidade nativa disponível em todos os planos. Qualquer membro da conta pode consultar os campos necessários ao agendamento; criar, atualizar, remover e consultar dados de gestão exige administrador ou a permissão appointment_manage.

Autenticação e erros de acesso

Os exemplos usam um api_access_token pertencente a um usuário. O backend também aceita uma sessão ou cabeçalhos Devise válidos do usuário; tokens de AgentBot não autorizam estas rotas. Credencial inválida retorna 401. Conta inexistente, suspensa, malformada ou inacessível ao usuário retorna o mesmo 404 genérico, sem revelar se o ID pertence a outro tenant. Nas mutações, falta de permissão retorna 403.

Envelopes de erro

Erros comuns de autenticação, recurso e parâmetro usam error. Validações do profissional usam errors. O corpo de 403 indica falta de permissão.

{ "error": "mensagem" }

Visão Geral

Cada profissional tem horários de atendimento configurados por dia da semana, buffer entre consultas, cor para o calendário e especialidade.

Campo opcional agent_id vincula o profissional a um usuário NooviChat quando ele também opera o sistema diretamente. Em dados legados, um vínculo que não pertence mais à conta é protegido na leitura e aparece como null para quem possui acesso de gestão.

Resposta conforme a permissão

Todo membro recebe somente os campos operacionais de agendamento: id, account_id, name, specialty, color, buffer_minutes, working_hours, active, service_ids e avatar_url. Administradores e usuários com appointment_manage também recebem registro, contato, atributos internos, auditoria, timestamps e agent_id.

Envelope do body

Em POST e PATCH, envie os atributos dentro do objeto professional. A API ainda aceita os mesmos atributos no nível raiz por compatibilidade com clientes legados, mas o envelope aninhado é o contrato recomendado.

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

Lista todos os profissionais ativos da conta (não-descartados), ordenados por nome. Qualquer membro da conta pode visualizar.

Sem filtros nem paginação

Esta listagem retorna sempre todos os profissionais ativos da conta — não aceita parâmetros de query de filtro ou paginação.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/professionals" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Lista de profissionais
json
{
  "data": [
    {
      "id": 3,
      "account_id": 1,
      "name": "Dr. Maria Santos",
      "specialty": "Odontologia Geral",
      "color": "#3B82F6",
      "buffer_minutes": 10,
      "working_hours": {
        "mon": [{ "start": "08:00", "end": "18:00" }],
        "tue": [{ "start": "08:00", "end": "18:00" }],
        "fri": [{ "start": "08:00", "end": "13:00" }]
      },
      "active": true,
      "service_ids": [7],
      "avatar_url": null
    }
  ]
}
401Token ou sessão ausente ou inválida.
404Conta inexistente, suspensa, malformada ou inacessível; o corpo é sempre genérico.
POST/api/v1/accounts/{account_id}/professionals

Cria novo profissional. Exige administrador ou a permissão appointment_manage.

Body (professional)

NomeTipoObrigatorioDescricao
namestringSimNome completo do profissional
specialtystring | nullNaoEspecialidade (Odontologia, Fisioterapia etc.)
registrystring | nullNaoNúmero do registro profissional (CRM, CRO, CRP etc.)
emailstring | nullNaoEmail do profissional
phonestring | nullNaoTelefone do profissional
colorstring | nullNaoValor de cor usado no calendário (padrão #3B82F6)
buffer_minutesintegerNaoBuffer em minutos entre consultas, de 0 a 2147483647 (padrão 0)
working_hoursobjectNaoHorários por mon, tue, wed, thu, fri, sat ou sun; cada dia recebe um array de janelas start/end em HH:MM
custom_attributesobjectNaoMetadados livres associados ao profissional
agent_idinteger (int64) | nullNaoID de um usuário que seja membro desta mesma conta; null deixa/remove o vínculo
activebooleanNaoStatus ativo (padrão true)
service_idsarray[integer (int64)]NaoLista completa de IDs de serviços desta conta. Envie dentro de professional; o nível raiz segue aceito por compatibilidade.
avatarstring | file | nullNaoID assinado de blob no JSON ou arquivo no multipart/form-data

Vínculos são validados pela conta

agent_id e todos os itens de service_ids precisam pertencer à conta autenticada. Um ID de outra conta, malformado ou fora do intervalo suportado rejeita a requisição inteira com 422; a API não remove nem filtra IDs silenciosamente.

Semântica de service_ids

Enviar service_ids: [] define a lista como vazia. Omitir o campo cria um profissional sem serviços no POST e preserva os vínculos atuais no PATCH. null, itens nulos/vazios ou valores aninhados retornam 422 sem mutação parcial.

Em multipart/form-data, use o valor literal professional[service_ids]=[] para limpar todos. Para atribuir IDs, repita professional[service_ids][]=ID para cada serviço.

Contrato de working_hours

As chaves aceitas são mon, tue, wed, thu, fri, sat e sun. Cada janela deve ter start e end com hora zero-padded entre 00:00 e 23:59, e start deve ser anterior a end. Janelas adjacentes são aceitas; sobrepostas ou duplicadas, container nulo e dias desconhecidos retornam 422.

O objeto vazio {} é válido: a listagem de disponibilidade não gera slots, enquanto uma criação direta não recebe restrição de horário de trabalho. Dados legados malformados falham fechados e não disponibilizam horários.

Avatar

No JSON, avatar recebe um ID assinado válido do Active Storage. Em multipart/form-data, pode receber o arquivo diretamente. São aceitas imagens PNG, JPEG/JPG, GIF e WEBP de até 5 MB. ID assinado ou arquivo inválido retorna 422; em uma atualização, null ou string vazia remove o avatar.

curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/professionals" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "professional": {
      "name": "Dr. Maria Santos",
      "specialty": "Odontologia Geral",
      "registry": "CRO-SP 12345",
      "color": "#3B82F6",
      "buffer_minutes": 10,
      "agent_id": 12,
      "service_ids": [7],
      "working_hours": {
        "mon": [{"start": "08:00", "end": "18:00"}],
        "tue": [{"start": "08:00", "end": "18:00"}],
        "fri": [{"start": "08:00", "end": "13:00"}]
      }
    }
  }'
201Profissional criado
json
{
  "data": {
    "id": 3,
    "account_id": 1,
    "name": "Dr. Maria Santos",
    "specialty": "Odontologia Geral",
    "registry": "CRO-SP 12345",
    "email": "maria@example.com",
    "phone": "+5511999990000",
    "color": "#3B82F6",
    "buffer_minutes": 10,
    "working_hours": {
      "mon": [{ "start": "08:00", "end": "18:00" }],
      "tue": [{ "start": "08:00", "end": "18:00" }],
      "fri": [{ "start": "08:00", "end": "13:00" }]
    },
    "active": true,
    "custom_attributes": {},
    "discarded_at": null,
    "discarded_by_id": null,
    "discard_reason": null,
    "created_at": "2027-07-21T12:00:00.000Z",
    "updated_at": "2027-07-21T12:00:00.000Z",
    "agent_id": 12,
    "service_ids": [7],
    "avatar_url": null
  }
}
401Token ou sessão ausente ou inválida.
403Usuário sem permissão de gerenciamento.
422Parâmetro inválido retorna { error: string }; falha de validação do recurso retorna { errors: { campo: string[] } }.
404Conta inexistente, suspensa, malformada ou inacessível; o corpo é sempre genérico.
GET/api/v1/accounts/{account_id}/professionals/{professional_id}

Retorna detalhes de um profissional específico.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/professionals/3" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Projeção de agendamento; usuários com permissão de gestão recebem também os campos privados descritos acima.
json
{
  "data": {
    "id": 3,
    "account_id": 1,
    "name": "Dr. Maria Santos",
    "specialty": "Odontologia Geral",
    "color": "#3B82F6",
    "buffer_minutes": 10,
    "working_hours": {
      "mon": [{ "start": "08:00", "end": "18:00" }],
      "tue": [{ "start": "08:00", "end": "18:00" }],
      "fri": [{ "start": "08:00", "end": "13:00" }]
    },
    "active": true,
    "service_ids": [7],
    "avatar_url": null
  }
}
401Token ou sessão ausente ou inválida.
404Conta inexistente, suspensa, malformada ou inacessível, ou profissional não encontrado.
PATCH/api/v1/accounts/{account_id}/professionals/{professional_id}

Atualiza dados do profissional. Exige administrador ou a permissão appointment_manage.

bash
curl -X PATCH "https://chat.seudominio.com/api/v1/accounts/1/professionals/3" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "professional": { "buffer_minutes": 15, "service_ids": [] } }'

Campos omitidos são preservados

O PATCH altera apenas os atributos enviados. Para os vínculos, agent_id: null remove o agente; service_ids: [] remove todos os serviços; omitir service_ids mantém os serviços atuais. Enviar service_ids: null retorna 422 sem alterar o profissional.

200Profissional atualizado; o corpo retorna o recurso completo em data.
json
{
  "data": {
    "id": 3,
    "account_id": 1,
    "name": "Dr. Maria Santos",
    "specialty": "Odontologia Geral",
    "registry": "CRO-SP 12345",
    "email": "maria@example.com",
    "phone": "+5511999990000",
    "color": "#3B82F6",
    "buffer_minutes": 15,
    "working_hours": {
      "mon": [{ "start": "08:00", "end": "18:00" }],
      "tue": [{ "start": "08:00", "end": "18:00" }],
      "fri": [{ "start": "08:00", "end": "13:00" }]
    },
    "active": true,
    "custom_attributes": {},
    "discarded_at": null,
    "discarded_by_id": null,
    "discard_reason": null,
    "created_at": "2027-07-21T12:00:00.000Z",
    "updated_at": "2027-07-21T12:00:00.000Z",
    "agent_id": 12,
    "service_ids": [],
    "avatar_url": null
  }
}
401Token ou sessão ausente ou inválida.
403Usuário sem permissão de gerenciamento.
422Nenhuma alteração é aplicada. Parâmetro inválido retorna { error: string }; validação do recurso retorna { errors: { campo: string[] } }.
404Conta ou profissional não encontrado.
DELETE/api/v1/accounts/{account_id}/professionals/{professional_id}

Remove o profissional por soft-delete. Exige administrador ou appointment_manage; o histórico de atendimentos é preservado.

bash
curl -X DELETE "https://chat.seudominio.com/api/v1/accounts/1/professionals/3" \
  -H "api_access_token: YOUR_TOKEN"
204Profissional removido; a resposta não possui corpo.

Efeito do soft-delete

O registro deixa de aparecer na listagem e novas consultas diretas por seu ID retornam 404. Atendimentos históricos preservam professional_id e a projeção compacta do profissional arquivado.

401Token ou sessão ausente ou inválida.
403Usuário sem permissão de gerenciamento.
404Conta ou profissional não encontrado.
GET/api/v1/accounts/{account_id}/professionals/{professional_id}/availability

Retorna slots livres do profissional. A data é opcional e usa o fuso de agendamento da conta.

Parâmetros de Query

NomeTipoObrigatorioDescricao
date(query)string (date)NaoData estrita em YYYY-MM-DD. Padrão: hoje no fuso de agendamento da conta.
service_id(query)integer (int64)NaoServiço desta conta oferecido pelo profissional; usa o override de duração da oferta quando configurado
duration_minutes(query)integer (int32)NaoDuração entre 1 e 2147483647 quando service_id não for informado (padrão 60). Com service_id, ainda é validado, mas a duração efetiva prevalece

Data e fuso horário

Quando date é omitido, a API usa a data atual no fuso de agendamento da conta: primeiro reporting_timezone, depois o fuso salvo no onboarding e, sem uma configuração válida, America/Sao_Paulo. Os timestamps de slots carregam o offset desse fuso.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/professionals/3/availability?date=2027-08-03&service_id=7" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Slots disponíveis (array de timestamps de início ISO 8601)
json
{
  "data": {
    "date": "2027-08-03",
    "professional_id": 3,
    "slots": [
      "2027-08-03T08:00:00-03:00",
      "2027-08-03T08:15:00-03:00",
      "2027-08-03T08:30:00-03:00"
    ]
  }
}

Apenas slots livres

A resposta lista somente os horários de início disponíveis. Horários ocupados são omitidos — não há campo available nem objetos com start/end. A grade avança em intervalos de 15 minutos e, para a data atual, horários que já passaram no fuso da conta são removidos. A duração, o buffer_minutes e os compromissos existentes também participam do cálculo.

Com service_id, a duração efetiva é override_duration_minutes da oferta, quando configurado, ou a duração base do serviço.

401Token ou sessão ausente ou inválida.
404Conta inexistente, suspensa, malformada ou inacessível; profissional não encontrado; ou service_id não oferecido por ele nesta conta.
422date, service_id ou duration_minutes malformado ou fora do intervalo suportado.