Documentation Carregando eventos

Capture Leads e use a API de Leads

Um Lead é uma pessoa que deixou contato em um dos seus sites, guardada no seu próprio Node. Este artigo vai do power-up Leads desligado até um Lead capturado por um formulário e atualizado pelo seu servidor, e mostra como provar cada passo.

Ele é escrito para dois leitores ao mesmo tempo: o operador que configura o Node e o Console, e o desenvolvedor que liga um formulário ou um CRM. Você não precisa saber o que é uma Property nem o que é um identificador do Node antes de começar.

O que é um Lead no seu Node

  • Uma linha por pessoa por Property. Uma captura seguinte da mesma pessoa atualiza o mesmo Lead: o contador de capturas sobe e a última vez avança. A mesma pessoa em duas Properties são dois Leads.
  • O primeiro toque é escrito uma vez. As UTMs, a página de entrada e o domínio do referrer da primeira captura são gravados na criação do Lead, e nunca mais reescritos. Só o domínio do referrer é guardado, nunca a URL completa de origem.
  • A identidade não mora no Lead. Nome, e-mail, telefone, empresa, cargo e endereço ficam com a identidade da pessoa no seu Node e são lidos por um join. O Lead em si carrega os campos de pipeline.
  • Sandbox fica separado. Uma captura feita com o Node em modo sandbox nunca altera um Lead real, e um Lead de sandbox nunca aparece na lista.
  • É seu. Os Leads moram no seu Node. O navegador manda para o seu Node pelo loader, e o seu servidor posta direto no seu Node. Os servidores da Supreme nunca veem um Lead, um e-mail ou um telefone.

Ative o power-up Leads

Abra Settings no rodapé do menu lateral do Console, vá para a aba Núcleo do sistema e encontre a linha Leads dentro de Power-ups, logo abaixo do cartão de licença.

A linha mostra um de três estados:

Selo O que significa O que a linha diz
Ativo o Leads está no seu plano "Leads está ativo no seu plano."
Disponível o plano não pôde ser confirmado agora, e o Leads segue usável "Não conseguimos confirmar seu plano agora; o Leads segue disponível."
Indisponível o Leads não está no seu plano "Leads não faz parte do seu plano.", com Ver planos se você é o dono do Node e Peça ao dono do Node se não é

Disponível não é um Ativo degradado. Significa que o Console não conseguiu ler o seu plano naquele momento e escolheu manter o Leads usável em vez de te trancar fora dos seus próprios dados.

Se a entrada Leads não aparece na navegação do Console, é o Node que ainda não responde por Leads. O Console diz isso — "Este Node ainda não tem Leads." — e oferece Abrir Saúde do Node, onde você atualiza o Node. O resto do Console continua funcionando enquanto isso.

Se o Leads sair do seu plano

Seus leads, fontes e credenciais continuam intactos e legíveis. Novas configurações ficam bloqueadas até o Leads voltar ao seu plano.

É isso que acontece, e é só isso. Nada é apagado, pausado ou revogado, e o seu Node nunca é desligado. Seus Leads continuam listados e legíveis no Console, e uma credencial que você já emitiu continua sendo aceita pelo seu Node. O que para é configuração nova: os caminhos de captura deixam de ser oferecidos, então você não consegue gerar nem rotacionar credencial até o Leads voltar ao seu plano.

Capturar pelo navegador: um contrato, três caminhos

Os três caminhos produzem o mesmo evento canônico lead, então a forma dos campos, as regras e os códigos de erro são idênticos em qualquer um deles. A referência completa dos campos está na seção Eventos de Lead de O payload canônico de evento.

Os três precisam do loader na página, carregando o id da Property a que o Lead pertence. Veja Instale o Loader.

Três regras valem para os três caminhos:

  • Um lead precisa de e-mail ou telefone em context.user. Sem nenhum dos dois, o evento é recusado.
  • O conjunto de identidade estendido — full_name, company, job_title e os campos de endereço — é lido só em eventos lead. Qualquer outro evento continua lendo email, phone, first_name e last_name.
  • Nunca mande property_id, channel, action_source nem provider. Esses são do Node: a Property vem do ?pid= do loader, e o resto é carimbado pela via que recebeu o evento.

