ContractPayment) é a unidade mínima de cobrança dentro de um contrato. Representa uma obrigação de pagamento individual com valor nominal e data de vencimento definidos. Um contrato agrupa um ou mais pagamentos, que em conjunto correspondem ao valor total da operação formalizada.status do contrato pai (ver Contratos.md, seção 2.4 — transições automáticas de ACTIVE → OVERDUE → DEFAULTED).allowedPaymentTypes no seu schema, quais tipos de pagamento são permitidos. O tipo padrão na criação é herdado de paymentDefaults.typeDefault do schema do contrato.paymentDefaults.interestApplicable = false (ex: CPR_PHYSICAL) não terão cálculo automático de juros nos seus pagamentos.correctionIndex != NONE, os pagamentos exibem um campo calculado amounts.corrected que representa o valor da parcela atualizado pelo índice de correção até a data da consulta. Esse valor é informativo — não altera o amounts.value armazenado. A correção efetiva é aplicada no momento do registro de baixa (ver Baixas.md).Contrato de API (não confundir com armazenamento). Esta tabela descreve o payload das respostas e requisições da API. A estrutura aninhada ( amounts,charges,discount,createdBy) é resultado de serialização — o modelo de dados em12. Modelo de Dados.mdarmazena os campos em colunas flat. O backend hidrata e agrupa na hora de devolver.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | UUID | Sim | Identificador único do pagamento. |
contractId | UUID | Sim | Contrato ao qual o pagamento pertence. |
companyId | UUID | Sim | Empresa. Desnormalizado para facilitar consultas. |
code | String | Não | Código ou número do pagamento (ex: NF-001, CPR-2024-03). Único por contrato quando informado. |
type | Enum | Sim | Tipo: CPR, INVOICE, PURCHASE_SALE_CONTRACT, CCB, PROMISSORY_NOTE, OTHER. Deve estar contido no allowedPaymentTypes do schema do contrato pai. Quando omitido na criação, herda paymentDefaults.typeDefault. |
description | String | Condicional | Descrição livre. Obrigatório quando type = OTHER. |
dueDate | DateTime (ISO 8601 UTC) | Sim | Data de vencimento. |
status | Enum | Sim | PENDING, PAID, PARTIALLY_PAID, OVERDUE, DEFAULTED, RENEGOTIATED, CANCELLED. Fixo em PENDING na criação manual via POST. Em importação (ver Importação.md) aceita outros valores para migração de parcelas legadas. |
overdueDays | Integer | Não | Dias em atraso. Calculado em tempo de leitura quando em atraso. null para demais status. |
amounts | Object | Sim | Objeto com os valores monetários da parcela. Ver detalhe abaixo. |
charges | Object | Sim | Objeto com encargos (juros, multa, desconto). Sempre presente, mesmo quando todos os componentes estão null. Ver detalhe abaixo. |
createdBy | Object | Sim | Usuário que criou, hidratado: { id, name }. Ver detalhe abaixo. |
createdAt | DateTime (ISO 8601 UTC) | Sim | Data de criação. |
updatedAt | DateTime (ISO 8601 UTC) | Sim | Data da última atualização. |
paidAt | DateTime (ISO 8601 UTC) | Não | Data em que foi integralmente liquidado. Preenchido ao mover para PAID. |
defaultedAt | DateTime (ISO 8601 UTC) | Não | Data em que foi marcado como inadimplência formal. Preenchido ao mover para DEFAULTED. |
cancelledAt | DateTime (ISO 8601 UTC) | Não | Data de cancelamento. |
amounts (objeto)| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amounts.value | Decimal | Sim | Valor da parcela em BRL — o valor original da obrigação, sem acréscimos. |
amounts.corrected | Decimal | Não | Valor da parcela corrigido pelo índice de correção monetária do contrato. Campo calculado em tempo de leitura. null quando correctionIndex = NONE. |
amounts.due | Decimal | Não | Valor total devido: corrected ?? value + charges.interest + charges.fine − charges.discount.calculatedAmount. Campo calculado em tempo de leitura. |
amounts.received | Decimal | Não | Valor total efetivamente recebido. Soma do receivedAmount de todas as baixas com status = ACTIVE (ver Baixas.md). |
amounts.remaining | Decimal | Não | Valor em aberto: due − received. Campo calculado em tempo de leitura. |
charges (objeto)| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
charges.interest | Decimal | Não | Juros de mora calculados automaticamente em tempo de leitura. null quando não aplicável ou parcela não está em atraso. |
charges.fine | Decimal | Não | Multa por atraso. Aplicada a partir do 1º dia de atraso. null quando não aplicável. |
charges.discount | Object | Sim | Objeto de desconto. Sempre presente, mesmo quando não há desconto configurado (nesse caso, type e value ficam null). Ver detalhe abaixo. |
charges.discount (objeto)| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
charges.discount.type | Enum | Não | FIXED ou PERCENTAGE. null quando não há desconto configurado. |
charges.discount.value | Decimal | Não | Quando type = FIXED, valor monetário do desconto. Quando type = PERCENTAGE, percentual aplicado sobre amounts.value. null quando type é null. |
charges.discount.calculatedAmount | Decimal | Não | Valor monetário efetivo do desconto. Quando type = FIXED, igual a discount.value. Quando type = PERCENTAGE, amounts.value × (discount.value / 100). Campo calculado em tempo de leitura. null quando não há desconto. |
createdBy (objeto)| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
createdBy.id | UUID | Sim | ID do usuário que criou a parcela. |
createdBy.name | String | Sim | Nome do usuário, hidratado pelo backend a partir do User vinculado. |
PENDING ◄──► OVERDUE ──► DEFAULTED ──► PAID / PARTIALLY_PAID / RENEGOTIATED / CANCELLED
│ ▲
└──────────────────────────┘
(PENDING também pode ir direto a PAID / PARTIALLY_PAID / RENEGOTIATED / CANCELLED)
(OVERDUE volta a PENDING quando a parcela é liquidada antes da formalização da inadimplência)| Transição | Tipo | Descrição |
|---|---|---|
| PENDING → PAID | Automática (via baixa) | Baixa integral registrada. |
| PENDING → PARTIALLY_PAID | Automática (via baixa) | Baixa parcial. Valor menor que amounts.due. |
| PENDING → OVERDUE | Automática (via job) | dueDate ultrapassado. Job diário (Pagamento → OVERDUE). |
| PENDING → CANCELLED | Manual | Cancelamento administrativo. |
| PENDING → RENEGOTIATED | Manual (via contrato) | Substituído por renegociação do contrato pai. |
| PARTIALLY_PAID → PAID | Automática (via baixa) | Baixa do saldo restante (amounts.remaining = 0). |
| PARTIALLY_PAID → OVERDUE | Automática (via job) | Parcialmente pago mas dueDate ultrapassado e ainda há saldo aberto. Histórico de baixas anteriores preservado em amounts.received. |
| OVERDUE → PENDING | Automática (via job) | Parcela em atraso é liquidada antes da formalização da inadimplência (raro — ocorre se dueDate é movido para futuro via PATCH, situação anômala). |
| OVERDUE → PAID | Automática (via baixa) | Baixa integral após vencimento. |
| OVERDUE → PARTIALLY_PAID | Automática (via baixa) | Baixa parcial após vencimento. |
| OVERDUE → DEFAULTED | Automática (via job) ou Manual | Job: daysToDefault do contrato ultrapassado. Manual: usuário marca via PUT /status. |
| OVERDUE → RENEGOTIATED | Manual (via contrato) | Renegociação do contrato. |
| DEFAULTED → PAID | Automática (via baixa) | Baixa integral mesmo após inadimplência formal. |
| DEFAULTED → PARTIALLY_PAID | Automática (via baixa) | Baixa parcial após inadimplência. |
| DEFAULTED → RENEGOTIATED | Manual (via contrato) | Renegociação. |
| DEFAULTED → CANCELLED | Manual | Cancelamento administrativo após inadimplência. |
status técnico (enum). O label exibido na UI é derivado pelo frontend a partir desse status — não é um campo retornado pela API.| status (backend) | Label exibida (frontend) |
|---|---|
PENDING | "Em aberto" |
OVERDUE | "Em atraso" |
DEFAULTED | "Inadimplente" |
PARTIALLY_PAID | "Parcialmente pago" |
PAID | "Pago" |
RENEGOTIATED | "Renegociado" |
CANCELLED | "Cancelado" |
finePercentage, dailyInterestPercentage) e condicionados pelo tipo via paymentDefaults do template. Não existe hierarquia multi-nível — o contrato é a fonte única de configuração.| Fonte | Descrição |
|---|---|
| Contrato | finePercentage e dailyInterestPercentage definem os percentuais. Quando não informados, encargos não são calculados. |
Template (paymentDefaults) | Define se juros, multa e desconto são aplicáveis. Quando interestApplicable = false, o cálculo é ignorado independente do que estiver no contrato. |
| Sobrescrita na baixa | No momento da baixa, o usuário pode informar valores diferentes dos calculados. Ver Baixas.md. |
paymentDefaults:| paymentDefaults | Efeito |
|---|---|
interestApplicable = false | charges.interest permanece null. Juros não calculados. |
fineApplicable = false | charges.fine permanece null. |
discountApplicable = false | Objeto charges.discount é aceito mas type/value rejeitados na criação. Permanece como { type: null, value: null, calculatedAmount: null }. |
nominalAmount, interestAmount, etc. — nomes das colunas pendentes de alinhamento com a nomenclatura value); aqui usamos a notação aninhada do contrato de API.charges.interest):SIMPLE:charges.interest = amounts.value × (contract.dailyInterestPercentage / 100) × overdueDaysCOMPOUND:charges.interest = amounts.value × ((1 + contract.dailyInterestPercentage / 100) ^ overdueDays − 1)dailyInterestPercentage do contrato não informado:MONTHLY: dailyRate = contract.interestRate / 30ANNUAL: dailyRate = contract.interestRate / 365charges.fine):charges.fine = amounts.value × (contract.finePercentage / 100)charges.discount.calculatedAmount):charges.discount.type = FIXED: calculatedAmount = charges.discount.value.charges.discount.type = PERCENTAGE: calculatedAmount = amounts.value × (charges.discount.value / 100).charges.discount.type = null: calculatedAmount = null.amounts.corrected):amounts.corrected = amounts.value × (índice acumulado no período)null quando contract.correctionIndex = NONE.amounts.due):base = amounts.corrected ?? amounts.value
amounts.due = base + (charges.interest ?? 0) + (charges.fine ?? 0) − (charges.discount.calculatedAmount ?? 0)PENDING e a data de baixa é anterior ou igual ao dueDate. Após o vencimento, o calculatedAmount deixa de ser aplicado no cálculo de due (o desconto vira informativo).amounts.remaining):amounts.remaining = amounts.due − amounts.receivedstatus = DRAFT, ACTIVE ou OVERDUE. Erro: INVALID_CONTRACT_STATUS.code, quando informado, deve ser único dentro do contrato. Erro: PAYMENT_CODE_ALREADY_EXISTS.dueDate deve estar dentro do intervalo startDate — endDate do contrato. Erro: DUE_DATE_OUT_OF_CONTRACT_RANGE.type deve estar em allowedPaymentTypes do schema do contrato. Quando omitido, herda paymentDefaults.typeDefault. Erro: INCOMPATIBLE_PAYMENT_TYPE.status é fixo em PENDING no POST /payments (criação manual) — não pode ser informado pelo cliente. Em importação (ver Importação.md), o campo status é aceito no payload para permitir migração de parcelas legadas já em estados como PAID, PARTIALLY_PAID ou CANCELLED. Erro: INVALID_STATUS_TRANSITION quando o valor informado em importação é inválido para o ciclo de vida da parcela.amounts.value das parcelas corresponde ao amounts.value do contrato. Divergências geram alerta TOTAL_AMOUNT_MISMATCH (não bloqueante).Pagamento → OVERDUE, ver Visão Geral, seção 11) move pagamentos PENDING ou PARTIALLY_PAID com dueDate ultrapassado para OVERDUE. Quando o status passa de PARTIALLY_PAID para OVERDUE, o amounts.received (valor já liquidado por baixas anteriores) é preservado — a trilha histórica de pagamentos parciais não é perdida.OVERDUE → DEFAULTED ocorre por duas vias:Pagamento → DEFAULTED) move parcelas em OVERDUE para DEFAULTED quando o prazo daysToDefault do contrato (ver Contratos.md, seção 2.1) é ultrapassado contado a partir do dueDate.PUT /status, quando a operação reconhece a inadimplência formalmente antes do prazo configurado.daysToDefault configurado, a transição automática não ocorre — DEFAULTED só por marcação manual.OVERDUE ou DEFAULTED fazem o contrato transitar para OVERDUE (e eventualmente DEFAULTED) conforme regras documentadas em Contratos.md (RN-CONT-011 e RN-CONT-012).status = PENDING podem ser cancelados diretamente via PUT /status. Pagamentos em OVERDUE, PARTIALLY_PAID, DEFAULTED ou PAID exigem fluxos específicos: renegociação (via contrato) ou cancelamento de baixa (ver Baixas.md — não há estorno no domínio). Erro: PAYMENT_NOT_CANCELLABLE.RENEGOTIATED ocorre em conjunto com a renegociação do contrato. Todos os pagamentos em aberto (PENDING, OVERDUE, DEFAULTED, PARTIALLY_PAID) são movidos simultaneamente.OVERDUE, o sistema recalcula diariamente charges.interest e charges.fine com base nos percentuais definidos no contrato (finePercentage, dailyInterestPercentage). Quando os percentuais não estão configurados no contrato, os encargos correspondentes não são calculados (null).Baixas.md.amounts.due, o pagamento transita para PARTIALLY_PAID e o amounts.remaining é recalculado. Múltiplas baixas parciais são permitidas — a parcela permanece em PARTIALLY_PAID enquanto houver saldo aberto. Transita para PAID quando amounts.remaining = 0. A multa (charges.fine) é aplicada uma única vez sobre o título (não acumula por baixa).charges.discount é sempre presente na resposta, mesmo quando não há desconto configurado (nesse caso type, value e calculatedAmount ficam null). Na criação ou edição, o campo charges.discount.type aceita FIXED ou PERCENTAGE. value deve ser numérico positivo. Quando o type é informado, value é obrigatório (e vice-versa) — informar um sem o outro gera erro INVALID_DISCOUNT_CONFIG. Quando paymentDefaults.discountApplicable = false, qualquer configuração de desconto (type/value não nulos) é rejeitada. Erro: DISCOUNT_NOT_ALLOWED. O campo calculatedAmount é sempre derivado em tempo de leitura — não pode ser enviado pelo cliente; se enviado, é ignorado.PENDING podem ser editados via PATCH. Erro: PAYMENT_IMMUTABLE.CANCELLED ou PAID.| Status | Código | Descrição |
|---|---|---|
| 404 | PAYMENT_NOT_FOUND | Pagamento não encontrado. |
| 409 | PAYMENT_CODE_ALREADY_EXISTS | Código duplicado no contrato. |
| 422 | INVALID_CONTRACT_STATUS | Contrato não está em DRAFT ou ACTIVE. |
| 422 | DUE_DATE_OUT_OF_CONTRACT_RANGE | dueDate fora da vigência do contrato. |
| 422 | INCOMPATIBLE_PAYMENT_TYPE | Tipo não permitido para o contrato. |
| 422 | MISSING_DESCRIPTION | type = OTHER sem description informado. |
| 422 | INVALID_STATUS_TRANSITION | Status informado na criação ou transição requisitada não é permitida. |
| 422 | PAYMENT_NOT_CANCELLABLE | Apenas PENDING pode ser cancelado. |
| 422 | PAYMENT_IMMUTABLE | Pagamento em status que não permite edição. |
| 422 | INVALID_DISCOUNT_CONFIG | charges.discount.type informado sem value (ou vice-versa), ou valor não numérico/negativo. |
| 422 | DISCOUNT_NOT_ALLOWED | Desconto não aplicável ao tipo do contrato (paymentDefaults.discountApplicable = false). |
| 422 | TOTAL_AMOUNT_MISMATCH | Soma dos amounts.value das parcelas diverge do amounts.value do contrato (alerta). |
/v2/companies/:companyId/portfolios/:portfolioId/contracts/:contractId/paymentsPENDING na criação manual (RN-PAY-004B).payment:create{
"code": "NF-001",
"type": "INVOICE",
"amounts": {
"value": 150000.00
},
"dueDate": "2024-03-14T00:00:00.000+00:00",
"charges": {
"discount": {
"type": "PERCENTAGE",
"value": 2.0
}
}
}CPR_PHYSICAL (sem desconto):{
"code": "CPR-001",
"amounts": {
"value": 450000.00
},
"dueDate": "2025-04-15T00:00:00.000+00:00"
}{
"id": "pay-001",
"contractId": "contract-001",
"companyId": "company-001",
"code": "NF-001",
"type": "INVOICE",
"description": null,
"dueDate": "2024-03-14T00:00:00.000+00:00",
"status": "PENDING",
"overdueDays": null,
"amounts": {
"value": 150000.00,
"corrected": null,
"due": 147000.00,
"received": 0.00,
"remaining": 147000.00
},
"charges": {
"interest": null,
"fine": null,
"discount": {
"type": "PERCENTAGE",
"value": 2.0,
"calculatedAmount": 3000.00
}
},
"createdBy": {
"id": "8c3f1a2b-...",
"name": "João Silva"
},
"createdAt": "2025-03-17T09:00:00.000+00:00",
"updatedAt": "2025-03-17T09:00:00.000+00:00",
"paidAt": null,
"defaultedAt": null,
"cancelledAt": null
}payment:read| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
status | Enum (multi) | Não | Filtrar por status. |
dueDateStart | Date (ISO) | Não | dueDate >=. |
dueDateEnd | Date (ISO) | Não | dueDate <=. |
orderBy | Enum | Não | Ordenação: dueDate, amounts.value, overdueDays, status, createdAt. Default: dueDate. |
order | Enum | Não | asc ou desc. Default: asc. |
offset | Integer | Não | Default: 0. |
limit | Integer | Não | Default: 20. Máximo: 100. |
{
"items": [
{
"id": "pay-001",
"contractId": "contract-001",
"code": "NF-001",
"type": "INVOICE",
"description": null,
"dueDate": "2026-05-13T13:32:32.209+00:00",
"status": "OVERDUE",
"overdueDays": 3,
"amounts": {
"value": 150000.00,
"corrected": null,
"due": 150225.00,
"received": 0.00,
"remaining": 150225.00
},
"charges": {
"interest": 225.00,
"fine": 3000.00,
"discount": {
"type": "PERCENTAGE",
"value": 2.0,
"calculatedAmount": null
}
},
"createdBy": {
"id": "8c3f1a2b-...",
"name": "João Silva"
},
"createdAt": "2025-03-17T09:00:00.000+00:00",
"updatedAt": "2025-03-17T09:00:00.000+00:00",
"paidAt": null,
"defaultedAt": null,
"cancelledAt": null
}
],
"nextPage": false
}Nota sobre o exemplo acima: charges.discount.calculatedAmountaparece comonullporque a parcela está emOVERDUE— após o vencimento o desconto deixa de ser aplicado (RN-PAY-014 + seção 2.4). A configuração (typeevalue) permanece registrada.
payment:readstatus = PENDING.payment:updatecode, type, description, dueDate, amounts.value, charges.discount.type, charges.discount.value.Os demais campos de amountsechargessão derivados em tempo de leitura e não podem ser enviados pelo cliente — se enviados, são ignorados.
{
"code": "NF-001-REV",
"amounts": {
"value": 155000.00
},
"dueDate": "2024-04-14T00:00:00.000+00:00",
"charges": {
"discount": {
"type": null,
"value": null
}
}
}payment:update{
"status": "CANCELLED",
"reason": "Pagamento emitido com valor incorreto."
}{
"status": "DEFAULTED",
"reason": "Cliente comunicou impossibilidade de pagamento."
}{
"id": "pay-001",
"status": "CANCELLED",
"cancelledAt": "2025-03-17T12:00:00.000+00:00",
"updatedAt": "2025-03-17T12:00:00.000+00:00"
}| Resource | Domínio | Actions |
|---|---|---|
payment | TENANT | create, read, update |
ContractPayment — apenas o resource RBAC foi renomeado para payment (mais conciso, dado que o contexto do módulo já implica que pagamento é de contrato).