Documentation Index Fetch the complete documentation index at: https://docs.caibo.digital/llms.txt
Use this file to discover all available pages before exploring further.
H2H Notifications
Host-to-Host API provides real-time payment status notifications through webhooks, enabling automatic updates when payment statuses change. This guide covers webhook setup, handling, and security best practices.
Webhook Overview
Notification System
Real-time Updates : Automatic payment status notifications via webhooks
HTTP POST : Notifications sent as HTTP POST requests
Content Type : application/x-www-form-urlencoded
Requirement : Notifications only sent if notify URL is configured
Configuration
Dashboard Setup : Set notify URL in dashboard profile page
Per-Request Override : Override notify URL in individual payment requests
Multiple Endpoints : Configure different URLs for different notification types
Notification Fields
Field Description idPayment request identifier transactionIdPayment request transaction identifier transactionStatusIdTransaction status: 1 – approved, 2 – declined paymentRequestStatusIdPayment status: 1 – paid, 2 – unpaid merchantIdMerchant identifier (from control panel) unitPayment currency grossAmountPayment gross amount including fees feePayment fee amount netAmountNet amount deposited to merchant wallet referenceIdCustom reference details notesPayment notes clientIdPayment sender customer identifier clientNamePayment sender customer name clientEmailPayment sender customer email clientPhonePayment sender customer phone clientMemberIdPayment sender customer member identifier messagePayment failure reason message codePayment failure reason code
Example Notification
id=16772761082427695&transactionId=265111&transactionStatusId=1&paymentRequestStatusId=1&merchantId=16762420400394816&unit=USD&grossAmount=10&fee=0.5&netAmount=9.5&referenceId=12345¬es=Payment notes&clientId=16772748432912191&clientName=Client Name&clientEmail=client@email.com&clientPhone=1234567890&clientMemberId=12345&message=Stolen Card&code=008
Webhook Handler Implementation
Basic Webhook Handler
// Handle payment status notifications
app . post ( '/webhooks/payment-notification' , ( req , res ) => {
try {
const notification = req . body ;
// Verify notification authenticity (implement signature verification)
if ( ! verifyNotificationSignature ( req )) {
return res . status ( 401 ). send ( 'Unauthorized' );
}
// Process payment status update
const {
transactionId ,
merchantReference ,
status ,
amount ,
currency ,
timestamp
} = notification ;
// Update your database
updatePaymentStatus ( merchantReference , {
transactionId ,
status ,
amount ,
currency ,
updatedAt: timestamp
});
// Handle different status types
switch ( status ) {
case 'completed' :
handleSuccessfulPayment ( merchantReference );
break ;
case 'failed' :
handleFailedPayment ( merchantReference , notification . errorCode );
break ;
case 'pending' :
handlePendingPayment ( merchantReference );
break ;
case 'cancelled' :
handleCancelledPayment ( merchantReference );
break ;
}
// Always return 200 OK to acknowledge receipt
res . status ( 200 ). send ( 'OK' );
} catch ( error ) {
console . error ( 'Webhook processing error:' , error );
res . status ( 200 ). send ( 'OK' ); // Still return 200 to prevent retries
}
});
Advanced Webhook Handler
const crypto = require ( 'crypto' );
// Enhanced webhook handler with validation and processing
app . post ( '/webhooks/payment-notification' , async ( req , res ) => {
const startTime = Date . now ();
try {
// Parse notification data
const notification = parseNotificationData ( req . body );
// Verify webhook signature
if ( ! verifyWebhookSignature ( req , notification )) {
console . warn ( 'Invalid webhook signature' );
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
// Check for duplicate notifications
if ( await isDuplicateNotification ( notification . id , notification . transactionId )) {
console . log ( 'Duplicate notification ignored' );
return res . status ( 200 ). send ( 'OK' );
}
// Process notification
await processPaymentNotification ( notification );
// Log successful processing
const processingTime = Date . now () - startTime ;
console . log ( `Webhook processed successfully in ${ processingTime } ms` );
res . status ( 200 ). send ( 'OK' );
} catch ( error ) {
console . error ( 'Webhook processing failed:' , error );
// Log error details for debugging
await logWebhookError ( req , error );
// Return 200 to prevent webhook retries for non-recoverable errors
res . status ( 200 ). send ( 'OK' );
}
});
function parseNotificationData ( body ) {
// Parse URL-encoded data
const params = new URLSearchParams ( body );
return {
id: params . get ( 'id' ),
transactionId: params . get ( 'transactionId' ),
transactionStatusId: parseInt ( params . get ( 'transactionStatusId' )),
paymentRequestStatusId: parseInt ( params . get ( 'paymentRequestStatusId' )),
merchantId: params . get ( 'merchantId' ),
unit: params . get ( 'unit' ),
grossAmount: parseFloat ( params . get ( 'grossAmount' )),
fee: parseFloat ( params . get ( 'fee' )),
netAmount: parseFloat ( params . get ( 'netAmount' )),
referenceId: params . get ( 'referenceId' ),
notes: params . get ( 'notes' ),
clientId: params . get ( 'clientId' ),
clientName: params . get ( 'clientName' ),
clientEmail: params . get ( 'clientEmail' ),
clientPhone: params . get ( 'clientPhone' ),
clientMemberId: params . get ( 'clientMemberId' ),
message: params . get ( 'message' ),
code: params . get ( 'code' )
};
}
Notification Verification
Signature Verification
Verify notification authenticity using HMAC SHA512 signature:
function verifyNotificationSignature ( req ) {
const signature = req . headers [ 'x-signature' ];
const payload = req . body ;
const apiKey = process . env . Caibo_API_KEY ;
if ( ! signature || ! payload || ! apiKey ) {
return false ;
}
const hash = crypto
. createHmac ( 'sha512' , apiKey )
. update ( payload )
. digest ( 'base64' );
return hash === signature ;
}
Verification Process
Header Check : Check X-Signature header in notification request
Algorithm : HMAC SHA512 hash in Base64 format
Key : Use your API key from the control panel
// Complete signature verification example
function verifyWebhookSignature ( req , notification ) {
const receivedSignature = req . headers [ 'x-signature' ];
if ( ! receivedSignature ) {
console . warn ( 'Missing X-Signature header' );
return false ;
}
const payload = req . rawBody || req . body ;
const apiKey = process . env . Caibo_API_KEY ;
const expectedSignature = crypto
. createHmac ( 'sha512' , apiKey )
. update ( payload , 'utf8' )
. digest ( 'base64' );
// Use timing-safe comparison
return crypto . timingSafeEqual (
Buffer . from ( receivedSignature ),
Buffer . from ( expectedSignature )
);
}
Status Processing
Payment Status Mapping
function mapPaymentStatus ( transactionStatusId , paymentRequestStatusId ) {
// Transaction Status: 0 – waiting, 1 – approved, 2 – declined, 3 – pending
// Payment Request Status: 1 – paid, 2 – unpaid, 3 – cancelled
if ( transactionStatusId === 1 && paymentRequestStatusId === 1 ) {
return 'completed' ;
} else if ( transactionStatusId === 2 ) {
return 'failed' ;
} else if ( transactionStatusId === 3 ) {
return 'pending' ;
} else if ( paymentRequestStatusId === 3 ) {
return 'cancelled' ;
} else {
return 'unknown' ;
}
}
Business Logic Processing
async function processPaymentNotification ( notification ) {
const status = mapPaymentStatus (
notification . transactionStatusId ,
notification . paymentRequestStatusId
);
// Update payment record
await updatePaymentRecord ( notification . referenceId , {
transactionId: notification . transactionId ,
status: status ,
grossAmount: notification . grossAmount ,
fee: notification . fee ,
netAmount: notification . netAmount ,
updatedAt: new Date ()
});
// Execute business logic based on status
switch ( status ) {
case 'completed' :
await handlePaymentSuccess ( notification );
break ;
case 'failed' :
await handlePaymentFailure ( notification );
break ;
case 'pending' :
await handlePaymentPending ( notification );
break ;
case 'cancelled' :
await handlePaymentCancelled ( notification );
break ;
}
// Send internal notifications
await sendInternalNotification ( notification , status );
}
async function handlePaymentSuccess ( notification ) {
// Fulfill order
await fulfillOrder ( notification . referenceId );
// Send confirmation email
await sendPaymentConfirmation ( notification . clientEmail , {
amount: notification . netAmount ,
currency: notification . unit ,
transactionId: notification . transactionId
});
// Update inventory
await updateInventory ( notification . referenceId );
}
async function handlePaymentFailure ( notification ) {
// Cancel order
await cancelOrder ( notification . referenceId );
// Send failure notification
await sendPaymentFailureNotification ( notification . clientEmail , {
reason: notification . message ,
code: notification . code
});
// Release inventory
await releaseInventory ( notification . referenceId );
}
Error Handling
Duplicate Prevention
async function isDuplicateNotification ( paymentId , transactionId ) {
const key = `webhook_ ${ paymentId } _ ${ transactionId } ` ;
// Check if we've already processed this notification
const exists = await redis . exists ( key );
if ( exists ) {
return true ;
}
// Mark as processed (expire after 24 hours)
await redis . setex ( key , 86400 , '1' );
return false ;
}
Retry Logic
async function processWithRetry ( notification , maxRetries = 3 ) {
let attempt = 0 ;
while ( attempt < maxRetries ) {
try {
await processPaymentNotification ( notification );
return ; // Success
} catch ( error ) {
attempt ++ ;
if ( attempt >= maxRetries ) {
// Final attempt failed, log and alert
await logCriticalError ( notification , error );
await sendAlertToAdmins ( notification , error );
throw error ;
}
// Wait before retry (exponential backoff)
await delay ( Math . pow ( 2 , attempt ) * 1000 );
}
}
}
Security Best Practices
Webhook Security
Signature Verification : Always verify webhook signatures
HTTPS Only : Use HTTPS endpoints for webhook URLs
IP Whitelisting : Restrict webhook sources to known IPs
Rate Limiting : Implement rate limiting on webhook endpoints
Data Protection
Sensitive Data : Never log sensitive payment information
PCI Compliance : Follow PCI DSS guidelines for payment data
Access Control : Restrict access to webhook processing systems
Audit Logging : Maintain audit logs of all webhook processing
Error Handling
Graceful Failures : Handle errors gracefully without exposing system details
Monitoring : Monitor webhook processing success rates
Alerting : Set up alerts for webhook processing failures
Backup Processing : Implement backup processing for failed webhooks
Testing and Validation
Webhook Testing
// Test webhook endpoint
async function testWebhookEndpoint () {
const testNotification = {
id: 'test_12345' ,
transactionId: 'test_txn_67890' ,
transactionStatusId: 1 ,
paymentRequestStatusId: 1 ,
merchantId: 'test_merchant' ,
unit: 'USD' ,
grossAmount: 10.00 ,
fee: 0.50 ,
netAmount: 9.50 ,
referenceId: 'test_order_123'
};
// Send test notification
const response = await fetch ( '/webhooks/payment-notification' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded' ,
'X-Signature' : generateTestSignature ( testNotification )
},
body: new URLSearchParams ( testNotification ). toString ()
});
console . log ( 'Test webhook response:' , response . status );
}
Best Practices
Implementation
Idempotency : Handle duplicate notifications gracefully
Fast Response : Respond quickly to webhook requests (< 30 seconds)
Async Processing : Process notifications asynchronously when possible
Status Codes : Return appropriate HTTP status codes
Monitoring
Success Rates : Monitor webhook processing success rates
Response Times : Track webhook processing response times
Error Patterns : Analyze error patterns and common failures
Alert Thresholds : Set up appropriate alerting thresholds
Reliability
Retry Mechanisms : Implement retry logic for failed processing
Dead Letter Queue : Use dead letter queues for failed notifications
Backup Processing : Implement backup processing mechanisms
Health Checks : Regular health checks on webhook endpoints
Next Steps
Request Structure Learn about H2H API request format and parameters
Response Structure Understand H2H API response handling
Payment Methods Explore available payment methods and implementations