Step by Step Process for merchant onboard API:
Step1:Initialize Required Constants
String clientId = "";
String clientSecret = "";
String encryptionKeyBase64 = "a6T8tOCYiSzDTrcqPvCbJfy0wSQOVcfaevH0gtwCtoU=";
String uri = "/isu/pg/apimerchantOnboarding";
String method = "POST";
String contentType = "application/json";
String accept = "application/json";
This sets up the configuration for encryption and signature generation.
String clientSecret = "";
String encryptionKeyBase64 = "a6T8tOCYiSzDTrcqPvCbJfy0wSQOVcfaevH0gtwCtoU=";
String uri = "/isu/pg/apimerchantOnboarding";
String method = "POST";
String contentType = "application/json";
String accept = "application/json";
This sets up the configuration for encryption and signature generation.
Step2:Create Payload
JSONObject payload = new JSONObject()
.put("apiOperation", "ADD")
.put("programType", "PG")
.put("programName", "PayFac")
.put("requestId", "98698698")
.put("merchantId", 94320873287538L)
.put("merchantData", new JSONObject()
.put("merchantEmail", "[email protected]")
.put("merchantName", "Ecom Holdings Online Inc")
.put("iOSAppStoreURL", "https://appstoretest.com")
.put("merchantLogoUri", "https://example.com/ecom-online-ltd/images/ecom-logo.png")
.put("merchantUri", "https://example.com/ecom-online-ltd/basket.html")
.put("googlePlayStoreURL", "https://playtest.com")
.put("t&CUrl", "https://test.com/t&C.html")
.put("refund&ReturnsPolicyURL", "https://test.com/refund&return.html")
.put("companyDbaName", "FieldTestMerchant01_update12")
.put("vat", "1234567890123Z1")
.put("tin", "4545CC8787897")
.put("corporateTAX", "78687678")
.put("merchantAddress", new JSONObject()
.put("name", "Ecom Online Store")
.put("line1", "100 Avenue Lane Street")
.put("line2", "Address line 2")
.put("line3", "Address line 3")
.put("city", "Metropolis")
.put("state", "MH")
.put("countryCode", "US")
.put("zip", "41321"))
.put("merchantAccount", new JSONObject()
.put("accountNumber", "56785678")
.put("bankName", "CITI")
.put("swiftOrBICcode", "CITI7878")
.put("accountType", "CURRENT"))
.put("paymentProcessor", "ISU")
.put("cardAcceptance", "MC")
.put("acceptanceCurrency", "AED")
.put("settlementCurrency", "AED")
.put("maximumTransactionSize", "999999")
.put("annualVolume", "999999999")
.put("integrationMode", "API")
.put("threeDSRequired", "Y")
.put("tokenizationRequired", "Y")
.put("merchantCountryCode", "356")
.put("recurringBy", "Merchant")
.put("sale", "Y")
.put("preauth", "Y")
.put("preauthcomp", "Y")
.put("refund", "Y")
.put("void", "Y")
.put("isdcc", "N")
.put("multiClearingCapture", "N")
.put("isInternationalCardAcceptance", "N"))
.put("acquirerData", new JSONObject()
.put("acquirerIca", "12345")
.put("acquirerBin", "112233")
.put("schemeMerchantId", ""))
.put("merchantCategoryCodes", new JSONArray().put("1234"));
This creates the JSON request body.
.put("apiOperation", "ADD")
.put("programType", "PG")
.put("programName", "PayFac")
.put("requestId", "98698698")
.put("merchantId", 94320873287538L)
.put("merchantData", new JSONObject()
.put("merchantEmail", "[email protected]")
.put("merchantName", "Ecom Holdings Online Inc")
.put("iOSAppStoreURL", "https://appstoretest.com")
.put("merchantLogoUri", "https://example.com/ecom-online-ltd/images/ecom-logo.png")
.put("merchantUri", "https://example.com/ecom-online-ltd/basket.html")
.put("googlePlayStoreURL", "https://playtest.com")
.put("t&CUrl", "https://test.com/t&C.html")
.put("refund&ReturnsPolicyURL", "https://test.com/refund&return.html")
.put("companyDbaName", "FieldTestMerchant01_update12")
.put("vat", "1234567890123Z1")
.put("tin", "4545CC8787897")
.put("corporateTAX", "78687678")
.put("merchantAddress", new JSONObject()
.put("name", "Ecom Online Store")
.put("line1", "100 Avenue Lane Street")
.put("line2", "Address line 2")
.put("line3", "Address line 3")
.put("city", "Metropolis")
.put("state", "MH")
.put("countryCode", "US")
.put("zip", "41321"))
.put("merchantAccount", new JSONObject()
.put("accountNumber", "56785678")
.put("bankName", "CITI")
.put("swiftOrBICcode", "CITI7878")
.put("accountType", "CURRENT"))
.put("paymentProcessor", "ISU")
.put("cardAcceptance", "MC")
.put("acceptanceCurrency", "AED")
.put("settlementCurrency", "AED")
.put("maximumTransactionSize", "999999")
.put("annualVolume", "999999999")
.put("integrationMode", "API")
.put("threeDSRequired", "Y")
.put("tokenizationRequired", "Y")
.put("merchantCountryCode", "356")
.put("recurringBy", "Merchant")
.put("sale", "Y")
.put("preauth", "Y")
.put("preauthcomp", "Y")
.put("refund", "Y")
.put("void", "Y")
.put("isdcc", "N")
.put("multiClearingCapture", "N")
.put("isInternationalCardAcceptance", "N"))
.put("acquirerData", new JSONObject()
.put("acquirerIca", "12345")
.put("acquirerBin", "112233")
.put("schemeMerchantId", ""))
.put("merchantCategoryCodes", new JSONArray().put("1234"));
This creates the JSON request body.
Step3:Encrypt the Payload
String encryptedPayload = encryptRequest(payload, encryptionKeyBase64);
public static String encryptRequest(Object incomingJsonReq, String key) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(key);
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
byte[] payloadBytes = incomingJsonReq.toString().getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] encryptedBytes = cipher.doFinal(payloadBytes);
byte[] result = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, result, 0, iv.length);
}
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));
System.arraycopy(encryptedBytes, 0, result, iv.length, encryptedBytes.length);
return Base64.getEncoder().encodeToString(result);
This step ensures that the payload is encrypted with AES/CBC/PKCS5Padding using the base64 encoded key.
public static String encryptRequest(Object incomingJsonReq, String key) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(key);
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
byte[] payloadBytes = incomingJsonReq.toString().getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] encryptedBytes = cipher.doFinal(payloadBytes);
byte[] result = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, result, 0, iv.length);
}
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));
System.arraycopy(encryptedBytes, 0, result, iv.length, encryptedBytes.length);
return Base64.getEncoder().encodeToString(result);
This step ensures that the payload is encrypted with AES/CBC/PKCS5Padding using the base64 encoded key.
Step4:Wrap Encrypted Payload in JSON
JSONObject encreq = new JSONObject();
encreq.put("RequestData", encryptedPayload);
encreq.put("RequestData", encryptedPayload);
This prepares the final JSON body to be sent.
Step 5: Generate Timestamp and Trace ID
String timestamp = String.valueOf(System.currentTimeMillis());
String traceId = UUID.randomUUID().toString().replace("-", "");
String traceId = UUID.randomUUID().toString().replace("-", "");
Used for request tracking and signature.
Step 6: Generate HMAC Signature
String hmacSignature = generateHMAC(method, uri, timestamp, clientId, encreq.toString(), clientSecret, traceId, contentType, accept);
public static String generateHMAC(String method, String uri, String timestamp, String clientId, String payload, String clientSecret, String traceId, String contentType, String accept) throws Exception {
String payloadHash = sha256Hex(payload);
String canonicalString = String.join("|", method, uri, contentType, accept, traceId, timestamp, payloadHash.toUpperCase());
SecretKeySpec signingKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(canonicalString.getBytes(StandardCharsets.UTF_8));
return bytesToHex(rawHmac);
}
private static String sha256Hex(String data) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return bytesToHex(digest.digest(data.getBytes(StandardCharsets.UTF_8)));
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString();
}
The HMAC is created from a canonical string using the SHA-256 hash of the payload.
public static String generateHMAC(String method, String uri, String timestamp, String clientId, String payload, String clientSecret, String traceId, String contentType, String accept) throws Exception {
String payloadHash = sha256Hex(payload);
String canonicalString = String.join("|", method, uri, contentType, accept, traceId, timestamp, payloadHash.toUpperCase());
SecretKeySpec signingKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(canonicalString.getBytes(StandardCharsets.UTF_8));
return bytesToHex(rawHmac);
}
private static String sha256Hex(String data) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return bytesToHex(digest.digest(data.getBytes(StandardCharsets.UTF_8)));
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString();
}
The HMAC is created from a canonical string using the SHA-256 hash of the payload.
Step 7: Log the Final Request Details
System.out.println("Encrypted Payload Object:\n" + encreq.toString());
System.out.println("HMAC Signature:\n" + hmacSignature);
System.out.println("Timestamp:\n" + timestamp);
System.out.println("Trace ID:\n" + traceId);
System.out.println("HMAC Signature:\n" + hmacSignature);
System.out.println("Timestamp:\n" + timestamp);
System.out.println("Trace ID:\n" + traceId);
This shows the values needed for API call headers and body.
To send the request, you'll typically do the following (outside of this test):
Headers:
clientId: your clientId
signature: the HMAC signature
traceId: same as above
timestamp: same as above
Content-Type: application/json
Accept: application/json
Body:
json fomat
{
"RequestData": "Base64EncryptedPayload"
}
clientId: your clientId
signature: the HMAC signature
traceId: same as above
timestamp: same as above
Content-Type: application/json
Accept: application/json
Body:
json fomat
{
"RequestData": "Base64EncryptedPayload"
}
Example:
Base URL: https://apitest.txninfra.com/hmacV2/isu/pg/apimerchantOnboarding
Headers:
Content-Type: application/json
Accept: application/json
Authorization: HMACSignature QC62FQKXT2DQTO43LMWH5A44UKVPQ7LK5Y6HVHRQ3XTIKLDTB6HA:a0e73956779d362e039df04af12b 45970936074c402bb610401aeafdaeecbc95
Traceid: f8567cd967ed46bfaedd1437f39eb06d
Timestamp: 1748337693776
Accept: application/json
Authorization: HMACSignature QC62FQKXT2DQTO43LMWH5A44UKVPQ7LK5Y6HVHRQ3XTIKLDTB6HA:a0e73956779d362e039df04af12b 45970936074c402bb610401aeafdaeecbc95
Traceid: f8567cd967ed46bfaedd1437f39eb06d
Timestamp: 1748337693776
Sample Request Body (Encrypted):
Sample Response Body (Encrypted):