Esta página descreve as rotas da F2 que recebem os títulos a pagar e a receber do ERP do parceiro. O formato da carga é o contrato v1 de títulos do ERP (obligations.v1). O upload por planilha tem um guia próprio. A conciliação com os débitos bancários está em Conciliação assistida, e o diagnóstico e os alertas em Liquidez e alertas.
A carga é dado do parceiro, não de Open Finance. Toda resposta destas rotas traz data_origin: "partner_erp". A Malvo não dá baixa no ERP: nenhuma rota desta página grava nada no sistema do parceiro.

Chaves do módulo

Todas as chaves nascem desligadas. Com qualquer uma desligada, as rotas correspondentes não existem e respondem 404. Sem armazenamento de arquivo configurado, a prévia de CSV responde 503 FILE_STORAGE_UNAVAILABLE.

Regras comuns

  • Autenticação: header X-API-KEY da aplicação. Sem token, 403. Perfil ou origem de outra aplicação responde 404 NOT_FOUND.
  • Valores: string decimal ^\d{1,15}\.\d{2,4}$, nunca número JSON. Totais são somas decimais exatas: "1000.0400" + "0.2000" = "1000.2400".
  • Instantes: RFC 3339 com fuso na entrada. As respostas devolvem UTC com Z.
  • Corpo estrito: campo desconhecido no corpo responde 400 VALIDATION_ERROR.
  • Erros: o envelope é o mesmo das demais rotas (code, message, codeDescription, requestId). Erros da carga trazem também errors, uma lista com code, field, line, external_obligation_id e settlement_id quando houver.
  • Identificadores: {importId} é o id da carga na Malvo. O import_id do contrato é a sua chave idempotente.

Origens

A origem (source_system) identifica o ERP dentro da aplicação. Ela é registrada uma vez, com o modo de monitoramento, e vale para todos os perfis que recebem cargas dela.

POST /obligation-sources

Registra a origem. Responde 201 na criação e 200 se ela já existia; nesse caso, o modo é atualizado.
Registrar origem
Origem registrada 201

GET /obligation-sources

Lista as origens da aplicação em results. Com OBLIGATION_SOURCE_ACTIVITY_ENABLED, cada origem traz também o último sinal de atividade, a cadência e os perfis cobertos (os que têm carga ativa da origem).
Origens com cadência
Em profiles, import_id é o id da carga ativa na Malvo. effective_source_as_of é o source_as_of da carga avançado pelas confirmações de atividade (veja Cadência).

Cargas

Uma carga é a fotografia completa dos títulos de um perfil no recorte declarado, no formato obligations.v1. A validação é inteira e a troca da carga ativa é atômica: uma recusa não mexe na carga ativa nem nos títulos. Não há aceite parcial de linhas válidas. channel diz por onde a carga chegou: api ou csv. API e CSV compartilham a identidade da origem e a ordem das versões.

POST /financial-profiles/{id}/obligation-imports

Recebe a carga em JSON, no formato do contrato v1. O financial_profile_id do corpo precisa ser o da rota e o source_system precisa estar registrado. Uma carga válida e finalizada é ativada na hora. O conteúdo é comparado depois de normalizar a ordem das coberturas, dos títulos e das liquidações, com o texto exato dos valores. API e CSV com o mesmo conjunto geram o mesmo conteúdo.
Carga ativada 201
Carga recusada 422
409 IMPORT_ID_CONFLICT
422 SOURCE_NOT_REGISTERED

Regras de troca atômica

A carga é conferida contra o estado atual antes de qualquer escrita: A ativação também absorve as correspondências confirmadas cujo título mudou (veja Absorção pela origem).

POST /financial-profiles/{id}/obligation-imports/preview

Recebe um CSV em multipart/form-data com duas partes, metadata e file, valida e guarda a prévia sem ativar. O formato do arquivo, o csv_format e os erros específicos estão no guia CSV.
Prévia de CSV 200
Os totais da prévia são somas decimais exatas por natureza. Vencido em aberto é o título com outstanding_amount maior que zero e vencimento anterior à data civil de source_as_of em America/Sao_Paulo.

GET /financial-profiles/{id}/obligation-imports/{importId}

Devolve a carga com o estado, o motivo, as contagens, o arquivo (sem o conteúdo) e os erros. Uma prévia guardada traz também preview. Carga de outro perfil ou de outra aplicação responde 404 NOT_FOUND.
Carga não ativada 200

POST /financial-profiles/{id}/obligation-imports/{importId}/activate

Ativa uma prévia de CSV sem erros, com a mesma troca atômica da API. Exige a permissão obligation_imports.activate_csv da aplicação, desligada por padrão. O dono ou um admin do time concede a permissão no console. O corpo exige actor (até 128 caracteres, quem ativou do lado do parceiro) e reason (até 500). Os dois ficam na carga como activated_by e activation_reason.
Ativar prévia
Prévia ativada 200
403 PERMISSION_REQUIRED

Títulos

GET /financial-profiles/{id}/obligations?scope=&direction=&status=&page=&pageSize=

Devolve a agenda do perfil e os títulos, paginados (pageSize padrão 20, máximo 500). Valor fora da lista responde 400 VALIDATION_ERROR. agenda.state é missing com reason: "NO_ACTIVE_IMPORT" enquanto nenhuma carga finalizada e completa estiver ativa. O diagnóstico usa esse estado para mostrar “Diagnóstico indisponível — agenda financeira não informada”. Com carga ativa, o estado é available e cada origem traz a carga ativa e a mais recente que não virou ativa. Uma carga válida com zero títulos e empty_snapshot_confirmed: true fica ativa com data e escopo: significa “nenhum título em aberto no recorte declarado”, não ausência de dívida. Com OBLIGATION_SOURCE_ACTIVITY_ENABLED, a resposta traz quality, a qualidade da agenda para o diagnóstico (veja Cadência).
Agenda e títulos 200
Os campos do título seguem o contrato v1. Cada título traz também obligation_id (id na Malvo), active, active_import_id, removed_at, version_id e version_created_at.

