REDA One Centro de ajuda
PT
Idioma
English EN Español ES Português PT Italiano em breve Français FR Deutsch em breve العربية em breve
reda.one ↗
Início / REDA Financials AI / API e integração / Extensibilidade / Pacotes de extensão

Pacotes de extensão

Algumas integrações são produtos por si só — feeds bancários com credenciais de provedor, fatura eletrônica em APIs governamentais. A REDA Financials estrutura essas integrações como pacotes de extensão: o núcleo define um contrato abstrato global, a extensão o implementa, e um registro de configuração conecta os dois. Hoje são dois contratos base, mais três interfaces de capacidade opcionais que um provedor implementa apenas se precisar delas.

Como o padrão funciona

Ambos os contratos seguem a mesma arquitetura, e ambos os cabeçalhos de classe descrevem isso com as mesmas palavras: "The core package resolves the provider at runtime via: Type.forName(setup.Provider_Class__c).newInstance()". Nenhum dos dois contratos codifica um fornecedor de forma fixa. Há quatro partes móveis, cada uma com um responsável claro:

ParteResponsávelFunção
Contrato abstrato — refin.BankFeedProvider / refin.EInvoiceProviderPacote principalClasses abstratas globais (ambas marcadas com @since 2026-05-28) que definem as assinaturas de método e os formatos de resultado. Global = parte da superfície estável do pacote gerenciado.
ImplementaçãoPacote de extensão (ou sua organização)Uma classe concreta que estende o contrato; contém toda a lógica de API específica do provedor. Segundo ambas as documentações de classe: "Authentication and API credentials are managed entirely by the extension package."
Registro de configuração — refin__Bank_Feed_Setup__c / refin__E_Invoice_Setup__cSeu administradorRegistra a classe implementadora totalmente qualificada em Provider_Class__c, além das configurações de ambiente, ativação e escopo.
Objeto de resultado — BankFeedResult / EInvoiceResultPacote principalA classe interna global que todo método retorna, para que os resultados sejam registrados de forma uniforme, seja qual for o provedor.
Contratos vs. orquestração. Este artigo documenta os contratos de extensão — as duas classes globais e seus objetos de configuração, que são a superfície estável e publicada. Como o pacote principal orquestra essas classes em tempo de execução (jobs agendados de sincronização, criação automática de histórico quando documentos são contabilizados) depende da versão e ainda está evoluindo. Projete e programe contra os contratos; confirme o comportamento de orquestração da sua versão instalada do pacote principal com a REDA antes de comprometer um design operacional a ele.

refin.BankFeedProvider — extratos bancários automatizados

  • O contrato: três métodos que uma implementação fornece — connect (o fluxo de vinculação do provedor), sync (buscar transações desde o cursor e entregar linhas de extrato), disconnect (revogar o acesso). Os resultados retornam em um formato padrão (sucesso, transações importadas, cursor atualizado, saldo, erro).
  • A conexão: um registro de Configuração de feed bancário por conta conectada — nome do provedor, ambiente (Sandbox/Production), o nome da classe implementadora, cursor de sincronização e status (Active / Paused / Error / Disconnected), última sincronização. As configurações ficam na página de registro da conta bancária.
  • As credenciais permanecem com a extensão — o núcleo nunca vê os tokens do provedor; a extensão é responsável por toda a sua autenticação de ponta a ponta.
  • O resultado: os extratos chegam como extratos bancários comuns (origem de importação marcada de acordo) e seguem para a mesma correspondência e conciliação que um CSV teria — automação a montante, fluxo de trabalho familiar a jusante.

O contrato de feed bancário, método a método

Cada método recebe o registro de configuração como seu contexto. A documentação da classe explica o modelo: "Each method receives the Bank_Feed_Setup__c record as the primary context — the provider reads the linked bank account and its own credentials to execute sync logic."

global abstract BankFeedResult sync(refin__Bank_Feed_Setup__c setup);

