Saldo Acumulado

Endpoints da WebApiAlcance para gerenciar saldos acumulados - o saldo tributário acumulado de um contribuinte por tributo (ex.: valores abaixo do mínimo de recolhimento de R$ 10,00 que ficam retidos até atingir o piso). Cada saldo é identificado pela chave funcional (cnpj, tributo) no contexto do usuário autenticado (multi-tenant). Cobrem criação, upsert idempotente, listagem com filtros, detalhamento por ID, atualização e soft delete.

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/saldos-acumulados

Escopos necessários

  • saldos_acumulados:read - listagem e detalhamento
  • saldos_acumulados:write - criação, upsert, atualização e soft delete

O escopo é derivado da rota: o prefixo público /saldos-acumulados vira o recurso saldos_acumulados (hífen → underscore), e o método HTTP define a ação (read para GET, write para POST/PUT/DELETE).

Endpoints

POST /saldos-acumulados/

Cria um novo saldo acumulado vinculado ao usuário autenticado. O id_usuario_created é preenchido a partir do usuário logado - não é aceito no body.

Parâmetros

Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (SaldoAcumuladoCreate): cnpj, tributo, saldo e mes_referencia (todos obrigatórios).

Request

{
  "cnpj": "12345678000190",
  "tributo": "pis",
  "saldo": "8.45",
  "mes_referencia": "2026-05"
}

Response 201 Created

{
  "success": true,
  "message": "Saldo acumulado criado com sucesso!",
  "data": {
    "id": 1,
    "cnpj": "12345678000190",
    "tributo": "pis",
    "saldo": "8.45",
    "mes_referencia": "2026-05",
    "id_usuario_created": 42,
    "id_usuario_updated": null,
    "created_at": "2026-05-31T12:00:00Z",
    "updated_at": "2026-05-31T12:00:00Z",
    "deleted_at": null
  }
}

Já existir saldo para (usuário, cnpj, tributo) retorna 409 Conflict (use POST /saldos-acumulados/upsert para idempotência); falhas de validação retornam 422 Unprocessable Entity. Escopo: saldos_acumulados:write

POST /saldos-acumulados/upsert

Cria ou atualiza o saldo pela chave funcional (cnpj, tributo) do usuário autenticado - idempotente. Se o saldo já existe, atualiza saldo e mes_referencia; caso contrário, cria. Saldos em soft delete são "ressuscitados" (deleted_at limpo) e atualizados.

Parâmetros

Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (SaldoAcumuladoUpsert), com os mesmos campos de SaldoAcumuladoCreate (cnpj, tributo, saldo, mes_referencia).

Request

{
  "cnpj": "12345678000190",
  "tributo": "pis",
  "saldo": "9.10",
  "mes_referencia": "2026-06"
}

Response 200 OK

{
  "success": true,
  "message": "Saldo acumulado upserted!",
  "data": {
    "id": 1,
    "cnpj": "12345678000190",
    "tributo": "pis",
    "saldo": "9.10",
    "mes_referencia": "2026-06",
    "id_usuario_created": 42,
    "id_usuario_updated": 42,
    "created_at": "2026-05-31T12:00:00Z",
    "updated_at": "2026-06-30T12:00:00Z",
    "deleted_at": null
  }
}

Escopo: saldos_acumulados:write

GET /saldos-acumulados/

Lista os saldos acumulados do usuário autenticado, com filtros e paginação opcionais. Lista vazia é um estado válido - sempre retorna 200 OK, inclusive com data: [] e a mensagem "Nenhum saldo acumulado encontrado.".

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
cnpjstrquerynãoFiltro por CNPJ (14 dígitos, sem máscara).
tributostrquerynãoFiltro por tributo. Aceita: pis, cofins, irpj, csll.
pageintquerynãoPágina 1-based (>= 1).
per_pageintquerynãoItens por página (1..500).

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Saldos recuperados com sucesso!",
  "data": [
    {
      "id": 1,
      "cnpj": "12345678000190",
      "tributo": "pis",
      "saldo": "8.45",
      "mes_referencia": "2026-05",
      "id_usuario_created": 42,
      "id_usuario_updated": null,
      "created_at": "2026-05-31T12:00:00Z",
      "updated_at": "2026-05-31T12:00:00Z",
      "deleted_at": null
    }
  ]
}

Escopo: saldos_acumulados:read

GET /saldos-acumulados/{saldo_id}