GET /financial-profiles/{id}/obligations/{obligationId}

Um título, as liquidações da versão atual e todas as versões guardadas em versions, da mais recente para a mais antiga. Cada versão aponta a carga que a trouxe (obligation_import_id). Título de outro perfil responde 404 NOT_FOUND.
Título com versões 200

Cadência e atividade por origem (FR-035)

Com OBLIGATION_SOURCE_ACTIVITY_ENABLED, cada origem tem uma cadência calculada na leitura, pelo relógio do servidor. Os prazos são requisitos de produto do PRD v1.3 (seção 10, “Frequência e elegibilidade das cargas”), não norma externa. A elegibilidade é da origem: um problema em um perfil deixa a origem inelegível em todos os perfis cobertos. Cada motivo traz o perfil afetado (financial_profile_id, quando houver) e o prazo vencido (due_at). Todo prazo vence depois do instante: às 06h00 em ponto a carga do dia anterior ainda vale. O último sinal (heartbeat_at) é a confirmação de atividade ou a ativação de carga mais recente da origem. activity_due_at é o próximo sinal esperado (uma hora depois de heartbeat_at); a origem só perde a atividade depois de duas horas sem sinal. Perder a atividade é registrado em activity_lost_at e só volta com uma carga válida: novas confirmações não bastam. Os outros motivos somem quando a carga que falta chega. A perda de elegibilidade é estado de qualidade dos dados, não deterioração financeira. Depois de cada ciclo de sincronização bancária do perfil, a Malvo publica financial_profile.bank_position_updated. Responder com uma fotografia daquele perfil é opcional e não muda os prazos da tabela.

POST /obligation-sources/{sourceId}/activity

Confirma a atividade da origem. Uma confirmação cobre todos os perfis da origem.
  • confirmed_until: instante até o qual a origem confirma não ter alteração pendente de envio. Ele avança o source_as_of efetivo de todos os perfis cobertos. Não cria carga, não mexe em títulos e não dispara sincronização bancária. Uma confirmação mais antiga que a guardada não faz o valor recuar.
  • pending_changes (opcional, até 100): alteração relevante já feita no ERP (baixa, cancelamento, reabertura, valor ou vencimento) que ainda não chegou numa carga. Ela limita o source_as_of efetivo do perfil ao changed_at e abre o prazo de carga do modo. Uma carga ativada no perfil com source_as_of igual ou posterior ao changed_at resolve a alteração.
  • Numa origem csv, a confirmação fica registrada e as alterações pendentes valem, mas o confirmed_until não avança o source_as_of efetivo: o CSV é análise pontual da fotografia.
A confirmação não substitui uma carga quando houver alterações e não prova que o operador já deu baixa num pagamento no ERP.
Confirmar atividade
A resposta 200 é o estado da origem, no mesmo formato de um item de GET /obligation-sources. Com a alteração pendente acima, o source_as_of efetivo do perfil fica limitado ao changed_at e o prazo de carga do modo api vence 2 horas depois.
Atividade confirmada 200
Se a carga não chegar até 11h40 UTC, a origem passa a trazer:
Cadência com carga vencida
422 ACTIVITY_INSTANT_IN_FUTURE

Qualidade para o diagnóstico

GET /financial-profiles/{id}/obligations traz quality quando a cadência está ligada:
  • favorable_conclusion_allowed: false se não houver carga ativa, se alguma origem do perfil estiver inelegível ou se a coerência com o banco falhar.
  • reasons: NO_ACTIVE_IMPORT, SOURCE_INELIGIBLE, SOURCE_BEHIND_BANK_POSITION ou BANK_POSITION_UNKNOWN.
  • oldest_bank_position_at: posição mais antiga das contas bancárias vinculadas, pelo updateDateTime do saldo da API Contas.
  • sources[].coherence.state: coherent, source_behind_bank (o source_as_of efetivo é anterior à posição bancária mais antiga em mais de 1 hora, limit_seconds: 3600) ou bank_position_unknown. lag_seconds é a posição mais antiga menos o source_as_of efetivo: negativo quando o ERP está à frente do banco.
Exemplo do PRD: source_as_of efetivo às 06h30 e posição mais antiga às 08h00 dão 1h30 de diferença, acima de 1 hora. O diagnóstico não conclui cobertura favorável, mas pode mostrar uma insuficiência já demonstrável.

Retenção

Nenhum valor de título vai para log.

Base normativa

  • Contrato obligations.v1 (Títulos do ERP — contrato v1): campos, padrões, estados, idempotência e versões.
  • API Contas do Open Finance Brasil 2.5.1 (api_accounts_-_open_finance_brasil/2.5.1.yaml, lido em 12/10/2026): padrão de valor ^\d{1,15}\.\d{2,4}$ e AccountBalancesData.updateDateTime como posição bancária da coerência. Títulos de ERP não fazem parte dessa API.
  • Lei nº 13.709/2018 (LGPD), art. 6º, 7º, 15, 16 e 18, e a política de retenção da Malvo aprovada em 10/10/2026.
  • PRD v1.3, seções 10, 13 e 14 (FR-027, FR-034, FR-035; AC-029 a AC-031, AC-035, AC-048 a AC-051, AC-054, AC-062 e AC-063). Os prazos da FR-035 (06h00, 2 horas, 15 minutos, atividade por hora, 24 horas no CSV e coerência de 1 hora) são regras de produto, sem norma externa.