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

# Criar um plugin

> Como empacotar hooks reutilizáveis em um plugin

## Visão geral

Plugins são módulos que empacotam hooks do **pagamentos.dev** em unidades
reutilizáveis. Um plugin nada mais é do que uma função que retorna um array
de hooks configurados.

Você pode criar plugins para:

* Enviar notificações (e-mail, Slack, SMS)
* Sincronizar dados com CRM, banco de dados ou ERP
* Rastrear analytics e métricas
* Cache de consultas
* Auditoria e logging
* Qualquer lógica que reaja a eventos de pagamento

## Estrutura de um plugin

```
pagamentos-plugin-meu-plugin/
├── package.json
├── tsconfig.json
├── src/
│   └── index.ts
├── README.md
└── .npmignore
```

## Passo a passo

### 1. Instale as dependências

```bash npm theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
npm i pagamentos --save-peer
```

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "name": "pagamentos-plugin-meu-plugin",
  "peerDependencies": {
    "pagamentos": "^0.x"
  },
  "devDependencies": {
    "pagamentos": "file:../pagamentos"
  }
}
```

### 2. Defina as opções do plugin

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export interface PluginNotificacoesOptions {
  webhookUrl: string
  canal?: 'slack' | 'discord' | 'teams'
}
```

### 3. Escolha os hooks necessários

O **pagamentos.dev** oferece dois tipos de hooks que seu plugin pode usar:

| Tipo               | Quando dispara                        | Exemplos de uso                      |
| ------------------ | ------------------------------------- | ------------------------------------ |
| **Lifecycle hook** | Após uma operação de API bem-sucedida | Sincronizar dados, cache, auditoria  |
| **Webhook hook**   | Quando um evento assíncrono chega     | Notificar pagamento, liberar produto |

### 4. Implemente o plugin

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import {
  onCobrancaCreated,
  onWebhookEvent,
  onCobrancaCancelled,
  type LifecycleHook,
  type WebhookHook
} from 'pagamentos'

export interface PluginNotificacoesOptions {
  webhookUrl: string
  canal: 'slack' | 'discord' | 'teams'
}

export function pluginNotificacoes(
  options: PluginNotificacoesOptions
): (LifecycleHook | WebhookHook)[] {
  return [
    // Notifica quando uma cobrança é criada
    onCobrancaCreated(async (evt) => {
      await enviarNotificacao(options, {
        texto: `Nova cobrança criada: R$ ${(evt.input.valor / 100).toFixed(2)}`,
        cor: 'azul'
      })
    }),

    // Notifica quando o pagamento é confirmado
    onWebhookEvent('pagamento.realizado', async (event) => {
      await enviarNotificacao(options, {
        texto: `Pagamento confirmado: R$ ${(event.data.cobranca.valor / 100).toFixed(2)}`,
        cor: 'verde'
      })
    }),

    // Notifica quando a cobrança é cancelada
    onCobrancaCancelled(async (evt) => {
      await enviarNotificacao(options, {
        texto: `Cobrança cancelada: ${evt.output.id}`,
        cor: 'vermelho'
      })
    })
  ]
}

async function enviarNotificacao(
  options: PluginNotificacoesOptions,
  payload: { texto: string; cor: string }
) {
  // Implementação específica para cada canal
  await fetch(options.webhookUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ text: payload.texto })
  })
}
```

### 5. Consumindo o plugin

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { Pagamentos, mercadopago } from 'pagamentos'
import { pluginNotificacoes } from 'pagamentos-plugin-notificacoes'

const pg = new Pagamentos({
  providers: [mercadopago({ accessToken: '...' })],
  hooks: [
    ...pluginNotificacoes({
      webhookUrl: process.env.SLACK_WEBHOOK_URL!,
      canal: 'slack'
    })
  ]
})
```

## Tipos de plugin

### Plugin de lifecycle

Reage a operações de API. Ideal para ações síncronas e previsíveis.

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { onClienteCreated, onCobrancaCancelled } from 'pagamentos'

export function pluginSyncDatabase(db: Database) {
  return [
    onClienteCreated(async (evt) => {
      await db.clientes.upsert({
        id: evt.output.id,
        nome: evt.input.nome
      })
    }),
    onCobrancaCancelled(async (evt) => {
      await db.cobrancas.update(evt.output.id, { status: 'cancelado' })
    })
  ]
}
```

### Plugin de webhook

Reage a eventos assíncronos do provedor. Ideal para processar mudanças de
status que acontecem fora do seu fluxo.

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { onWebhookEvent } from 'pagamentos'

export function pluginEmailNotificacao(sender: EmailSender) {
  return [
    onWebhookEvent('pagamento.realizado', async (event) => {
      await sender.send({
        to: event.data.cliente?.email,
        template: 'pagamento_confirmado',
        vars: { nome: event.data.cliente?.nome }
      })
    }),
    onWebhookEvent('cobranca.vencida', async (event) => {
      await sender.send({
        to: event.data.cobranca.cliente.email,
        template: 'cobranca_vencida'
      })
    })
  ]
}
```

### Plugin híbrido

Combina lifecycle e webhook hooks para cobertura completa.

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { onCobrancaCreated, onWebhookEvent } from 'pagamentos'

export function pluginAnalytics(tracker: Tracker) {
  return [
    onCobrancaCreated(async (evt) => {
      tracker.track('cobranca_criada', { valor: evt.input.valor })
    }),
    onWebhookEvent('pagamento.realizado', async (event) => {
      tracker.track('pagamento_convertido', {
        cobrancaId: event.data.cobranca.id
      })
    })
  ]
}
```

## Boas práticas

### 1. Seja idempotente

Webhooks podem ser entregues mais de uma vez. Verifique se o evento já foi
processado:

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
onWebhookEvent('pagamento.realizado', async (event) => {
  const jaProcessado = await db.eventos.exists({ id: event.id })
  if (jaProcessado) return
  // ...
})
```

### 2. Não quebre o fluxo principal

Hooks que falham nunca propagam erro para o fluxo principal, mas é boa
prática capturar erros para logging:

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
onCobrancaCreated(async (evt) => {
  try {
    await lógicaExterna()
  } catch (error) {
    console.error('[meu-plugin] Erro:', error)
  }
})
```

### 3. Aceite opções, não dependências globais

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
// ✅ Bom
export function plugin(options: { apiKey: string })

// ❌ Evite
export function plugin() { process.env.API_KEY }
```

### 4. Documente os hooks que seu plugin registra

```md theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
## Eventos

- `onCobrancaCreated` — dispara após `pg.cobrancas.create()`
- `onWebhookEvent('pagamento.realizado')` — dispara quando o provedor confirma
```

### 5. Use tipagem forte

Exporte interfaces de opções para autocomplete:

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export interface PluginMeuPluginOptions {
  apiKey: string
  ambiente?: 'producao' | 'sandbox'
}
```

## Exemplo completo

Veja a página de [Plugins](/features/plugins) para um exemplo completo de
plugin de cache com invalidação automática.
