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

# Webhooks

> Receba notificações automáticas da AbacatePay sempre que algo importante acontecer — como um pagamento aprovado ou um saque concluído.

Pense nos webhooks como **“mensagens enviadas pela AbacatePay para o seu sistema”**, sem que você precise ficar consultando a API o tempo todo.

***

## Por que usar webhooks?

Sem webhooks, sua aplicação teria que **perguntar para a API a cada segundo**:

> "Esse pagamento já foi confirmado?"

Isso é lento e ineficiente.

Com webhooks, a AbacatePay avisa você **imediatamente**:

> "O pagamento foi confirmado. Aqui estão os dados."

Assim você pode:

* atualizar o status de um pedido
* liberar acesso a um produto
* enviar e-mails automáticos
* registrar movimentações financeiras

Tudo isso sem precisar fazer nada manualmente, e sem fazer seu cliente esperar.

***

## Como funciona na prática?

1. **Você cria um endpoint no seu sistema**\
   Ex.: `https://meusite.com/webhooks/abacatepay`

2. **Você cadastra esse endpoint no dashboard da AbacatePay**

3. **Sempre que algo importante acontece**, como um pagamento aprovado:
   * A AbacatePay envia um POST para a sua URL
   * O POST contém o evento (ex: `checkout.completed`, `transparent.completed`)
   * Seu sistema processa esse evento

É como receber uma notificação push — só que para servidores.

***

## Ambientes (Dev mode vs Produção)

<Card title="Ambientes da AbacatePay" horizontal>
  * Webhooks criados em **Dev mode** recebem eventos simulados
  * Webhooks criados em **Produção** recebem eventos reais

  Dessa forma, você pode testar tudo antes de ir para produção.
</Card>

***

## Segurança dos webhooks

Webhooks precisam ser seguros — afinal, qualquer pessoa poderia tentar enviar requisições falsas para sua aplicação.

Por isso, recomendamos duas camadas de proteção:

***

### 🔐 1. Secret na URL

Cada webhook tem um secret único, que vai na query string.