global abstract BankFeedResult connect(
    refin__Bank_Feed_Setup__c setup,
    Map<String, String> params
);

global abstract void disconnect(refin__Bank_Feed_Setup__c setup);
MétodoO que o contrato exige dele (segundo a documentação da classe)
sync"The provider fetches new transactions from the bank API (using the sync cursor from the setup record), converts them to Bank Statement Lines via the core package's internal import path, and returns the updated cursor for persistence." A documentação acrescenta que é "Called by the core scheduled batch job" — veja a ressalva de orquestração acima; o lado do agendamento depende da versão do pacote principal.
connectInicia o fluxo de vinculação para uma nova conta bancária. "Provider-specific: may involve OAuth redirect, token exchange, or API key validation. The params map carries provider-specific connection parameters (e.g. public_token for Plaid, link_id for Belvo)."
disconnect"Revokes access tokens, removes webhooks, and cleans up provider-side resources. The core package updates the setup record's Sync_Status to Disconnected after this method completes."

BankFeedResult é uma classe interna global — todo membro é @AuraEnabled global, e o construtor define success como false e transactionsImported como 0 por padrão, de modo que uma implementação precisa conquistar um sucesso:

MembroTipoSignificado
successBooleanSe a operação foi concluída. Padrão false.
transactionsImportedIntegerQuantas transações a sincronização entregou. Padrão 0.
updatedCursorStringA nova posição incremental, retornada "for persistence" para que a próxima sincronização retome de onde esta terminou.
currentBalanceDecimalO saldo da conta informado pelo provedor no momento da sincronização.
errorMessageStringDetalhe honesto da falha quando success é falso.

refin__Bank_Feed_Setup__c — referência de campos

CampoO que ele contém
Bank_Account__cA conta bancária REDA que esse feed atende — uma configuração por conta conectada.
Provider_Class__c (rótulo "Provider Class")O coração da conexão. Descrição literal: "Fully qualified Apex class name that extends refin.BankFeedProvider… Extension packages register their implementation here (e.g. plaid.PlaidBankFeedProvider)."
Provider__cApenas um nome de exibição — segundo sua própria descrição, "The actual integration logic is determined by Provider_Class__c, not this field."
Environment__cQual ambiente do provedor a conexão tem como alvo (Sandbox / Production).
Is_Active__cSe o feed participa da sincronização.
Sync_Cursor__cA posição incremental do provedor — sync a lê e retorna o valor atualizado em BankFeedResult.updatedCursor.
Sync_Status__cLista de seleção: Active / Paused / Error / Disconnected. A ajuda do valor Error é explícita: "Error: last sync failed — check Audit Log for details."
Last_Sync__cQuando o feed sincronizou pela última vez.
Provider_Account_Id__cO identificador, no lado do provedor, da conta vinculada.
Como as linhas de extrato realmente chegam. A documentação da classe diz que o provedor grava as transações em Bank_Statement__c / Bank_Statement_Line__c por meio do serviço de importação interno do pacote principal — mas esse serviço não faz parte da superfície global, então o mecanismo exato de entrega de extratos disponível a uma extensão depende da sua versão do pacote principal. Trate o contrato (buscar, entregar, retornar o cursor) como fixo e confirme o caminho de entrega com a REDA ao construir um provedor.

Um esqueleto de implementação

Aqui está o formato de um provedor — a equipe da Meridian esboçando um contra a API direta do banco americano deles. Apenas as peças do contrato são reais; os comentários marcam onde entra a lógica do seu provedor:

