> ## 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

> Webhook notifications for Host-to-Host payment status updates and handling

# 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                                    |
| ------------------------ | ---------------------------------------------- |
| `id`                     | Payment request identifier                     |
| `transactionId`          | Payment request transaction identifier         |
| `transactionStatusId`    | Transaction status: 1 – approved, 2 – declined |
| `paymentRequestStatusId` | Payment status: 1 – paid, 2 – unpaid           |
| `merchantId`             | Merchant identifier (from control panel)       |
| `unit`                   | Payment currency                               |
| `grossAmount`            | Payment gross amount including fees            |
| `fee`                    | Payment fee amount                             |
| `netAmount`              | Net amount deposited to merchant wallet        |
| `referenceId`            | Custom reference details                       |
| `notes`                  | Payment notes                                  |
| `clientId`               | Payment sender customer identifier             |
| `clientName`             | Payment sender customer name                   |
| `clientEmail`            | Payment sender customer email                  |
| `clientPhone`            | Payment sender customer phone                  |
| `clientMemberId`         | Payment sender customer member identifier      |
| `message`                | Payment failure reason message                 |
| `code`                   | Payment 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&notes=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

```javascript theme={null}
// 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

```javascript theme={null}
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:

```javascript theme={null}
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

1. **Header Check**: Check `X-Signature` header in notification request
2. **Algorithm**: HMAC SHA512 hash in Base64 format
3. **Key**: Use your API key from the control panel

```javascript theme={null}
// 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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

1. **Signature Verification**: Always verify webhook signatures
2. **HTTPS Only**: Use HTTPS endpoints for webhook URLs
3. **IP Whitelisting**: Restrict webhook sources to known IPs
4. **Rate Limiting**: Implement rate limiting on webhook endpoints

### Data Protection

1. **Sensitive Data**: Never log sensitive payment information
2. **PCI Compliance**: Follow PCI DSS guidelines for payment data
3. **Access Control**: Restrict access to webhook processing systems
4. **Audit Logging**: Maintain audit logs of all webhook processing

### Error Handling

1. **Graceful Failures**: Handle errors gracefully without exposing system details
2. **Monitoring**: Monitor webhook processing success rates
3. **Alerting**: Set up alerts for webhook processing failures
4. **Backup Processing**: Implement backup processing for failed webhooks

## Testing and Validation

### Webhook Testing

```javascript theme={null}
// 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

1. **Idempotency**: Handle duplicate notifications gracefully
2. **Fast Response**: Respond quickly to webhook requests (\< 30 seconds)
3. **Async Processing**: Process notifications asynchronously when possible
4. **Status Codes**: Return appropriate HTTP status codes

### Monitoring

1. **Success Rates**: Monitor webhook processing success rates
2. **Response Times**: Track webhook processing response times
3. **Error Patterns**: Analyze error patterns and common failures
4. **Alert Thresholds**: Set up appropriate alerting thresholds

### Reliability

1. **Retry Mechanisms**: Implement retry logic for failed processing
2. **Dead Letter Queue**: Use dead letter queues for failed notifications
3. **Backup Processing**: Implement backup processing mechanisms
4. **Health Checks**: Regular health checks on webhook endpoints

## Next Steps

<Card title="Request Structure" icon="arrow-up" href="/h2h/request-structure">
  Learn about H2H API request format and parameters
</Card>

<Card title="Response Structure" icon="arrow-down" href="/h2h/response-structure">
  Understand H2H API response handling
</Card>

<Card title="Payment Methods" icon="credit-card" href="/h2h/payment-methods">
  Explore available payment methods and implementations
</Card>
