# 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

```json
{
  "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:

    ```javascript
    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:

```javascript
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.