window.supremeSend à mão

Chame quando o seu formulário reportar sucesso, não quando o botão de enviar for clicado.

window.supremeSend({
  payload: {
    events: [{ name: 'lead', data: { params: {
      value: 150.5, currency: 'BRL',
      lead: { status: 'qualified', source: 'landing-page', source_lead_id: 'form-2026-0001',
              custom_fields: { plan_interest: 'pro', employees: 12, newsletter: true } }
    } } }],
    context: { user: { email: 'maria@example.com', phone: '+5511987654321',
                       first_name: 'Maria', last_name: 'Silva',
                       company: 'Acme', job_title: 'Head of Growth' } }
  }
});

Tudo dentro de params.lead é opcional. Um id de evento seu pode ir em id, ao lado de name, com até 50 bytes UTF-8.

Uma versão mínima desse trecho está pronta para copiar no Console, em Leads → Como capturar Leads → Browser/GTM.

O template do Google Tag Manager

Escolha Lead como evento. A tag então mostra um grupo Lead com Lead Status, Lead Source, Source Lead ID, Lead Value e Lead Currency, mais uma tabela Custom Fields com linhas de Key e Value. Os campos de identidade ganharam Full Name, Company, Job Title e Street Address 2.

A tag recusa, antes de enviar, todo Lead que o Node recusaria, e imprime o código da recusa no console de depuração do Preview. Você vê o problema no GTM em vez de descobrir um Lead faltando depois.

Veja Connect Google Tag Manager (em inglês).

A skill de Web Events

A partir da 1.3.0 a skill traz um padrão Contact Form Lead, que liga o envio de um formulário a um evento lead, com custom_fields incluído, e um validador que recusa um Lead com os mesmos códigos que o Node usa.

Veja Instale a skill de Web Events.

Campos canônicos e custom_fields

Os campos do produto têm nome; todo o resto é seu e vai em custom_fields.

Campo Regra Se você não mandar
params.lead.status um de new, contacted, qualified, won, lost new na criação. Um Lead existente mantém o status que tem: uma captura que o omite nunca o reseta
params.lead.source string que atende ^[a-z0-9][a-z0-9_.-]{0,63}$ o Node preenche o default do canal na criação do Lead — website pelo navegador, api pela API de Leads — e nunca reescreve depois
params.lead.source_lead_id 1 a 191 caracteres, sem caractere de controle fica vazio. Uma captura seguinte preenche só enquanto ainda estiver vazio; um valor diferente é ignorado
params.lead.custom_fields objeto raso, regras abaixo os campos já guardados ficam como estão
params.value número ≥ 0, em unidades maiores, como 150.5 o Lead não carrega valor
params.currency código ISO-4217, três letras maiúsculas; obrigatório quando value vem —

source_lead_id é uma referência ao sistema de onde o lead veio. Nunca substitui o identificador que o seu Node tem para aquela pessoa, e nunca vira external_id em um payload enviado a uma plataforma de anúncios.

custom_fields

  • Um objeto JSON, nunca uma lista. As chaves atendem ^[a-z][a-z0-9_]{0,63}$, e são no máximo 50.
  • Os valores são só escalares: string, inteiro, float finito, boolean ou null. Nenhum array, nenhum objeto aninhado.
  • Tamanho: o objeto codificado em JSON com Unicode e barras não escapados precisa ter no máximo 16384 bytes.
  • Chaves reservadas, recusadas se usadas: email, phone, first_name, last_name, full_name, company, job_title, street, street2, city, state, zip, country, gender, birth_date, external_id, lead_source, ip_address, user_agent, lead_id, status, source, source_lead_id, value, currency, property_id, stuid, event_id, event_name, event_time, channel, action_source, provider, source_platform, metadata, context, user, params, attribution, utm_source, utm_medium, utm_campaign, utm_content, utm_term, gclid, gbraid, wbraid, gad_source, fbclid, fbc, fbp, msclkid, ttclid, rdt_cid, srsltid, ga_client_id, ga_session_id, ctwa_clid, delivery, session_id, page_url, referrer, created_at, updated_at, first_seen_at, last_seen_at, is_sandbox.

