12 min de leitura
salesforce
integração
arquitectura
saas
api

Integrar Salesforce com uma aplicação interna sem criar dívida

Guia prático para integrar Salesforce com uma aplicação interna: APIs, OAuth, eventos, limites, modelos de dados e erros comuns em produção.

Duas pessoas conversam na copa do escritório com cafés e um contrato de dados impresso no balcão.
  • Integrar Salesforce bem começa por decidir quem é a fonte de verdade: Salesforce, a aplicação interna, ou um modelo partilhado com regras explícitas.
  • Para a maioria das aplicações internas, REST API com OAuth 2.0 e External IDs chega. Bulk API 2.0 e eventos entram quando há volume, latência assíncrona ou sincronização contínua.
  • O maior erro não é técnico. É mapear objectos Salesforce como se fossem tabelas normais e ignorar permissões, Record Types, picklists, automações e limites de API.
  • Não faças chamadas síncronas a Salesforce dentro de fluxos críticos sem fallback. Trata Salesforce como sistema externo: lento, limitado e ocasionalmente indisponível.
  • Uma boa integração precisa de fila, idempotência, auditoria, reconciliação e observabilidade desde o início. Sem isso, vais descobrir erros pelos utilizadores.

1. Antes de escrever código, define o contrato de dados

A pergunta “como integrar Salesforce com uma aplicação interna?” parece uma pergunta de API. Na prática, é uma pergunta de arquitectura de dados.

Salesforce raramente é apenas uma base de dados de CRM. Tem validações, workflows, flows, triggers Apex, permissões por perfil, campos calculados, layouts, Record Types, objectos standard e objectos customizados. Se a tua aplicação interna tratar Salesforce como uma tabela remota chamada accounts, vais criar uma integração frágil.

O primeiro passo é responder a quatro perguntas.

Primeiro: quem é a fonte de verdade para cada entidade?

Por exemplo, uma aplicação interna de billing pode ser a fonte de verdade para planos, facturas e estados de pagamento. Salesforce pode ser a fonte de verdade para contas, oportunidades e owners comerciais. Mas há campos cinzentos: morada fiscal, VAT ID, segmento, estado do cliente, data de activação. Se estes campos forem editáveis nos dois lados sem regra, vais ter divergências.

Segundo: qual é a direcção da sincronização?

Há integrações unidireccionais, como “quando um cliente é criado na aplicação interna, criar ou actualizar Account e Contact em Salesforce”. Há integrações bidireccionais, como “alterações de owner em Salesforce devem reflectir-se na aplicação interna”. Bidireccional parece apelativo, mas aumenta muito a complexidade. Precisas de resolução de conflitos, timestamps fiáveis, ownership por campo e reconciliação.

Terceiro: qual é a latência aceitável?

Se a equipa comercial precisa de ver uma activação em Salesforce nos próximos 5 minutos, não precisas de uma integração síncrona. Um job assíncrono chega e é mais previsível. Se um utilizador não pode avançar no checkout sem validar um estado em Salesforce, estás a pôr uma dependência externa no caminho crítico. Isso deve ser uma decisão consciente, não um acidente.

Quarto: qual é o identificador estável?

Nunca dependas apenas do Name de uma Account ou do email de um Contact. Usa External IDs em Salesforce. Um campo como Internal_Customer_Id__c, marcado como External ID e idealmente Unique, permite fazer upsert sem procurar primeiro o registo. Isto reduz chamadas de API e evita duplicados.

Na Impact Origin, quando desenhamos integrações deste tipo, insistimos neste documento de contrato antes da implementação. Não precisa de ter 40 páginas. Mas tem de dizer, campo a campo, origem, destino, direcção, obrigatoriedade, transformação e regra de conflito.

2. Escolher o padrão de integração certo

Há quatro padrões principais para integrar uma aplicação interna com Salesforce. A escolha errada normalmente aparece mais tarde como timeouts, custos operacionais ou dados duplicados.

REST API directa

É a opção mais comum. A aplicação interna chama a Salesforce REST API para criar, actualizar, consultar ou apagar registos. A documentação oficial está em https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/.

Funciona bem para volumes moderados, operações imediatas e equipas que querem controlo sobre o código. Em Node.js 22 LTS, Python 3.12.NET 8 ou Java 21, a integração é directa. O ponto crítico é não espalhar chamadas Salesforce por toda a codebase. Cria um módulo ou serviço dedicado, com retries, logging, normalização de erros e limites.

