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

# Webhooks

> Receba notificações em tempo real sobre eventos de pagamento

## Visão Geral

Webhooks permitem que sua aplicação receba notificações automáticas quando eventos importantes acontecem, como quando um pagamento é confirmado ou um produto é criado.

## Configurando Webhooks

<Steps>
  <Step title="Acesse o Dashboard">
    Faça login no [Dashboard da Garu](https://garu.com.br/inicio)
  </Step>

  <Step title="Navegue até Webhooks">
    Vá para **Configurações** → **Webhooks**
  </Step>

  <Step title="Adicione um endpoint">
    Clique em **Adicionar webhook** e insira a URL do seu endpoint
  </Step>

  <Step title="Selecione os eventos">
    Escolha quais eventos deseja receber
  </Step>

  <Step title="Copie o segredo">
    Salve o segredo do webhook para validar as assinaturas
  </Step>
</Steps>

## Eventos Disponíveis

### Eventos de Produto

| Evento            | Descrição                  |
| ----------------- | -------------------------- |
| `product.created` | Um novo produto foi criado |
| `product.updated` | Um produto foi atualizado  |
| `product.deleted` | Um produto foi desativado  |

### Eventos de Transação

| Evento                          | Descrição                                                                                                             |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `transaction.created`           | Uma nova transação foi iniciada                                                                                       |
| `transaction.updated`           | Uma transação teve seus dados atualizados                                                                             |
| `transaction.payment.succeeded` | Pagamento confirmado                                                                                                  |
| `transaction.payment.failed`    | Pagamento recusado (com `failureCode` normalizado — ver [Códigos de falha](/api-reference/webhooks/codigos-de-falha)) |
| `transaction.canceled`          | Transação cancelada (pelo seller, contrato ou operadora)                                                              |
| `transaction.chargeback`        | Chargeback registrado pelo emissor                                                                                    |
| `transaction.refunded`          | Pagamento estornado                                                                                                   |

<Note>
  O evento legado `transaction.failed` continua sendo entregue para endpoints que já o assinam, mas a partir da v0.8.0 prefira `transaction.payment.failed` / `transaction.canceled` / `transaction.chargeback` — eles separam falha técnica, cancelamento e chargeback.
</Note>

### Eventos de Cobrança Agendada (Scheduled Charge)

| Evento                                          | Descrição                                                                                  |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `scheduled_charge.created`                      | Cobrança agendada criada                                                                   |
| `scheduled_charge.updated`                      | Dados da série atualizados                                                                 |
| `scheduled_charge.canceled`                     | Cobrança avulsa cancelada                                                                  |
| `scheduled_charge.paid`                         | Ciclo da série pago (carrega `seriesId` + `cycleNumber`)                                   |
| `scheduled_charge.overdue`                      | Ciclo entrou em atraso                                                                     |
| `scheduled_charge.cycle_failed`                 | Retries de cartão esgotados (carrega `failureCode`, `failureReason`, `gatewayFailureCode`) |
| `scheduled_charge.recurrence_canceled`          | Recorrência cancelada (cancela ciclos futuros)                                             |
| `scheduled_charge.cancel_at_period_end_set`     | Soft-cancel ativado                                                                        |
| `scheduled_charge.cancel_at_period_end_cleared` | Soft-cancel revertido                                                                      |
| `scheduled_charge.payment_method_attached`      | Cartão salvo no ciclo 1                                                                    |
| `scheduled_charge.payment_method_changed`       | Cartão trocado                                                                             |
| `scheduled_charge.payment_method_cleared`       | Cartão removido (DELETE /:id/payment-method)                                               |

### Eventos de Customer (Trial)

| Evento                     | Descrição                    |
| -------------------------- | ---------------------------- |
| `customer.trial_started`   | Trial iniciado               |
| `customer.trial_converted` | Trial converteu em pagamento |
| `customer.trial_lapsed`    | Trial expirou sem pagamento  |

### Eventos de Payment Method (Cartão Salvo)

| Evento                         | Descrição                                                            |
| ------------------------------ | -------------------------------------------------------------------- |
| `payment_method.expiring_soon` | Cartão vence em D-30, D-14 ou D-7 (um disparo por estágio)           |
| `payment_method.expired`       | Cartão venceu — Garu flippou o status para `expired` automaticamente |

### Eventos de Assinatura

| Evento                   | Descrição              |
| ------------------------ | ---------------------- |
| `subscription.created`   | Nova assinatura criada |
| `subscription.activated` | Assinatura ativada     |
| `subscription.paused`    | Assinatura pausada     |
| `subscription.cancelled` | Assinatura cancelada   |
| `subscription.renewed`   | Assinatura renovada    |

<Note>
  **[Pix Automático](/guias/pix-automatico) não cria eventos novos.** Assinaturas e cobranças no Pix Automático disparam exatamente os mesmos eventos de assinatura e transação que o cartão. Para diferenciar a origem, verifique `paymentMethod === 'pix_automatic'` no payload — o campo `paymentMethod` aceita `pix`, `boleto`, `card` e `pix_automatic`.
</Note>

### Eventos de Checkout Session

| Evento                       | Descrição                                   |
| ---------------------------- | ------------------------------------------- |
| `checkout.session.completed` | Pagamento da checkout session foi concluído |
| `checkout.session.expired`   | Checkout session expirou sem pagamento      |

## Formato do Payload

Todos os webhooks seguem este formato:

```json theme={null}
{
  "event": "transaction.paid",
  "timestamp": "2024-12-24T10:30:00.000Z",
  "data": {
    // Dados específicos do evento
  }
}
```

### Exemplo: Pagamento Confirmado

```json theme={null}
{
  "event": "transaction.paid",
  "timestamp": "2024-12-24T10:30:00.000Z",
  "data": {
    "id": 456,
    "productId": 123,
    "productName": "Curso de Marketing Digital",
    "value": 297.00,
    "paymentMethod": "pix",
    "customer": {
      "name": "João Silva",
      "email": "joao@email.com",
      "document": "123.456.789-00"
    },
    "paidAt": "2024-12-24T10:30:00.000Z"
  }
}
```

### Exemplo: Produto Criado

```json theme={null}
{
  "event": "product.created",
  "timestamp": "2024-12-24T10:30:00.000Z",
  "data": {
    "id": 123,
    "name": "Curso de Marketing Digital",
    "value": 297.00,
    "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "sellerId": 456
  }
}
```

### Exemplo: Checkout Session Concluída

```json theme={null}
{
  "event": "checkout.session.completed",
  "timestamp": "2024-12-24T14:30:00.000Z",
  "data": {
    "id": "cs_ABC123xyz",
    "status": "complete",
    "product_id": 123,
    "transaction_id": 789,
    "customer_email": "joao@email.com",
    "metadata": {
      "order_id": "12345"
    },
    "client_reference_id": "order_abc123",
    "completed_at": "2024-12-24T14:30:00.000Z"
  }
}
```

### Exemplo: Checkout Session Expirada

```json theme={null}
{
  "event": "checkout.session.expired",
  "timestamp": "2024-12-25T12:00:00.000Z",
  "data": {
    "id": "cs_DEF456uvw",
    "status": "expired",
    "product_id": 123,
    "metadata": {
      "order_id": "67890"
    },
    "client_reference_id": "order_def456",
    "expires_at": "2024-12-25T12:00:00.000Z"
  }
}
```

## Validando Assinaturas

Para garantir que o webhook veio da Garu, valide a assinatura:

<Snippet file="snippets/webhook-validation.mdx" />

## Boas Práticas

<AccordionGroup>
  <Accordion title="Responda rapidamente">
    Retorne HTTP 200 o mais rápido possível (em até 5 segundos). Processe a lógica de negócio de forma assíncrona.
  </Accordion>

  <Accordion title="Implemente idempotência">
    Webhooks podem ser enviados mais de uma vez. Use o ID do evento para evitar processamento duplicado.
  </Accordion>

  <Accordion title="Use HTTPS">
    Configure seu endpoint com HTTPS para garantir a segurança dos dados.
  </Accordion>

  <Accordion title="Valide sempre a assinatura">
    Nunca processe webhooks sem validar a assinatura. Isso protege contra ataques.
  </Accordion>

  <Accordion title="Monitore falhas">
    Configure alertas para quando seu endpoint falhar em receber webhooks.
  </Accordion>
</AccordionGroup>

## Retry Policy

Se seu endpoint não responder com 2xx, a Garu tentará reenviar com backoff:

| Tentativa | Intervalo desde a anterior |
| --------- | -------------------------- |
| 1         | 1 minuto                   |
| 2         | 5 minutos                  |
| 3         | 30 minutos                 |
| 4         | 2 horas                    |
| 5         | 8 horas                    |
| 6         | 16 horas                   |

Após 6 tentativas sem sucesso (\~26h36min de janela total), o webhook é marcado como falho.

## Testando Webhooks

Para testar localmente, use ferramentas como:

* [ngrok](https://ngrok.com/) - Cria um túnel para seu localhost
* [webhook.site](https://webhook.site/) - Inspeciona webhooks recebidos

```bash theme={null}
# Usando ngrok
ngrok http 3000

# Seu endpoint público será algo como:
# https://abc123.ngrok.io/webhooks/garu
```

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Exemplos de Código" icon="code" href="/api-reference/exemplos">
    Implementações completas em várias linguagens
  </Card>

  <Card title="Solução de Problemas" icon="wrench" href="/api-reference/troubleshooting">
    Resolva erros comuns
  </Card>
</CardGroup>