Ex.: [https://meusite.com/webhook/abacatepay?webhookSecret=SEU\_SECRET](https://meusite.com/webhook/abacatepay?webhookSecret=SEU_SECRET)

Seu backend confere:

```js theme={null}
if (req.query.webhookSecret !== process.env.WEBHOOK_SECRET) {
  return res.status(401).json({ error: "Unauthorized" });
}
```

### 🛡️ 2. Assinatura HMAC (verificação do corpo)

Mesmo que alguém descubra sua URL e seu secret, ainda não consegue falsificar o evento.

**Por quê?**\
Porque cada webhook enviado pela AbacatePay inclui uma assinatura no header:

Essa assinatura é gerada usando **HMAC-SHA256** e garante que:

* o corpo da requisição **não foi alterado**
* o evento realmente foi enviado pela AbacatePay

Seu backend deve recalcular a assinatura e comparar:

* Se for igual → ✅ evento é legítimo
* Se for diferente → ❌ evento rejeitado

Esse é o mesmo método usado por **Stripe, PayPal, Shopify, GitHub**, etc.

***

## 🔧 Exemplo de validação HMAC (Node.js)

> Este exemplo mostra como validar a assinatura HMAC enviada no header\
> `X-Webhook-Signature`.

```typescript theme={null}
import crypto from "node:crypto";

// Public HMAC key
const ABACATEPAY_PUBLIC_KEY =
  "t9dXRhHHo3yDEj5pVDYz0frf7q6bMKyMRmxxCPIPp3RCplBfXRxqlC6ZpiWmOqj4L63qEaeUOtrCI8P0VMUgo6iIga2ri9ogaHFs0WIIywSMg0q7RmBfybe1E5XJcfC4IW3alNqym0tXoAKkzvfEjZxV6bE0oG2zJrNNYmUCKZyV0KZ3JS8Votf9EAWWYdiDkMkpbMdPggfh1EqHlVkMiTady6jOR3hyzGEHrIz2Ret0xHKMbiqkr9HS1JhNHDX9";

/**
 * Verifies if the webhook signature matches the expected HMAC.
 * @param rawBody Raw request body string.
 * @param signatureFromHeader The signature received from `X-Webhook-Signature`.
 * @returns true if the signature is valid, false otherwise.
 */
export function verifyAbacateSignature(rawBody: string, signatureFromHeader: string) {
  const bodyBuffer = Buffer.from(rawBody, "utf8")

  const expectedSig = crypto
    .createHmac("sha256", ABACATEPAY_PUBLIC_KEY)
    .update(bodyBuffer)
    .digest("base64");

  const A = Buffer.from(expectedSig);
  const B = Buffer.from(signatureFromHeader);

  return A.length === B.length && crypto.timingSafeEqual(A, B);
}
```

***

## Criando um webhook no dashboard

<Steps>
  <Step title="Acesse a seção de Webhooks">
    <Card>
      <img src="https://mintcdn.com/abacatepay/A_mLrlQaTYJZv5aB/images/criar-webhook.png?fit=max&auto=format&n=A_mLrlQaTYJZv5aB&q=85&s=703a5b545260e77e7ad02809d5c18c79" alt="Interface mostrando webhooks" width="1898" height="940" data-path="images/criar-webhook.png" />

      <Card title="Abra a área de Webhooks">
        É aqui que você cria e gerencia seus endpoints de notificação.
      </Card>
    </Card>
  </Step>

  <Step title="Clique em Criar">
    <Card>
      <img src="https://mintcdn.com/abacatepay/A_mLrlQaTYJZv5aB/images/salvar-webhook.png?fit=max&auto=format&n=A_mLrlQaTYJZv5aB&q=85&s=169ad6e56800ce1e272b4e9e329adac8" alt="Configuração de webhook" width="1900" height="940" data-path="images/salvar-webhook.png" />

      <Card title="Inicie a configuração">
        Informe o nome e a URL que receberá os eventos.
      </Card>
    </Card>
  </Step>

  <Step title="Configure os detalhes">
    <Card>
      <Card title="O que você deve informar:" horizontal>
        * **Nome**: Ex.: “Pagamentos confirmados”
        * **URL**: Endpoint HTTPS que receberá os eventos
        * **Secret**: Chave usada para verificar a autenticidade
      </Card>
    </Card>
  </Step>
</Steps>

***

## Eventos suportados

| Evento                   | Quando é disparado                                     |
| ------------------------ | ------------------------------------------------------ |
| `checkout.completed`     | Pagamento de um checkout foi confirmado                |
| `checkout.refunded`      | Reembolso de um checkout foi concluído                 |
| `checkout.disputed`      | Disputa/chargeback aberta em um checkout               |
| `transparent.completed`  | Pagamento de um checkout transparente confirmado       |
| `transparent.refunded`   | Reembolso de um checkout transparente foi concluído    |
| `transparent.disputed`   | Disputa/chargeback aberta em um pagamento transparente |
| `subscription.completed` | Assinatura criada e ativada                            |
| `subscription.cancelled` | Assinatura cancelada                                   |
| `subscription.renewed`   | Cobrança recorrente da assinatura foi paga             |
| `transfer.completed`     | Transferência concluída com sucesso                    |
| `transfer.failed`        | Transferência falhou                                   |
| `payout.completed`       | Saque concluído com sucesso                            |
| `payout.failed`          | Saque falhou                                           |

Todos os webhooks v2 compartilham o mesmo formato de payload:

```json theme={null}
{
  "id": "log_abc123xyz",
  "event": "checkout.completed",
  "apiVersion": 2,
  "devMode": false,
  "data": { ... }
}
```

<Info>
  **Dados sensíveis:** O campo `taxId` (CPF/CNPJ) é mascarado nos payloads (ex: `123.***.***-**`). Para pagamentos com cartão, apenas os últimos 4 dígitos e a bandeira são enviados.
</Info>

Os payloads detalhados de cada evento estão documentados individualmente na seção **Eventos** na barra lateral.

***

## Estrutura dos payloads

### Quando `customer` está vazio

Se não houver cliente vinculado ao checkout, pagamento ou assinatura, o objeto `customer` será `null`.

***

## Boas práticas

<Card title="Recomendações importantes" horizontal>
  * Use **HTTPS** em todos os webhooks
  * Valide o **secret** e a **assinatura HMAC**
  * Registre cada evento recebido — processe cada um **uma única vez**
  * Responda **200 OK** somente após concluir o processamento
  * Implemente **retentativas com idempotência**
  * **Não realize validação do payload inteiro** dos webhooks (como com Zod), **evitando que mudanças futuras não quebrem seu endpoint**
</Card>

***

<Card title="Precisa de ajuda?" icon="headset" color="#25c2a0">
  Nossa equipe pode te ajudar. Contate-nos: <Icon icon="envelope" type="solid" /> [ajuda@abacatepay.com](mailto:ajuda@abacatepay.com)
</Card>
