Skip to main content
Uma Conversão é a prova auditável de “por que este Afiliado merece Comissão sobre este cliente”. Quando você registra uma conversão pela API, o Repass roda de forma síncrona todo o pipeline de decisão (matching de identidade, Atribuição ao Clique/Cupom vencedor, resolução da regra de Comissão, scoring antifraude e geração da Comissão do ciclo 1) e congela cada decisão em snapshots imutáveis. Esta página cobre as duas formas de enviar conversões server-to-server (S2S): POST /conversions, o endpoint S2S direto, e POST /ingest/custom, o endpoint genérico de Ingestão para quem não usa um gateway suportado. Para o conceito completo de atribuição e do motor antifraude, veja Conversões e fraude; para a mecânica de idempotência, veja Idempotência.

Qual endpoint usar

Os dois endpoints alimentam o mesmo motor de criação de conversões. A diferença está no contrato e na origem registrada.
Ambos exigem autenticação por sessão (cookie) ou API key (Authorization: Bearer rstr_...). O organizationId e o ator vêm do contexto de auth. Você nunca envia o organizationId no corpo. Veja Autenticação.

Registrar uma conversão com POST /conversions

Você precisa enviar o tipo, o valor (em centavos), o cliente, um sourceEventId e ao menos um identificador de matching. O motor decide a atribuição e devolve a conversão criada, ou explica por que não criou.

Identificadores de matching

O matching é um fallthrough determinístico: o primeiro identificador que produzir candidatos vence. A ordem é fixa:
1

clickId

Clique explícito (clk_<ULID>). Só é candidato se pertence ao mesmo Programa, não é bot, não expirou e ocorreu antes da conversão. Um clickId inválido não falha: o motor desce para o próximo identificador.
2

visitorId

Identidade do visitante para matching cross-device.
3

emailHash

Hash SHA-256 do e-mail do cliente (hex). Se você não enviar emailHash mas enviar customer.email, o Repass deriva o hash do e-mail em minúsculas e usa tanto no matching quanto no customerEmailHash persistido.
4

fingerprint

Hash SHA-256 (hex) de fingerprint do dispositivo.
Além desses, você pode enviar couponCode (1 a 64 chars, normalizado para maiúsculas). Cupom inválido ou inativo rejeita a conversão com 404. Quando há Cupom de um Afiliado e Clique atribuível de outro, o Repass aplica a política de conflito do Programa (coupon_wins, click_wins ou split_50_50). Veja Atribuição.
Pelo menos um identificador é obrigatório: clickId, visitorId, emailHash, fingerprint, couponCode ou customer.email. Um corpo sem nenhum deles retorna 400 parameter_invalid.

Parâmetros do corpo

string
required
Tipo da conversão: subscription_created, one_time_purchase, trial_converted, upgrade ou custom. O tipo upgrade tem semântica de dedupe especial (veja Duplicatas e dedupe).
integer
required
Valor da cobrança que originou a conversão, em centavos (inteiro ≥ 0). Nunca use floats.
string
Sempre BRL (único valor aceito). Default BRL.
object
required
Identificação do cliente.
string
required
Chave de idempotência de negócio (1 a 255 chars), permanente por organização. Veja Idempotência por sourceEventId.
string
prog_<ULID>. Necessário quando a organização tem mais de um Programa e você não envia clickId.
string
clk_<ULID> do Clique a atribuir.
string
Identidade do visitante.
string
SHA-256 hex do e-mail do cliente.
string
SHA-256 hex do fingerprint do dispositivo.
string
Código do Cupom (1 a 64 chars).
string
Produto/plano da cobrança. Confrontado com applicableProductIds da regra: se a regra restringe produtos e o productId não está na lista, a Comissão é pulada (product_not_applicable). Sem productId, comissiona normalmente.
string
Momento de negócio da conversão (ISO 8601). Default: agora.

Exemplo

Desfechos possíveis

A criação não é binária. O envelope sempre traz attributed, e flags como replayed ou deduplicated quando aplicável. O status HTTP reflete o desfecho:
attributed: false com 200 não é erro: significa que o evento chegou mas não havia a quem atribuir. Trate-o como “nada a comissionar”, não como falha de envio. Reenviar o mesmo sourceEventId não muda o resultado.

Idempotência

Existem duas camadas independentes de idempotência em POST /conversions, em chaves diferentes. Entender a distinção evita conversões duplicadas e reentregas problemáticas.

Idempotência por sourceEventId

