> ## Documentation Index
> Fetch the complete documentation index at: https://userepass.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrar Stripe

> Conecte o Stripe e propague repass_cid na metadata para atribuir cada venda ao afiliado certo.

Conectar o Stripe à Repass **não** atribui vendas sozinho. São duas etapas:

1. **Receber o fato financeiro** — webhook do Stripe → ingestão (assinatura criada, cobrança, estorno, cancelamento).
2. **Saber o afiliado** — colocar o id do clique (`repass_cid` = `clk_…`) na metadata do checkout/assinatura, ou usar fallbacks (visitante, e-mail identificado, cupom).

Sem o passo 2, o webhook responde `200` com `outcome: unmatched` e **nada é gravado**.

<Warning>
  O passo que a maioria esquece é a **metadata**. Sem `repass_cid` (prefixo `clk_`) no objeto certo do Stripe, a venda chega na Repass mas não casa com nenhum afiliado.
</Warning>

## Pré-requisitos

Antes do primeiro webhook útil:

* Programa ativo com [regra de comissão](/docs/conceitos/programas-e-regras) vigente
* Afiliado aprovado com [link rastreável](/docs/conceitos/links-e-cupons)
* (Recomendado) [tracker client-side](/docs/guias/script-tracker-client-side) no seu site, para capturar `repass_cid` / `repass_vid` da URL após o redirect `/t/{token}`

## Passo 1: conectar o Stripe

No painel da Repass, em **Configurações → Integrações**:

* **Conectar Stripe** (OAuth) — configura webhook e credenciais em um passo, ou
* **Configurar manualmente** — aponte um webhook no Stripe para:

```
https://api.userepass.com/ingest/stripe/{organizationId}
```

Eventos a assinar:

* `invoice.paid` (ou `invoice.payment_succeeded`)
* `checkout.session.completed`
* `charge.refunded`
* `customer.subscription.deleted`
* `charge.dispute.created` (só tem efeito se você gravar também a **secret key** `sk_…`)

Cole o signing secret (`whsec_…`) no painel. A secret key da API (`sk_…`) é opcional: habilita chargebacks, taxas de gateway e resolução de cupom Stripe → atribuição por cupom.

<Info>
  Só **BRL** é suportado. Eventos em outra moeda são ignorados (`unsupported_currency`).
</Info>

Detalhes de autenticação HMAC, desfechos e configuração: [Ingestão](/docs/conceitos/ingestao).

## Passo 2: capturar o clique no seu site

Quando o visitante clica no link do afiliado (`GET /t/{token}`), a Repass redireciona para o seu destino com `repass_cid` e `repass_vid` na query. Persista esses valores até o checkout (a tag [`/t.js`](/docs/guias/script-tracker-client-side) faz isso automaticamente).

No signup/login, associe o visitante ao e-mail (`Repass.identify(...)`) para atribuição cross-device.

## Passo 3: injetar a metadata no Stripe (obrigatório para atribuição explícita)

A Repass lê dois campos da metadata:

| Campo        | Significado               | Prefixo                  |
| ------------ | ------------------------- | ------------------------ |
| `repass_cid` | Id do clique (`clickId`)  | deve começar com `clk_`  |
| `repass_pid` | Id do programa (opcional) | deve começar com `prog_` |

Valor sem o prefixo é descartado em silêncio.

### Assinatura (Checkout `mode: subscription`)

A conversão canônica vem de `invoice.paid` com `billing_reason = subscription_create`. O `checkout.session.completed` em modo subscription é **ignorado** de propósito (evita duplicar). Coloque a metadata na **subscription**:

```js theme={null}
const clickId = Repass.getClickId(); // ou o valor que você persistiu

const session = await stripe.checkout.sessions.create({
  mode: "subscription",
  line_items: [{ price: "price_...", quantity: 1 }],
  subscription_data: {
    metadata: {
      repass_cid: clickId, // clk_...
      // repass_pid: "prog_...", // se a org tem mais de um programa
    },
  },
});
```

