Skip to main content

Visão Geral

A integração via API REST permite que você envie conversões diretamente do seu backend usando API keys. Perfeito para integrações server-side com gateways não suportados.
Pré-requisito: A SDK JavaScript deve estar instalada no seu site! Ela é responsável por salvar o cookie com o código do afiliado. Esta integração API REST é complementar à SDK.
Quando usar:
  • Você processa conversões no backend
  • Usa gateway não suportado (Mercado Pago, PagSeguro, Asaas)
  • Quer integração server-to-server
  • Já tem a SDK instalada

Como Funciona

  1. SDK salva cookie: Cliente acessa com ?ref=CODIGO, SDK salva no cookie
  2. Cliente finaliza compra no seu sistema
  3. Seu backend processa o pagamento
  4. Backend lê o código do afiliado (do cookie ou session)
  5. Backend envia conversão via API REST
  6. API valida e cria a conversão
Papel da SDK: Ela salva o código do afiliado em um cookie que dura 30 dias. Seu backend deve ler esse cookie antes de enviar a conversão via API.

Configuração

Passo 1: Crie uma API Key

  1. No dashboard, vá em “Configurações”“API Keys”
  2. Clique em “Nova API Key”
  3. Dê um nome descritivo (ex: “Servidor de Produção”)
  4. Copie a chave imediatamente - ela só será exibida uma vez!
A API key é exibida apenas uma vez por segurança. Guarde em um local seguro (ex: variáveis de ambiente, gerenciador de secrets).

Passo 2: Armazene com Segurança

Nunca exponha sua API key no frontend ou em repositórios públicos. Boas práticas:
# .env (adicione ao .gitignore)
AFFILIATUS_API_KEY=your_api_key_here
AFFILIATUS_API_URL=https://api.affiliatus.io

Endpoint da API

URL Base

https://api.affiliatus.io/v1/events

Autenticação

Envie a API key no header X-API-Key:
POST https://api.affiliatus.io/v1/events
Content-Type: application/json
X-API-Key: your_api_key_here

Enviar Conversão

Endpoint Flexível: A API /v1/events é muito flexível! Requer apenas event_type, campaign_id e affiliate_id. Os campos session_id, properties e device_info são opcionais (exceto conversões que precisam de order_id e order_value).

Payload Mínimo

{
  "batch": true,
  "events": [
    {
      "event_type": "conversion",
      "campaign_id": "abc-123-def",
      "affiliate_id": "CODIGO_DO_AFILIADO",
      "properties": {
        "order_id": "PEDIDO-12345",
        "order_value": 99.9
      }
    }
  ]
}

Payload Completo

{
  "batch": true,
  "events": [
    {
      "event_type": "conversion",
      "campaign_id": "abc-123-def",
      "affiliate_id": "JOAO1",
      "properties": {
        "url": "https://seusite.com/checkout",
        "order_id": "ORDER-789",
        "order_value": 199.99,
        "product": "Plano Premium",
        "customer_email": "[email protected]",
        "customer_name": "João Silva",
        "timestamp": "2024-01-15T10:30:00Z"
      },
      "device_info": {
        "user_agent": "Mozilla/5.0...",
        "ip": "192.168.1.1",
        "language": "pt-BR",
        "screen_width": 1920,
        "screen_height": 1080
      }
    }
  ]
}

Parâmetros

Event Object

CampoTipoObrigatórioDescrição
event_typeString Sim"conversion", "lead" ou "page_view"
campaign_idString SimID público da sua campanha
affiliate_idString SimCódigo do afiliado (referralId)
session_idStringOpcionalID único da sessão do usuário
propertiesObjectOpcional*Dados do evento (*obrigatório para conversões)
device_infoObjectOpcionalInformações do dispositivo

Properties Object

CampoTipoObrigatórioDescrição
order_idString SimID único do pedido
order_valueNumber SimValor da venda em reais
urlStringRecomendadoURL da página de checkout
productStringOpcionalNome do produto/plano
customer_emailStringOpcionalE-mail do cliente
customer_nameStringOpcionalNome do cliente
timestampStringOpcionalISO 8601 timestamp

Device Info Object

CampoTipoDescrição
user_agentStringUser agent do navegador
ipStringIP do cliente
languageStringIdioma do navegador
screen_widthNumberLargura da tela
screen_heightNumberAltura da tela

