Skip to main content

Webhook Events

Zentra sends webhook notifications for various events in your account. This page shows common event families and representative payload shapes, not a reviewed schema bundle for every tenant and rail combination.
Treat event names and fields here as implementation guidance. Exact event availability and payload shape can vary by tenant capability, provider path, and rollout phase.

Event Structure

All webhook payloads follow this structure:
{
  "event": "event.type",
  "data": {
    // Event-specific data
  },
  "created_at": "2024-01-15T10:30:00Z",
  "webhook_id": "wh_abc123"
}

Virtual Account Events

virtual_account.created

Triggered when a virtual account is successfully created.
{
  "event": "virtual_account.created",
  "data": {
    "id": "va_123",
    "customer_id": "cus_456",
    "account_number": "0123456789",
    "bank_name": "GTBank",
    "status": "active"
  }
}

virtual_account.credited

Triggered when a payment is received in a virtual account.
{
  "event": "virtual_account.credited",
  "data": {
    "id": "va_123",
    "account_number": "0123456789",
    "amount_minor": 50000,
    "sender_name": "Jane Smith",
    "sender_account": "9876543210",
    "sender_bank": "Zenith Bank",
    "reference": "TRF12345",
    "narration": "Payment",
    "credited_at": "2024-01-15T10:30:00Z"
  }
}

virtual_account.closed

Triggered when a virtual account is closed.
{
  "event": "virtual_account.closed",
  "data": {
    "id": "va_123",
    "account_number": "0123456789",
    "reason": "Customer request",
    "closed_at": "2024-01-15T10:30:00Z"
  }
}

Transfer Events

transfer.pending

Transfer initiated and pending processing.
{
  "event": "transfer.pending",
  "data": {
    "id": "trn_123",
    "amount_minor": 50000,
    "recipient_account": "0123456789",
    "recipient_bank": "GTBank",
    "reference": "TRF_123",
    "status": "pending"
  }
}

transfer.processing

Transfer is being processed by the bank.
{
  "event": "transfer.processing",
  "data": {
    "id": "trn_123",
    "status": "processing",
    "session_id": "SES_xyz"
  }
}

transfer.completed

Transfer successfully completed.
{
  "event": "transfer.completed",
  "data": {
    "id": "trn_123",
    "amount_minor": 50000,
    "recipient_name": "John Doe",
    "reference": "TRF_123",
    "status": "completed",
    "completed_at": "2024-01-15T10:35:00Z"
  }
}

transfer.failed

Transfer failed to process.
{
  "event": "transfer.failed",
  "data": {
    "id": "trn_123",
    "amount_minor": 50000,
    "reference": "TRF_123",
    "status": "failed",
    "reason": "Insufficient balance",
    "failed_at": "2024-01-15T10:35:00Z"
  }
}

Payment Events

payment.pending

Payment created and awaiting customer action or downstream completion.
{
  "event": "payment.pending",
  "data": {
    "id": "pay_123",
    "amount_minor": 100000,
    "customer_email": "customer@example.com",
    "reference": "PAY_123",
    "authorization_url": "https://checkout.zentra.io/pay_123"
  }
}

payment.successful

Payment completed successfully.
{
  "event": "payment.successful",
  "data": {
    "id": "pay_123",
    "amount_minor": 100000,
    "customer_email": "customer@example.com",
    "reference": "PAY_123",
    "payment_method": "card",
    "status": "successful",
    "paid_at": "2024-01-15T10:40:00Z"
  }
}

payment.failed

Payment failed.
{
  "event": "payment.failed",
  "data": {
    "id": "pay_123",
    "amount_minor": 100000,
    "reference": "PAY_123",
    "reason": "Declined by bank",
    "status": "failed"
  }
}

Card Events

card.created

Card successfully issued.
{
  "event": "card.created",
  "data": {
    "id": "crd_123",
    "customer_id": "cus_456",
    "last4": "4567",
    "brand": "visa",
    "type": "virtual",
    "status": "active"
  }
}

card.transaction

Transaction made with the card.
{
  "event": "card.transaction",
  "data": {
    "id": "crd_123",
    "transaction_id": "txn_789",
    "amount_minor": 15000,
    "merchant": "Netflix",
    "status": "approved",
    "timestamp": "2024-01-15T10:45:00Z"
  }
}

card.locked

Card has been locked.
{
  "event": "card.locked",
  "data": {
    "id": "crd_123",
    "reason": "Customer request",
    "locked_at": "2024-01-15T10:50:00Z"
  }
}

card.unlocked

Card has been unlocked.
{
  "event": "card.unlocked",
  "data": {
    "id": "crd_123",
    "reason": "Risk review cleared",
    "unlocked_at": "2024-01-15T10:55:00Z"
  }
}

KYC Events

kyc.completed

KYC verification completed.
{
  "event": "kyc.completed",
  "data": {
    "customer_id": "cus_123",
    "verification_type": "bvn",
    "status": "verified",
    "verified_at": "2024-01-15T11:00:00Z"
  }
}

kyc.failed

KYC verification failed.
{
  "event": "kyc.failed",
  "data": {
    "customer_id": "cus_123",
    "verification_type": "bvn",
    "status": "failed",
    "reason": "BVN mismatch",
    "failed_at": "2024-01-15T11:00:00Z"
  }
}

Customer Events

customer.created

New customer created.
{
  "event": "customer.created",
  "data": {
    "id": "cus_123",
    "email": "customer@example.com",
    "name": "John Doe",
    "created_at": "2024-01-15T11:05:00Z"
  }
}

customer.updated

Customer information updated.
{
  "event": "customer.updated",
  "data": {
    "id": "cus_123",
    "updated_fields": ["phone", "address"],
    "updated_at": "2024-01-15T11:10:00Z"
  }
}

Wallet Events

wallet.credited

Wallet credited with funds.
{
  "event": "wallet.credited",
  "data": {
    "wallet_id": "wal_123",
    "amount_minor": 100000,
    "source": "virtual_account",
    "reference": "DEP_123",
    "balance_minor": 250000,
    "credited_at": "2024-01-15T11:15:00Z"
  }
}

wallet.debited

Wallet debited.
{
  "event": "wallet.debited",
  "data": {
    "wallet_id": "wal_123",
    "amount_minor": 50000,
    "purpose": "transfer",
    "reference": "TRF_123",
    "balance_minor": 200000,
    "debited_at": "2024-01-15T11:20:00Z"
  }
}

Handling Events

app.post('/webhooks/zentra', (req, res) => {
  const { event, data } = req.body;
  
  switch (event) {
    case 'virtual_account.credited':
      handleAccountCredit(data);
      break;
    case 'transfer.completed':
      handleTransferComplete(data);
      break;
    case 'payment.successful':
      handlePaymentSuccess(data);
      break;
    default:
      console.log(`Unhandled event: ${event}`);
  }
  
  res.status(200).send('OK');
});

Next Steps

Configure Webhooks

Set up webhook endpoints

Verify Signatures

Secure your webhooks

Handling Guide

Best practices

Test Events

Test in sandbox