Chamados
Realm interno (operadores do escritório) dos chamados de suporte abertos pelas empresas no Portal do Cliente. Por aqui o time lista e filtra a fila, conversa na thread (respostas públicas e notas internas), anexa arquivos, muda o status do chamado e registra a avaliação interna da empresa.
Superfície do cliente
Este router atende só o realm interno. A superfície do cliente é registrada separadamente, sob /portal/chamados, com o token do Portal (não com API Key nem JWT interno) e sem os escopos abaixo. Ela fica documentada na página Portal do Cliente. Os dois conjuntos de rotas leem os mesmos dados de propósito: uma rota única com os dois principals exigiria ramificar o corpo por tipo de usuário.
Base path
Todos os endpoints abaixo são montados sob o prefixo:
/api/v1/chamadosA URL completa em produção é https://api.contabilidadealcance.com.br/api/v1/chamados.
Escopos necessários
O router é montado com _SCOPE_DEP, que deriva o escopo do primeiro segmento após /api/v1/ e do método HTTP (GET = read; POST/PUT/DELETE = write). O mesmo _SCOPE_DEP aplica o gate de senha provisória: um JWT de usuário cuja senha vigente foi definida por outra pessoa recebe 403 até o titular definir uma senha própria (o gate não se aplica a API Key).
| Escopo | Operações permitidas |
|---|---|
chamados:read | GET /, GET /cliente/{id_cliente}, GET /resumo, GET /nao-lidas, GET /avaliacao-interna/resumo, GET /{chamado_id}, GET /{chamado_id}/avaliacao, GET /{chamado_id}/avaliacao-interna, GET /{chamado_id}/mensagens, GET /mensagens/{mensagem_id}, GET /anexos/{anexo_id}, GET /{chamado_id}/anexos |
chamados:write | POST /, PUT /{chamado_id}, DELETE /{chamado_id}, POST /{chamado_id}/leitura, POST /{chamado_id}/avaliacao-interna, POST /{chamado_id}/mensagens, PUT /mensagens/{mensagem_id}, DELETE /mensagens/{mensagem_id}, DELETE /anexos/{anexo_id}, POST /{chamado_id}/anexos |
Além do escopo, algumas rotas têm guard próprio:
| Rota | Guard adicional |
|---|---|
DELETE /chamados/{chamado_id} | Perfil administrador ou diretoria (require_perfil). Demais perfis recebem 403. |
DELETE /chamados/anexos/{anexo_id} | Perfil administrador ou diretoria (require_perfil). |
DELETE /chamados/mensagens/{mensagem_id} | Por autoria: o operador apaga só as próprias mensagens; administrador/diretoria apagam qualquer uma. Sem perfil exigido na frente. |
POST /chamados/{chamado_id}/avaliacao-interna | Gestão (administrador, diretoria, gestor) avalia qualquer chamado; o responsável atual avalia se ainda não há nota ou se a nota é dele. |
Envelope de resposta
As rotas respondem com success_response: { "status": "success", "message": "...", "data": ... }. Erros de validação e de regra saem como HTTPException ({ "detail": ... }) com os status descritos em cada rota.
Status e tipos do chamado
O vocabulário vive em StatusChamado e TipoChamado. As colunas são varchar livres no banco; a restrição é aplicada na borda (schemas de escrita), de forma fail-closed: valor desconhecido vira 422.
| Status | Significado |
|---|---|
aberto | Chamado sem triagem - ninguém respondeu publicamente ainda. |
em_andamento | Atendimento em curso, incluindo a espera por retorno do cliente. |
concluido | Encerrado. Não aceita mensagens nem anexos novos até ser reaberto. |
Na escrita (PUT), o campo status aceita também as grafias em andamento e fechado (este vira concluido), com comparação sem acento e sem diferenciar maiúsculas. O status aguardando_cliente existiu até a v5.199.0 e foi removido.
| Tipo | Grafias aceitas na escrita |
|---|---|
problema | problema, bug, erro (default na criação) |
solicitacao | solicitacao |
duvida | duvida |
sugestao | sugestao |
Transições
- Automática: quando um operador posta mensagem com
visibilidade: "publica"em chamadoaberto, o chamado passa paraem_andamento. Nota interna e mensagem do cliente não movem o status. - Manual (
PUT /chamados/{chamado_id}): o código não impõe matriz de transição - qualquer valor do vocabulário pode ser enviado. O que muda é o efeito sobre o trio do fechamento (data_hora_fechamento,id_usuario_fechamento,motivo_fechamento):- entrando em
concluido: grava a data (horário de São Paulo), o usuário que fez a ação e o motivo (opcional); - saindo de
concluido(reabertura): limpa os três; - já
concluido, reenviandostatus: "concluido"commotivo_fechamento: reescreve só o motivo, sem mover a data; - demais casos: não toca no trio.
- entrando em
motivo_fechamentosemstatus: "concluido"no mesmo corpo é422.- O cliente também pode encerrar o chamado pela superfície do Portal; reabrir é sempre um
PUTinterno.
Endpoints
GET /chamados/
Lista os chamados, opcionalmente filtrados. Sem sort_by, ordena do mais recente para o mais antigo. Cada item vem enriquecido com nao_lidas e ultima_mensagem_em do operador logado (mensagens do cliente ainda não vistas por ele, só em chamados não concluídos e do escopo dele: responsável por ele, sem responsável ou com responsável de conta inativa).
A paginação é opt-in: sem page e per_page, data é um array de ChamadoRead (caminho legado, com limit/offset). Com os dois, data é o envelope PaginatedChamados e limit/offset são ignorados. Informar só um deles mantém o caminho legado. Lista vazia no caminho legado retorna 200 OK com data: [] e a mensagem "Nenhum chamado encontrado.".
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_cliente | int | query | não | Filtra por empresa. |
status | str | query | não | Filtra por status. Comparação exata: use o valor canônico (aberto, em_andamento, concluido). |
tipo | str | query | não | Filtra por tipo. Comparação exata: use o valor canônico. |
id_usuario_responsavel | int | query | não | Filtra por responsável. |
busca | str | query | não | Busca em titulo e detalhamento. Termo só de dígitos casa também o número do chamado. % e _ são literais. |
sort_by | str | query | não | data_hora_criacao, titulo, tipo ou status. Fora disso, 422. |
sort_dir | str | query | não | asc ou desc (default desc). |
page | int | query | não | Página (1-based, >= 1). Ativa a paginação junto de per_page. |
per_page | int | query | não | Itens por página (1 a 100). Ativa a paginação junto de page. |
limit | int | query | não | Caminho legado: 1 a 500 (default 100). |
offset | int | query | não | Caminho legado: >= 0 (default 0). |
Request
Sem corpo de requisição.
Response 200 OK (com page=1&per_page=20)
{
"status": "success",
"message": "Chamados recuperados com sucesso",
"data": {
"items": [
{
"id": 318,
"titulo": "Guia do DAS não aparece",
"detalhamento": "A guia de setembro não está disponível na área de documentos.",
"tipo": "problema",
"id_cliente": 1234,
"id_portal_user": 57,
"status": "em_andamento",
"id_usuario_responsavel": 42,
"id_usuario_fechamento": null,
"data_hora_criacao": "2026-10-14T09:12:00",
"data_hora_edicao": "2026-10-14T10:03:00",
"data_hora_fechamento": null,
"motivo_fechamento": null,
"nao_lidas": 1,
"ultima_mensagem_em": "2026-10-14T15:40:00"
}
],
"total": 1,
"total_pages": 1,
"current_page": 1,
"per_page": 20
}
}total reflete o conjunto já filtrado. Escopo: chamados:read
GET /chamados/cliente/{id_cliente}
Lista os chamados de uma empresa. Ordenação padrão (mais recente primeiro). Esta rota não calcula nao_lidas/ultima_mensagem_em, que vêm com o default (0 e null). Sem resultados, retorna 200 OK com data: [] e a mensagem "Nenhum chamado encontrado para esta empresa.".
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_cliente | int | path | sim | ID da empresa. |
status | str | query | não | Filtra por status (valor canônico). |
limit | int | query | não | 1 a 500 (default 100). |
offset | int | query | não | >= 0 (default 0). |
Request
Sem corpo de requisição.
Response 200 OK
Array de ChamadoRead em data, com a mensagem "Chamados recuperados com sucesso".
Escopo: chamados:read
GET /chamados/resumo
Contagem da fila por status, para a faixa de abas ("Todos / Aberto / Em andamento / Concluído"). Os filtros compõem com a listagem: o resumo conta exatamente o conjunto que GET /chamados/ pagina. Não aceita status de propósito - a faixa precisa do número de todas as abas o tempo todo; se enviado, é ignorado. Todos os status vêm com zero explícito, e total é a soma.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_cliente | int | query | não | Filtra por empresa. |
tipo | str | query | não | Filtra por tipo. |
id_usuario_responsavel | int | query | não | Filtra por responsável. |
busca | str | query | não | Mesma busca textual da listagem. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Resumo recuperado com sucesso",
"data": {
"aberto": 4,
"em_andamento": 7,
"concluido": 112,
"total": 123
}
}Escopo: chamados:read
GET /chamados/nao-lidas
Números do badge da fila para o operador logado. Conta só mensagens do cliente ainda não vistas por ele (nota interna e resposta de colega não contam), ignora chamados concluídos e considera só o escopo do operador (responsável por ele, sem responsável ou com responsável de conta inativa). chamados_com_novidade bate com a quantidade de linhas com nao_lidas > 0 em GET /chamados/ para o mesmo usuário.
Parâmetros
Este endpoint não recebe parâmetros. O operador é o usuário autenticado.
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Contagem recuperada com sucesso",
"data": {
"nao_lidas": 3,
"chamados_com_novidade": 2
}
}Escopo: chamados:read
GET /chamados/avaliacao-interna/resumo
Nota geral de uma empresa a partir das avaliações internas (o escritório avaliando a empresa). media tem uma casa decimal e é null quando não há avaliação.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_cliente | int | query | sim | Empresa avaliada. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Nota geral recuperada com sucesso",
"data": {
"media": 4.5,
"quantidade": 8
}
}Escopo: chamados:read
GET /chamados/{chamado_id}
Retorna um chamado pelo ID. Inexistente: 404 Not Found ("Chamado não encontrado.").
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Request
Sem corpo de requisição.
Response 200 OK
ChamadoRead em data, com a mensagem "Chamado recuperado com sucesso". Nesta rota nao_lidas e ultima_mensagem_em vêm com o default (0 e null).
Escopo: chamados:read
POST /chamados/
Abre um chamado pelo realm interno, em nome de uma empresa (id_cliente obrigatório; no Portal a empresa vem da sessão). O chamado nasce com status aberto.
Parâmetros
Sem parâmetros de rota ou query. Corpo ChamadoCreate.
Request
{
"id_cliente": 1234,
"titulo": "Envio do extrato de setembro",
"detalhamento": "Cliente pediu por telefone para registrar o envio do extrato bancário.",
"tipo": "solicitacao",
"id_usuario_responsavel": 42
}Response 201 Created
{
"status": "success",
"message": "Chamado criado com sucesso",
"data": {
"id": 319,
"titulo": "Envio do extrato de setembro",
"detalhamento": "Cliente pediu por telefone para registrar o envio do extrato bancário.",
"tipo": "solicitacao",
"id_cliente": 1234,
"id_portal_user": null,
"status": "aberto",
"id_usuario_responsavel": 42,
"id_usuario_fechamento": null,
"data_hora_criacao": "2026-10-15T08:30:00",
"data_hora_edicao": null,
"data_hora_fechamento": null,
"motivo_fechamento": null,
"nao_lidas": 0,
"ultima_mensagem_em": null
}
}id_cliente ou id_usuario_responsavel inexistente: 404 (mensagem com "não encontrado") ou 422 para os demais erros de valor. Campos fora do vocabulário ou fora dos limites: 422. Escopo: chamados:write
PUT /chamados/{chamado_id}
Atualiza um chamado, inclusive a transição de status (ver a seção "Transições" acima). Patch parcial: só os campos enviados mudam. Não aceita id_cliente nem id_portal_user - mover chamado de empresa não é permitido.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Corpo ChamadoUpdate.
Request
{
"status": "concluido",
"motivo_fechamento": "Guia reenviada por e-mail e disponibilizada no Portal."
}Response 200 OK
ChamadoRead atualizado em data, com a mensagem "Chamado atualizado com sucesso". Ao concluir, data_hora_fechamento e id_usuario_fechamento vêm preenchidos.
Inexistente: 404. id_usuario_responsavel inexistente: 404/422. motivo_fechamento sem status: "concluido": 422. Escopo: chamados:write
DELETE /chamados/{chamado_id}
Exclui o chamado e, em cascata, toda a thread (mensagens, anexos). Operação destrutiva e irreversível: o caminho normal para encerrar é PUT com status: "concluido", que preserva o histórico.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Chamado removido com sucesso",
"data": null
}Perfil sem permissão: 403. Inexistente: 404. Escopo: chamados:write + perfil administrador ou diretoria.
POST /chamados/{chamado_id}/leitura
Marca até onde o operador logado leu a thread. Sem corpo: o servidor grava a data da última mensagem existente no chamado (de qualquer autor e visibilidade), nunca o horário atual nem uma data enviada. Idempotente e monotônica - a marca nunca retrocede. ultima_mensagem_lida_em vem null quando o chamado ainda não tem mensagens.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Leitura registrada com sucesso",
"data": {
"ultima_mensagem_lida_em": "2026-10-14T15:40:00"
}
}Inexistente: 404. Escopo: chamados:write (é um POST, embora não altere o chamado).
GET /chamados/{chamado_id}/avaliacao
Avaliação que o cliente deu ao atendimento (gravada pelo Portal; aqui é só leitura). Chamado ainda não avaliado retorna 200 OK com data: null - ausência de registro, não recurso inexistente.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Avaliação recuperada com sucesso",
"data": {
"nota": 5,
"comentario": "Resolveram no mesmo dia.",
"data_hora_criacao": "2026-10-14T17:02:00",
"data_hora_edicao": null
}
}Chamado inexistente: 404. Escopo: chamados:read
GET /chamados/{chamado_id}/avaliacao-interna
Avaliação que o escritório deu à empresa neste chamado, ou data: null se ainda não houver. Não existe rota equivalente no Portal.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Avaliação interna recuperada com sucesso",
"data": {
"nota": 4,
"comentario": "Enviou a documentação completa após o primeiro pedido.",
"id_usuario": 42,
"data_hora_criacao": "2026-10-14T17:30:00",
"data_hora_edicao": null
}
}Chamado inexistente: 404. Escopo: chamados:read
POST /chamados/{chamado_id}/avaliacao-interna
Grava (upsert) a avaliação interna da empresa no chamado. A autoria vem do usuário logado. Só é aceita em chamado concluido.
Quem pode gravar:
- gestão (
administrador,diretoria,gestor): qualquer chamado; - responsável atual do chamado (inclusive
funcionario): se ainda não há nota ou se a nota existente é dele; - demais usuários: nunca.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Corpo ChamadoAvaliacaoInternaCreate (campos extras são rejeitados).
Request
{
"nota": 4,
"comentario": "Enviou a documentação completa após o primeiro pedido."
}Response 200 OK
ChamadoAvaliacaoInternaRead em data, com a mensagem "Avaliação interna registrada com sucesso".
Chamado inexistente: 404. Chamado não concluído: 409. Sem permissão: 403. Nota fora de 1 a 5 ou campo extra: 422. Escopo: chamados:write
GET /chamados/{chamado_id}/mensagens
Retorna a thread completa, em ordem cronológica. O realm interno enxerga também as notas internas (visibilidade: "interna"). Sem mensagens, retorna 200 OK com data: [] e a mensagem "Nenhuma mensagem encontrada.".
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
limit | int | query | não | 1 a 500 (default 100). |
offset | int | query | não | >= 0 (default 0). |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Mensagens recuperadas com sucesso",
"data": [
{
"id": 901,
"id_chamado": 318,
"autor_realm": "portal",
"id_portal_user": 57,
"id_usuario": null,
"texto": "A guia de setembro não aparece para mim.",
"visibilidade": "publica",
"data_hora_criacao": "2026-10-14T09:12:00",
"autor_nome": null,
"autor_foto_url": null
},
{
"id": 902,
"id_chamado": 318,
"autor_realm": "interno",
"id_portal_user": null,
"id_usuario": 42,
"texto": "Conferir se a guia foi gerada no lote de ontem.",
"visibilidade": "interna",
"data_hora_criacao": "2026-10-14T09:40:00",
"autor_nome": null,
"autor_foto_url": null
}
]
}Chamado inexistente: 404. Escopo: chamados:read
POST /chamados/{chamado_id}/mensagens
Posta uma mensagem na thread como operador (autor_realm: "interno", autoria do usuário logado). visibilidade tem default interna (fail-closed): para responder ao cliente é preciso enviar "publica" explicitamente. Resposta pública em chamado aberto move o chamado para em_andamento.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
Corpo ChamadoMensagemCreate.
Request
{
"texto": "A guia foi gerada e já está disponível na área de documentos.",
"visibilidade": "publica"
}Response 201 Created
ChamadoMensagemRead em data, com a mensagem "Mensagem postada com sucesso".
Chamado inexistente: 404. Chamado concluido: 409 ("Chamado concluído não aceita novas mensagens. Reabra o chamado antes."). Escopo: chamados:write
GET /chamados/mensagens/{mensagem_id}
Retorna uma mensagem pelo ID (qualquer visibilidade). Inexistente: 404 ("Mensagem não encontrada.").
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
mensagem_id | int | path | sim | ID da mensagem. |
Request
Sem corpo de requisição.
Response 200 OK
ChamadoMensagemRead em data, com a mensagem "Mensagem recuperada com sucesso".
Escopo: chamados:read
PUT /chamados/mensagens/{mensagem_id}
Edita o texto e/ou a visibilidade de uma mensagem. Não aceita id_chamado - mover mensagem de thread mudaria quem a enxerga. Esta rota não verifica autoria nem perfil além do escopo.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
mensagem_id | int | path | sim | ID da mensagem. |
Corpo ChamadoMensagemUpdate.
Request
{
"visibilidade": "publica"
}Response 200 OK
ChamadoMensagemRead atualizado em data, com a mensagem "Mensagem atualizada com sucesso".
Inexistente: 404. Visibilidade fora do vocabulário: 422. Escopo: chamados:write
DELETE /chamados/mensagens/{mensagem_id}
Exclui uma mensagem e, em cascata, os anexos presos a ela. Regra por autoria: o operador apaga só as mensagens que ele mesmo escreveu (autor_realm: "interno" e id_usuario igual ao dele); administrador e diretoria apagam qualquer uma, inclusive as do cliente. Mensagem alheia retorna 403 (não 404), porque a thread já é legível no realm interno.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
mensagem_id | int | path | sim | ID da mensagem. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Mensagem removida com sucesso",
"data": null
}Inexistente: 404. Sem autoria nem acesso total: 403 ("Você só pode apagar mensagens de sua autoria."). Escopo: chamados:write
GET /chamados/anexos/{anexo_id}
Baixa um anexo com conteudo_base64. É a única rota que expõe o conteúdo do arquivo; as listagens trazem só metadados.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
anexo_id | int | path | sim | ID do anexo. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Anexo recuperado com sucesso",
"data": {
"id": 77,
"id_chamado": 318,
"id_mensagem": 903,
"nome_arquivo": "print_documentos.png",
"mime_type": "image/png",
"tamanho_bytes": 184320,
"data_hora_criacao": "2026-10-14T10:05:00",
"conteudo_base64": "iVBORw0KGgoAAAANSUhEUgAA..."
}
}Inexistente: 404 ("Anexo não encontrado."). Escopo: chamados:read
DELETE /chamados/anexos/{anexo_id}
Exclui um anexo.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
anexo_id | int | path | sim | ID do anexo. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Anexo removido com sucesso",
"data": null
}Perfil sem permissão: 403. Inexistente: 404. Escopo: chamados:write + perfil administrador ou diretoria.
GET /chamados/{chamado_id}/anexos
Lista os anexos do chamado (só metadados, sem conteudo_base64). Sem id_mensagem, traz todos os anexos do chamado; com ele, só os de uma mensagem. Sem anexos, retorna 200 OK com data: [] e a mensagem "Nenhum anexo encontrado.".
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
id_mensagem | int | query | não | Restringe aos anexos de uma mensagem. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Anexos recuperados com sucesso",
"data": [
{
"id": 77,
"id_chamado": 318,
"id_mensagem": 903,
"nome_arquivo": "print_documentos.png",
"mime_type": "image/png",
"tamanho_bytes": 184320,
"data_hora_criacao": "2026-10-14T10:05:00"
}
]
}Chamado inexistente: 404. Escopo: chamados:read
POST /chamados/{chamado_id}/anexos
Anexa um arquivo em base64 ao chamado (anexo da abertura, sem id_mensagem) ou a uma mensagem dele. A mensagem informada precisa pertencer ao mesmo chamado. O nome do arquivo é sanitizado no servidor (componentes de caminho e caracteres fora de letras, dígitos, ., _, - e espaço são removidos ou trocados por _).
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
chamado_id | int | path | sim | ID do chamado. |
id_mensagem | int | query | não | Prende o anexo a uma mensagem; omitido = anexo da abertura. |
Corpo ChamadoAnexoCreate.
Request
{
"nome_arquivo": "guia_das_setembro.pdf",
"mime_type": "application/pdf",
"conteudo_base64": "JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PC9MZW5ndGggNiAwIFIv..."
}Response 201 Created
ChamadoAnexoRead em data (sem o conteúdo), com a mensagem "Anexo enviado com sucesso".
Arquivo inválido (MIME, tamanho, base64, executável ou cota): 400 com a mensagem do motivo. Chamado inexistente, mensagem de outro chamado ou chamado concluido: 404 ("Chamado ou mensagem não encontrado, ou chamado já concluído."). Escopo: chamados:write
Limites de anexo
O servidor garante os limites abaixo independentemente do front - quem chama a API direto está sujeito às mesmas regras.
Limites de anexo
- Tipos aceitos (allowlist):
application/pdf,image/pngeimage/jpeg. Qualquer outro MIME é recusado. - Tamanho por arquivo: 5 MB, medidos no binário decodificado.
- Quantidade: até 5 anexos por registro (abertura do chamado ou cada mensagem).
- Cota agregada: 50 MB somando todos os anexos do chamado.
- Assinatura de executável: conteúdo que começa como executável Windows (
MZ), Linux (ELF) ou script com shebang é recusado, mesmo declarado com MIME permitido.
Schemas
ChamadoCreate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id_cliente | int | sim | Empresa do chamado. |
titulo | str | sim | 1 a 200 caracteres. |
detalhamento | str | sim | 1 a 20000 caracteres. |
tipo | str | não | Vocabulário de tipos. Default problema. |
id_usuario_responsavel | int | null | não | Operador responsável. |
ChamadoUpdate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
titulo | str | não | 1 a 200 caracteres. |
detalhamento | str | não | 1 a 20000 caracteres. |
tipo | str | não | Vocabulário de tipos. |
status | str | não | Vocabulário de status. |
id_usuario_responsavel | int | null | não | Operador responsável. |
motivo_fechamento | str | null | não | Até 20000 caracteres. Só junto de status: "concluido". Em branco vira null. |
ChamadoRead
| Campo | Tipo | Descrição |
|---|---|---|
id | int | Número do chamado. |
titulo | str | Título. |
detalhamento | str | Descrição do chamado. |
tipo | str | Tipo. |
id_cliente | int | Empresa. |
id_portal_user | int | null | Usuário do Portal que abriu (nulo quando aberto pelo realm interno). |
status | str | Status. |
id_usuario_responsavel | int | null | Operador responsável. |
id_usuario_fechamento | int | null | Quem concluiu. |
data_hora_criacao | datetime | Abertura. |
data_hora_edicao | datetime | null | Última edição. |
data_hora_fechamento | datetime | null | Conclusão. |
motivo_fechamento | str | null | Motivo declarado na conclusão. |
nao_lidas | int | Mensagens do cliente não lidas pelo operador (só em GET /chamados/; default 0). |
ultima_mensagem_em | datetime | null | Data da última mensagem relevante (só em GET /chamados/; default null). |
PaginatedChamados
| Campo | Tipo | Descrição |
|---|---|---|
items | list[ChamadoRead] | Itens da página. |
total | int | Total do conjunto filtrado. |
total_pages | int | Total de páginas. |
current_page | int | Página atual. |
per_page | int | null | Itens por página. |
ChamadoMensagemCreate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
texto | str | sim | 1 a 20000 caracteres. |
visibilidade | str | não | publica ou interna. Default interna. |
ChamadoMensagemUpdate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
texto | str | não | 1 a 20000 caracteres. |
visibilidade | str | não | publica ou interna. |
ChamadoMensagemRead
| Campo | Tipo | Descrição |
|---|---|---|
id | int | ID da mensagem. |
id_chamado | int | Chamado da thread. |
autor_realm | str | portal (cliente) ou interno (operador). |
id_portal_user | int | null | Autor do Portal. |
id_usuario | int | null | Autor interno. |
texto | str | Conteúdo. |
visibilidade | str | publica ou interna. |
data_hora_criacao | datetime | Envio. |
autor_nome | str | null | Primeiro nome do atendente - resolvido só no caminho do Portal. |
autor_foto_url | str | null | URL da foto do atendente - resolvida só no caminho do Portal. |
ChamadoAnexoCreate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
nome_arquivo | str | sim | 1 a 255 caracteres (sanitizado no servidor). |
mime_type | str | sim | application/pdf, image/png ou image/jpeg. |
conteudo_base64 | str | sim | Conteúdo do arquivo em base64. |
ChamadoAnexoRead / ChamadoAnexoDownload
| Campo | Tipo | Descrição |
|---|---|---|
id | int | ID do anexo. |
id_chamado | int | Chamado. |
id_mensagem | int | null | Mensagem à qual o anexo está preso (nulo = abertura). |
nome_arquivo | str | Nome sanitizado. |
mime_type | str | MIME declarado. |
tamanho_bytes | int | Tamanho do binário. |
data_hora_criacao | datetime | Envio. |
conteudo_base64 | str | Só em ChamadoAnexoDownload (GET /chamados/anexos/{anexo_id}). |
ChamadoAvaliacaoRead
| Campo | Tipo | Descrição |
|---|---|---|
nota | int | 1 a 5. |
comentario | str | null | Comentário do cliente. |
data_hora_criacao | datetime | Avaliação. |
data_hora_edicao | datetime | null | Última alteração. |
ChamadoAvaliacaoInternaCreate
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
nota | int | sim | 1 a 5 (sem zero nem meia nota). |
comentario | str | null | não | Até 2000 caracteres. Em branco vira null. |
Campos extras são rejeitados com 422.
ChamadoAvaliacaoInternaRead
| Campo | Tipo | Descrição |
|---|---|---|
nota | int | 1 a 5. |
comentario | str | null | Comentário. |
id_usuario | int | Quem avaliou. |
data_hora_criacao | datetime | Primeira gravação. |
data_hora_edicao | datetime | null | Último reenvio (nulo = nunca reenviada). |
ChamadoAvaliacaoInternaResumo
| Campo | Tipo | Descrição |
|---|---|---|
media | float | null | Média com uma casa; null sem avaliação. |
quantidade | int | Quantidade de avaliações. |
ChamadoResumoFila
| Campo | Tipo | Descrição |
|---|---|---|
aberto | int | Chamados aberto. |
em_andamento | int | Chamados em_andamento. |
concluido | int | Chamados concluido. |
total | int | Soma dos três. |
Notas
- Consumidor: a fila interna é atendida no Hub - os comentários do código citam a faixa de abas e o badge do Hub, e as notificações de chamado apontam para a tela de atendimento do Hub.
- Notificações: abertura de chamado e mensagem do cliente (ambas vindas do Portal) geram notificação interna best-effort no sistema
hub. Chamado sem responsável notifica o time; com responsável, só ele. Mensagens de operador não notificam ninguém internamente. - Ordem das rotas:
GET /chamados/resumoeGET /chamados/nao-lidassão declaradas antes deGET /chamados/{chamado_id}por necessidade - invertidas, o segmento literal cairia na rota dinâmica e daria422. - Filtros de listagem (
status,tipo) comparam o valor exato gravado no banco: use sempre o valor canônico. A normalização de grafias (fechado,em andamento,bug...) vale só nos schemas de escrita. - Exclusão de chamado e de anexo é restrita a
administrador/diretoria. Para encerrar um atendimento, usePUTcomstatus: "concluido".