O tradutor procura `repass_cid` / `repass_pid` na metadata da invoice, do line item e do `subscription_details` (incluindo o layout da API Stripe 2025+).

### Compra avulsa (Checkout `mode: payment`)

Coloque a metadata na **session**:

```js theme={null}
const session = await stripe.checkout.sessions.create({
  mode: "payment",
  metadata: {
    repass_cid: clickId,
  },
  line_items: [{ price: "price_...", quantity: 1 }],
  // ...
});
```

### Payment Intents / Subscriptions via API

Mesma ideia: grave `repass_cid` (e opcionalmente `repass_pid`) na metadata do objeto que o webhook traduz.

## O que cada evento vira

| Evento Stripe                                       | Vira na Repass                         |
| --------------------------------------------------- | -------------------------------------- |
| `invoice.paid` (`subscription_create`)              | Conversão `subscription_created`       |
| `invoice.paid` (ciclo / update / threshold)         | Cobrança (`charge`) do ciclo 2+        |
| `checkout.session.completed` (`mode: payment`)      | Conversão `one_time_purchase`          |
| `checkout.session.completed` (`mode: subscription`) | Ignorado (usa o invoice)               |
| `charge.refunded`                                   | Refund / clawback                      |
| `charge.dispute.created` + `sk_`                    | Chargeback                             |
| `customer.subscription.deleted`                     | Cancelamento (anula comissões em hold) |

Depois da primeira conversão atribuída, renovações e estornos amarram pelo `customerId` do Stripe — você **não** precisa reenviar `repass_cid` em cada ciclo.

## Desfechos (`outcome`)

O webhook responde **200** sempre que a assinatura é válida. O corpo traz o desfecho real:

| Outcome     | Significado                                                       |
| ----------- | ----------------------------------------------------------------- |
| `processed` | Conversão/comissão/refund aplicado                                |
| `replayed`  | Mesmo fato financeiro já processado (`sourceEventId`)             |
| `unmatched` | Sem afiliado (`no_attribution`) — quase sempre falta `repass_cid` |
| `skipped`   | Regra de negócio impediu o efeito                                 |
| `ignored`   | Evento não mapeado ou moeda ≠ BRL                                 |

## Fallbacks sem metadata

Se o cliente passou por um link rastreado e você identificou o e-mail (`/track/identify`), a Repass ainda pode atribuir pela cascata `visitorId` → `emailHash` → fingerprint. A metadata continua sendo o caminho **explícito e mais confiável**, especialmente quando o checkout não herda cookies do site.

Cupons sincronizados com o Stripe também atribuem quando a secret key está configurada (promotion code → `couponCode`).

## Alternativas ao webhook Stripe

| Caminho                                                   | Quando usar                                                     |
| --------------------------------------------------------- | --------------------------------------------------------------- |
| [`POST /conversions`](/docs/guias/conversoes-server-to-server) | Você controla o momento e manda `clickId` direto                |
| [`POST /ingest/custom`](/docs/conceitos/ingestao)              | Gateway que não é Stripe                                        |
| [Tracker client-side](/docs/guias/script-tracker-client-side)  | Complemento; confirme com S2S/webhook e o mesmo `sourceEventId` |

## Próximos passos

<CardGroup cols={2}>
  <Card title="Ingestão" icon="inbox-in" href="/docs/conceitos/ingestao">
    Contrato normalizado, HMAC e configuração do webhook.
  </Card>

  <Card title="Tracker client-side" icon="code" href="/docs/guias/script-tracker-client-side">
    Capturar repass\_cid no browser sem backend.
  </Card>

  <Card title="Conversões S2S" icon="server" href="/docs/guias/conversoes-server-to-server">
    Enviar conversões pelo seu backend.
  </Card>

  <Card title="Refund e clawback" icon="rotate-left" href="/docs/guias/refund-e-clawback">
    Como estornos viram comissões negativas.
  </Card>
</CardGroup>
