Webhook Callback

TemboPlus sends real-time webhook notifications when transactions occur in your collection accounts. When a transaction happens, the system sends a POST request to your designated webhook URL.

🎯 Overview

When transactions occur on your allocated accounts, our system sends real-time webhook notifications to your configured endpoint. This enables immediate transaction processing and reconciliation in your application.

πŸ“¨ Webhook Request Format

Your webhook endpoint will receive HTTP POST requests with these characteristics:

  • Method: POST

  • Content-Type: application/json

  • Headers: Standard HTTP headers plus x-request-id for tracing

Request Body Structure

{
  "timestamp": "2025-09-15T12:34:56+03:00",
  "signature": "base64-encoded-hmac-sha256",
  "payload": "stringified-json-of-transaction-data"
}

Transaction Data (inside payload string)

{
  "event": "transaction.created",
  "account": {
    "accountNo": "1234567890",
    "accountName": "Business Account Ltd",
    "bankId": "uuid-of-bank"
  },
  "transaction": {
    "id": "unique-transaction-id",
    "transactionId": "bank-transaction-id-or-null",
    "reference": "TXN-REF-123456",
    "paymentReference": "PAY-REF-789",
    "transactionDate": "2025-09-15T10:30:00+03:00",
    "creditOrDebit": "CREDIT",
    "currency": "TZS",
    "amountCredit": 50000.00,
    "amountDebit": 0,
    "availableBalance": 150000.00,
    "currentBalance": 150000.00,
    "description": "Customer payment received"
  },
  "counterparty": null
}

πŸ” Security Verification

HMAC Signature Validation Process

Each webhook includes a cryptographic signature that you must verify:

  1. Extract Components: Get timestamp, signature, and payload from request body

  2. Create Signing Content: Concatenate timestamp + payload as a string

  3. Calculate HMAC: Use HMAC-SHA256 with your provided hash key (base64 decode the key first)

  4. Encode Result: Base64 encode the HMAC result

  5. Compare: The calculated signature must exactly match the received signature

Signature Validation Algorithm

signing_content = timestamp + payload
calculated_hmac = HMAC-SHA256(base64_decode(your_hash_key), signing_content)
expected_signature = base64_encode(calculated_hmac)
is_valid = (expected_signature === received_signature)

Example Implementation (Node.js)

const crypto = require('crypto');

function validateWebhook(envelope, yourHashKey) {
  const { timestamp, signature, payload } = envelope;
  
  // Create signing content by concatenating timestamp and payload
  const signingContent = timestamp + payload;
  
  // Calculate HMAC-SHA256 signature
  const expectedSignature = crypto
    .createHmac('sha256', Buffer.from(yourHashKey, 'base64'))
    .update(signingContent, 'utf-8')
    .digest('base64');
  
  // Compare signatures
  return signature === expectedSignature;
}

πŸ—οΈ Implementation Requirements

1. Endpoint Configuration

  • Protocol: HTTPS only (HTTP not supported)

  • Method: Accept POST requests

  • Content-Type: Parse application/json

  • Response Time: Respond within 30 seconds

  • Response Code: Return HTTP 200 for successful processing

2. Request Processing Flow

  1. Receive Request: Accept POST with JSON body

  2. Validate Signature: Verify HMAC signature (reject if invalid)

  3. Parse Payload: Extract transaction data from payload string

  4. Check Duplicates: Handle potential duplicate deliveries

  5. Process Transaction: Execute your business logic

  6. Respond: Return HTTP 200 success response

3. Idempotency Handling

Webhooks may be delivered multiple times. Implement duplicate detection using:

  • Transaction ID: Use the unique transaction.id field

  • Storage: Track processed transaction IDs in database/cache

  • Response: Return HTTP 200 for already-processed transactions

πŸ”„ Delivery Behavior

Retry Policy

Our system automatically retries failed webhook deliveries:

  • Success Criteria: HTTP status codes 200-299

  • Permanent Failures: HTTP 400-499 (except 408 Request Timeout, 429 Too Many Requests)

  • Temporary Failures: HTTP 500-599, network errors, timeouts

  • Retry Schedule: Exponential backoff starting at 2 seconds

  • Maximum Attempts: Up to 20 retries over 24 hours

