Tembo
  • Welcome!
  • Introduction
  • Reference
    • Merchant Virtual Accounts
      • Create Merchant Virtual Account
      • Get Account Balance
      • Get Account Statement
      • Webhook Callback
    • Banking & Wallets
      • Create Wallet
      • Deposit Funds
      • Withdraw Funds
      • Wallet to Wallet Transfer
      • Wallet Balance
      • Wallet Statement
      • Main Balance
      • Main Statement
      • List Wallets
    • Make Payment
      • Pay to Mobile
      • Pay to Other Banks
      • Utility Payments
      • Payment Status
    • Collect Money
      • Collect from Mobile Money
      • Collection Balance
      • Collection Statement
      • Payment Status
    • eKYC
      • Start Onboarding
      • Retrieve First Question
      • Reply to Question
    • Remittance
      • API Overview
      • Create Remittance
      • Transaction Status
      • Callback Notification
Powered by GitBook
On this page
  • Overview
  • Request Structure
  • Payload Details
  • Security and Signature Verification
  • Signature Generation
  • Example Implementation
  • Additional Notes
  1. Reference
  2. Merchant Virtual Accounts

Webhook Callback

Overview

TemboPlus provides a webhook-based callback service that enables merchants to receive notifications of transactions in their virtual accounts. When a new transaction occurs, the system submits a callback request to a designated URL using the POST method.

Request Structure

HTTP Method

POST

Headers

Header
Description

content-type

application/json

x-request-id

A unique UUID tracking the request. Callbacks related to the same request share the same ID.

x-request-timestamp

Number of milliseconds since the Unix epoch, indicating when the request was sent.

x-request-signature

HMAC signature for verifying the authenticity and integrity of the payload.

Payload Details

Field
Type
Description

accountNo

String

The merchant virtual account number where the transaction occurred.

payerName

String

The name of the payer. This field will be set to null for debit transactions. If the system fails to extract the payer's name, this field will also be set to null.

id

UUID

A globally unique identifier for this transaction.

transactionId

String

Identifies a transaction within the banking system. If the transaction has related sub-transactions, such as charges or VAT, these related transactions will share the same transaction ID, and as a result, this field may not be unique.

reference

String

A unique reference for the transaction, generated by the system. However, certain transactions, such as VAT or bank charges, may have a fixed reference, meaning this field may not be unique for these transaction types.

transactionType

String

The type of transaction. Example: H4.

channel

String

The channel through which the transaction was made. Example: CMM.

transactionDate

DateTime

Timestamp of the transaction.

postingDate

DateTime

Timestamp when the transaction was posted.

valueDate

DateTime

Value date of the transaction.

narration

String

Description or details of the transaction.

currency

String

Currency code for the transaction (e.g., TZS, USD).

amountCredit

Decimal

Amount credited to the account.

amountDebit

Decimal

Amount debited from the account.

clearedBalance

Decimal

The cleared balance in the account after the transaction.

bookedBalance

Decimal

The booked balance in the account after the transaction.

Sample Payload

{
  "accountNo": "0150089761300",
  "payerName": "TEMBOPLUS COMPANY LIMITED",
  "id": "25b91d28-6441-50c1-9456-ae986bd13d44",
  "transactionId": "181934dcb3ed4mp6",
  "reference": "CMFECA52AA9E17",
  "transactionType": "H4",
  "channel": "CMM",
  "transactionDate": "2024-11-21T11:16:25.855+03:00",
  "postingDate": "2024-11-21T11:16:25.857+03:00",
  "valueDate": "2024-11-21T11:16:25.812+03:00",
  "narration": "TZ#R90RTGO243260036#MT103#TEMBOPLUS COMPANY LIMITED#2411210PYT8L,Prefund Payouts,,RTGS4112",
  "currency": "TZS",
  "amountCredit": 97000000,
  "amountDebit": 0,
  "clearedBalance": 719936914.34,
  "bookedBalance": 719936914.34
}

Security and Signature Verification

To ensure the integrity and authenticity of the callback payload, TemboPlus signs each request using an HMAC signature. The signature is provided in the x-request-signature header.

Signature Generation

The signature is computed using the following steps:

  1. Generate a Timestamp A timestamp is generated at the time of request in milliseconds since the Unix epoch. This value is sent in the x-request-timestamp header.

  2. Concatenate Fields A string is formed by concatenating specific fields from the payload in the following order:

    x-request-timestamp + accountNo + id + transactionId + reference + transactionType
    + channel + transactionDate + postingDate + valueDate + narration + currency +
    truncated(amountCredit) + truncated(amountDebit) + truncated(clearedBalance) +
    truncated(bookedBalance)

    Truncated Values: Amount-related fields (amountCredit, amountDebit, clearedBalance, bookedBalance) are truncated to remove decimal values. For example, 97000000.34 becomes 97000000.

  3. Compute the HMAC Using the concatenated string:

    • The HMAC digest is computed with the SHA-256 hashing algorithm.

    • The secret key, specific to the account, is base64-decoded before use.

    • The resulting digest is encoded as a base64 string to produce the final signature.

  4. Send the Signature

    • The computed signature is included in the x-request-signature header.

    • The x-request-timestamp header accompanies the request to provide the timestamp used during signature generation.

Example Implementation

Below is a sample code snippet for verifying the signature in Node.js:

const crypto = require('crypto');

function verifySignature(secretBase64, timestamp, body, receivedSignature) {
  // Decode the secret
  const secret = Buffer.from(secretBase64, 'base64');
  
  // Reconstruct the concatenated string
  const concatenatedString =
    timestamp +
    body.accountNo +
    body.id +
    body.transactionId +
    body.reference +
    body.transactionType +
    body.channel +
    body.transactionDate +
    body.postingDate +
    body.valueDate +
    body.narration +
    body.currency +
    Math.trunc(body.amountCredit).toString() +
    Math.trunc(body.amountDebit).toString() +
    Math.trunc(body.clearedBalance).toString() +
    Math.trunc(body.bookedBalance).toString();
  
  // Compute the HMAC
  const hmac = crypto.createHmac('sha-256', secret);
  hmac.update(Buffer.from(concatenatedString, 'utf-8'));
  const computedSignature = hmac.digest().toString('base64');
  
  // Compare the signatures
  return computedSignature === receivedSignature;
}

Additional Notes

  1. Timestamp Validity

    • Ensure the x-request-timestamp is recent (e.g., within 5 minutes) to mitigate replay attacks.

    • However, note that callbacks may be retried by the system in case of server errors or network outages.

    • In such cases, the retried callback will carry the original timestamp, which may fall outside the expected window.

    • As a result, timestamp validation may fail for these retries. You may consider not validating timestamps at all to avoid such issues.

  2. Truncated Values

    • The truncation step ensures consistency in signature computation. Decimal values must be removed before concatenation.

  3. Handling Secret Keys

    • The secret key will be shared during onboarding and can be changed upon request if it is determined that the key has been compromised or needs to be rotated to meet your organization policy.

PreviousGet Account StatementNextBanking & Wallets

Last updated 13 days ago