program (e, opcionalmente, a um usuário da plataforma), com status, tier e dados de pagamento/fiscais próprios. O mesmo parceiro pode ter registros independentes em programas diferentes, cada um com seu próprio ciclo de vida.
Esta página descreve como afiliados entram em um programa, como são aprovados, como mudam de tier e como seu estado evolui ao longo do tempo. Para o cálculo de quanto recebem, veja Comissões; para os links que geram, veja Links e cupons.
Anatomia de um afiliado
O recursoaffiliate usa o prefixo de ID aff_ seguido de um ULID (veja IDs e recursos). Campos relevantes ao negócio:
string
Identificador do afiliado (
aff_ + ULID).string
Programa (
prog_) ao qual a participação pertence.string
Nome do afiliado (1 a 120 caracteres).
string
E-mail do afiliado. Sempre normalizado para minúsculas e único por programa.
string
Estado do ciclo de vida:
pending, approved, rejected, paused ou banned. Resolvido na criação a partir do mode e do approvalMode do programa (ver a seção Aprovação abaixo).string | null
Nome do tier. Validado contra os tiers do programa quando o programa os define; texto livre quando não.
string | null
Regra de comissão específica deste afiliado (
comm_rule_), sobrepondo a do programa/tier. Deve pertencer ao mesmo programa.integer | null
Versão dos termos do programa aceita pelo afiliado.
string
Método de pagamento:
pix, bank_transfer, wise ou paypal. Default pix.string | null
Chave PIX (1 a 140 caracteres). Acoplada a
pixKeyType: ambas definidas ou ambas nulas.string | null
Tipo da chave PIX:
cpf, cnpj, email, phone ou random.string | null
CNPJ normalizado a 14 dígitos (sem máscara). Todo afiliado é pessoa jurídica; o CNPJ é insumo da validação de nota fiscal quando a política
nfMode a exige (veja Fiscal).Dinheiro é sempre representado em centavos (inteiros) e percentuais em basis points. O saldo do afiliado usa moeda fixa
BRL.Ciclo de vida
O status do afiliado segue uma máquina de estados explícita. A criação resolve o estado inicial (pending ou approved); a partir daí, o status só muda pelas ações dedicadas.
rejected e banned são estados terminais: não há transição de saída. Qualquer transição não listada (por exemplo pause a partir de pending, ou approve a partir de approved) é rejeitada com 409 Conflict (param status). Veja Erros para o envelope completo.
Efeitos por estado
pending: afiliado pode acessar o portal, mas os links ainda não rastreiam (cliques redirecionam sem registrar).approved: operação plena; o afiliado recebe um link default automaticamente.paused: links continuam redirecionando e cliques são registrados, mas novas conversões não geram comissão (motivoaffiliate_paused). Comissões existentes seguem seu ciclo normalmente.rejected: portal em modo somente leitura do próprio cadastro; links inativos.banned: links inativos imediatamente; aciona a revisão das comissões existentes e bloqueia payouts futuros.
Modos de cadastro
Há dois modos de criação via API, controlados pelo campomode em POST /programs/:programId/affiliates (default direct):
direct: cadastro direto pelo operador
direct: cadastro direto pelo operador
O operador cria o afiliado já aprovado. Ignora o
approvalMode do programa: entra approved mesmo em programa com aprovação manual, e recebe o link default na criação.invite: convite individual por e-mail
invite: convite individual por e-mail
O estado inicial é resolvido pelo
approvalMode do programa (ver abaixo). Use quando o parceiro precisa passar pelo fluxo de aprovação do programa.Para migrar histórico de outra plataforma, a criação aceita os campos
importedTotalEarnedCents e importedSince: metadados informativos do histórico pré-migração que não geram eventos de comissão nativos.Aprovação
Paramode=invite, o estado inicial vem do approvalMode configurado no Programa (veja Programas e regras):
Afiliados que entram
approved (na criação direta, por aprovação automática ou via ação approve) recebem um link default automaticamente. A criação do link é idempotente: se já existe um link default, o existente é retornado, por isso re-aprovações nunca duplicam links. A ação resume não recria o link default.
Exemplos
Resposta da criação (201)
Banimento e tratamento de comissões
ban (e reject) exige um reason no corpo. A ausência retorna 400 (param reason). A razão entra no payload do evento. O banimento não apaga histórico: os dados são retidos por obrigação de auditoria financeira.
Ao banir, as comissões existentes do afiliado são tratadas automaticamente (a operação é idempotente, então repeti-la não gera efeitos duplicados):
- Comissões
pending→voided(razãoaffiliate_banned, eventocommission.voided). - Comissões
approvedainda não pagas → entram em revisão manual (underReview, eventocommission.review_required). - Comissões já pagas permanecem intactas.
Os eventos
commission.* gerados pela revisão de comissões pertencem às comissões e não aparecem na timeline do afiliado, que lista apenas eventos do próprio afiliado. Veja Conversões e fraude para o ciclo de comissões.Tiers e mudança de tier
Um Programa pode definir tiers ordenados (por exemplo bronze → prata → ouro), cada um com seu próprio histórico (opcional) de regra de comissão; um tier sem regra própria usa a regra padrão do programa. A mudança de tier é feita porPOST /affiliates/:affiliateId/tier com { "tier": "ouro" } (ou { "tier": null } para limpar).
- Tier deve existir quando o programa define tiers; um nome desconhecido retorna
404(paramtier). Se o programa não define tiers, qualquer texto é aceito. - Limpar o tier (
null) é sempre permitido. - No-op: trocar para o tier atual retorna o afiliado sem emitir evento.
- Mudança vale para o futuro: afeta apenas comissões de conversões futuras. Para aplicar retroativamente, use Reprocessamento.
affiliate.tier_changed com before e after (nomes de tier, podendo ser null).
Aceite de termos
O cadastro do afiliado está sujeito ao aceite dos termos versionados do programa. Cada programa mantém sua própria sequência de versões, chaveada por(programId, version). Veja Termos.
Quando um afiliado aceita uma versão, o campo acceptedTermsVersion é gravado e o evento affiliate.terms_accepted é emitido (com programId e termsVersion). A versão precisa existir, caso contrário a operação retorna 404 (param termsVersion).
A API de termos publica e lista as versões por programa. Ao registrar um aceite,
acceptedTermsVersion é gravado no afiliado e affiliate.terms_accepted é emitido. Veja Termos.Saldo e timeline
Cada afiliado tem dois recursos de consulta derivados:Saldo
GET /affiliates/:affiliateId/balance: resumo financeiro derivado das comissões.Timeline
GET /affiliates/:affiliateId/timeline: eventos de domínio do afiliado, em ordem cronológica de auditoria.BRL) traz:
integer
Comissões pendentes.
integer
Comissões aprovadas e ainda não pagas.
integer
Comissões em revisão manual.
integer
Estornos (débitos).
integer
Projeção do próximo payout =
max(0, approvedCents + clawbackCents). A projeção nunca é negativa: um débito que excede o aprovado não vira cobrança, rola para payouts futuros.GET /affiliates/aff_01J9.../balance
affiliate.created, affiliate.approved, affiliate.tier_changed, etc.), cada um com id, type, payload, metadata, occurredAt e recordedAt. Veja Event store para como consultar e auditar eventos pela API.
Listagem e filtros
GET /affiliates usa paginação por cursor (veja Paginação): limit (1 a 100, default 25), starting_after, ending_before. Filtros disponíveis: program_id, status, tier (igualdade exata) e q (busca case-insensitive por substring em nome ou e-mail).
{ "data": [...], "hasMore": boolean }. Este recurso não suporta expand[].
Regras de negócio
Estado inicial por modo de aprovação
Estado inicial por modo de aprovação
Por convite, o estado inicial vem do
approvalMode do programa: automatic → approved; manual → pending; domain_whitelist → approved se o domínio do e-mail estiver na whitelist (case-insensitive), senão pending. mode=direct ignora o approvalMode e entra sempre approved.Participações independentes por programa
Participações independentes por programa
O mesmo parceiro pode participar de múltiplos programas (da mesma org ou de orgs diferentes). Cada participação é um registro
affiliate independente, com status, tier e dados próprios. O e-mail é único por programa, não global.Aceite de termos versionados
Aceite de termos versionados
O cadastro está sujeito ao aceite dos termos versionados do programa, resolvidos por
(programId, version). O aceite grava acceptedTermsVersion e emite affiliate.terms_accepted.Transições válidas e eventos
Transições válidas e eventos
Transições permitidas:
pending → approved/rejected; approved ↔ paused; approved/paused → banned. rejected e banned são terminais. Toda transição gera um evento próprio com o ator (user, system ou api_key).Efeitos de estado e banimento
Efeitos de estado e banimento
Cada estado tem efeitos definidos (ver acima). O banimento exige razão registrada, gera
affiliate.banned com reason e ator, e dispara a revisão das comissões existentes. O histórico não é apagado (retenção para auditoria financeira).Tiers
Tiers
O programa pode definir tiers ordenados, cada um com seu próprio histórico (opcional) de regra de comissão; sem regra própria, o tier usa a regra padrão do programa. A mudança de tier afeta apenas conversões futuras (retroatividade só via Reprocessamento) e gera
affiliate.tier_changed. Downgrade nunca é permitido no meio de um ciclo de payout aberto.Todos os endpoints exigem autenticação via API key (
Authorization: Bearer rstr_...). As operações são sempre resolvidas no escopo da sua conta. Veja Autenticação.Próximos passos
Programas e regras
Configure o
approvalMode, a whitelist de domínios e os tiers que governam a entrada e a comissão dos afiliados.Links e cupons
Entenda o link default criado na aprovação e como gerar links e cupons adicionais.
Comissões
Veja como o tier e a regra custom do afiliado determinam quanto ele recebe.
Termos
Publique versões de termos por programa e acompanhe os aceites.