Prós: simples, controlo total, fácil de testar, sem fornecedor intermédio.

Contras: tens de gerir OAuth, rate limits, retries, paginação, idempotência e observabilidade.

Bulk API 2.0

Quando tens dezenas ou centenas de milhares de registos, REST deixa de ser a ferramenta certa. Bulk API 2.0 é assíncrona, trabalha por jobs e é indicada para importações, migrações e sincronizações massivas. A documentação oficial está em https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/bulk_api_2_0.htm.

Usaria Bulk API 2.0 para carregar 500.000 Accounts, actualizar estados de 2 milhões de subscrições, ou fazer reconciliações nocturnas. Não a usaria para uma alteração interactiva feita por um utilizador.

Prós: preparada para grandes volumes, menos pressão em chamadas REST individuais, modelo assíncrono.

Contras: feedback não imediato, tratamento de erros por ficheiro ou job, mais complexidade operacional.

Platform Events e Change Data Capture

Se queres reagir a alterações em Salesforce, Platform Events e Change Data Capture são boas opções. Em vez de fazer polling a cada minuto, subscreves eventos. Isto reduz chamadas e melhora a frescura dos dados. A documentação está em https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/ e https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/.

Usaria CDC para reflectir alterações de Account, Contact ou Opportunity numa aplicação interna. Mas não assumiria que isto substitui reconciliação. Eventos podem chegar fora de ordem, podem falhar no consumidor, e há janelas de retenção. Precisas de guardar checkpoints.

Prós: bom para sincronização contínua, reduz polling, separa sistemas.

Contras: exige consumidor persistente, gestão de replay IDs, reconciliação e atenção a limites de retenção.

iPaaS, como MuleSoft, Workato, Make ou Zapier

Pode fazer sentido quando a equipa não tem capacidade técnica ou quando a integração é simples e não crítica. Para workflows internos pequenos, é aceitável. Para processos core, com regras de negócio complexas, tenho reservas. O problema não é a ferramenta. É a lógica de negócio crítica ficar escondida em fluxos visuais difíceis de versionar, testar e rever.

Prós: arranque rápido, conectores prontos, útil para operações internas.

Contras: debugging limitado, custos crescem com volume, versionamento e testes podem ser fracos, risco de lógica crítica fora do código principal.

A minha opinião: se a integração afecta billing, onboarding, compliance ou operações principais, escreve-a como parte da tua plataforma, com disciplina de engenharia. Se é uma automação lateral para uma equipa pequena, um iPaaS pode ser suficiente.

3. Autenticação: OAuth sem atalhos perigosos

Salesforce suporta vários fluxos OAuth 2.0. A escolha depende do tipo de aplicação.

Para uma aplicação interna server-side, o padrão mais limpo costuma ser OAuth 2.0 JWT Bearer Flow ou Web Server Flow com refresh token guardado de forma segura. Evita username-password flow, mesmo que pareça mais rápido. Está documentado, mas é uma má escolha para produção porque incentiva armazenamento de credenciais humanas e cria problemas com MFA, rotação e auditoria.

O JWT Bearer Flow funciona bem quando tens uma integração server-to-server. Configuras uma Connected App em Salesforce, associas um certificado, concedes permissões e emites tokens sem intervenção humana. A documentação oficial está em https://help.salesforce.com/ e na secção OAuth da plataforma Salesforce.

Pontos práticos que não deves ignorar:

  • Cria um utilizador técnico dedicado para a integração.
  • Dá permissões mínimas, não perfil de System Administrator por preguiça.
  • Usa Permission Sets específicos para os objectos e campos necessários.
  • Guarda segredos em AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, Doppler ou Vault. Não em variáveis soltas sem rotação.
  • Regista o client_id, user, scope, data de expiração e ambiente.
  • Se tens sandbox e produção, usa Connected Apps e certificados separados.

Uma armadilha comum: a integração funciona em sandbox com um utilizador admin e falha em produção com INSUFFICIENT_ACCESS_OR_READONLY. Isto acontece porque Field-Level Security e permissões por objecto contam na API. A API não é um bypass mágico às regras de Salesforce. Testa com o utilizador técnico real, não com o teu utilizador de administrador.

4. Modelar upserts, idempotência e erros

A operação mais importante numa integração Salesforce é o upsert. Criar sempre é perigoso. Actualizar sempre exige descobrir o Salesforce ID. Upsert por External ID é o meio-termo certo.