Exemplos de Implementação

Node.js (Fetch)

const AFFILIATUS_API_KEY = process.env.AFFILIATUS_API_KEY;
const AFFILIATUS_API_URL = "https://api.affiliatus.io/v1/events";

async function sendConversion(orderId, orderValue, affiliateCode) {
  try {
    const response = await fetch(AFFILIATUS_API_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": AFFILIATUS_API_KEY,
      },
      body: JSON.stringify({
        batch: true,
        events: [
          {
            event_type: "conversion",
            campaign_id: "abc-123-def",
            affiliate_id: affiliateCode,
            properties: {
              order_id: orderId,
              order_value: orderValue,
            },
          },
        ],
      }),
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    }

    const data = await response.json();
    console.log("Conversão enviada:", data);
    return data;
  } catch (error) {
    console.error("Erro ao enviar conversão:", error);
    throw error;
  }
}

// Uso
await sendConversion("ORDER-123", 99.9, "JOAO1");

Node.js (Axios)

const axios = require("axios");

const affiliatusClient = axios.create({
  baseURL: "https://api.affiliatus.io",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": process.env.AFFILIATUS_API_KEY,
  },
});

async function sendConversion(orderId, orderValue, affiliateCode) {
  try {
    const response = await affiliatusClient.post("/v1/events", {
      batch: true,
      events: [
        {
          event_type: "conversion",
          campaign_id: "abc-123-def",
          affiliate_id: affiliateCode,
          properties: {
            order_id: orderId,
            order_value: orderValue,
          },
        },
      ],
    });

    console.log("Conversão enviada:", response.data);
    return response.data;
  } catch (error) {
    console.error("Erro:", error.response?.data || error.message);
    throw error;
  }
}

PHP (cURL)

<?php

function sendConversion($orderId, $orderValue, $affiliateCode) {
    $apiKey = getenv('AFFILIATUS_API_KEY');
    $apiUrl = 'https://api.affiliatus.io/v1/events';

    $payload = json_encode([
        'batch' => true,
        'events' => [
            [
                'event_type' => 'conversion',
                'campaign_id' => 'abc-123-def',
                'affiliate_id' => $affiliateCode,
                'properties' => [
                    'order_id' => $orderId,
                    'order_value' => $orderValue,
                ],
            ],
        ],
    ]);

    $ch = curl_init($apiUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'X-API-Key: ' . $apiKey,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("HTTP Error: $httpCode - $response");
    }

    return json_decode($response, true);
}

// Uso
try {
    $result = sendConversion('ORDER-123', 99.90, 'JOAO1');
    echo "Conversão enviada: " . print_r($result, true);
} catch (Exception $e) {
    echo "Erro: " . $e->getMessage();
}

Python (Requests)

import os
import requests
from datetime import datetime

AFFILIATUS_API_KEY = os.getenv('AFFILIATUS_API_KEY')
AFFILIATUS_API_URL = 'https://api.affiliatus.io/v1/events'

def send_conversion(order_id, order_value, affiliate_code):
    headers = {
        'Content-Type': 'application/json',
        'X-API-Key': AFFILIATUS_API_KEY,
    }

    payload = {
        'batch': True,
        'events': [
            {
                'event_type': 'conversion',
                'campaign_id': 'abc-123-def',
                'affiliate_id': affiliate_code,
                'properties': {
                    'order_id': order_id,
                    'order_value': order_value,
                },
            },
        ],
    }

    try:
        response = requests.post(AFFILIATUS_API_URL, json=payload, headers=headers)
        response.raise_for_status()
        print('Conversão enviada:', response.json())
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f'Erro ao enviar conversão: {e}')
        raise

# Uso
send_conversion('ORDER-123', 99.90, 'JOAO1')

Ruby (Net::HTTP)

require 'net/http'
require 'json'
require 'uri'

AFFILIATUS_API_KEY = ENV['AFFILIATUS_API_KEY']
AFFILIATUS_API_URL = 'https://api.affiliatus.io/v1/events'

