Integração — guia para o desenvolvedor
Este documento é tudo o que você precisa para integrar uma plataforma de vendas ao UTM Intelligence. Não é preciso conhecer o sistema por dentro.
Painel: https://utmfy.hnvag0.easypanel.host
Ao final da integração, cada venda que entrar vai:
- aparecer no painel em segundos, já atribuída à campanha/anúncio que a gerou;
- disparar notificação no celular do dono (push), Telegram, Discord ou e-mail.
Visão geral
São duas peças independentes. Você pode fazer só a primeira e o sistema já funciona — a segunda é o que permite saber de qual anúncio veio cada venda.
| Peça | O que faz | Onde vive |
|---|---|---|
| 1. Webhook de vendas | Manda a venda para o sistema | Servidor da plataforma de checkout |
| 2. Script de rastreamento | Identifica o visitante e guarda a origem | Página de vendas do cliente |
Onde pegar as credenciais
No painel, em Configurações → Instalação:
| Credencial | Formato | Para que serve |
|---|---|---|
| Chave pública | 32 caracteres | Vai no script de rastreamento (pode ficar exposta) |
| Chave secreta | 48 caracteres | Vai na URL do webhook e na API. Nunca exponha no navegador. |
Parte 1 — Webhook de vendas
Endpoint
POST https://utmfy.hnvag0.easypanel.host/webhook/generic/{CHAVE_SECRETA}
Content-Type: application/json
Responde 200 {"ok":true} imediatamente e processa em segundo plano — a venda aparece no painel em poucos segundos. Se receber qualquer coisa diferente de 200, reenvie.
Corpo da requisição
{
"order_id": "PED-12345",
"status": "approved",
"payment_method": "pix",
"currency": "BRL",
"total": 497.00,
"fee": 44.68,
"cost": 40.00,
"product": {
"id": "curso-completo",
"name": "Curso Completo"
},
"customer": {
"email": "cliente@email.com",
"name": "Maria Silva",
"country": "BR"
},
"tracking": {
"vid": "8f14e45f-ceea-467a-9d1a-2f3b4c5d6e7f",
"sid": "3c59dc04-8e88-4c04-9f31-b2f0e1a2c3d4",
"utm_source": "facebook",
"utm_medium": "cpc",
"utm_campaign": "Black Friday",
"utm_content": "criativo-video-01",
"click_id": "IwAR3xK9..."
},
"items": [
{ "id": "curso-completo", "name": "Curso Completo", "quantity": 1, "price": 497.00 },
{ "id": "bump-planilhas", "name": "Planilhas", "quantity": 1, "price": 47.00, "is_bump": true }
],
"created_at": "2026-08-01T14:32:10-03:00",
"approved_at": "2026-08-01T14:32:45-03:00"
}
Campos
| Campo | Obrigatório | Observação |
|---|---|---|
order_id | sim | ID do pedido na sua plataforma. É a chave de idempotência. |
status | sim | Ver tabela de status abaixo. |
total | sim | Na unidade da moeda: 497.00 = R$ 497,00. Ver aviso abaixo. |
payment_method | não | pix, credit_card, boleto, debit_card, paypal… |
currency | não | Padrão BRL. |
fee | não | Taxa do gateway. Entra no cálculo de lucro. |
cost | não | Custo do produto. Entra no cálculo de lucro. |
product.id / product.name | não | Alimenta o ranking de produtos. |
customer.email | não | Usado para reconhecer o comprador entre dispositivos. |
tracking.* | não | Ver Parte 2. É o que liga a venda ao anúncio. |
items[] | não | Detalhe por item; use is_bump para order bumps. |
created_at / approved_at | não | ISO 8601 ou timestamp Unix. Padrão: agora. |
⚠️ O erro mais comum: valor em centavos
totalé lido na unidade da moeda.497.00e497são ambos R$ 497,00 — não R$ 4,97.Se a sua plataforma trabalha em centavos, divida por 100 antes de enviar:
"total": 49700seria interpretado como R$ 49.700,00.
Status aceitos
| Envie | Significado | Sinônimos aceitos |
|---|---|---|
approved | Pagamento confirmado | paid, completed, succeeded, aprovado, pago |
pending | Aguardando pagamento | (padrão quando não reconhecido) |
refused | Recusado | declined, failed, recusado |
refunded | Reembolsado | refund, estornado, reembolsado |
chargeback | Contestação | dispute |
canceled | Cancelado | cancelled, cancelado |
expired | Expirado | expirado |
Só approved conta como faturamento.
Idempotência e ciclo de vida
Reenvie o mesmo order_id a cada mudança de status. O sistema atualiza o pedido existente em vez de duplicar.
Fluxo típico de um Pix:
1. Pix gerado → {"order_id":"PED-1","status":"pending", "total":497.00}
2. Pix pago → {"order_id":"PED-1","status":"approved", "total":497.00}
3. Reembolso → {"order_id":"PED-1","status":"refunded", "total":497.00}
Duas proteções que você não precisa implementar do seu lado:
- Reenvio duplicado não gera venda dupla nem alerta repetido.
- Webhook fora de ordem não regride o status: se o "aprovado" chegar depois
- do "reembolsado", o pedido continua reembolsado.
Assinatura (recomendado)
Para o sistema recusar requisições forjadas, configure um segredo compartilhado e envie o HMAC do corpo cru:
X-Signature: hmac_sha256(corpo_cru_da_requisicao, SEGREDO)
$body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$signature = hash_hmac('sha256', $body, $segredo);
// envie $body como corpo e $signature no header X-Signature
Sem segredo configurado no painel, a verificação é ignorada — útil em testes.
Testando
curl -X POST "https://utmfy.hnvag0.easypanel.host/webhook/generic/SUA_CHAVE_SECRETA" \
-H "Content-Type: application/json" \
-d '{
"order_id": "TESTE-001",
"status": "approved",
"payment_method": "pix",
"total": 497.00,
"product": { "id": "teste", "name": "Produto de Teste" },
"customer": { "email": "teste@exemplo.com" }
}'
Esperado: {"ok":true}, e em poucos segundos a venda aparece no painel com o alerta/push correspondente.
Parte 2 — Rastreamento e atribuição
Sem esta parte, todas as vendas aparecem como tráfego direto. Com ela, você sabe qual anúncio pagou cada venda.
Passo 1 — Instalar o script na página de vendas
<script src="https://utmfy.hnvag0.easypanel.host/track.js?k=SUA_CHAVE_PUBLICA" defer></script>
Sozinho, ele já:
- registra as visitas e as sessões;
- captura
utm_source,utm_medium,utm_campaign,utm_content,utm_term; - captura os IDs de clique:
fbclid,gclid,gbraid,wbraid,ttclid, msclkid,twclid,epik,sccid;- guarda essa origem por até 13 meses (cookie de 1ª parte + localStorage);
- deduz a origem de tráfego orgânico e social quando não há UTM;
- acrescenta
utmi_videutmi_sidaos links que apontam para o checkout.
Passo 2 — Levar os identificadores até o webhook
É o passo que fecha o ciclo. Existem três cenários — use o que se aplica:
Cenário A — O checkout é uma plataforma externa (Hotmart, Kiwify…)
O script já anexa utmi_vid e utmi_sid na URL do checkout. Configure a plataforma para repassar esses parâmetros no webhook, no campo de rastreamento que ela oferecer (sck, src, tracking, custom_fields…):
"tracking": { "vid": "<utmi_vid recebido>", "sid": "<utmi_sid recebido>" }
Cenário B — Checkout próprio
Leia os identificadores no navegador e envie junto com o pedido:
const ids = utmi('ids'); // { vid: "...", sid: "..." }
const utms = utmi('params'); // { utm_source: "...", fbclid: "...", ... }
fetch('/api/criar-pedido', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...dadosDoPedido, tracking: { ...ids, ...utms } })
});
Guarde tracking junto do pedido no seu banco e repasse no webhook.
Cenário C — Não dá para passar nada
Envie ao menos o e-mail do comprador em customer.email. O sistema tenta casar com um visitante conhecido (funciona inclusive entre celular e desktop).
Se a venda chegar antes do rastreamento, o sistema guarda os identificadores e corrige a atribuição sozinho minutos depois. Você não precisa controlar essa ordem.
Eventos opcionais
Melhoram o funil e a detecção de queda de conversão:
utmi('track', 'initiate_checkout'); // entrou no checkout
utmi('track', 'lead', { origem: 'formulario' }); // lead capturado
utmi('track', 'add_to_cart', {}, 197.00); // com valor
utmi('identify', 'cliente@email.com'); // liga o visitante ao e-mail
Ou sem JavaScript, por atributo:
<button data-utmi-event="clicou_comprar">Comprar agora</button>
initiate_checkout também é detectado automaticamente em links cuja URL contenha checkout, carrinho, pagamento ou pay..
Parte 3 — API (opcional)
Base https://utmfy.hnvag0.easypanel.host/api/v1 · Header Authorization: Bearer {CHAVE_SECRETA}
| Endpoint | Uso |
|---|---|
POST /orders | Criar/atualizar venda sem webhook (mesmo corpo da Parte 1) |
POST /ad-spend | Importar investimento do Meta/Google Ads (lote de até 5.000 linhas) |
GET /metrics | Métricas consolidadas do período |
GET /ranking | Ranking por anúncio, campanha, produto, origem… |
GET /orders | Listar vendas |
GET /health | Monitoramento (sem autenticação) |
Importar gasto de mídia é o que habilita ROAS, ROI, CAC e a lista de anúncios que estão queimando verba:
curl -X POST "https://utmfy.hnvag0.easypanel.host/api/v1/ad-spend" \
-H "Authorization: Bearer SUA_CHAVE_SECRETA" \
-H "Content-Type: application/json" \
-d '{ "rows": [{
"date": "2026-08-01", "source": "facebook",
"campaign_id": "1202100001", "campaign_name": "Black Friday",
"ad_id": "1202100001-ad1", "ad_name": "Criativo A",
"spend": 450.00, "impressions": 38000, "clicks": 620
}] }'
Idempotente por dia + anúncio: reenviar o mesmo dia atualiza, não duplica.
Referência completa em API.md.
Códigos de resposta
| Código | O que significa | O que fazer |
|---|---|---|
200 | Recebido | Nada |
401 | Chave inválida | Conferir a chave secreta na URL/header |
404 | Gateway não registrado | Usar /webhook/generic/… |
422 | Corpo inválido | Ler o campo error da resposta |
429 | Excesso de requisições | Aguardar e reenviar |
5xx | Falha do servidor | Reenviar — o sistema é idempotente |
Checklist de entrega
- Webhook disparando em todas as mudanças de status, não só na aprovação
-
totalna unidade da moeda (497.00), não em centavos - Mesmo
order_idreenviado a cada atualização - Reenvio automático quando a resposta não for
200 - Script de rastreamento na página de vendas
-
utmi_vid/utmi_sidchegando notrackingdo webhook -
customer.emailenviado (atribuição entre dispositivos) -
feeecostpreenchidos, se houver (necessários para lucro real) - Venda de teste aparecendo no painel
Perguntas frequentes
A venda apareceu como "direct". Por quê? Nenhum identificador chegou no tracking. Confira o Cenário A/B da Parte 2. Aguarde alguns minutos: se o rastreamento chegar depois, o sistema corrige sozinho.
Posso mandar o mesmo pedido várias vezes? Sim — é o comportamento esperado. A chave é o order_id.
O valor apareceu errado (100× maior ou menor). Unidade do total. Envie 497.00, não 49700.
Preciso do script se o checkout é externo? Sim. É ele que identifica o visitante antes de a venda existir. Sem ele, não há como saber de qual anúncio veio.
Reembolso desconta do faturamento? Sim. Reenvie o mesmo order_id com status: "refunded".