global class MeridianBankFeedProvider extends refin.BankFeedProvider {

    global override refin.BankFeedProvider.BankFeedResult connect(
            refin__Bank_Feed_Setup__c setup, Map<String, String> params) {
        refin.BankFeedProvider.BankFeedResult result =
            new refin.BankFeedProvider.BankFeedResult();
        // Exchange the connection parameters (e.g. public_token) with the
        // provider. Store credentials in YOUR package — never in core objects.
        result.success = true;
        return result;
    }

    global override refin.BankFeedProvider.BankFeedResult sync(
            refin__Bank_Feed_Setup__c setup) {
        refin.BankFeedProvider.BankFeedResult result =
            new refin.BankFeedProvider.BankFeedResult();
        // 1. Fetch transactions since setup.refin__Sync_Cursor__c
        // 2. Deliver them as bank statement lines
        // 3. Return the new cursor so it can be persisted
        result.transactionsImported = 42;
        result.updatedCursor = 'cursor-after-this-batch';
        result.success = true;
        return result;
    }

    global override void disconnect(refin__Bank_Feed_Setup__c setup) {
        // Revoke tokens and webhooks on the provider side; the core
        // sets Sync_Status to Disconnected after this completes.
    }
}

refin.EInvoiceProvider — fatura eletrônica obrigatória

  • O contrato: submit (montar o payload da jurisdição a partir do documento e chamar a autoridade), checkStatus (consultar autoridades assíncronas), cancel (regras específicas por jurisdição se aplicam — a própria nota do contrato cita a janela de 24 horas do Brasil e a aceitação do destinatário no México).
  • A conexão: uma Configuração de fatura eletrônica por entidade/país — provedor, ambiente, classe implementadora, quais tipos de documento participam, e uma opção Auto Submit On Post; toda tentativa de envio é registrada como um Histórico de fatura eletrônica no documento (status, UUID e número fiscal, payloads, resposta, contagem de tentativas) — a trilha de auditoria de conformidade que os reguladores exigem.
  • Nota sobre disponibilidade: os históricos e listas relacionadas são visíveis em todo o aplicativo (você já viu Históricos de fatura eletrônica nas páginas de fatura); o envio ao vivo requer a extensão de provedor da sua jurisdição — confirme o que está disponível para o seu país com a REDA.

O contrato de fatura eletrônica, método a método

MétodoAssinaturaContrato
submitglobal abstract EInvoiceResult submit(refin__E_Invoice_Trail__c trail, SObject sourceDocument)O documento de origem é um refin__Sales_Invoice__c ou refin__Purchase_Invoice__c; o provedor monta o XML/JSON da jurisdição e chama a API governamental; o núcleo atualiza o Histórico a partir do resultado
checkStatusglobal abstract EInvoiceResult checkStatus(refin__E_Invoice_Trail__c trail)Consulta para autoridades assíncronas que respondem depois
cancelglobal abstract EInvoiceResult cancel(refin__E_Invoice_Trail__c trail)"Jurisdiction-specific rules apply (e.g. Brazil NF-e cancellation within 24h, Mexico CFDI cancellation with receiver acceptance)."

Os três retornam um EInvoiceResult — membros: success, status, fiscalUUID, fiscalNumber, responseCode, responseMessage, xmlPayload, responsePayload, errorMessage.

Os objetos de fatura eletrônica — referência de campos

Campo de refin__E_Invoice_Setup__cFunção
Entity__c · Country_Code__c · Environment__c · Is_Active__cQual empresa, qual jurisdição, teste vs. produção, ativado/desativado
Provider__cApenas nome de exibição
Provider_Class__cA classe Apex totalmente qualificada que estende refin.EInvoiceProvider (exemplo do próprio campo: sovos.SovosEInvoiceProvider)
Document_Types__cSeleção múltipla: Fatura de venda / Nota de crédito / Fatura de compra / Nota de crédito de fornecedor — o "core package checks this field when determining whether to create an E-Invoice Trail record"
Auto_Submit_On_Post__cLiteral: "When checked, posting a Sales Invoice or Purchase Invoice automatically creates an E-Invoice Trail record in Draft status, triggering the asynchronous submission process. When unchecked, e-invoice submission must be initiated manually via a quick action or API call."

