NFS-e/Repasse: Demonstrativo
Endpoints da WebApiAlcance para gerenciar demonstrativos de repasse - os comprovantes (individuais por médico ou consolidados) gerados a partir de um repasse de NFS-e médica. Cobrem criação, listagem com filtros, listagem por repasse, detalhamento por ID, atualização, exclusão e o sub-recurso de histórico de eventos (registro/persistência do ciclo de vida do demonstrativo). O arquivo_url aponta para o PDF gerado do demonstrativo.
Escopo compartilhado nfse-repasse
Este domínio compartilha o primeiro segmento de rota nfse-repasse com os demais recursos de NFS-e/Repasse. O escopo é derivado do primeiro segmento: /nfse-repasse/... vira o recurso nfse_repasse (hífen → underscore). Portanto os escopos são nfse_repasse:read (GET) e nfse_repasse:write (POST/PUT/DELETE) - não existe um escopo demonstrativos:* separado. O mesmo par de escopos vale para todos os recursos sob /api/v1/nfse-repasse/.
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/nfse-repasse/demonstrativosEscopos necessários
nfse_repasse:read- listagens (todas, por repasse), detalhamento e leitura do históriconfse_repasse:write- criação, atualização, exclusão e registro de eventos no histórico
O escopo é derivado do primeiro segmento da rota: /nfse-repasse vira o recurso nfse_repasse (hífen → underscore), e o método HTTP define a ação (read para GET, write para POST/PUT/DELETE).
Camada single-company: perfil administrador nas escritas
Nesta migração single-company (app webapp-nfs-repasse-medico), além do escopo nfse_repasse:write, as operações de escrita (POST /, PUT, DELETE e POST .../historico) exigem que o usuário autenticado tenha perfil administrador. A leitura (GET) é liberada para qualquer usuário autenticado (get_current_user).
Endpoints
POST /nfse-repasse/demonstrativos/
Cria um novo demonstrativo de repasse vinculado a um repasse de NFS-e médica. O campo id_usuario_created não entra no body - é forçado pelo service a partir do usuário autenticado.
Parâmetros
Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (DemonstrativoRepasseCreate): id_repasse (obrigatório), id_medico, tipo_demonstrativo (default individual_medico), arquivo_url, campos de envio e uuid_legado (opcional, só para correlação de migração).
Request
{
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf"
}Response 201 Created
{
"success": true,
"message": "Demonstrativo criado com sucesso!",
"data": {
"id": 1,
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"status_envio": "nao_enviado",
"enviado_em": null,
"id_usuario_enviou": null,
"tentativas_envio": 0,
"erro_envio": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
}Escopo: nfse_repasse:write (+ perfil administrador)
GET /nfse-repasse/demonstrativos/by-repasse/{repasse_id}
Lista os demonstrativos de um repasse específico. Declarada antes da rota dinâmica /{demonstrativo_id} para não ser interpretada como um ID.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
repasse_id | int | path | sim | ID do repasse (repasse.id). |
status_envio | str | query | não | Filtro por status de envio: nao_enviado, enviado ou erro. |
page | int | query | não | Página 1-based (≥1, opcional). |
per_page | int | query | não | Itens por página (1-500, opcional). |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Demonstrativos recuperados com sucesso!",
"data": [
{
"id": 1,
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"status_envio": "nao_enviado",
"enviado_em": null,
"id_usuario_enviou": null,
"tentativas_envio": 0,
"erro_envio": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/demonstrativos/
Lista todos os demonstrativos, com filtros opcionais combináveis. Lista vazia é um estado válido - retorna 200 OK com data: [].
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_repasse | int | query | não | Filtro por repasse (repasse.id). |
id_medico | int | query | não | Filtro por médico (medico.id). |
status_envio | str | query | não | Filtro por status de envio: nao_enviado, enviado ou erro. |
page | int | query | não | Página 1-based (≥1, opcional). |
per_page | int | query | não | Itens por página (1-500, opcional). |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Demonstrativos recuperados com sucesso!",
"data": [
{
"id": 1,
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"status_envio": "nao_enviado",
"enviado_em": null,
"id_usuario_enviou": null,
"tentativas_envio": 0,
"erro_envio": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
POST /nfse-repasse/demonstrativos/{demonstrativo_id}/historico
Registra um evento no histórico do demonstrativo (sub-recurso aninhado, declarado antes de /{demonstrativo_id}). O id_demonstrativo_repasse vem do path, não do body.
Histórico é apenas persistência
Este endpoint apenas registra/persiste eventos (ex.: gerado, enviado, reenviado). O envio de e-mail em si é fase posterior, executada por um worker Celery - não há endpoint de envio aqui.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
demonstrativo_id | int | path | sim | ID do demonstrativo-pai. |
O corpo da requisição segue o schema DemonstrativoHistoricoCreate, cujo único campo obrigatório é evento.
Request
{
"evento": "enviado",
"destinatario_email": "medico@exemplo.com.br",
"status": "sucesso"
}Response 201 Created
{
"success": true,
"message": "Evento registrado com sucesso!",
"data": {
"id": 1,
"id_demonstrativo_repasse": 1,
"evento": "enviado",
"id_medico": 1,
"id_usuario": 42,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"destinatario_email": "medico@exemplo.com.br",
"status": "sucesso",
"erro_mensagem": null,
"observacao": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:05:00Z"
}
}Escopo: nfse_repasse:write (+ perfil administrador)
GET /nfse-repasse/demonstrativos/{demonstrativo_id}/historico
Lista o histórico de eventos de um demonstrativo (append-only, ordenado por criação). Demonstrativo inexistente retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
demonstrativo_id | int | path | sim | ID do demonstrativo-pai. |
page | int | query | não | Página 1-based (≥1, opcional). |
per_page | int | query | não | Itens por página (1-500). |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Histórico recuperado com sucesso!",
"data": [
{
"id": 1,
"id_demonstrativo_repasse": 1,
"evento": "enviado",
"id_medico": 1,
"id_usuario": 42,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"destinatario_email": "medico@exemplo.com.br",
"status": "sucesso",
"erro_mensagem": null,
"observacao": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:05:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/demonstrativos/{demonstrativo_id}
Detalha um demonstrativo pelo ID inteiro. Quando não encontrado, retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
demonstrativo_id | int | path | sim | ID interno do demonstrativo. |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Demonstrativo encontrado!",
"data": {
"id": 1,
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"status_envio": "nao_enviado",
"enviado_em": null,
"id_usuario_enviou": null,
"tentativas_envio": 0,
"erro_envio": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
}Escopo: nfse_repasse:read
PUT /nfse-repasse/demonstrativos/{demonstrativo_id}
Atualiza um demonstrativo existente. O body é um DemonstrativoRepasseUpdate com campos parciais - somente o que vier preenchido é alterado. Os campos id, uuid_legado, id_usuario_created, id_repasse, created_at e updated_at são imutáveis (não aparecem no Update, o que bloqueia mass-assignment e transferência de repasse).
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
demonstrativo_id | int | path | sim | ID do demonstrativo. |
Request (DemonstrativoRepasseUpdate - todos os campos opcionais)
{
"status_envio": "enviado",
"enviado_em": "2026-07-03T12:10:00Z",
"id_usuario_enviou": 42
}Response 200 OK
{
"success": true,
"message": "Demonstrativo atualizado!",
"data": {
"id": 1,
"id_repasse": 1,
"id_medico": 1,
"tipo_demonstrativo": "individual_medico",
"arquivo_url": "https://.../demonstrativos/1/individual/1/demo.pdf",
"status_envio": "enviado",
"enviado_em": "2026-07-03T12:10:00Z",
"id_usuario_enviou": 42,
"tentativas_envio": 1,
"erro_envio": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:10:00Z"
}
}Escopo: nfse_repasse:write (+ perfil administrador)
DELETE /nfse-repasse/demonstrativos/{demonstrativo_id}
Remove um demonstrativo pelo ID.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
demonstrativo_id | int | path | sim | ID do demonstrativo. |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Demonstrativo removido!",
"data": null
}Escopo: nfse_repasse:write (+ perfil administrador)
Schemas
DemonstrativoRepasseCreate
id_usuario_created não entra no Create (forçado pelo service). uuid_legado é aceito apenas para correlação na migração e torna-se imutável depois.
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
id_repasse | int | sim | ID do repasse (repasse.id). |
id_medico | int | não | ID do médico. Opcional (consolidado não tem médico). |
tipo_demonstrativo | str | não | individual_medico (default) ou consolidado. Máx. 40 caracteres. |
arquivo_url | str | não | URL pública do PDF gerado. |
status_envio | str | não | nao_enviado (default), enviado ou erro. Máx. 30. |
enviado_em | datetime | não | Timestamp do envio (preenchido pelo worker Celery - fase posterior). |
id_usuario_enviou | int | não | ID do usuário que disparou o envio (auditoria). |
tentativas_envio | int | não | Contador de tentativas (≥0, default 0). |
erro_envio | str | não | Mensagem do último erro de envio. |
uuid_legado | str | não | UUID do registro original no Supabase (máx. 36). Imutável depois. |
DemonstrativoRepasseUpdate
Todos os campos são opcionais; apenas os enviados são atualizados. Campos de identidade/origem são imutáveis e não aparecem aqui.
| Campo | Tipo | Observações |
|---|---|---|
id_medico | int | Reatribui o médico do demonstrativo. |
tipo_demonstrativo | str | Máx. 40 caracteres. |
arquivo_url | str | Nova URL do PDF. |
status_envio | str | nao_enviado, enviado ou erro. Máx. 30. |
enviado_em | datetime | Timestamp do envio. |
id_usuario_enviou | int | Usuário que disparou o envio. |
tentativas_envio | int | Contador de tentativas (≥0). |
erro_envio | str | Mensagem do último erro. |
DemonstrativoRepasseRead
Estende o Base com os campos gerenciados (ID, owner, timestamps).
| Campo | Tipo | Notas |
|---|---|---|
id | int | ID interno do demonstrativo. |
id_repasse | int | ID do repasse. |
id_medico | int | ID do médico (nulo em consolidado). |
tipo_demonstrativo | str | individual_medico ou consolidado. |
arquivo_url | str | URL pública do PDF. |
status_envio | str | nao_enviado, enviado ou erro. |
enviado_em | datetime | Timestamp do envio (ou null). |
id_usuario_enviou | int | Usuário que disparou o envio. |
tentativas_envio | int | Contador de tentativas. |
erro_envio | str | Mensagem do último erro. |
uuid_legado | str | UUID de origem (migração). |
id_usuario_created | int | Usuário que criou (auditoria). |
created_at | datetime | Timestamp de criação (server-side). |
updated_at | datetime | Timestamp da última atualização. |
DemonstrativoHistoricoCreate
Evento de histórico do demonstrativo. id_demonstrativo_repasse vem do path da rota; id_usuario_created é forçado pelo service.
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
evento | str | sim | Evento registrado (gerado, enviado, reenviado, …). Máx. 40. |
id_medico | int | não | ID do médico. |
id_usuario | int | não | ID do usuário que disparou o evento. |
tipo_demonstrativo | str | não | individual_medico (default) ou consolidado. Máx. 40. |
arquivo_url | str | não | URL do PDF no evento. |
destinatario_email | str | não | E-mail destinatário (quando o evento é um envio). Máx. 150. |
status | str | não | sucesso (default) ou erro. Máx. 20. |
erro_mensagem | str | não | Mensagem de erro do evento. |
observacao | str | não | Observação livre. |
uuid_legado | str | não | UUID de origem (migração). Máx. 36. |
O schema de leitura correspondente, DemonstrativoHistoricoRead, adiciona id, id_demonstrativo_repasse, id_usuario_created, uuid_legado e created_at (append-only - sem updated_at).
Notas
- Toda resposta segue o envelope
{ success, message, data }(ou{ success: false, message, details }em erro). - As rotas com path estático (
/by-repasse/{repasse_id}) e os sub-recursos aninhados (/{demonstrativo_id}/historico) são declarados antes da rota dinâmica/{demonstrativo_id}. O FastAPI faz match na ordem de declaração - inverter quebraria os endpoints estáticos. arquivo_urlreferencia o PDF do demonstrativo. A geração e o envio de e-mail são fases posteriores executadas por worker Celery; este domínio apenas persiste os campos de status de envio e registra eventos no histórico.- Erros de negócio são mapeados por mensagem canônica do service: "não encontrado" →
404, "já existe" →409, "acesso negado" →403, demais →422.