Numa captura seguinte o objeto é mesclado, não substituído: chave presente na nova captura sobrescreve, chave ausente dela é preservada, e chave enviada com null remove. O resultado mesclado também obedece aos dois limites — se não obedecer, a captura inteira é recusada, não sobrando nem evento nem linha.

Códigos de erro

Código Quando
lead_block_not_object params.lead presente e não é objeto
lead_status_invalid status fora do conjunto
lead_source_invalid source fora da regex
source_lead_id_invalid vazio, com mais de 191 caracteres, ou com caractere de controle
custom_fields_not_object custom_fields presente e não é objeto
custom_field_key_invalid chave fora da regex
custom_field_key_reserved chave reservada
custom_field_value_not_scalar valor array ou objeto (ou float não finito)
custom_fields_too_many mais de 50 chaves (na captura ou no resultado mesclado)
custom_fields_too_large mais de 16384 bytes (na captura ou no resultado mesclado)
value_invalid value não numérico, negativo ou não finito
currency_invalid currency fora de ^[A-Z]{3}$
currency_required value presente sem currency
identity_required nem e-mail nem telefone
event_id_too_long event id com mais de 50 bytes UTF-8

Severidade por canal

São duas regras diferentes, e há um motivo:

  • Um bloco params.lead inválido — qualquer código lead_*, source_* ou custom_* acima — recusa o evento inteiro, em todos os canais. Nada legado manda esse bloco, então nada quebra por ser estrito.
  • Um value ou currency inválido é recusado pela API de Leads e pelas superfícies (o template do Google Tag Manager, a skill de Web Events). No caminho de navegador do Node, o evento segue como hoje e o Lead simplesmente não recebe valor nem moeda. value e currency já chegam em produção em payloads de lead, então não podem passar a derrubar eventos.

A API de Leads: do seu servidor para o seu Node

Use quando o Lead nasce fora do navegador — um CRM, um back office, uma ligação digitada num formulário pela sua equipe — ou quando precisa atualizar um Lead que o seu site já capturou. A forma é a canônica: o mesmo conteúdo pelas duas portas produz o mesmo Lead.

A credencial

Uma credencial por Property. No Console, abra Leads, escolha a Property em Propriedade, então Como capturar Leads → a aba API → Gerar credencial.

  • O segredo aparece uma única vez. O Console avisa: "Guarde agora: este segredo não aparece de novo." Coloque num cofre do seu servidor antes de sair da tela. Ele é guardado no seu Node só como hash — não há recuperação nem segunda cópia.
  • Só no servidor. Nunca coloque em código de navegador, em log, em URL, em diagnóstico, em print ou em repositório.
  • A Master Key não serve aqui. Apresentada nesta via, ela é respondida com 401, exatamente como um segredo errado.
  • O cartão então mostra URL do endpoint, ID público, os quatro últimos caracteres do segredo em Segredo, e Criada em, Rotacionada em, Último uso, Requisições e Último resultado.
  • Rotacionar segredo emite um segredo novo e pede confirmação antes: "A credencial anterior para de funcionar imediatamente. Atualize o segredo no seu servidor." Não existe janela de graça. A URL do endpoint e o ID público não mudam.

Copie a URL do endpoint que o Console mostra. Não monte ela à mão.

A requisição

POST <a URL do endpoint que o Console mostra>
Authorization: Bearer <SEU_SEGREDO>
Content-Type: application/json
Idempotency-Key: lead-0001

Authorization e Content-Type são obrigatórios; Idempotency-Key é opcional. Uma requisição que não é JSON é respondida com 415, e um corpo acima de 65536 bytes com 413 — as duas antes mesmo de a credencial ser lida, então um segredo correto não salva uma requisição malformada.

O corpo:

