A Malvo conecta seus usuários por redes reguladas de compartilhamento de dados financeiros e normaliza os resultados no mesmo contrato de Items, Accounts e Transactions. A infraestrutura e a jurisdição mudam; a API pública consumida pela sua aplicação permanece a mesma.

Como a Malvo conecta

O usuário autoriza o compartilhamento no banco, por uma jornada OAuth/redirect, sem fornecer credenciais bancárias à sua aplicação.
A integração é exclusivamente de dados. A Malvo não expõe PIS, iniciação de pagamentos, Pix, boletos ou transferências, mesmo quando uma API upstream possui operações de pagamento. supportsPaymentInitiation permanece sempre false.

Cobertura internacional

A configuração aceita estas 31 jurisdições ISO-3166-1 alpha-2:
Isso corresponde a Áustria, Bélgica, Bulgária, Croácia, Chipre, República Tcheca, Dinamarca, Estônia, Finlândia, França, Alemanha, Grécia, Hungria, Islândia, Irlanda, Itália, Letônia, Liechtenstein, Lituânia, Luxemburgo, Malta, Países Baixos, Noruega, Polônia, Portugal, Romênia, Eslováquia, Eslovênia, Espanha, Suécia e Reino Unido. Para Reino Unido, use GB, não UK.
Os 31 países são a cobertura configurável, não uma promessa de todos os bancos. A lista efetiva depende das jurisdições habilitadas e das instituições ativas naquele ambiente. Consulte GET /connectors?isOpenFinance=true&countries=... em runtime; instituições ausentes da fotografia mais recente são marcadas OFFLINE.

O fluxo de redirecionamento e consentimento

Em conectores de Open Finance, o usuário não digita a senha do banco na sua aplicação — ele é redirecionado ao banco para autenticar e autorizar o consentimento.
1

Crie o Item informando o redirect

POST /items com connectorId e oauthRedirectUri. No Brasil, envie os parameters pedidos pelo conector, normalmente cpf ou cnpj. Em conectores internacionais, parameters normalmente é {}; se connector.credentials anunciar o select authMethod, envie somente uma opção declarada. Isso seleciona a jornada, não coleta credenciais bancárias. Informe um clientUserId estável para correlacionar o usuário e evitar duplicatas. A resposta carrega a URL de autorização em connector.oauthUrl.
2

O usuário autoriza no banco

O usuário abre a URL, autentica no banco e autoriza o consentimento. Enquanto isso, o Item usa status=LOGIN_IN_PROGRESS e executionStatus=USER_AUTHORIZATION_PENDING.
3

Retorno via oauthRedirectUri

Concluída a autorização, o provedor retorna ao callback da Malvo. A Malvo valida state, troca o código por consentimento/sessão e redireciona para o seu oauthRedirectUri, acrescentando itemId e status (e message em erro). A coleta continua de forma assíncrona até UPDATED.
Trate cada URL de autorização como efêmera e de uso único. Não a registre nem a envie por canais que geram pré-visualização automática. Abra-a apenas no momento da ação do usuário.

Semântica dos dados no Brasil

As regras abaixo são específicas do Open Finance Brasil e não devem ser aplicadas automaticamente a conectores internacionais.

Histórico e atualizações incrementais

  • Sincronização inicial: até 365 dias de histórico.
  • Toda sincronização: avalia também transactions-current, que cobre aproximadamente os últimos 7 dias, enquanto houver capacidade diária na rota e no recurso.
  • Reconciliação histórica: o histórico completo possui uma cota própria e restrita; ele é carregado inicialmente e reconciliado segundo sua cadência, sem substituir a janela recente.
  • A profundidade do histórico de transações dos meios de pagamento (PIX, TED, DOC, TEF, Boleto) varia de 3 a 24 meses por instituição e por rail.

Retry e indisponibilidade temporária

Algumas instituições deixam uma API ou uma família inteira do Open Finance indisponível temporariamente. Para evitar concluir uma importação incompleta por causa de uma oscilação curta, a Malvo aplica a seguinte política:
  • Falhas de transporte/rede e respostas 5xx recebem até 3 tentativas no total, com 10 segundos entre elas, na mesma execução.
  • A propagação de um consentimento recém-autorizado, durante a criação do token OPF ou a descoberta de recursos, também recebe até 3 tentativas no total, com 10 segundos entre elas.
  • Cada tentativa física conta no consumo da rota. Se a capacidade diária ou mensal terminar antes da terceira tentativa, a Malvo respeita o lock e não o ultrapassa.
  • Se uma rota esgotar as três tentativas, os recursos irmãos dessa mesma rota usam o último valor persistido durante o restante da execução, evitando repetir a indisponibilidade para cada conta.
  • 429, 423 do HOLDER, cota mensal, erros permanentes 4xx e cancelamento não usam esse retry curto; cada um segue sua janela de recuperação específica.
Se o consentimento ainda não tiver propagado depois das três tentativas, o Item permanece LOGIN_IN_PROGRESS / USER_AUTHORIZATION_PENDING, sem ser tratado como revogado, e fica elegível para a recuperação assíncrona. Se as três tentativas transitórias falharem apenas para parte dos dados, os dados válidos já importados são preservados e a execução termina em PARTIAL_SUCCESS, com PROVIDER_TEMPORARILY_UNAVAILABLE na família afetada. Essa execução parcial dispara item/updated depois de persistir os dados válidos; leia statusDetail para identificar o que ficou incompleto. Uma execução posterior que concluir as famílias restantes dispara um novo item/updated.

Limite de recursos por conta