Exemplo com REST API, assumindo API version v61.0. Confirma a versão suportada no teu org em Setup ou na documentação actual.

curl -X PATCH \
  "https://your-instance.my.salesforce.com/services/data/v61.0/sobjects/Account/Internal_Customer_Id__c/cus_12345" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "Name": "ACME Ltd",
    "BillingCountry": "PT",
    "Customer_Status__c": "active"
  }'

Este padrão evita uma pesquisa prévia por Internal_Customer_Id__c. Se existir, actualiza. Se não existir, cria. Para entidades internas como clientes, subscrições ou unidades operacionais, isto é quase sempre preferível.

Mas upsert não resolve tudo. Precisas de idempotência ao nível da tua aplicação. Se um job falhar depois de enviar a alteração para Salesforce mas antes de marcar a operação como concluída, vai tentar novamente. Isso deve ser seguro. External IDs ajudam, mas também deves guardar eventos de integração.

Um esquema simples em PostgreSQL 16 pode chegar:

create table integration_events (
  id bigserial primary key,
  provider text not null,
  entity_type text not null,
  entity_id text not null,
  event_type text not null,
  payload jsonb not null,
  status text not null check (status in ('pending', 'processing', 'done', 'failed')),
  attempts integer not null default 0,
  last_error text,
  created_at timestamptz not null default now(),
  processed_at timestamptz
);

create index integration_events_pending_idx
  on integration_events (provider, status, created_at);

Isto não é uma plataforma de mensageria completa, mas dá auditabilidade. Em sistemas maiores, usaria uma fila dedicada como SQS, RabbitMQ, Kafka, BullMQ sobre Redis, ou pgmq sobre PostgreSQL, dependendo do contexto. O ponto é simples: não deixes a integração depender apenas de chamadas HTTP espalhadas.

Também tens de classificar erros.

Erros 400 por validação de campos não devem ser repetidos infinitamente. Devem ir para dead letter com mensagem clara. Erros 401 pedem refresh de token ou intervenção de credenciais. Erros 403 indicam permissões. Erros 429 ou limites de API pedem backoff e redução de throughput. Erros 5xx pedem retry com jitter.

Em termos de latência, desenha como se uma chamada REST a Salesforce pudesse demorar entre 300 ms e 1200 ms em p95, dependendo da rede, automações internas e carga do org. Não prometas p99 de 100 ms num fluxo dependente de Salesforce. Se precisas de resposta imediata ao utilizador, grava localmente, enfileira a sincronização e mostra estado “a sincronizar”.

5. Limites de API, paginação e volume

Salesforce tem limites. E esses limites não são detalhe. São parte da arquitectura.

Os limites diários de API dependem da edição, licenças e add-ons do org. Não assumas um número fixo. Vai a Setup, procura “System Overview” e confirma. Também deves monitorizar o endpoint de limites da REST API, documentado em Salesforce, através de /services/data/vXX.X/limits.

Em REST, uma query SOQL pode devolver resultados paginados. O primeiro lote pode trazer até 2000 registos, e depois tens de seguir o nextRecordsUrl. Equipas que ignoram isto acabam com sincronizações incompletas e bugs silenciosos.

Também há limites em Composite API. A Composite API pode agrupar múltiplas subrequests, o que reduz overhead de HTTP, mas não a transforma numa transacção universal sem custos. Confirma limites actuais na documentação oficial antes de desenhar o batch. E atenção ao allOrNone: pode ser útil, mas também pode fazer falhar um conjunto inteiro por causa de um campo inválido num único registo.

Para volume, gosto desta regra prática:

  • Até algumas centenas de alterações por dia: REST simples com jobs chega.
  • Milhares a dezenas de milhares por dia: REST com fila, batching e backoff.
  • Centenas de milhares ou milhões: Bulk API 2.0 e reconciliação assíncrona.
  • Alterações frequentes originadas em Salesforce: CDC ou Platform Events.

Polling constante é o padrão que tento evitar. Fazer uma query a Salesforce a cada 30 segundos para descobrir alterações parece simples, mas consome API, perde eventos entre janelas se a query for mal feita, e cria pressão operacional. Se tiveres mesmo de fazer polling, usa campos SystemModstamp, paginação correcta, checkpoints persistidos e janelas sobrepostas para tolerar atrasos.

6. Mapeamento de dados: onde as integrações morrem devagar

A parte mais subestimada é o mapeamento de campos.