{
  "user": { "email": "maria@example.com", "phone": "+5511987654321",
            "first_name": "Maria", "last_name": "Silva",
            "company": "Acme", "job_title": "Head of Growth" },
  "params": { "value": 150.5, "currency": "BRL",
              "lead": { "status": "qualified", "source": "crm", "source_lead_id": "4821",
                        "custom_fields": { "plan_interest": "pro" } } },
  "event_time": "2026-09-23T12:00:00Z"
}
  • user aceita só email, phone, first_name, last_name, full_name, company, job_title, street, street2, city, state, zip e country. Um entre email e phone precisa estar lá.
  • params aceita só value, currency e lead.
  • event_time é opcional: ISO-8601 ou unix em segundos, com default agora.
  • Qualquer outra chave, no topo ou dentro de user e params, é recusada como unknown_field. Isso inclui property_id: a Property vem da credencial, nunca do corpo.

As respostas

HTTP Corpo Quando
201 {"ok":true,"result":"created","event_id":"…","lead":LeadWrite} o Lead foi criado
200 {"ok":true,"result":"updated","event_id":"…","lead":LeadWrite} um evento novo atualizou um Lead existente
200 {"ok":true,"result":"duplicate","event_id":"…","lead":LeadWrite} repetição da mesma Idempotency-Key; nenhum evento novo
400 {"ok":false,"error":"invalid_payload","errors":[{"field":"params.lead.custom_fields.foo","code":"custom_field_value_not_scalar"}]} qualquer regra acima foi quebrada — nada é gravado
401 {"ok":false,"error":"unauthorized"} sem header, segredo errado, id público desconhecido, segredo de outra Property, a Master Key, ou Property inativa
405 {"ok":false,"error":"method_not_allowed"} qualquer coisa que não seja POST
413 {"ok":false,"error":"payload_too_large"} corpo acima de 65536 bytes
415 {"ok":false,"error":"unsupported_media_type"} a requisição não é JSON
422 {"ok":false,"error":"custom_fields_merge_overflow"} a mesclagem estouraria 50 chaves ou 16384 bytes — nada é gravado

LeadWrite carrega lead_id, status, source, source_lead_id, value_cents, currency, custom_fields, first_seen_at, last_seen_at e capture_count. Nenhuma identidade volta na resposta, e nenhuma resposta revela se outra Property, Lead ou credencial existe.

O corpo e o status do 401 são idênticos em todos esses casos de propósito: um id público desconhecido nunca é respondido com 404, então a via não pode ser usada para descobrir quais credenciais existem.

Além dos códigos da tabela acima, errors[] pode trazer três que só esta via produz:

Código Quando
unknown_field chave fora do contrato, inclusive property_id no corpo
invalid_type o corpo, user ou params com tipo errado, um campo de user que não é string, ou event_time ilegível
idempotency_key_invalid o header Idempotency-Key fora do formato

Uma falha inesperada depois da validação é respondida com 500 e {"ok":false,"error":"internal_error"}. Nada é gravado pela metade.

A chamada

curl -X POST '<a URL do endpoint que o Console mostra>' \
  -H 'Authorization: Bearer <SEU_SEGREDO>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: lead-0001' \
  -d '{"user":{"email":"maria@example.com","first_name":"Maria"},"params":{"lead":{"status":"new","source":"crm"}}}'

O Console mostra esse mesmo comando em Exemplo de requisição, já com a sua URL de endpoint preenchida.

O que o Console conta sobre a via

Toda requisição autenticada move três campos no cartão da credencial: Requisições, Último uso e Último resultado. Último resultado mostra um entre Lead criado, Lead atualizado, Repetição ignorada (mesma Idempotency-Key), Payload recusado, Credencial recusada e Nenhuma requisição ainda.

É o jeito mais rápido de separar "meu servidor nunca chamou" de "meu servidor chamou e foi recusado".

Idempotência

