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.
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.
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 trazattributed, e flags como replayed ou deduplicated quando aplicável. O status HTTP reflete o desfecho:
Idempotência
Existem duas camadas independentes de idempotência emPOST /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 porsourceEventId, 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 emapproved 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:
conversion: nova relação cliente↔afiliado
conversion: nova relação cliente↔afiliado
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).charge: cobrança de ciclo 2+
charge: cobrança de ciclo 2+
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.refund: estorno total/parcial ou chargeback
refund: estorno total/parcial ou chargeback
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.cancellation: cancelamento de assinatura
cancellation: cancelamento de assinatura
Anula Comissões pendentes da assinatura. Idempotente: reentrega não re-anula o que já foi anulado.
Exemplo: cobrança de ciclo 2 por customerId
Desfechos da ingestão
Toda chamada produz exatamente umoutcome 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 porsourceEventId (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.