Atendimento: Modelos de Lembrete
Endpoints da WebApiAlcance para gerenciar modelos de lembrete - templates reutilizáveis de mensagens de atendimento, com suporte a recorrência, variáveis, vínculo com departamento/obrigação e anexo de mídia. Cobrem criação, listagem paginada com filtro por departamento, detalhamento por ID, atualização parcial, upload e download de anexo, e exclusão.
Todos os endpoints exigem autenticação. Veja Autenticação para o fluxo de API Key. O Swagger oficial está em api.contabilidadealcance.com.br/docs.
Base path
/api/v1/modelosA URL completa em produção é https://api.contabilidadealcance.com.br/api/v1/modelos.
Escopos necessários
modelos:read- listagem, detalhamento e download de anexomodelos:write- criação, atualização, upload de anexo e exclusão
O escopo é derivado da rota: o prefixo /modelos vira o recurso modelos, e o método HTTP define a ação (read para GET, write para POST/PUT/DELETE).
Endpoints
POST /modelos/
Cria um novo modelo de lembrete. Os campos obrigatórios são titulo e mensagem; os demais têm valores default ou aceitam null.
Parâmetros
Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (ModeloCreate). Veja o Schema ModeloCreate.
Request
{
"titulo": "Lembrete DAS mensal",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"horario_envio": "09:00:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": true,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento"
}Response 201 Created
{
"success": true,
"message": "Modelo criado com sucesso",
"data": {
"id": 42,
"titulo": "Lembrete DAS mensal",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"dia_semana": null,
"horario_envio": "09:00:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": true,
"telefone_avulso": null,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento",
"tipo_midia": null,
"arquivo_url": null,
"arquivo_nome": null,
"legacy_uuid": null,
"data_hora_criacao": "2026-07-03T09:00:00-03:00",
"data_hora_atualizacao": "2026-07-03T09:00:00-03:00"
}
}Erro de validação retorna 422 Unprocessable Entity.
Escopo: modelos:write
GET /modelos/
Lista os modelos cadastrados, com filtro opcional por departamento e paginação. Lista vazia é um estado válido - sempre retorna 200 OK, inclusive com data: [] e a mensagem "Nenhum modelo encontrado.".
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
departamento_id | int | query | não | Filtra os modelos pelo departamento vinculado. |
limit | int | query | não | Itens por página. Default 100, mínimo 1, máximo 500. |
offset | int | query | não | Offset de paginação. Default 0, mínimo 0. |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Modelos recuperados com sucesso",
"data": [
{
"id": 42,
"titulo": "Lembrete DAS mensal",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"dia_semana": null,
"horario_envio": "09:00:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": true,
"telefone_avulso": null,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento",
"tipo_midia": null,
"arquivo_url": null,
"arquivo_nome": null,
"legacy_uuid": null,
"data_hora_criacao": "2026-07-03T09:00:00-03:00",
"data_hora_atualizacao": "2026-07-03T09:00:00-03:00"
}
]
}Escopo: modelos:read
GET /modelos/anexo/{nome_disco}
Serve o arquivo de anexo (mídia) gravado em disco, protegido por autenticação e escopo. Retorna o binário do arquivo (FileResponse), não o envelope JSON.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
nome_disco | str | path | sim | Nome do arquivo em disco a ser servido. |
Request
Sem corpo de requisição.
Response 200 OK
Conteúdo binário do arquivo (FileResponse), sem envelope JSON. Quando o anexo não é encontrado, retorna 404 Not Found.
Escopo: modelos:read
GET /modelos/{modelo_id}
Detalha um modelo pelo ID inteiro. Quando não encontrado, retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
modelo_id | int | path | sim | ID interno do modelo |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Modelo recuperado com sucesso",
"data": {
"id": 42,
"titulo": "Lembrete DAS mensal",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"dia_semana": null,
"horario_envio": "09:00:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": true,
"telefone_avulso": null,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento",
"tipo_midia": null,
"arquivo_url": null,
"arquivo_nome": null,
"legacy_uuid": null,
"data_hora_criacao": "2026-07-03T09:00:00-03:00",
"data_hora_atualizacao": "2026-07-03T09:00:00-03:00"
}
}Escopo: modelos:read
PUT /modelos/{modelo_id}
Atualiza um modelo existente. O body é um ModeloUpdate com campos parciais - somente o que vier preenchido é alterado.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
modelo_id | int | path | sim | ID do modelo |
Request (ModeloUpdate - todos os campos opcionais)
{
"titulo": "Lembrete DAS mensal (revisado)",
"horario_envio": "08:30:00",
"recorrencia_ativa": false
}Response 200 OK
{
"success": true,
"message": "Modelo atualizado com sucesso",
"data": {
"id": 42,
"titulo": "Lembrete DAS mensal (revisado)",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"dia_semana": null,
"horario_envio": "08:30:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": false,
"telefone_avulso": null,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento",
"tipo_midia": null,
"arquivo_url": null,
"arquivo_nome": null,
"legacy_uuid": null,
"data_hora_criacao": "2026-07-03T09:00:00-03:00",
"data_hora_atualizacao": "2026-07-03T11:42:00-03:00"
}
}Modelo inexistente retorna 404 Not Found; erro de validação retorna 422 Unprocessable Entity.
Escopo: modelos:write
POST /modelos/{modelo_id}/anexo
Envia o anexo (mídia) de um modelo. Requisição multipart/form-data. O arquivo é gravado em <STORAGE_ROOT>/atendimento/modelos-anexos/ e os campos arquivo_url, arquivo_nome e tipo_midia do modelo são atualizados.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
modelo_id | int | path | sim | ID do modelo |
O corpo é enviado como multipart/form-data com os campos:
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
tipo_midia | str | sim | Um de image, video, audio, voice, document. |
arquivo | UploadFile | sim | Arquivo do anexo (até 50MB). |
Request
Corpo multipart/form-data com os campos tipo_midia e arquivo (arquivo binário). Não é JSON.
Response 200 OK
{
"success": true,
"message": "Anexo enviado com sucesso",
"data": {
"id": 42,
"titulo": "Lembrete DAS mensal",
"mensagem": "Olá {{nome}}, o DAS de {{mes}} vence em {{vencimento}}.",
"departamento_id": 3,
"dia_envio": 20,
"dia_semana": null,
"horario_envio": "09:00:00",
"ajuste_dia_util": "anterior",
"empresa_ids": [1234, 5678],
"variaveis": ["nome", "mes", "vencimento"],
"meses_ativos": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"obrigacao_nome": "DAS",
"recorrencia_ativa": true,
"telefone_avulso": null,
"tipo_recorrencia": "mensal",
"vinculo_mode": "departamento",
"tipo_midia": "image",
"arquivo_url": "/api/v1/modelos/anexo/9f3c2a1e-lembrete.png",
"arquivo_nome": "lembrete.png",
"legacy_uuid": null,
"data_hora_criacao": "2026-07-03T09:00:00-03:00",
"data_hora_atualizacao": "2026-07-03T12:05:00-03:00"
}
}Modelo inexistente retorna 404 Not Found; erro de validação retorna 422 Unprocessable Entity.
Escopo: modelos:write
DELETE /modelos/{modelo_id}
Remove um modelo de lembrete pelo ID. Modelo inexistente retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
modelo_id | int | path | sim | ID do modelo |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Modelo removido com sucesso",
"data": null
}Escopo: modelos:write
Schemas
ModeloCreate
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
titulo | str | sim | Título do modelo. Máx. 255 caracteres. |
mensagem | str | sim | Texto da mensagem do lembrete. Suporta variáveis (ex: {{nome}}). |
departamento_id | int | null | não | Departamento vinculado ao modelo. |
dia_envio | int | null | não | Dia do mês para envio. |
dia_semana | int | null | não | Dia da semana para envio. |
horario_envio | str | null | não | Horário de envio (ex: 09:00:00). Máx. 8 caracteres. |
ajuste_dia_util | str | null | não | Ajuste para dia útil (ex: anterior, posterior). Máx. 20 caracteres. |
empresa_ids | list | null | não | IDs de empresas/clientes vinculados. |
variaveis | list | null | não | Variáveis dinâmicas usadas na mensagem. |
meses_ativos | list | null | não | Meses em que o modelo fica ativo. |
obrigacao_nome | str | null | não | Nome da obrigação associada. Máx. 255 caracteres. |
recorrencia_ativa | bool | não | Indica recorrência ativa. Default false. |
telefone_avulso | str | null | não | Telefone avulso para envio. Máx. 50 caracteres. |
tipo_recorrencia | str | null | não | Tipo de recorrência (ex: mensal). Máx. 50 caracteres. |
vinculo_mode | str | null | não | Modo de vínculo (ex: departamento). Máx. 50 caracteres. |
tipo_midia | str | null | não | Tipo da mídia anexada. Máx. 20 caracteres. |
arquivo_url | str | null | não | URL/caminho do anexo. Máx. 500 caracteres. |
arquivo_nome | str | null | não | Nome do arquivo anexado. Máx. 255 caracteres. |
ModeloUpdate
Todos os campos são opcionais; apenas os enviados são atualizados. Os campos e limites são os mesmos do ModeloCreate, com a diferença de que recorrencia_ativa também é opcional (bool | null) - quando omitido, permanece inalterado.
ModeloRead
Estende os campos do ModeloCreate com os campos abaixo:
| Campo | Tipo | Notas |
|---|---|---|
id | int | Identificador do modelo. |
legacy_uuid | str | null | UUID de origem legada, quando aplicável. |
data_hora_criacao | datetime | Timestamp de criação. |
data_hora_atualizacao | datetime | Timestamp da última atualização. |
Notas
- Toda resposta segue o envelope
{ success, message, data }(ou{ success: false, message, details }em erro). GET /modelos/anexo/{nome_disco}é declarado antes da rota dinâmicaGET /modelos/{modelo_id}, entãoanexoé resolvido como rota estática (e não interpretado como ummodelo_id).- O download (
GET /modelos/anexo/{nome_disco}) e o upload (POST /modelos/{modelo_id}/anexo) retornam formatos diferentes: o download devolve o binário do arquivo, enquanto o upload devolve o envelope JSON com oModeloReadatualizado.
Envio com mídia
Para anexar arquivo a um modelo, use POST /modelos/{modelo_id}/anexo com multipart/form-data. Valores aceitos de tipo_midia: image, video, audio, voice, document. O arquivo é limitado a 50MB.