Descrição
O evento conversion rastreia quando uma venda é concretizada através de um afiliado. Este é o evento mais importante do sistema pois:
Gera comissões para os afiliados
Calcula o ROI do programa de afiliados
Determina os pagamentos (payouts)
Mede o sucesso real dos afiliados
Vincula receita à origem do tráfego
Conversões devem ter order_id único e order_value obrigatório . O
sistema automaticamente calcula a comissão baseado nas configurações da
campanha.
Quando Usar
Pagamento Confirmado Quando um pagamento é confirmado pelo gateway
Webhook Recebido Ao receber webhook de Stripe, Mercado Pago, etc
Assinatura Ativada Quando uma assinatura é criada/ativada
Pagamento Recebido Ao confirmar recebimento do pagamento
NUNCA envie conversões antes da confirmação do pagamento. Aguarde sempre o
webhook ou confirmação do gateway.
Propriedades Obrigatórias
ID único do pedido/transação (usado para idempotência ) Exemplo:
"ORDER-12345", "ch_1234abcd", "TXN-2024-001" Conversões com mesmo order_id serão ignoradas (deduplicação
automática)
Valor total da venda em reais (deve ser positivo ) Exemplo: 99.90,
299.00, 1499.99 A comissão será calculada automaticamente: Percentage → (order_value * commission_value / 100) | Fixed → commission_value fixo
Propriedades Opcionais
Nome do produto ou plano vendido Exemplo: "Plano Premium Anual",
"Produto X"
E-mail do cliente que comprou Exemplo: "cliente@email.com"
Nome do cliente que comprou Exemplo: "Maria Santos"
ID do cliente no seu sistema Exemplo: "user_abc123", "cus_1234abcd"
Método de pagamento usado Exemplo: "credit_card", "boleto", "pix",
"stripe"
ID da assinatura (para modelos recorrentes) Exemplo: "sub_abc123",
"subscription_456"
URL da página de checkout/confirmação Exemplo:
"https://seu-site.com/checkout/success"
Data/hora ISO 8601 da conversão Exemplo: "2024-01-15T10:45:00Z"
Exemplos de Implementação
SDK JavaScript - Página de Sucesso
<! DOCTYPE html >
< html >
< head >
< title > Compra Confirmada! </ title >
< script src = "https://cdn.affiliatus.io/latest/affiliatus.min.js" ></ script >
</ head >
< body >
< h1 >< Icon icon = "party-horn" /> Obrigado pela sua compra! </ h1 >
< p > Seu pedido foi confirmado com sucesso. </ p >
< script >
const affiliatus = new Affiliatus ( 'seu-campaign-id' );
// Dados do pedido (vindos do backend via template)
const orderData = {
order_id: '<?= $order->id ?>' ,
order_value: <?= $order -> total ?> ,
product : '<?= $order->product_name ?>' ,
customer_email : '<?= $customer->email ?>' ,
customer_name: '<?= $customer->name ?>' ,
payment_method: '<?= $order->payment_method ?>'
};
// Rastrear conversão
affiliatus . trackConversion ( orderData );
console . log ( 'Conversão rastreada:' , orderData );
</ script >
</ body >
</ html >
Webhook Stripe
const stripe = require ( "stripe" )( process . env . STRIPE_SECRET_KEY );
const express = require ( "express" );
const app = express ();
// Endpoint para webhook do Stripe
app . post (
"/webhook/stripe" ,
express . raw ({ type: "application/json" }),
async ( req , res ) => {
const sig = req . headers [ "stripe-signature" ];
let event ;
try {
// Verificar assinatura do webhook
event = stripe . webhooks . constructEvent (
req . body ,
sig ,
process . env . STRIPE_WEBHOOK_SECRET
);
} catch ( err ) {
console . error ( "Erro ao verificar webhook:" , err . message );
return res . status ( 400 ). send ( `Webhook Error: ${ err . message } ` );
}
// Processar evento de checkout completo
if ( event . type === "checkout.session.completed" ) {
const session = event . data . object ;
// Buscar affiliate_id e session_id dos metadata
const affiliateId = session . metadata . affiliate_id ;
const affiliateSessionId = session . metadata . session_id ;
if ( affiliateId ) {
console . log ( "Rastreando conversão para afiliado:" , affiliateId );
try {
await fetch ( "https://api.affiliatus.io/v1/events" , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"X-API-Key" : process . env . AFFILIATUS_API_KEY ,
},
body: JSON . stringify ({
events: [
{
event_type: "conversion" ,
campaign_id: process . env . CAMPAIGN_ID ,
affiliate_id: affiliateId ,
session_id: affiliateSessionId ,
properties: {
order_id: session . id ,
order_value: session . amount_total / 100 , // Stripe usa centavos
product: session . metadata . product_name || "Produto" ,
customer_email: session . customer_email ,
customer_id: session . customer ,
payment_method: "stripe" ,
subscription_id: session . subscription ,
url: session . success_url ,
timestamp: new Date (). toISOString (),
},
device_info: {
ip: req . ip ,
user_agent: req . headers [ "user-agent" ],
},
},
],
}),
});
console . log ( "Conversão rastreada com sucesso" );
} catch ( error ) {
console . error ( "Erro ao rastrear conversão:" , error );
}
}
}
res . json ({ received: true });
}
);
app . listen ( 3000 , () => console . log ( "Webhook server running on port 3000" ));
// No checkout, adicione affiliate_id aos metadata
const session = await stripe . checkout . sessions . create ({
payment_method_types: [ "card" ],
line_items: [
{
price: "price_abc123" ,
quantity: 1 ,
},
],
mode: "subscription" ,
success_url: "https://seu-site.com/success" ,
cancel_url: "https://seu-site.com/cancel" ,
metadata: {
affiliate_id: affiliateId , // ← Importante!
session_id: sessionId , // ← Importante!
product_name: "Plano Premium" ,
},
});
Webhook Mercado Pago
from flask import Flask, request, jsonify
import requests
import os
app = Flask( __name__ )
@app.route ( '/webhook/mercadopago' , methods = [ 'POST' ])
def mercadopago_webhook ():
"""Processar notificação de pagamento aprovado do Mercado Pago"""
data = request.json
# Verificar se é notificação de pagamento aprovado
if data.get( 'type' ) == 'payment' and data.get( 'action' ) == 'payment.approved' :
payment_id = data[ 'data' ][ 'id' ]
# Buscar detalhes do pagamento na API do Mercado Pago
payment = get_mercadopago_payment(payment_id)
# Buscar affiliate_id armazenado nos metadata
affiliate_id = payment.get( 'metadata' , {}).get( 'affiliate_id' )
session_id = payment.get( 'metadata' , {}).get( 'session_id' )
if affiliate_id:
# Enviar conversão para Affiliatus
payload = {
'events' : [{
'event_type' : 'conversion' ,
'campaign_id' : os.getenv( 'CAMPAIGN_ID' ),
'affiliate_id' : affiliate_id,
'session_id' : session_id,
'properties' : {
'order_id' : payment[ 'external_reference' ] or str (payment_id),
'order_value' : float (payment[ 'transaction_amount' ]),
'product' : payment[ 'description' ],
'customer_email' : payment[ 'payer' ][ 'email' ],
'customer_name' : payment[ 'payer' ][ 'name' ],
'customer_id' : str (payment[ 'payer' ][ 'id' ]),
'payment_method' : 'mercadopago' ,
'timestamp' : payment[ 'date_approved' ]
},
'device_info' : {
'ip' : request.remote_addr
}
}]
}
response = requests.post(
'https://api.affiliatus.io/v1/events' ,
headers = {
'Content-Type' : 'application/json' ,
'X-API-Key' : os.getenv( 'AFFILIATUS_API_KEY' )
},
json = payload
)
print ( f "Conversão rastreada: { response.json() } " )
return jsonify({ 'status' : 'ok' })
def get_mercadopago_payment ( payment_id ):
"""Buscar detalhes do pagamento no Mercado Pago"""
access_token = os.getenv( 'MERCADOPAGO_ACCESS_TOKEN' )
response = requests.get(
f 'https://api.mercadopago.com/v1/payments/ { payment_id } ' ,
headers = { 'Authorization' : f 'Bearer { access_token } ' }
)
return response.json()
if __name__ == '__main__' :
app.run( port = 3000 )
Webhook PagSeguro
<? php
// Webhook PagSeguro
if ( $_POST [ 'notificationCode' ]) {
$notificationCode = $_POST [ 'notificationCode' ];
// Consultar transação no PagSeguro
$transaction = consultarTransacaoPagSeguro ( $notificationCode );
// Verificar se pagamento foi aprovado (status 3 = Paga)
if ( $transaction [ 'status' ] == 3 ) {
// Buscar affiliate_id armazenado na referência
// Você deve ter salvo isso ao criar o pagamento
$reference = $transaction [ 'reference' ];
list ( $orderId , $affiliateId , $sessionId ) = explode ( '_' , $reference );
if ( $affiliateId ) {
// Preparar dados para Affiliatus
$data = [
'events' => [[
'event_type' => 'conversion' ,
'campaign_id' => $_ENV [ 'CAMPAIGN_ID' ],
'affiliate_id' => $affiliateId ,
'session_id' => $sessionId ,
'properties' => [
'order_id' => $orderId ,
'order_value' => floatval ( $transaction [ 'grossAmount' ]),
'product' => $transaction [ 'items' ][ 0 ][ 'description' ],
'customer_email' => $transaction [ 'sender' ][ 'email' ],
'customer_name' => $transaction [ 'sender' ][ 'name' ],
'payment_method' => 'pagseguro' ,
'timestamp' => date ( 'c' )
],
'device_info' => [
'ip' => $_SERVER [ 'REMOTE_ADDR' ]
]
]]
];
// Enviar para Affiliatus
$ch = curl_init ( 'https://api.affiliatus.io/v1/events' );
curl_setopt ( $ch , CURLOPT_HTTPHEADER , [
'Content-Type: application/json' ,
'X-API-Key: ' . $_ENV [ 'AFFILIATUS_API_KEY' ]
]);
curl_setopt ( $ch , CURLOPT_POSTFIELDS , json_encode ( $data ));
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
$response = curl_exec ( $ch );
$httpCode = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
curl_close ( $ch );
if ( $httpCode == 200 ) {
error_log ( "Conversão rastreada com sucesso: $orderId " );
} else {
error_log ( "Erro ao rastrear conversão: $response " );
}
}
}
}
function consultarTransacaoPagSeguro ( $notificationCode ) {
$email = $_ENV [ 'PAGSEGURO_EMAIL' ];
$token = $_ENV [ 'PAGSEGURO_TOKEN' ];
$url = "https://ws.pagseguro.uol.com.br/v3/transactions/notifications/ $notificationCode ?email= $email &token= $token " ;
$ch = curl_init ( $url );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
$xml = curl_exec ( $ch );
curl_close ( $ch );
// Converter XML para array
$transaction = simplexml_load_string ( $xml );
return json_decode ( json_encode ( $transaction ), true );
}
?>
Fluxo de Processamento
Quando uma conversão é recebida, o sistema executa os seguintes passos:
1. Validação
Verifica se campaign, affiliate e domain são válidos e ativos
2. Idempotência
Checa se order_id já existe no banco de dados (evita duplicatas)
3. Limites do Plano
Verifica se o plano do usuário suporta mais conversões no mês
4. Salvar Evento
Registra o evento na tabela events
5. Criar Conversão
Cria registro na tabela conversions com status pending
6. Calcular Comissão
Calcula comissão baseado em commission_type e commission_value
Cálculo de Comissão
O sistema calcula automaticamente a comissão baseado no tipo configurado na campanha:
Comissão Percentual (percentage)
commission_value = (order_value * campaign.commission_value) / 100
Exemplo:
order_value: R$ 100,00
commission_value: 10%
Comissão calculada: R$ 10,00
Comissão Fixa (fixed)
commission_value = campaign.commission_value
Exemplo:
order_value: R$ 100,00
commission_value: R$ 15,00
Comissão calculada: R$ 15,00 (independente do valor)
Status da Conversão
Após criação, a conversão passa pelos seguintes status:
pending
Pendente - Aguardando aprovação manual do merchant
approved
Aprovada - Conversão aprovada, comissão confirmada
rejected
Recusada - Conversão recusada (chargeback, fraude, cancelamento)
paid
Paga - Comissão foi paga ao afiliado
Métricas Geradas
Total de Conversões Número de vendas por afiliado
Receita Gerada Soma de order_value por afiliado
Comissões a Pagar Total de comissões calculadas
Taxa de Conversão Conversões / Visitas (%)
Ticket Médio Receita total / Número de conversões
ROI do Programa Receita gerada vs Comissões pagas
Boas Práticas
SEMPRE use order_id único
Use o ID da transação do seu sistema ou gateway. Nunca gere IDs aleatórios ou reutilize. // <Icon icon="check" color="#db2777" /> BOM - ID do Stripe
order_id : session . id // "cs_1234abcd"
// <Icon icon="check" color="#db2777" /> BOM - ID do seu banco de dados
order_id : `ORDER- ${ order . id } ` // "ORDER-12345"
// <Icon icon="x" /> RUIM - Aleatório
order_id : Math . random (). toString ()
// <Icon icon="x" /> RUIM - Timestamp
order_id : Date . now (). toString ()
Envie APENAS após confirmação
Aguarde webhook ou confirmação do gateway. Nunca envie no clique do botão de compra.// <Icon icon="x" /> ERRADO - No clique do botão
button . addEventListener ( 'click' , () => {
affiliatus . trackConversion ({ /* ... */ });
checkout ();
});
// <Icon icon="check" color="#db2777" /> CORRETO - No webhook após pagamento confirmado
app . post ( '/webhook/payment' , ( req , res ) => {
if ( req . body . status === 'paid' ) {
trackConversion ({ /* ... */ });
}
});
Envie o valor que o cliente realmente pagou (após descontos, mas antes de taxas). // <Icon icon="check" color="#db2777" /> CORRETO - Valor que o cliente pagou
order_value : 99.90 // Após desconto de R$ 10
// <Icon icon="x" /> ERRADO - Valor antes do desconto
order_value : 109.90
// <Icon icon="x" /> ERRADO - Valor após taxas do gateway
order_value : 94.90
Teste em ambiente sandbox
Use webhooks de teste dos gateways e uma campanha de testes antes de produção. Stripe: Use test keys e stripe trigger CLIMercado Pago: Use ambiente de testesPagSeguro: Use sandbox
Implemente retry com idempotência
Troubleshooting
Conversões não aparecem no dashboard
Verifique se order_value é positivo
O valor deve ser maior que zero // <Icon icon="check" color="#db2777" /> Válido
order_value : 99.90
// <Icon icon="x" /> Inválido
order_value : 0
order_value : - 50
Confirme se não é duplicata
Cheque se o order_id já foi usado anteriormente Query no dashboard ou logs do sistema
Valide limites do plano
Veja se não atingiu o limite mensal de conversões Dashboard → Configurações → Plano
Verifique logs de erro
Cheque resposta da API para mensagens de erro const response = await fetch ( /* ... */ );
const data = await response . json ();
if ( ! response . ok ) {
console . error ( 'Erro:' , data );
}
Conversões não geram comissão
Verifique se affiliate está ativo
Status deve ser active, não inactive
Confirme configuração da campanha
commission_type e commission_value devem estar configurados
Aprove manualmente no dashboard
Conversões ficam pending até aprovação manual Dashboard → Conversões →
Ações → Aprovar
Erro “order_id already exists”
Isso significa que você está tentando enviar uma conversão com order_id que já existe.
Soluções:
Se é uma tentativa de reenvio → Está tudo bem, o sistema já registrou
Se é uma nova venda → Use um order_id diferente e único
Próximos Passos
Integração Stripe Guia completo de integração com Stripe
Integração Woovi Guia completo de integração com Woovi (Pix)
Aprovar Conversões Gerenciar conversões no dashboard
Criar Payouts Processar pagamentos para afiliados