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