Skip to main content

Result Notification

After an order completes, the BBMSL Online Payment Gateway sends the payment result to your backend via a POST callback. Your backend must handle the result and reply with an acknowledgement.

Before you start

Set up your API credentials and understand how signing works before implementing notifications. See Integration Setup.

Acknowledge notifications

Your notification endpoint must return a plain-text OK response with an HTTP 2XX status code to acknowledge receipt. The BBMSL Online Payment Gateway treats any other response as a failed delivery and schedules a retry.

Do not rely solely on notifications

Always use the query API alongside callback notifications to reconcile transaction results. Notifications may be delayed or lost due to network conditions. See Query API for details.

Retry schedule

If the gateway does not receive a successful acknowledgement, it retries delivery at the following intervals:

AttemptDelay
115 s
215 s
330 s
41 min
52 min
65 min
75 min
810 min
920 min
1030 min
1130 min
1260 min
1360 min
142 h
154 h

Retries stop when the gateway receives a successful acknowledgement or when the maximum of 15 attempts is reached. The gateway cannot guarantee successful delivery even after all retry attempts.

Design for idempotency

The gateway may deliver the same notification more than once due to network fluctuations or other transient errors. Your backend must implement idempotent processing — deduplicate incoming notifications by orderId or merchantReference and always return HTTP 2XX even for duplicate deliveries.

Receive a notification

Provide a REST API endpoint for the gateway to POST payment results to. Configure the URL using the callbackUrl.notify or notifyUrl parameter when creating a payment request.

  • Request method: POST
  • Expected response: OK (plain text, HTTP 2XX)

Payment success notification (Hosted Model / Direct Model)

{
"amount": "15.00",
"maskedPan": "411111XXXXXX1111",
"orderId": "534027",
"signature": "a6+r+VKPlerOFkIFB5El5zXYsIIKGYtul1l/RMGQwf6DJtOe1DPxejffj5iSGhlAqyEJlAontp2EwNpIJ0mdl79RaTfxFvF1rkvNM2tQpQLPMr5+Bqb3YeVN2W7Un/yWQgkHCkFkEhJFx//BLAqkde+xHCnl9fkOxok/3UVBiM6pPbgE0BbLutsFGJ9I511cMS4zPTT4nW3Tet4NNvIelSDNoYjaE8eeoG+v34+9y7Oo/2mtz7maus0suLVCG/juAytPCAdFqijsAdrojSs3p5k1zTm737hpusJh3LiInTkh8lNF8elRmJkhiAN0s7UzpFiHx2nwWnwP3V+qm/D2BA==",
"cardType": "VISA",
"updateTime": "2025-05-13T03:46:06+0000",
"merchantReference": "merRef1747107896496",
"status": "SUCCESS"
}

Add token success notification

{
"userId": "userName",
"tokenId": "12541",
"type": "AddToken",
"maskedPan": "4325xxxxxxxx2654",
"signature": "c1hTR2RBNHRSNEIwd25GNk5yOFNocGZOTXRISVNXdXpMcGRLb05Xc2tJZ0Njc3BNVkZGemdrZXo0QnJtdFlYa01xWmgxdHl6LzhzTk5VM0YyVlR1MGZPeCtaUDRDbm1Wak51OGJjaXU0aFR0bnl0QTNZMUdaL3lYQVVEK21WWUdYZXlETzNmSHJxRGRJN2szeFYvUThGQ09kMGN1bFRzTjZSUk14TVpxK29xUjJ4K0VqT1hWb2ZwN0JaSndoUUU4VXM0QWw1NzNGUXo1RUhEdkNMeDM1bHEyaG9NaFhMQ1ZMVkRCSGNwQ2dvdHVZNG1nOTFNWGgvcXFjRkdZL2hRS2hHZFdBYlo5dGNwMlE1czJFU2gzN3JxeG5Pd1pycmVwSzhOQzZ2TUJQVWlTUHhRZWZwZXYybkcwSnpBSE9qUlBiQlhZdzFYQlM2UkJZS0FtdWZaWmlRPT0="
}

Verify notification signature

Each notification includes a signature field. Verify it using the BBMSL public key to confirm the message was sent by BBMSL and has not been tampered with.

note

Use the BBMSL public key obtained during Integration Setup to verify notification signatures.

Follow these steps to verify the signature:

  1. Remove the signature field from the notification payload.
  2. Sort the remaining fields alphabetically by key.
  3. Join all key-value pairs with & to form the pre-verify string:
    amount=15.00&cardType=VISA&maskedPan=411111XXXXXX1111&merchantReference=merRef1747107896496&orderId=534027&status=SUCCESS&updateTime=2025-05-13T03:46:06+0000
  4. Verify the signature against the pre-verify string using SHA256WithRSA and the BBMSL public key.

The BBMSL test environment public key for verifying notifications:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkDecXu4GFMxCqp4pjfwtN1nSQiV9kmdcBMnKq5IeLB6BYWOENqeY+JFftnNaxHOgnhOrbrl71D6G57G7rhNLClgBNerB7mINDBwvENkEVq6zNbJsjOJekJtTVkxs7KoBip44odCBmElCFrUsr0qOr10kzUzYHXXEUpTqQon3jDGm+EkFoNv3RLwn0ZWuwid5kuk6tZ0Xj3OxiKTrzXK2STjzJ8Q25e9CKbO03fpaMSpBRrkuA1NHRQoSO0ew6lGE4swQ+dseVbh+z7YFVUWqDyjJ6pB+F3p4vDniw4r9/rE+ikP0eLMg99vWDjuQbPtUHYaQtMYNSzrmcTkBCGkt6QIDAQAB

Code samples

Build the pre-verify string:

signature.java
public static String createPreVerifyString(Map<String, String> params) {

List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);

String prestr = "";

for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);

if (i == keys.size() - 1) {
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}

Verify the signature:

signature.java
private static final String KEY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";
private static final String DEFAULT_CHARSET = "UTF-8";

public static boolean verify(String content, String publicKey, String sign) throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(content.getBytes(DEFAULT_CHARSET));
return signature.verify(Base64.decode(sign));
}