O registro refin__E_Invoice_Trail__c é a linha de auditoria de cada envio: referências à configuração e à fatura de origem, Document_Type__c, Status__c, Fiscal_UUID__c, Fiscal_Number__c, XML_Payload__c, os campos de resposta (Response_Code__c/Message__c/Payload__c/Date__c), Submitted_Date__c, Retry_Count__c e Provider_Document_Id__c — a cadeia de evidências que os reguladores exigem, uma linha por tentativa. Status__c tem oito valores: Draft, Ready to Send, Queued, Submitted, Accepted, Rejected, Cancelled, Error.

Por que contratos em vez de recursos prontos? APIs bancárias e autoridades fiscais variam por país e mudam em seus próprios cronogramas. Um contrato global estável permite que pacotes especializados evoluam no seu próprio ritmo — e permite que sua organização troque de provedor mudando um registro de configuração, sem reimplementar a parte bancária.

Interfaces de capacidade opcionais — como um contrato congelado ainda cresce

O refin.EInvoiceProvider foi publicado como classe abstrata global em uma versão Managed-Released, o que significa que nenhum método pode mais ser adicionado a ele. Em vez de congelar o framework junto com ele, a REDA adiciona o comportamento novo como interfaces globais separadas, algo que o Salesforce permite. Um provedor estende EInvoiceProvider e implementa as interfaces de capacidade que suporta; o núcleo detecta o suporte com instanceof e simplesmente pula a capacidade para os provedores que não a implementam.

InterfaceMétodosImplemente quando
refin.EInvoiceQueueProviderdrain(setup, maxRecords) retornando List<EInvoiceEvent>; acknowledge(setup, events)Sua autoridade fiscal responde por uma fila de notificações em vez de uma resposta síncrona. Um único drain carrega as duas direções — atualizações de status de saída e documentos de fornecedor de entrada — diferenciadas por EInvoiceEvent.processType. Deliberadamente não existe um método separado para "buscar entrada".
refin.EInvoiceDocumentProviderfetchDocuments(trail) retornando List<EInvoiceDocument>Você recupera os artefatos legais (XML assinado, resposta da autoridade, uma representação imprimível como o DANFE brasileiro) sob demanda em vez de entregá-los junto com o evento. Dispense-a se seus eventos já trazem documents.
refin.EInvoiceProvisionerprovisionOrganization(setup, args); provisionCompany(setup, args), ambos retornando EInvoiceProvisionResultVocê suporta o provisionamento self-service das estruturas de conta do lado da autoridade a partir do próprio aplicativo. É uma capacidade de fase posterior: hoje essas estruturas são criadas manualmente pelo provedor de conformidade. Ela é declarada agora justamente porque uma API global já publicada não pode ser estendida depois.
Confirme só depois de ter persistido. O núcleo chama acknowledge apenas quando cada evento já está armazenado de forma durável; confirmar antes perderia a notificação para sempre. Um provedor não deve habilitar nenhum modo de confirmação automática que se antecipe a essa chamada, e drain deve devolver somente notificações não confirmadas, para que drains sucessivos avancem.

Os três tipos de dados que elas trocam

  • refin.EInvoiceEvent: um marco na vida de um documento perante a autoridade. O núcleo o correlaciona com uma trilha por erpDocumentId, um valor que o seu provedor carimba no envelope de saída e que a autoridade devolve. O status é normalizado para Accepted, Rejected, Cancelled ou InProgress: o núcleo baseia as novas tentativas e os estados terminais nesse campo, nunca no responseCode bruto. Também carrega notificationId, processType (Outbound / Inbound), responseMessage, fiscalUUID, fiscalNumber, uma lista opcional documents, payload e eventDate.
  • refin.EInvoiceDocument: um artefato, com title, fileExtension ('xml' ou 'pdf'), base64Body e documentKind ('Legal', 'LegalResponse' ou 'Representation'). O núcleo o decodifica e o anexa à trilha e à fatura de origem como arquivos do Salesforce, para que os usuários vejam os artefatos em conformidade no registro com que já trabalham.
  • refin.EInvoiceProvisionResult: success (que por padrão é false), externalId (o identificador do lado do provedor) e message.

