O CSV permite começar a medição com uma exportação do ERP, sem esperar a integração por API. Ele usa a mesma validação, a mesma identidade de origem e a mesma troca atômica da carga por API. O fluxo tem dois passos: a prévia, que valida e guarda o arquivo sem mexer na carga ativa, e a ativação, feita por um operador autorizado.
Uma carga por CSV é análise pontual da fotografia importada. Ela não habilita monitoramento contínuo entre uploads e perde atualidade 24 horas depois do source_as_of (veja Cadência).

Fluxo

1

Baixe o modelo

Use o modelo versionado obligation-import-v1.csv. A versão do modelo é a do contrato: schema_version: "obligations.v1".
2

Registre a origem

POST /obligation-sources com mode: "csv", uma vez por ERP. Veja Origens.
3

Envie a prévia

POST /financial-profiles/{id}/obligation-imports/preview com o arquivo e os metadados da carga.
4

Revise

Confira os totais por natureza, os vencidos, as liquidações e os erros. Com qualquer erro, a prévia fica rejected e nada é ativado.
5

Ative

POST /financial-profiles/{id}/obligation-imports/{importId}/activate com actor e reason. Exige a permissão obligation_imports.activate_csv da aplicação.

O modelo

O cabeçalho tem 22 colunas, com os nomes do contrato em inglês. A ordem das colunas é livre, mas os nomes são exatos e cada um aparece uma vez. record_type, external_obligation_id, direction, category, original_amount, outstanding_amount, currency, due_date, status, source_version, source_updated_at, source_reference, bank_obligation_reference, counterparty_id_type, counterparty_id, counterparty_name, settlement_id, settled_at, settled_amount, settlement_method, payment_reference, payment_match_id. Cada linha tem um record_type:
  • obligation: um título. As colunas de liquidação ficam vazias.
  • settlement: uma liquidação, ligada ao título pelo external_obligation_id. As colunas do título ficam vazias. Toda liquidação precisa de uma linha obligation com o mesmo identificador no arquivo.
O significado de cada coluna está no contrato v1. Os campos da carga (import_id, financial_profile_id, source_system, source_as_of, coverage, contagens e finalização) vão nos metadados do upload, não no arquivo. Exemplo com a fotografia de 12/10/2026 de um ERP sintético:
titulos-20261012.csv
Este arquivo gera a prévia mostrada em POST .../obligation-imports/preview: dois títulos a pagar (1250.10 de valor original, 1000.00 em aberto, uma liquidação de 250.10) e um a receber de 1000.0400, com as 4 casas preservadas.

Formato do arquivo

O formato é declarado no upload, em csv_format. A Malvo não adivinha separador nem decimal. Os três campos de csv_format são obrigatórios: sem algum deles, a prévia volta com MISSING_FIELD e o campo (csv_format.encoding, csv_format.delimiter ou csv_format.decimal_separator). Por que o decimal é sempre ponto: com ponto e vírgula como separador, 1.000,00 e 1000,00 são ambíguos entre exportações. O padrão de valor é o mesmo da API (^\d{1,15}\.\d{2,4}$). Exportação com ponto e vírgula, comum em planilhas em pt-BR, declarada no upload:
titulos-ponto-e-virgula.csv

Fórmulas são texto

Conteúdo de célula é sempre texto de dados. A Malvo nunca avalia fórmula. Uma célula que começa com =, +, - ou @:
  • numa coluna de valor, cai no padrão decimal e é recusada com INVALID_AMOUNT. =SUM(A1:A2) em outstanding_amount é um erro, não uma soma;
  • num campo livre (category, source_reference, counterparty_name), fica guardada exatamente como veio, por exemplo o texto =1+1.
Ao exibir esses campos numa planilha sua, trate-os como texto para não executar o conteúdo.

Linhas e colunas

Depois do arquivo, a carga passa pelas mesmas regras da API: estado coerente com o valor em aberto, moeda BRL, contagens, cobertura, versões e identidade (veja os códigos do contrato). Cada erro traz line (linha do arquivo, começando no cabeçalho como linha 1), field e, quando houver, external_obligation_id e settlement_id. A linha bruta não é guardada.
Prévia recusada 422
A prévia recusada ainda traz preview, com os totais das linhas que puderam ser lidas: valor fora do padrão não entra na soma. No exemplo, T-1001 tem original_amount 1000.00 e T-1003 tem outstanding_amount 500.00; os outros dois valores estão inválidos. Não há aceite parcial: com qualquer erro, a prévia inteira fica rejected e a carga ativa não muda. Corrija a exportação e envie de novo com outro import_id.

O upload

POST /financial-profiles/{id}/obligation-imports/preview, em multipart/form-data:
  • metadata: JSON com os campos da carga do contrato (sem obligations) e csv_format;
  • file: o CSV.
metadata
Enviar a prévia
As contagens declaradas precisam bater com o arquivo: obligation_count conta as linhas obligation e settlement_count as linhas settlement. Um reenvio idêntico (mesmo import_id e mesmo conteúdo) devolve o resultado da primeira prévia. API e CSV com o mesmo conjunto geram o mesmo conteúdo.

Conjunto vazio

Uma carga sem títulos é válida quando o recorte declarado está vazio de verdade. Envie só o cabeçalho, contagens zero e a confirmação explícita:
titulos-vazio.csv
metadata do conjunto vazio
Sem empty_snapshot_confirmed: true, a carga é recusada com EMPTY_SNAPSHOT_NOT_CONFIRMED. Um arquivo totalmente vazio, sem cabeçalho, é recusado com EMPTY_FILE. Ativada, a carga vazia significa “nenhum título em aberto no recorte declarado”, na data e no escopo dela. Não significa que a empresa não tem dívidas.

Ativação e auditoria

A ativação refaz as conferências de versão: se outra carga da mesma origem chegou depois da prévia, a prévia vira rejected com o motivo (por exemplo, STALE_SNAPSHOT). Um CSV nunca sobrescreve uma fotografia mais recente feita por API. Ficam auditáveis o autor e o motivo da ativação, o nome, o tamanho e o SHA-256 do arquivo, a versão do modelo, a posição (source_as_of), as contagens, os totais e a chave de idempotência. O CSV original é guardado em armazenamento privado por 30 dias e os erros por linha também por 30 dias. A trilha de auditoria não guarda valores.

Base normativa

  • Contrato obligations.v1 (Títulos do ERP — contrato v1).
  • RFC 4180 (formato CSV, aspas duplas) e RFC 3339 (instantes com fuso).
  • API Contas do Open Finance Brasil 2.5.1, lida em 12/10/2026: padrão de valor ^\d{1,15}\.\d{2,4}$, reusado nas colunas monetárias.
  • PRD v1.3, seção 13, “Importação CSV no piloto” (FR-034; AC-048, AC-049, AC-050 e AC-054), e a política de retenção da Malvo aprovada em 10/10/2026 (CSV original e erros por linha: 30 dias).