É a idempotência de negócio, permanente (sem TTL) e escopada por organização. O mesmo sourceEventId nunca cria duas conversões, qualquer que seja o Idempotency-Key. Uma reentrega devolve a conversão original com replayed: true, sem reemitir os eventos conversion.created / commission.created. Use como sourceEventId o id do fato financeiro na origem (o id da invoice, do pagamento ou do pedido no seu sistema), não um valor aleatório por requisição. Assim, quando seu sistema reenvia o mesmo fato, o Repass o reconhece.

Idempotency-Key (transporte HTTP)

É a idempotência de transporte, escopada a organização + usuário e calculada por chave + hash do corpo. Ela curto-circuita reentregas idênticas do mesmo cliente (timeouts, retries de rede) e devolve a resposta armazenada com header Idempotent-Replay: true. POST /conversions aceita o header Idempotency-Key.
As duas camadas operam de forma independente: a HTTP protege contra reenvios idênticos do seu cliente; a de negócio (sourceEventId) garante unicidade do fato mesmo entre requisições com Idempotency-Key diferentes. Detalhes em Idempotência.

Duplicatas e dedupe

Além do replay por sourceEventId, o motor aplica dedupe por cliente ativo: um cliente que já tem conversão pending ou approved no mesmo Programa não gera nova atribuição: a chamada retorna a conversão original com deduplicated: true. A exceção é type: upgrade: em vez de deduplicar, cria-se uma conversão filha vinculada à original via parentConversionId, herdando o Afiliado da conversão original (sem rodar matching de novo).

Estados da conversão

A conversão criada nasce em approved na maioria dos casos. Se o score antifraude cair na faixa de revisão, ela nasce pending e fica travada aguardando decisão manual, sem bloquear o resto do Programa. O scoring é determinístico (regras com pesos, score de 0 a 1) e as faixas de decisão (approveBelow / reviewAbove) são configuráveis por organização. A mecânica completa de sinais, faixas e a fila de revisão está em Conversões e fraude.

Ingestão via POST /ingest/custom

Quando você não tem um gateway suportado, POST /ingest/custom recebe o evento normalizado do ciclo financeiro inteiro num único contrato. Toda conversão criada por aqui registra source: "webhook", e a idempotência, a atribuição e a contabilidade de Comissões são herdadas integralmente dos módulos de Conversões e Comissões. Veja Ingestão. O corpo é uma união discriminada por kind:
Mesmos campos de POST /conversions (type, amountCents, customer, sourceEventId, identificadores de matching). Atribui e cria a conversão. Se não atribuir, o desfecho é unmatched (nada persistido).
Cobrança recorrente de uma conversão já existente. Referencia a conversão por conversionId ou customerId. A Comissão do ciclo é calculada pelo módulo de Comissões.
Referencia a cobrança original por chargeSourceEventId (ou billingCycle). Refund total de Comissão não paga vira void; parcial vira clawback proporcional. Para chargeback, envie chargeback: true.
Anula Comissões pendentes da assinatura. Idempotente: reentrega não re-anula o que já foi anulado.
Para charge, refund e cancellation você precisa enviar conversionId ou customerId (pelo menos um). Um conversionId explícito inexistente retorna 404; um customerId com mais de uma conversão ativa retorna o desfecho skipped (ambiguous_customer), nunca chuta.

Exemplo: cobrança de ciclo 2 por customerId

Desfechos da ingestão

Toda chamada produz exatamente um outcome terminal:
Diferente do webhook de gateway, POST /ingest/custom não mascara erros de domínio: um conversionId inexistente vira 404 e um conflito de domínio (ex.: cobrança contra conversão já refunded) vira 409. Veja Erros.

Idempotência na ingestão

A ingestão usa apenas a idempotência de negócio por sourceEventId (permanente). As rotas /ingest/ não aceitam o header Idempotency-Key. Não o envie aqui. Reentregas do mesmo fato (mesmo sourceEventId) produzem um único efeito e retornam replayed. Use o id do objeto financeiro de origem como sourceEventId para que reentregas sejam deduplicadas corretamente.

Boas práticas

sourceEventId estável

Derive-o do id do fato na origem (invoice, pedido), nunca de um UUID aleatório por requisição.

Trate attributed: false

Não é erro nem motivo para retry: é “sem a quem atribuir”.

Centavos e basis points

Valores monetários em centavos (inteiro); percentuais em basis points. Nunca floats.

Reenvie com segurança

Em timeouts, reenvie com o mesmo sourceEventId (e Idempotency-Key em /conversions).

Próximos passos

Idempotência

As duas camadas em detalhe e como compor as chaves.

Conversões e fraude

Pipeline de decisão, snapshots e o motor antifraude.

Atribuição

Modelos, janela e o conflito Cupom × Clique.

Refund e clawback

Estornos, chargebacks e devolução de Comissão.