Limite rígido: 260 recursos por conta. Ultrapassá-lo dispara warnings em statusDetail (os dados podem ser truncados). Projete a ingestão para tolerar truncamento.
Transações pendentes de conta-corrente permanecem PENDING enquanto processam; valores bloqueados acumulam no blockedBalance da conta. Em contas bancárias, balance representa o saldo disponível consolidado (incluindo aplicação automática quando informada), enquanto bankData.closingBalance representa o saldo contábil total: disponível mais bloqueado. O valor bloqueado também é exposto separadamente em bankData.blockedBalance e em GET /accounts/{id}/balance; automaticallyInvestedAmount já é consolidado pela especificação Open Finance e não é somado novamente.

Particularidades de cartão de crédito

Atualizações diárias de transações; os detalhes completos só ficam disponíveis após o fechamento da fatura. Faturas abertas só aparecem quando fechadas ou vencidas. O billId de uma transação só é atribuído quando a fatura já existe na instituição. Algumas transações aparecem apenas na listagem de faturas, nunca no stream de transações.
A maioria das instituições retorna apenas a primeira parcela de compras futuras nas atualizações diárias. BTG Pactual (connector 614) retorna todas as parcelas futuras como PENDING já na primeira conexão. XP Banking (connector 602) retorna o valor total da compra em vez das parcelas individuais.

Particularidades de investimentos

  • A sincronização inicial retorna apenas investimentos ativos; os resgatados aparecem depois com status TOTAL_WITHDRAWAL.
  • Notas de corretagem não são expostas.
  • “Caixinhas” (Nubank) e “Cofrinhos” (PicPay) aparecem como investimentos CDB. Transações de investimentos via Open Finance não são suportadas de forma transversal entre instituições.

Dados de contraparte (paymentData)

Os dados da contraparte de uma transação nem sempre existem. Normalmente faltam em: tarifas da instituição, portabilidade de salário, resgates de investimento, TED/PIX/Boleto em lote, depósitos abaixo de R$ 2.000 e transações de cartão de débito/pré-pago.

Semântica dos dados internacionais

  • Produtos: somente ACCOUNTS e TRANSACTIONS; os saldos são normalizados no objeto Account.
  • Primeira sincronização e reconsentimento: a Malvo solicita o maior histórico disponível. O período efetivamente devolvido depende do ASPSP e não possui garantia única para os 31 países.
  • Sincronizações incrementais: a Malvo busca desde lastUpdatedAt com sobreposição de 90 dias, para reconciliar lançamentos tardios ou alterados. A cada 30 dias tenta novamente o histórico completo nos ASPSPs compatíveis; quando a janela máxima não é suportada, preserva HISTORY_LIMITED e mantém a maior janela aceita sem repetir a estratégia incompatível.
  • Paginação: o cursor é opaco. A Malvo continua paginando enquanto houver uma próxima chave, inclusive quando uma página intermediária vier vazia.
  • Identidade da conta: os identificadores estáveis publicados pelo provedor são usados para preservar o mesmo Account após uma nova sessão ou reconsentimento.
  • Disponibilidade: consentimento, tipos de usuário pessoal/empresarial, validade máxima, filtros e profundidade de histórico variam por ASPSP.
Uma falha em parte das contas ou transações pode produzir PARTIAL_SUCCESS. Nesse caso, dados válidos são preservados, o cursor global não avança e uma execução posterior tenta completar a janela pendente.

Por que webhooks são a fonte da verdade

O estado de uma conexão é assíncrono: o consentimento depende do usuário no banco e o auto-sync roda em segundo plano. Por isso, a Malvo emite webhooks próprios a cada transição relevante — e eles, não o onSuccess do widget, são a fonte autoritativa do estado.
No fluxo internacional, a Malvo detecta alterações, expiração e revogação consultando a sessão e os endpoints de dados por scheduler ou refresh manual; os webhooks recebidos pela sua aplicação são gerados pela Malvo após a persistência local.
O padrão canônico de integração é “webhook como gatilho, REST como fonte da verdade”:
1

Registre um webhook na configuração da aplicação

Inscreva um endpoint HTTPS no evento all e roteie internamente.
2

Em qualquer evento item/*, re-busque o recurso canônico

Nunca confie apenas no payload: chame GET /items/{itemId} (status, error, consentExpiresAt) e depois GET /accounts?itemId=....
3

Em transactions/created e transactions/updated

Liste as contas do itemId, pagine GET /v2/transactions?accountId=... para cada uma e faça upsert por id da transação. Em transactions/deleted, exclua localmente pelos ids informados.
4

Em item/error e item/waiting_user_input

Marque o Item como “precisa de ação” e direcione o usuário de volta ao Connect Widget em modo de atualização.
As entregas de webhook não têm ordem garantida e podem ser reenviadas. Cada entrega carrega um eventId (UUID) que é reutilizado em todos os reenvios e em todos os endpoints inscritos — persista o eventId e trate duplicatas como no-op. Mesmo com webhooks, mantenha um job noturno de reconciliação que re-busca itens e transações para cobrir janelas de indisponibilidade.
Revogações e expirações de consentimento não geram um evento consent/*. Elas aparecem no estado do Item e em item/error; reabra o mesmo Item em modo de atualização para obter uma nova autorização. Após a coleta bem-sucedida, você recebe item/updated e o consentExpiresAt é renovado quando aplicável.

Próximos passos

Consents

Ciclo de vida, renovação no mesmo Item e limites mensais da rede.

Items

Máquina de estados e caminhos de recuperação da conexão.