Uma retentativa depois de um timeout não deveria produzir uma segunda captura. É para isso que existe a Idempotency-Key.

  • Formato: de 1 a 50 caracteres entre A–Z, a–z, 0–9, ., _, : e -. Uma chave inválida é respondida com 400 invalid_payload e {"field":"Idempotency-Key","code":"idempotency_key_invalid"}.
  • Mesma chave de novo: 200 com "result":"duplicate". Nenhum evento novo, nenhum segundo Lead, e o contador de capturas não se move.
  • Sem chave nenhuma: toda chamada é um evento novo no mesmo Lead — 200 com "result":"updated".

Derive a chave do id do lead no sistema de origem mais uma versão da alteração, por exemplo crm-4821:v3. Uma chave reaproveitada em duas atualizações genuinamente diferentes faz a segunda responder duplicate e não fazer nada, em silêncio.

Prove que a captura funcionou

Pelo navegador

  1. Envie o formulário real do seu site.
  2. Abra Leads no Console, escolha a Property e clique em Atualizar.
  3. A linha aparece. Abra para ver Identidade, Dados do Lead, Aquisição (primeiro contato), Campos personalizados e Capturas recentes.

Para olhar o evento em si, e não o Lead, siga Verifique seu primeiro evento.

Isso prova que a página emitiu o evento, que o seu Node aceitou e guardou, e que o Console leu de volta a partir desse Node. Não prova que a Meta, o GA4 ou qualquer outro destino aceitou um evento encaminhado — confira isso na view do próprio destino.

Pela API

  1. Troque <SEU_SEGREDO> pelo segredo que você guardou.
  2. Rode o comando: a resposta é 201 com "result":"created" e um lead_id.
  3. De volta em Leads, clique em Atualizar: o Lead está na lista.
  4. Rode o mesmo comando outra vez, com a mesma Idempotency-Key: a resposta é 200 com "result":"duplicate", e Capturas não se moveu.

O Console lista esses mesmos passos em Como provar, na aba API.

Troubleshooting sem expor PII

Antes de qualquer coisa: nunca cole segredo, e-mail ou telefone real em ticket, print ou chat. Use os valores de exemplo desta página. O Console nunca mostra um segredo duas vezes, e nenhuma resposta da API de Leads devolve identidade.

Sintoma Causa provável O que fazer
O Lead não aparece a captura não levou e-mail nem telefone adicione um dos dois em context.user ou em user; sem nenhum dos dois, o evento é recusado
O Lead não aparece o bloco params.lead estava inválido, e o evento inteiro foi recusado leia o código: no GTM ele está no console de depuração do Preview, pela API ele está em errors[]
O Lead aparece no site errado o loader da página carrega o id de outra Property corrija o ?pid= daquela página — veja Instale o Loader
O Lead não aparece em lugar nenhum, e nada é recusado o Node está em modo sandbox, e Lead de sandbox nunca é listado desligue o sandbox e capture de novo
401 da API segredo errado, segredo já rotacionado, segredo de outra Property, ou a Master Key a resposta é deliberadamente idêntica nos quatro casos. Rotacione o segredo no Console e atualize o seu servidor
400 com errors[] um campo quebrou uma regra confira cada code nas tabelas acima; nada foi gravado, então corrija e reenvie
422 custom_fields_merge_overflow a mesclagem estouraria 50 chaves ou 16384 bytes mande com null as chaves que você não precisa mais, para removê-las, ou mande menos chaves
415 ou 413 a requisição não é JSON, ou o corpo passa de 65536 bytes corrija o header ou o payload; o segredo nunca foi o problema
Um Lead capturado pelo navegador não tem valor currency ausente ou inválida o caminho de navegador deixa o evento passar e descarta só valor e moeda. Mande um código válido de três letras junto com o valor
duplicate quando você esperava uma mudança a Idempotency-Key foi reaproveitada use uma chave que muda com o conteúdo, como o id de origem mais uma versão
Leads não aparece na navegação o Node ainda não responde por Leads abra Saúde do Node e atualize o Node
Gerar credencial e Rotacionar segredo estão desabilitados o Leads não está no plano agora seus Leads e a credencial que você já tem seguem intactos; veja a seção do power-up acima

Próximos passos