Skip to main content

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.

O que são plugins?

Plugins são bibliotecas de terceiros que empacotam hooks do pagamentos.dev em módulos reutilizáveis. Eles permitem que você compartilhe integrações prontas — como envio de e-mails, auditoria, analytics, sincronização com CRMs, etc. — sem repetir código entre projetos. Um plugin nada mais é do que uma função (ou conjunto de funções) que retorna hooks configurados. Você os registra da mesma forma que hooks manuais:
import { Pagamentos, mercadopago } from 'pagamentos'
import { pluginAnalytics } from 'pagamentos-plugin-analytics'
import { pluginAuditLog } from 'pagamentos-plugin-audit'

const pg = new Pagamentos({
  providers: [mercadopago({ accessToken: '...' })],
  hooks: [
    ...pluginAnalytics({ tracker: 'segment' }),
    ...pluginAuditLog({ database: db })
  ]
})

Arquitetura de um plugin

A base de todo plugin são os hooks. Um plugin expõe hooks de lifecycle, webhooks, ou ambos:
// pagamentos-plugin-analytics/index.ts
import type { LifecycleHook, WebhookHook } from 'pagamentos'
import { onCobrancaCreated, onWebhookEvent } from 'pagamentos'

export interface AnalyticsPluginOptions {
  tracker: 'segment' | 'mixpanel' | 'posthog'
  apiKey: string
}

export function pluginAnalytics(
  options: AnalyticsPluginOptions
): (LifecycleHook | WebhookHook)[] {
  const client = createTracker(options.tracker, options.apiKey)

  return [
    // Lifecycle: rastreia criação de cobranças
    onCobrancaCreated(async (evt) => {
      client.track('cobranca_criada', {
        valor: evt.input.valor,
        metodo: evt.input.metodoPagamento,
        provider: evt.provider
      })
    }),

    // Webhook: rastreia conversão
    onWebhookEvent('pagamento.realizado', async (event) => {
      client.track('pagamento_convertido', {
        cobrancaId: event.data.cobranca.id,
        valor: event.data.cobranca.valor,
        provider: event.provider
      })
    })
  ]
}

Tipos de plugin

Plugin de lifecycle

Reage a operações de API que você realiza. Útil para ações síncronas e previsíveis:
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,
        documento: evt.input.documento
      })
    }),

    onCobrancaCancelled(async (evt) => {
      await db.cobrancas.update({
        id: evt.output.id,
        status: 'cancelado',
        canceladoEm: new Date()
      })
    })
  ]
}

Plugin de webhook

Reage a eventos assíncronos enviados pelo provedor. Útil para processar mudanças de status que acontecem fora do seu fluxo:
import { onWebhookEvent } from 'pagamentos'

export function pluginNotificacoesEmail(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,
          valor: event.data.cobranca.valor
        }
      })
    }),

    onWebhookEvent('cobranca.vencida', async (event) => {
      await sender.send({
        to: event.data.cobranca.cliente.email,
        template: 'cobranca_vencida',
        vars: {
          linkPagamento: event.data.cobranca.url
        }
      })
    })
  ]
}

Plugin híbrido

Combina lifecycle e webhook hooks para cobrir todo o ciclo de vida:
import { onCobrancaCreated, onWebhookEvent } from 'pagamentos'

export function pluginSlack(webhookUrl: string) {
  return [
    onCobrancaCreated(async (evt) => {
      await notifySlack(webhookUrl, {
        text: `Nova cobrança de R$ ${evt.input.valor / 100} criada`
      })
    }),

    onWebhookEvent('pagamento.realizado', async (event) => {
      await notifySlack(webhookUrl, {
        text: `Pagamento confirmado: R$ ${event.data.cobranca.valor / 100}`
      })
    })
  ]
}

Boas práticas para autores de plugins

1. Não quebre o fluxo principal