def send_conversion(order_id, order_value, affiliate_code)
  uri = URI.parse(AFFILIATUS_API_URL)

  payload = {
    batch: true,
    events: [
      {
        event_type: 'conversion',
        campaign_id: 'abc-123-def',
        affiliate_id: affiliate_code,
        properties: {
          order_id: order_id,
          order_value: order_value
        }
      }
    ]
  }

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri.path)
  request['Content-Type'] = 'application/json'
  request['X-API-Key'] = AFFILIATUS_API_KEY
  request.body = payload.to_json

  response = http.request(request)

  if response.code.to_i == 200
    puts "Conversão enviada: #{response.body}"
    JSON.parse(response.body)
  else
    raise "HTTP Error: #{response.code} - #{response.body}"
  end
end

# Uso
send_conversion('ORDER-123', 99.90, 'JOAO1')

Go

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "time"
)

type Event struct {
    EventType   string      `json:"event_type"`
    CampaignID  string      `json:"campaign_id"`
    AffiliateID string      `json:"affiliate_id"`
    Properties  Properties  `json:"properties"`
}

type Properties struct {
    OrderID    string  `json:"order_id"`
    OrderValue float64 `json:"order_value"`
    URL        string  `json:"url"`
    Timestamp  string  `json:"timestamp"`
}

type Payload struct {
    Batch  bool    `json:"batch"`
    Events []Event `json:"events"`
}

func sendConversion(orderID string, orderValue float64, affiliateCode string) error {
    apiKey := os.Getenv("AFFILIATUS_API_KEY")
    apiURL := "https://api.affiliatus.io/v1/events"

    payload := Payload{
        Batch: true,
        Events: []Event{
            {
                EventType:   "conversion",
                CampaignID:  "abc-123-def",
                AffiliateID: affiliateCode,
                Properties: Properties{
                    OrderID:    orderID,
                    OrderValue: orderValue,
                    URL:        "https://seusite.com/checkout",
                    Timestamp:  time.Now().UTC().Format(time.RFC3339),
                },
            },
        },
    }

    jsonData, err := json.Marshal(payload)
    if err != nil {
        return fmt.Errorf("error marshaling JSON: %w", err)
    }

    req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
    if err != nil {
        return fmt.Errorf("error creating request: %w", err)
    }

    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", apiKey)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return fmt.Errorf("error sending request: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        return fmt.Errorf("HTTP error: %d", resp.StatusCode)
    }

    fmt.Println("Conversão enviada com sucesso!")
    return nil
}

func main() {
    err := sendConversion("ORDER-123", 99.90, "JOAO1")
    if err != nil {
        fmt.Printf("Erro: %v\n", err)
    }
}

Resposta da API

Sucesso (200 OK)

{
  "success": true
}

Erros Comuns

401 Unauthorized - API Key Inválida

{
  "statusCode": 401,
  "message": "API Key is required",
  "error": "Unauthorized"
}
Solução: Verifique se o header X-API-Key está sendo enviado corretamente.

403 Forbidden - API Key Revogada

{
  "statusCode": 403,
  "message": "API Key is revoked or inactive",
  "error": "Forbidden"
}
Solução: A API key foi revogada. Crie uma nova em “Configurações” → “API Keys”.

403 Forbidden - Limite Excedido

{
  "statusCode": 403,
  "message": "Conversion limit exceeded: Monthly conversion limit reached for starter plan. Current: 500/500",
  "error": "Forbidden"
}
Solução: Você atingiu o limite mensal de conversões do seu plano. Faça upgrade ou aguarde o próximo mês.

400 Bad Request - Dados Inválidos

{
  "statusCode": 400,
  "message": ["order_value must be a positive number"],
  "error": "Bad Request"
}
Solução: Verifique se todos os campos obrigatórios estão presentes e válidos.

429 Too Many Requests - Rate Limit

{
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests",
  "error": "Too Many Requests"
}
Solução: Você excedeu o limite de 70 requisições por minuto. Aguarde 1 minuto ou implemente retry com backoff.

Rate Limiting

