Skip to main content

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

order_id
string
required
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)
order_value
number
required
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

product
string
Nome do produto ou plano vendido Exemplo: "Plano Premium Anual", "Produto X"
customer_email
string
E-mail do cliente que comprou Exemplo: "cliente@email.com"
customer_name
string
Nome do cliente que comprou Exemplo: "Maria Santos"
customer_id
string
ID do cliente no seu sistema Exemplo: "user_abc123", "cus_1234abcd"
payment_method
string
Método de pagamento usado Exemplo: "credit_card", "boleto", "pix", "stripe"
subscription_id
string
ID da assinatura (para modelos recorrentes) Exemplo: "sub_abc123", "subscription_456"
url
string
URL da página de checkout/confirmação Exemplo: "https://seu-site.com/checkout/success"
timestamp
string
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"));

Como Adicionar Metadata no Stripe

// 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

1. Validação

Verifica se campaign, affiliate e domain são válidos e ativos
2

2. Idempotência

Checa se order_id já existe no banco de dados (evita duplicatas)
3

3. Limites do Plano

Verifica se o plano do usuário suporta mais conversões no mês
4

4. Salvar Evento

Registra o evento na tabela events
5

5. Criar Conversão

Cria registro na tabela conversions com status pending
6

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

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()
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
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
Se falhar, pode tentar novamente. O sistema ignora duplicatas pelo order_id.
async function trackConversion(data, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      await sendToAffiliatus(data);
      return; // Sucesso
    } catch (error) {
      if (i === retries - 1) throw error;
      await sleep(1000 * Math.pow(2, i)); // Backoff exponencial
    }
  }
}

Troubleshooting

Conversões não aparecem no dashboard

1

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
2

Confirme se não é duplicata

Cheque se o order_id já foi usado anteriormenteQuery no dashboard ou logs do sistema
3

Valide limites do plano

Veja se não atingiu o limite mensal de conversõesDashboard → Configurações → Plano
4

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

1

Verifique se affiliate está ativo

Status deve ser active, não inactive
2

Confirme configuração da campanha

commission_type e commission_value devem estar configurados
3

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:
  1. Se é uma tentativa de reenvio → Está tudo bem, o sistema já registrou
  2. 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