Detalha um saldo acumulado do usuário autenticado pelo ID inteiro. Quando não encontrado (ou pertencente a outro usuário), retorna 404 Not Found.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
saldo_idintpathsimID interno do saldo

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Saldo acumulado encontrado!",
  "data": {
    "id": 1,
    "cnpj": "12345678000190",
    "tributo": "pis",
    "saldo": "8.45",
    "mes_referencia": "2026-05",
    "id_usuario_created": 42,
    "id_usuario_updated": null,
    "created_at": "2026-05-31T12:00:00Z",
    "updated_at": "2026-05-31T12:00:00Z",
    "deleted_at": null
  }
}

Escopo: saldos_acumulados:read

PUT /saldos-acumulados/{saldo_id}

Atualiza um saldo existente do usuário autenticado pelo ID. O body é um SaldoAcumuladoUpdate com campos parciais - somente o que vier preenchido é alterado. Os campos cnpj e tributo são imutáveis (compõem a chave única) e não aparecem no schema (proteção contra mass-assignment).

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
saldo_idintpathsimID do saldo

Request (SaldoAcumuladoUpdate - saldo e/ou mes_referencia, ambos opcionais)

{
  "saldo": "9.10",
  "mes_referencia": "2026-06"
}

Response 200 OK

{
  "success": true,
  "message": "Saldo acumulado atualizado!",
  "data": {
    "id": 1,
    "cnpj": "12345678000190",
    "tributo": "pis",
    "saldo": "9.10",
    "mes_referencia": "2026-06",
    "id_usuario_created": 42,
    "id_usuario_updated": 42,
    "created_at": "2026-05-31T12:00:00Z",
    "updated_at": "2026-06-30T12:00:00Z",
    "deleted_at": null
  }
}

Escopo: saldos_acumulados:write

DELETE /saldos-acumulados/{saldo_id}

Soft delete: marca deleted_at = NOW() em vez de remover o registro. O saldo continua no banco para auditoria fiscal, mas fica invisível a todos os endpoints GET. Um POST /saldos-acumulados/upsert subsequente com a mesma chave (cnpj, tributo) ressuscita o registro.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
saldo_idintpathsimID do saldo

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Saldo acumulado removido!",
  "data": null
}

Quando não encontrado, retorna 404 Not Found. Escopo: saldos_acumulados:write

Schemas

SaldoAcumuladoCreate

Herda todos os campos de SaldoAcumuladoBase.

CampoTipoObrigatórioObservações
cnpjstrsimCNPJ do contribuinte, 14 dígitos numéricos, sem máscara.
tributostrsimEnum literal: pis, cofins, irpj, csll.
saldoDecimalsimValor monetário acumulado, >= 0, compatível com Numeric(15,2).
mes_referenciastrsimÚltimo mês em que o saldo foi acumulado, no formato YYYY-MM (ex.: 2026-05).

SaldoAcumuladoUpsert

Mesmos campos de SaldoAcumuladoCreate (cnpj, tributo, saldo, mes_referencia). O par (cnpj, tributo) é usado como chave funcional para decidir entre criar e atualizar.

SaldoAcumuladoUpdate

Todos os campos são opcionais; apenas os enviados são atualizados. cnpj e tributo não aparecem aqui - são imutáveis (bloqueia mass-assignment).

CampoTipoObservações
saldoDecimalNovo valor acumulado (>= 0).
mes_referenciastrNova competência de referência, formato YYYY-MM.

SaldoAcumuladoRead

Estende SaldoAcumuladoBase com os campos gerenciados pelo service.

CampoTipoNotas
idintIdentificador do saldo acumulado.
cnpjstrCNPJ do contribuinte (14 dígitos).
tributostrpis, cofins, irpj ou csll.
saldoDecimalValor acumulado.
mes_referenciastrCompetência de referência (YYYY-MM).
id_usuario_createdintID do usuário que criou (multi-tenant).
id_usuario_updatedint | nullID do último usuário que atualizou o registro.
created_atdatetimeTimestamp de criação (server-side).
updated_atdatetimeTimestamp da última atualização (server-side).
deleted_atdatetime | nullTimestamp do soft delete (null = registro ativo).

Notas

  • Toda resposta segue o envelope { success, message, data } (ou { success: false, message, details } em erro). Códigos HTTP refletem semântica REST padrão.
  • Os saldos são isolados por usuário (multi-tenant): a listagem e o detalhamento só retornam registros do usuário autenticado.
  • Validações: cnpj deve ter exatamente 14 dígitos (não valida dígito verificador); saldo não pode ser negativo e deve ser < 10.000.000.000.000 (arredondado a 2 casas); mes_referencia deve casar YYYY-MM com mês 01-12.

Armadilha de roteamento FastAPI

A rota estática POST /saldos-acumulados/upsert é declarada antes da rota dinâmica GET|PUT|DELETE /saldos-acumulados/{saldo_id}. Inverter a ordem faria o FastAPI casar upsert como um saldo_id inválido. A ordem de declaração das rotas é intencional.