documentKind, processType e status são todos String e não enums, deliberadamente, para que o conjunto permitido possa crescer sem quebrar uma assinatura global congelada. Não faça um switch exaustivo sobre eles: trate os valores que você conhece e deixe os demais passarem.

Erros comuns a evitar

ErroPor que prejudicaFaça isto em vez disso
Erros de digitação em Provider_Class__cA resolução em tempo de execução é feita pelo nome — uma string errada faz o provedor simplesmente nunca rodarCopie o nome totalmente qualificado (namespace.NomeDaClasse) da documentação da extensão; teste a conexão imediatamente
Confiar em Provider__c para trocar de provedorÉ apenas um rótulo de exibição; "The actual integration logic is determined by Provider_Class__c, not this field."Altere Provider_Class__c; atualize o rótulo para os humanos
Armazenar credenciais de autoridades/bancos nos registros de configuraçãoO contrato é explícito: "Authentication and API credentials are managed entirely by the extension package"As credenciais vivem nas credenciais nomeadas próprias da extensão, governadas pela segurança da sua organização
Construir o código da sua organização contra os internos de um pacote de provedorPacotes de provedor evoluem em seu próprio cronograma — apenas os contratos globais refin. são a costura estávelIntegre por meio dos registros de configuração e dos históricos; trate o provedor como uma caixa-preta
Presumir detalhes de orquestração sem testar sua versãoO comportamento de agendamento e envio automático depende da versãoVerifique o agendamento de sincronização e o comportamento de envio automático em um sandbox nas suas versões instaladas antes de prometê-los ao negócio

Para equipes que constroem uma extensão

  • Implemente a classe abstrata no namespace do seu pacote; registre o nome de classe totalmente qualificado no registro de configuração.
  • Seja responsável pelas suas credenciais (credenciais nomeadas no seu pacote), pelo seu mapeamento de API, pela sua semântica de erros — retorne resultados honestos; o núcleo os exibe em Sync Status e nos históricos.
  • Programe apenas contra o contrato — a superfície global documentada é a estável (as regras).

O que vem a seguir

  1. Importação de extratos bancários — para onde os feeds fluem.
  2. Integrações do AppExchange — o panorama mais amplo do ecossistema.
  3. Desenvolvimento em Apex na REDA — as regras da superfície global.

Perguntas frequentes

O contrato foi projetado para o ecossistema de agregadores (Plaid, Belvo e afins são os arquétipos que ele nomeia). Pergunte à REDA quais extensões de provedor estão disponíveis atualmente para sua região — a disponibilidade evolui mais rápido do que a documentação.

O contrato resolve a classe implementadora pelo nome, então uma implementação local na organização é tecnicamente endereçável — sensata para uma API bancária sob medida. Empacote-a corretamente se ela vier a sobreviver a uma única organização.

Varia país a país (Brasil, México, Itália e Arábia Saudita lideram; muitos seguem). Seu consultor tributário responde pelo "se devemos"; a configuração + a extensão do provedor respondem pelo "como".

BankFeedResult informa success, transactionsImported, updatedCursor (onde a próxima sincronização retoma), currentBalance e errorMessage — os valores padrão são honestos (success=false, zero importado), para que um provedor descuidado não relate vitória por acidente. EInvoiceResult traz a resposta da autoridade: identificadores fiscais, payloads de resposta e o texto do erro quando ela recusou.

É a saúde da conexão em uma visão rápida — Active / Paused / Error / Disconnected. A própria orientação do campo para o estado ruim: "Error: last sync failed — check Audit Log for details." Disconnected é definido pelo núcleo depois que o disconnect do seu provedor é concluído.

Isso foi útil?