Hooks que falham podem impactar o fluxo do usuário. Sempre envolva lógica externa em try/catch:
export function pluginSeguro(handler: () => Promise<void>) {
  return onCobrancaCreated(async (evt) => {
    try {
      await handler()
    } catch (error) {
      // Loga o erro, mas não propaga para não quebrar o fluxo
      console.error('[meu-plugin] Falha ao processar hook:', error)
    }
  })
}
Lifecycle hooks que lançam exceções interrompem o retorno da operação principal para o chamador. Veja a página de Hooks para mais detalhes sobre o comportamento de erro.

2. Seja idempotente

Webhooks podem ser entregues mais de uma vez. Plugins que processam webhooks devem verificar se o evento já foi tratado:
onWebhookEvent('pagamento.realizado', async (event) => {
  const jaProcessado = await db.eventos.exists({ id: event.id })
  if (jaProcessado) return

  await liberarProduto(event.data.cobranca.id)
  await db.eventos.insert({ id: event.id, processadoEm: new Date() })
})

3. Documente os eventos suportados

Deixe claro quais hooks o plugin registra e em que momento eles disparam:
## Eventos

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

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

Receba clientes e configurações via argumentos em vez de importar variáveis globais:
// Bom
export function pluginMeuCRM(client: MeuCRMClient, options?: { debug?: boolean })

// Evite
export function pluginMeuCRM() // usa process.env.MEU_CRM_TOKEN implicitamente

5. Use tipagem forte

Exporte as interfaces de opções para que os usuários tenham autocomplete:
export interface PluginMeuPluginOptions {
  apiKey: string
  ambiente: 'producao' | 'sandbox'
}

export function pluginMeuPlugin(options: PluginMeuPluginOptions) {
  // ...
}

Publicando um plugin

Plugins são pacotes npm comuns. A estrutura mínima recomendada é:
pagamentos-plugin-meu-plugin/
├── package.json
├── tsconfig.json
├── src/
│   └── index.ts
└── README.md
No package.json, declare o pagamentos como peerDependency:
{
  "name": "pagamentos-plugin-meu-plugin",
  "peerDependencies": {
    "pagamentos": "^0.x"
  },
  "devDependencies": {
    "pagamentos": "file:../pagamentos"
  }
}
Isso evita múltiplas cópias do SDK no node_modules do usuário e garante que os tipos sejam compatíveis.

Exemplo completo: Plugin de Cache

// pagamentos-plugin-cache/index.ts
import {
  type LifecycleHook,
  onCobrancaCreated,
  onCobrancaRetrieved,
  onCobrancaUpdated,
  onClienteCreated,
  onClienteRetrieved,
  onClienteUpdated
} from 'pagamentos'

export interface CachePluginOptions {
  adapter: CacheAdapter // { get(key), set(key, value, ttl), del(key) }
  ttl?: number // segundos
}

export function pluginCache(options: CachePluginOptions): LifecycleHook[] {
  const { adapter, ttl = 300 } = options

  return [
    // Invalida cache em mutações
    onCobrancaCreated(async (evt) => {
      await adapter.del(`cobrancas:list:${evt.input.cliente?.documento}`)
    }),

    onCobrancaUpdated(async (evt) => {
      await adapter.del(`cobrancas:${evt.output.id}`)
    }),

    // Popula cache em consultas
    onCobrancaRetrieved(async (evt) => {
      await adapter.set(
        `cobrancas:${evt.output.id}`,
        evt.output,
        ttl
      )
    }),

    onClienteRetrieved(async (evt) => {
      await adapter.set(
        `clientes:${evt.output.id}`,
        evt.output,
        ttl
      )
    }),

    onClienteCreated(async (evt) => {
      await adapter.del('clientes:list')
    }),

    onClienteUpdated(async (evt) => {
      await adapter.del(`clientes:${evt.output.id}`)
      await adapter.del('clientes:list')
    })
  ]
}
Uso:
import { Pagamentos, mercadopago } from 'pagamentos'
import { pluginCache } from 'pagamentos-plugin-cache'
import { redis } from './redis'

const pg = new Pagamentos({
  providers: [mercadopago({ accessToken: '...' })],
  hooks: [
    ...pluginCache({ adapter: redis, ttl: 600 })
  ]
})