Avistadocs
Webhooks V2

Overview

What are V2 Webhooks?

V2 Webhooks are notifications sent to your application when important events occur in your PIX transactions. The V2 format uses a {type, data} envelope structure that makes processing easier and provides more detail about each event.

To receive V2 webhooks, your account must have the webhook version configured to V2. See how to activate.

Base Structure

All V2 webhooks follow this structure:

{
  "type": "RECEIVE" | "TRANSFER" | "REFUND",
  "data": {
    // Event-specific data
  }
}

Event Types

TypeDescriptionV1 Equivalent
RECEIVEPIX received (Cash-In)CashIn
TRANSFERPIX sent (Cash-Out)CashOut
REFUNDRefund (In or Out)CashInReversal / CashOutReversal

Complete Data Structure

interface WebhookV2Data {
  // Identifiers
  id: number;                    // Transaction ID
  txId: string | null;           // Charge identifier (txid)
  endToEndId: string | null;     // End to End ID of the PIX transaction

  // PIX Key
  pixKey: string | null;         // PIX key used

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

  // Payment
  payment: {
    amount: string;              // Amount (string with 2 decimals)
    currency: string;            // Currency (BRL)
  };

  // Refunds
  refunds: RefundInfo[];         // List of refunds (empty if none)

  // Dates
  createdAt: string;             // Creation date (ISO 8601)

  // Error
  errorCode: string | null;      // Error code (if any)

  // Operation type
  webhookType: 'RECEIVE' | 'TRANSFER' | 'REFUND';
  creditDebitType: 'CREDIT' | 'DEBIT';
  transactionType: 'PIX';
  localInstrument: 'DICT';

  // Accounts
  debtorAccount: AccountInfo;    // Payer/Sender
  creditorAccount: AccountInfo;  // Receiver/Recipient

  // Idempotency
  idempotencyKey: string | null;

  // Additional data
  ticketData: object;
  remittanceInformation: string | null;  // Transaction description
}

interface AccountInfo {
  ispb: string | null;           // Bank ISPB code
  name: string | null;           // Bank name
  issuer: string | null;         // Bank code
  number: string | null;         // Account number
  document: string | null;       // CPF/CNPJ (masked)
  accountType: string | null;    // Account type
}

interface RefundInfo {
  status: 'PENDING' | 'LIQUIDATED' | 'ERROR';
  payment: {
    amount: number;              // Refund amount (number!)
    currency: string;
  };
  errorCode: string | null;
  eventDate: string;             // Refund date
  endToEndId: string | null;     // Refund E2E ID
  information: string | null;    // Refund description
}

V1 vs V2 Differences

AspectV1V2
FormatFields at rootEnvelope {type, data}
Event typeevent: "CashIn"type: "RECEIVE"
AspectV1V2
PIX successCONFIRMEDLIQUIDATED
Refund successCONFIRMEDREFUNDED
ErrorERRORERROR
AspectV1V2
FieldcounterpartdebtorAccount / creditorAccount
Bankbank.bankNamename
ISPBbank.bankISPBispb
AspectV1V2
Typenumberstring
Format100.00"100.00"

Account Mapping

PIX Received (RECEIVE)

debtorAccount = Who paid (counterparty)
creditorAccount = Your account (receiver)
creditDebitType = CREDIT

PIX Sent (TRANSFER)

debtorAccount = Your account (payer)
creditorAccount = Who received (counterparty)
creditDebitType = DEBIT

Receipt Refund (REFUND - CashInReversal)

debtorAccount = Your account (refunding)
creditorAccount = Who will receive back (counterparty)
creditDebitType = DEBIT

Transfer Refund (REFUND - CashOutReversal)

debtorAccount = Who is refunding (counterparty)
creditorAccount = Your account (receiving back)
creditDebitType = CREDIT

Endpoint Configuration

Requirements

  • HTTPS URL required
  • Maximum timeout: 10 seconds
  • Expected response: HTTP 2xx

Authentication

Webhooks are sent with Basic Auth:

Authorization: Basic base64(username:password)

Configure credentials in the dashboard or contact support.

Handler Example

import express from 'express';

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

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

// Set for idempotency
const processedIds = new Set<number>();

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

  // Respond quickly
  res.status(200).json({ acknowledged: true });

  // Check idempotency
  if (processedIds.has(webhook.data.id)) {
    console.log(`Webhook ${webhook.data.id} already processed`);
    return;
  }
  processedIds.add(webhook.data.id);

  // Process by type
  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 received: R$ ${amount}`);
    // Credit in the system
  }
}

function handleTransfer(data: WebhookV2Data) {
  if (data.status === 'LIQUIDATED') {
    console.log(`PIX sent: ${data.endToEndId}`);
    // Confirm transfer
  } else if (data.status === 'ERROR') {
    console.log(`PIX failed: ${data.errorCode}`);
    // Reverse operation
  }
}

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

Retries

If your endpoint does not respond with HTTP 2xx within 10 seconds:

AttemptIntervalCumulative
1stImmediate0 min
2nd5 minutes5 min
3rd5 minutes10 min
4th15 minutes25 min

After 4 unsuccessful attempts, the webhook will no longer be automatically resent.

Implement periodic polling as a fallback to ensure no transactions are missed.

Next Steps

On this page