Expected Response Format

Your endpoint should return a simple HTTP 200 success response:

{
  "message": "Transaction processed successfully",
  "transactionId": "unique-transaction-id"
}

πŸ’» Implementation Example

Conceptual Flow (Language Agnostic)

1. Receive HTTP POST request
2. Parse JSON request body
3. Validate HMAC signature
   - If invalid: Return HTTP 401
4. Extract transaction data from payload
5. Check if transaction already processed
   - If duplicate: Return HTTP 200
6. Execute business logic:
   - Update account balances
   - Trigger notifications
   - Log transaction
   - Update records
7. Mark transaction as processed
8. Return HTTP 200 success

Node.js Implementation Example

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

// In-memory storage (use database in production)
const processedTransactions = new Set();

app.post('/webhook/transactions', async (req, res) => {
  try {
    // 1. Validate webhook signature
    if (!validateWebhook(req.body, YOUR_HASH_KEY)) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    
    // 2. Parse transaction data
    const data = JSON.parse(req.body.payload);
    const transactionId = data.transaction.id;
    
    // 3. Handle duplicates
    if (processedTransactions.has(transactionId)) {
      return res.status(200).json({ message: 'Already processed' });
    }
    
    // 4. Process transaction
    await processTransaction(data);
    
    // 5. Mark as processed
    processedTransactions.add(transactionId);
    
    // 6. Return success
    res.status(200).json({ 
      message: 'Transaction processed',
      transactionId 
    });
    
  } catch (error) {
    console.error('Webhook processing error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

async function processTransaction(webhookData) {
  const { account, transaction } = webhookData;
  
  // Your business logic here
  console.log(`Processing ${transaction.creditOrDebit} of ${transaction.currency} ${transaction.amountCredit || transaction.amountDebit} on account ${account.accountNo}`);
  
  // Example actions:
  // - Update local account balance
  // - Send customer notification
  // - Trigger reconciliation process
  // - Log to audit trail
}

βš™οΈ Setup Requirements

Partner Configuration

  1. Webhook URL: Provide your HTTPS endpoint URL

  2. Hash Key: You'll receive a base64-encoded signing key

  3. Account Allocation: Ensure accounts are allocated to your partner account

Testing Your Implementation

Test Request Format

POST https://your-domain.com/webhook/transactions
Content-Type: application/json

{
  "timestamp": "2025-09-15T12:00:00+03:00",
  "signature": "calculated-signature-here",
  "payload": "{\"event\":\"transaction.created\",\"account\":{\"accountNo\":\"TEST123\",\"accountName\":\"Test Account\",\"bankId\":\"test-bank\"},\"transaction\":{\"id\":\"TEST-001\",\"reference\":\"TEST-REF\",\"transactionDate\":\"2025-09-15T11:30:00+03:00\",\"creditOrDebit\":\"CREDIT\",\"currency\":\"TZS\",\"amountCredit\":1000,\"amountDebit\":0,\"currentBalance\":5000,\"description\":\"Test payment\"}}"
}

βœ… Implementation Checklist

Essential Requirements

Recommended Enhancements

πŸ› Troubleshooting

Common Issues

No webhooks received

  • Verify endpoint URL is publicly accessible via HTTPS

  • Confirm accounts are properly allocated to your partner

  • Check that endpoint responds with HTTP 200

Signature validation failures

  • Ensure hash key is stored and used correctly

  • Verify signing content is exactly timestamp + payload (string concatenation)

  • Confirm payload is the raw JSON string, not a parsed object

  • Check that hash key is base64-decoded before HMAC calculation

Duplicate processing

  • Implement idempotency using the unique transaction.id

  • Store processed IDs in persistent storage (database, not memory)

  • Always return HTTP 200 for already-processed transactions

Processing timeouts

  • Ensure webhook processing completes within 30 seconds

  • Consider async processing for complex business logic

  • Return HTTP 200 immediately, then process in background

πŸ“ž Support

For webhook integration assistance, contact our technical support team with:

  • Your partner identifier

  • Webhook endpoint URL

  • Sample request/response logs

  • Error messages or unexpected behavior details


πŸ”’ Security Note: Always validate webhook signatures before processing transaction data to ensure authenticity and prevent unauthorized access to your system.

Last updated