Salesforce tem objectos standard como Account, Contact, Lead, Opportunity, Case e Product2. Mas cada org real tem custom fields, validações, picklists e Record Types. O mesmo campo pode ser obrigatório para um Record Type e irrelevante para outro. Uma picklist pode aceitar Active em sandbox e Activo em produção porque alguém alterou valores manualmente. Isto acontece.

Armadilhas comuns que aparecem em produção:

  • Picklists com valores diferentes entre sandbox e produção.
  • Campos obrigatórios impostos por validation rules, não pelo schema visível.
  • Flows que alteram campos depois da API gravar o registo.
  • Triggers Apex que falham para volumes maiores.
  • Contactos duplicados porque email foi tratado como identificador único.
  • Timezones mal tratadas em datas de renovação, sobretudo com date versus datetime.
  • Moedas e países guardados em texto livre numa aplicação e como picklist em Salesforce.
  • Sandboxes desactualizadas face à produção.

A solução é tratar o mapeamento como contrato versionado. Guarda-o em repositório. Revê alterações com a equipa que administra Salesforce. Se possível, cria testes de contrato que validem campos obrigatórios, picklists e permissões contra uma sandbox.

Também recomendo criar uma página interna de “estado de integração”. Deve mostrar últimos eventos processados, falhas, payload resumido, Salesforce ID, External ID e botão de retry controlado. Isto poupa horas à equipa de suporte e evita que engenharia seja chamada para cada erro de validação.

Outro ponto importante: não copies todo o objecto Salesforce para a tua base de dados só porque é possível. Sincroniza os campos que a tua aplicação precisa. Quanto maior o espelho local, maior a superfície de inconsistência.

7. Plano de implementação recomendado

Um plano prático para integrar Salesforce com uma aplicação interna seria este.

Primeiro, faz o inventário. Lista entidades, campos, direcção de sincronização, fonte de verdade, volume esperado, latência aceitável e regras de conflito. Inclui também quem pode alterar cada campo em cada sistema.

Segundo, prepara Salesforce. Cria Connected App, utilizador técnico, Permission Sets, External IDs e campos necessários. Confirma Record Types, validation rules, flows e triggers relevantes. Não deixes isto para o fim.

Terceiro, implementa um cliente Salesforce isolado na aplicação interna. Deve tratar autenticação, refresh ou emissão de tokens, retries, backoff, normalização de erros e métricas. O resto da aplicação não deve conhecer detalhes da REST API.

Quarto, cria a camada de eventos ou fila. Cada alteração relevante deve gerar um evento persistido. O worker processa, chama Salesforce e actualiza estado. Para baixa escala, uma tabela em PostgreSQL pode chegar. Para maior escala, usa uma fila dedicada.

Quinto, implementa reconciliação. Mesmo com eventos, precisas de um job periódico que compare amostras ou conjuntos completos. Por exemplo, clientes activos na aplicação interna que não têm Internal_Customer_Id__c em Salesforce, ou Accounts em Salesforce sem correspondência local. Isto detecta falhas silenciosas.

Sexto, observa. Métricas mínimas: eventos pendentes, eventos falhados, tentativas médias, latência por chamada, taxa de erros por código HTTP, consumo de API limits, idade do evento mais antigo por processar. Logs devem incluir correlation ID, entidade interna, Salesforce object, operação e erro normalizado. Se usas OpenTelemetry, propaga trace IDs nos workers.

Sétimo, faz rollout por fases. Começa por leitura ou escrita de baixo risco. Depois activa upserts para um subconjunto de entidades. Só depois automatiza fluxos críticos. Ter um feature flag para desligar escrita em Salesforce é uma rede de segurança útil.

A minha preferência é começar simples, mas não simplista. REST API com OAuth, External IDs, fila e reconciliação cobre a maioria dos casos. Só introduziria CDC, Platform Events ou Bulk API quando o volume e a direcção dos dados justificam.

Conclusão

Integrar Salesforce com uma aplicação interna não é difícil por causa da API. É difícil porque estás a ligar dois modelos de negócio com regras, donos e ritmos diferentes. Decide a fonte de verdade, usa External IDs, evita dependências síncronas desnecessárias e constrói auditoria desde o primeiro dia.

Se estás a enfrentar um problema parecido, marca uma conversa em https://impact-origin.com/agendamento.

Impact OriginGostaste deste artigo?Na Impact Origin ajudamos fundadores e equipas a construir e escalar software à medida, do MVP da startup ao próximo passo. Se tens um projeto em mente, vamos falar.
Integrar Salesforce com uma aplicação interna sem criar