A API tem limite de 70 requisições por minuto por API key. Boas práticas:
// Implementar retry com exponential backoff
async function sendConversionWithRetry(data, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await sendConversion(data);
    } catch (error) {
      if (error.response?.status === 429 && i < maxRetries - 1) {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        await new Promise((resolve) => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

Envio em Lote

Você pode enviar múltiplos eventos em uma única requisição:
{
  "batch": true,
  "events": [
    {
      "event_type": "conversion",
      "campaign_id": "abc-123-def",
      "affiliate_id": "JOAO1",
      "properties": {
        "order_id": "ORDER-1",
        "order_value": 99.90
      }
    },
    {
      "event_type": "conversion",
      "campaign_id": "abc-123-def",
      "affiliate_id": "MARIA2",
      "properties": {
        "order_id": "ORDER-2",
        "order_value": 149.90
      }
    }
  ]
}
Enviar em lote reduz o número de requisições e melhora performance!

Testando a Integração

1. Teste com cURL

curl -X POST https://api.affiliatus.io/v1/events \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sua_api_key_aqui" \
  -d '{
    "batch": true,
    "events": [{
      "event_type": "conversion",
      "campaign_id": "abc-123-def",
      "affiliate_id": "TEST01",
      "properties": {
        "order_id": "TEST-'$(date +%s)'",
        "order_value": 99.90
      }
    }]
  }'

Testando Page View ou Lead (Sem Properties)

curl -X POST https://api.affiliatus.io/v1/events \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sua_api_key_aqui" \
  -d '{
    "batch": true,
    "events": [{
      "event_type": "page_view",
      "campaign_id": "abc-123-def",
      "affiliate_id": "TEST01"
    }]
  }'

2. Verifique no Dashboard

  1. Vá em “Conversões” no menu lateral
  2. Procure pela conversão com o order_id de teste
  3. O status inicial será “Pendente”

3. Teste com Postman/Insomnia

Importe esta collection:
{
  "name": "Affiliatus API",
  "requests": [
    {
      "name": "Send Conversion",
      "method": "POST",
      "url": "https://api.affiliatus.io/v1/events",
      "headers": {
        "Content-Type": "application/json",
        "X-API-Key": "{{API_KEY}}"
      },
      "body": {
        "events": [
          {
            "event_type": "conversion",
            "campaign_id": "{{CAMPAIGN_ID}}",
            "affiliate_id": "{{AFFILIATE_CODE}}",
            "properties": {
              "order_id": "TEST-{{$timestamp}}",
              "order_value": 99.9
            }
          }
        ]
      }
    }
  ]
}

Solução de Problemas

Conversão não aparece no dashboard

Verifique:
  1. API key está ativa (não revogada)
  2. campaign_id está correto
  3. affiliate_id corresponde a um afiliado ativo
  4. Header X-API-Key está sendo enviado
  5. Response da API retornou 200 OK

Erro de autenticação

# Teste se a API key está válida
curl -X POST https://api.affiliatus.io/v1/events \
  -H "X-API-Key: sua_api_key" \
  -H "Content-Type: application/json" \
  -d '{"events":[]}'
Se retornar 200 OK, a chave está válida.

Timeout ou erro de rede

Implemente timeout e retry:
const axios = require("axios");

const client = axios.create({
  timeout: 10000, // 10 segundos
  retry: 3,
});

Comparação: API REST vs SDK JavaScript

CaracterísticaAPI RESTSDK JavaScript
Onde rodaBackend/ServerFrontend/Browser
Requer código Sim Sim
AutenticaçãoAPI KeyCampaign ID
SegurançaAlta (server-side)Média (client-side)
DependênciaNenhumaJavaScript habilitado
Rate limit70/min por key70/min por IP
Ideal paraIntegrações backendSites tradicionais

Boas Práticas

Faça

  • Armazene API key em variáveis de ambiente
  • Use HTTPS sempre
  • Implemente retry com backoff exponencial
  • Valide dados antes de enviar
  • Logue erros para debugging
  • Use order_id único para evitar duplicação
  • Envie eventos em lote quando possível
  • Use apenas os campos necessários - o endpoint é flexível

Não Faça

  • Nunca exponha a API key no frontend
  • Não commite API keys no Git
  • Não ignore erros da API
  • Não envie conversões duplicadas com mesmo order_id
  • Não ultrapasse o rate limit (70/min)

Próximos Passos


Precisa de Ajuda?

Não! A API key deve ser usada apenas no backend. No frontend, use o SDK JavaScript.
Não há limite. Crie quantas precisar (ex: uma para produção, outra para staging).
Não é possível recuperar. Você precisará revogar a antiga e criar uma nova.
Não, ela permanece válida até ser revogada manualmente.
Sim! Você pode enviar page_view e lead também usando o mesmo formato.
Dúvidas? Entre em contato pelo suporte ou consulte a documentação da API.