Forgedocs
Webhooks V2

Descripción General

Que son los Webhooks V2?

Los Webhooks V2 son notificaciones enviadas a su aplicación cuando ocurren eventos importantes en sus transacciones PIX. El formato V2 usa una estructura de envelope {type, data} que facilita el procesamiento y proporciona mas detalle sobre cada evento.

Para recibir webhooks V2, su cuenta debe tener la versión de webhook configurada a V2. Vea como activar.

Estructura Base

Todos los webhooks V2 siguen esta estructura:

{
  "type": "RECEIVE" | "TRANSFER" | "REFUND",
  "data": {
    // Datos especificos del evento
  }
}

Tipos de Eventos

TipoDescripciónEquivalente V1
RECEIVEPIX recibido (Cash-In)CashIn
TRANSFERPIX enviado (Cash-Out)CashOut
REFUNDDevolución (entrada o salida)CashInReversal / CashOutReversal

Estructura de Datos Completa

interface WebhookV2Data {
  // Identificadores
  id: number;                    // ID de la transacción
  txId: string | null;           // Identificador del cobro (txid)
  endToEndId: string | null;     // End to End ID de la transacción PIX

  // Clave PIX
  pixKey: string | null;         // Clave PIX utilizada

  // Estado
  status: 'PENDING' | 'LIQUIDATED' | 'REFUNDED' | 'ERROR';

  // Pago
  payment: {
    amount: string;              // Monto (string con 2 decimales)
    currency: string;            // Moneda (BRL)
  };

  // Devoluciones
  refunds: RefundInfo[];         // Lista de devoluciones (vacia si no hay)

  // Fechas
  createdAt: string;             // Fecha de creación (ISO 8601)

  // Error
  errorCode: string | null;      // Codigo de error (si hay)

  // Tipo de operación
  webhookType: 'RECEIVE' | 'TRANSFER' | 'REFUND';
  creditDebitType: 'CREDIT' | 'DEBIT';
  transactionType: 'PIX';
  localInstrument: 'DICT';

  // Cuentas
  debtorAccount: AccountInfo;    // Pagador/Emisor
  creditorAccount: AccountInfo;  // Receptor/Destinatario

  // Idempotencia
  idempotencyKey: string | null;

  // Datos adicionales
  ticketData: object;
  remittanceInformation: string | null;  // Descripción de la transacción
}

interface AccountInfo {
  ispb: string | null;           // Codigo ISPB del banco
  name: string | null;           // Nombre del banco
  issuer: string | null;         // Codigo del banco
  number: string | null;         // Numero de cuenta
  document: string | null;       // CPF/CNPJ (enmascarado)
  accountType: string | null;    // Tipo de cuenta
}

interface RefundInfo {
  status: 'PENDING' | 'LIQUIDATED' | 'ERROR';
  payment: {
    amount: number;              // Monto de devolución (numero!)
    currency: string;
  };
  errorCode: string | null;
  eventDate: string;             // Fecha de devolución
  endToEndId: string | null;     // E2E ID de la devolución
  information: string | null;    // Descripción de la devolución
}

Diferencias V1 vs V2

AspectoV1V2
FormatoCampos en la raizEnvelope {type, data}
Tipo de eventoevent: "CashIn"type: "RECEIVE"
AspectoV1V2
PIX exitosoCONFIRMEDLIQUIDATED
Devolución exitosaCONFIRMEDREFUNDED
ErrorERRORERROR
AspectoV1V2
CampocounterpartdebtorAccount / creditorAccount
Bancobank.bankNamename
ISPBbank.bankISPBispb
AspectoV1V2
Tiponumberstring
Formato100.00"100.00"

Mapeo de Cuentas

PIX Recibido (RECEIVE)

debtorAccount = Quien pago (contraparte)
creditorAccount = Su cuenta (receptor)
creditDebitType = CREDIT

PIX Enviado (TRANSFER)

debtorAccount = Su cuenta (pagador)
creditorAccount = Quien recibio (contraparte)
creditDebitType = DEBIT

Devolución de Recepción (REFUND - CashInReversal)

debtorAccount = Su cuenta (devolviendo)
creditorAccount = Quien recibira de vuelta (contraparte)
creditDebitType = DEBIT

Devolución de Transferencia (REFUND - CashOutReversal)

debtorAccount = Quien esta devolviendo (contraparte)
creditorAccount = Su cuenta (recibiendo de vuelta)
creditDebitType = CREDIT

Configuración del Endpoint

Requisitos

  • URL HTTPS requerida
  • Timeout máximo: 10 segundos
  • Respuesta esperada: HTTP 2xx

Autenticación

Los webhooks se envian con Basic Auth:

Authorization: Basic base64(username:password)

Configure las credenciales en el dashboard o contacte a soporte.

Ejemplo de Handler

import express from 'express';

const app = express();
app.use(express.json());

interface WebhookV2 {
  type: 'RECEIVE' | 'TRANSFER' | 'REFUND';
  data: WebhookV2Data;
}

// Set para idempotencia
const processedIds = new Set<number>();

app.post('/webhooks/pix', (req, res) => {
  const webhook: WebhookV2 = req.body;

  // Responder rapidamente
  res.status(200).json({ acknowledged: true });

  // Verificar idempotencia
  if (processedIds.has(webhook.data.id)) {
    console.log(`Webhook ${webhook.data.id} ya procesado`);
    return;
  }
  processedIds.add(webhook.data.id);

  // Procesar por tipo
  switch (webhook.type) {
    case 'RECEIVE':
      handleReceive(webhook.data);
      break;
    case 'TRANSFER':
      handleTransfer(webhook.data);
      break;
    case 'REFUND':
      handleRefund(webhook.data);
      break;
  }
});

function handleReceive(data: WebhookV2Data) {
  if (data.status === 'LIQUIDATED') {
    const amount = parseFloat(data.payment.amount);
    console.log(`PIX recibido: R$ ${amount}`);
    // Acreditar en el sistema
  }
}

function handleTransfer(data: WebhookV2Data) {
  if (data.status === 'LIQUIDATED') {
    console.log(`PIX enviado: ${data.endToEndId}`);
    // Confirmar transferencia
  } else if (data.status === 'ERROR') {
    console.log(`PIX fallido: ${data.errorCode}`);
    // Revertir operación
  }
}

function handleRefund(data: WebhookV2Data) {
  if (data.status === 'REFUNDED') {
    const refund = data.refunds[0];
    console.log(`Devolución: R$ ${refund.payment.amount}`);
    // Procesar devolución
  }
}

Reintentos

Si su endpoint no responde con HTTP 2xx dentro de 10 segundos:

IntentoIntervaloAcumulado
1roInmediato0 min
2do5 minutos5 min
3ro5 minutos10 min
4to15 minutos25 min

Después de 4 intentos fallidos, el webhook ya no sera reenviado automáticamente.

Implemente un sondeo periodico como respaldo para asegurar que no se pierdan transacciones.

Próximos Pasos

En esta página