Do lead à receita: um contrato de eventos para resultados comerciais
Defina identidade, valor, moeda, datas e correções para resultados comerciais, com um contrato proposto e um teste local sem envio a plataformas.
Para conectar um lead à receita, registre o resultado comercial com identidade estável, significado explícito e vínculo verificável ao negócio. Um contrato comum organiza esses dados, mas não transforma oportunidade ganha em pagamento nem comprova atribuição ou entrega a anúncios. Este artigo propõe um contrato editorial, não uma nova API ClickTrail.
Resumo: Um evento comercial precisa dizer o que aconteceu, em qual objeto, quando e sob qual origem confiável. Valor e moeda devem conservar sua unidade; ganho, pagamento e reembolso são fatos diferentes. O contrato proposto abaixo inclui identidade, proveniência e versão. Um teste local rejeita exemplos inválidos, enquanto autenticação, persistência, consentimento operacional e aceitação externa continuam exigindo provas próprias.
Por FunnelSheet. Revisão técnica: 15 de setembro de 2026. Conflito de interesse: a FunnelSheet desenvolve e divulga ClickTrail. Os exemplos são sintéticos; não representam receita de clientes nem uma integração implantada.
Qual resultado comercial o evento representa?
O evento deve representar um fato definido pelo sistema responsável. Cadastro, qualificação, oportunidade ganha, pagamento e reembolso precisam de nomes distintos no seu contrato. A escolha determina o que pode ser somado e qual documento permite conferir o resultado.
Considere uma oportunidade hipotética de R$ 8.000. O vendedor marca o negócio como ganho na segunda-feira; o cliente paga R$ 2.000 na sexta-feira. O relatório de valor contratado pode registrar R$ 8.000. O de dinheiro recebido registra R$ 2.000. Somar os dois como receita gera R$ 10.000 sem que esse valor tenha ocorrido em qualquer dessas medidas.
No exemplo público Twenty da ClickTrail, o estágio won produz o nome Purchase. Esse comportamento de código não comprova pagamento. Quem adotar o exemplo precisa decidir se o mapeamento comercial serve ao próprio negócio antes de utilizá-lo em relatórios.
Para entender as ligações anteriores ao resultado, consulte a visão de atribuição entre Twenty e Chatwoot. Aqui, o foco é o contrato do fato comercial depois que essas associações já existem.
Quais identidades impedem contar o mesmo fato duas vezes?
Separe a identidade do evento, do objeto comercial e da pessoa. Um contato pode participar de vários negócios; um negócio pode gerar vários pagamentos. Usar apenas o contato como chave eliminaria operações legítimas. Usar um número aleatório a cada tentativa contaria novamente o mesmo fato.
Nesta proposta, a chave de evento combina escopo da organização, objeto e ocorrência comercial. O exemplo demo:op-17:won:1 identifica o primeiro ganho da oportunidade fictícia op-17, dentro do escopo demo. O identificador deve nascer de dados confiáveis no servidor. Um campo oculto de formulário não pode conceder autoridade sobre uma oportunidade.
| Identidade proposta | Pergunta respondida | Exemplo sintético |
|---|---|---|
eventId |
Qual ocorrência estou processando? | demo:op-17:won:1 |
objectId |
Qual negócio originou o fato? | op-17 |
tenantId |
De qual organização é o registro? | demo |
| Vínculo da pessoa | Quem está associado ao negócio? | Registro separado no CRM |
O vínculo da pessoa fica fora do exemplo mínimo porque o teste não consulta um CRM. Em produção, confira a associação no sistema responsável, incluindo o escopo da organização. O guia para preservar identificadores do formulário ao CRM trata dessa fronteira de transporte.
Como preservar data, valor e moeda sem mudar o significado?
Registre a data do fato separadamente da data de recebimento. Para dinheiro, explicite moeda e unidade antes de converter o valor. Neste contrato restrito a BRL, amountMinor: 800000 representa R$ 8.000,00; não representa oitocentos mil reais nem um valor convertido de dólares.
A proposta usa um inteiro seguro em centavos para evitar arredondamentos intermediários de uma soma financeira. Isso é uma decisão deste exercício. Não é uma regra universal para todas as moedas, nem o formato garantido de uma API externa. Cada adaptador precisa converter para o formato exigido pelo destino e testar a conversão.
O evento hipotético ocorreu em 2026-09-15T08:00:00.000Z e foi recebido cinco segundos depois. Essa diferença pode ajudar a investigar atraso. Ela não deve mudar a competência do resultado automaticamente. Se um reprocessamento acontece amanhã, conservar a data original evita deslocar o fato para outro período por acidente.
Também é preciso distinguir zero de ausência. Uma oportunidade sem valor definido não vira uma venda de zero reais só para satisfazer um campo numérico. O contrato abaixo exige valor para o resultado escolhido e rejeita moeda ausente; outros tipos de evento poderiam ter regras diferentes.
Como validar um evento proposto com um teste local?
O código abaixo valida apenas um contrato BRL de oportunidade ganha. Ele rejeita identidade fora do conjunto sintético confiável, data inválida, moeda ausente e valor inadequado. A lista confiável é um substituto explícito da consulta ao CRM, não um mecanismo de autenticação.
Salve o bloco completo como contrato.mjs e execute node contrato.mjs. Foi executado com Node.js v24.15.0. Não há dependências, credenciais ou chamadas de rede. A saída esperada é B09: contrato local OK.
import assert from 'node:assert/strict';
const known = new Set(['demo:op-17']);
function validate(e) {
assert.equal(e.schemaVersion, 1);
assert.equal(e.type, 'opportunity.won');
assert(known.has(`${e.tenantId}:${e.objectId}`));
assert.equal(e.eventId, `${e.tenantId}:${e.objectId}:won:1`);
for (const key of ['occurredAt', 'receivedAt']) {
const time = Date.parse(e[key]);
assert(Number.isFinite(time));
assert.equal(new Date(time).toISOString(), e[key]);
}
assert.equal(e.currency, 'BRL');
assert(Number.isSafeInteger(e.amountMinor) && e.amountMinor >= 0);
return e;
}
const event = {
schemaVersion: 1, type: 'opportunity.won', tenantId: 'demo',
objectId: 'op-17', eventId: 'demo:op-17:won:1',
occurredAt: '2026-09-15T08:00:00.000Z',
receivedAt: '2026-09-15T08:00:05.000Z',
amountMinor: 800000, currency: 'BRL'
};
assert.equal(validate(event).amountMinor, 800000);
for (const change of [
{ currency: undefined }, { occurredAt: 'ontem' },
{ objectId: 'intruso' }, { amountMinor: NaN }
]) assert.throws(() => validate({ ...event, ...change }));
console.log('B09: contrato local OK');
O teste força o formato UTC com milissegundos para manter a comparação reproduzível. Um consumidor que aceita outros formatos precisaria normalizá-los antes desse contrato. O código não controla atrasos máximos, eventos futuros ou reabertura de negócios; essas regras dependem do processo escolhido.
Onde entram proveniência e permissão de uso?
Proveniência descreve de onde veio uma associação; permissão determina se ela pode ser usada naquela finalidade. Não transforme a existência de um GCLID, de um e-mail ou de um referrer em autorização automática. O registro comercial e a exportação publicitária podem ter condições operacionais diferentes.
Como extensão proposta, guarde uma referência à submissão original, a regra de associação e a versão da política aplicada. Evite copiar toda a conversa ou todos os campos do cliente para o evento. Um identificador que permita consultar a evidência autorizada costuma ser mais auditável do que espalhar dados pessoais entre destinos.
Se o negócio não tiver origem associada, conserve o resultado com origem desconhecida. Excluí-lo do total só porque faltou atribuição altera a medida comercial. O total financeiro precisa continuar reconciliável; a parcela atribuída é uma classificação adicional, sujeita à regra de associação escolhida.
Antes da exportação, verifique novamente a condição aplicável. A decisão registrada na captura pode ter mudado. Este artigo define uma separação de responsabilidades; não implementa uma política de consentimento nem oferece uma conclusão jurídica sobre qualquer operação.
Como tratar repetição, correção e reembolso?
Repetir uma entrega deve conservar a identidade do fato. Corrigir um valor deve deixar uma trilha que explique a alteração. Um reembolso precisa apontar para a transação correspondente, sem apagar silenciosamente o evento original ou reutilizar o identificador como se nada tivesse mudado.
No exemplo de R$ 8.000, uma segunda tentativa do mesmo ganho continua com demo:op-17:won:1. Uma correção para R$ 7.500 exige uma política explícita: nova revisão ligada ao fato anterior, ou atualização controlada com histórico. Os consumidores devem saber se recebem o valor substituto ou a diferença de R$ 500. Misturar essas duas convenções produz totais errados.
Para pagamentos parcelados, cada pagamento recebe identidade própria. O ganho da oportunidade não deve ser reutilizado como chave de todas as parcelas. Reabertura e novo ganho também exigem uma definição de ocorrência: a política pode restaurar o mesmo fato corrigido ou reconhecer um novo ciclo, mas não pode depender de quantas notificações chegaram.
O teste mostrado valida formato; não implementa um livro de eventos persistente. Uma restrição de unicidade e uma transação de armazenamento são provas adicionais necessárias quando vários trabalhadores podem processar a mesma entrega.
O contrato comum substitui os adaptadores dos destinos?
O contrato reduz traduções repetidas, mas cada destino continua com seus requisitos. Identidade comercial, elegibilidade, datas e respostas precisam de adaptação. Organizar N origens e M destinos ao redor de um formato comum não elimina autenticação, diferenças semânticas nem tratamento de falhas.
A documentação Google sobre conversões offline separa configuração, construção dos dados, importação e diagnóstico. Na consulta de 15 de setembro de 2026, também orienta novos casos afetados pela restrição de acesso de junho de 2026 a usar Data Manager API. Portanto, um payload genérico não é uma instrução de instalação nem garantia de compatibilidade com uma conta.
No código do MCP ClickTrail, as ferramentas de envio constroem payloads sem efeitos externos, e a consulta de status informa unknown. O guia de diagnóstico local com MCP explica como usar essa camada sem confundi-la com um recibo de entrega.
Como versionar e aceitar a primeira implementação?
A primeira versão deve ter um produtor, um consumidor e casos de compatibilidade verificáveis. Só amplie o contrato depois de demonstrar que ambos interpretam a mesma ocorrência, unidade monetária e política de repetição.
- Escolha um resultado comercial e nomeie seu sistema responsável.
- Documente campos obrigatórios, unidade, escopo e origem de cada identidade.
- Execute o caso válido e as rejeições antes de conectar transporte.
- Preserve fixtures da versão anterior quando mudar o contrato.
- Verifique persistência e associação ao negócio em ambiente controlado.
- Avalie a resposta do destino separadamente, quando houver integração autorizada.
A entrega deste exercício é um vocabulário operacional acompanhado de uma validação mínima. O próximo passo é comparar esse contrato com um objeto real do seu CRM e decidir quais campos têm evidência suficiente. Só depois faz sentido construir o adaptador que os transportará.