Fund Transfer 27112021

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

Transaction Banking

Fund Transfer API


SPECIFICATIONS

Release: 1.3
Date: 08th March 2021

Revision History
Revision date Author Version Summary of changes
th
24 June 2019 Pravin Navele 1.0 Draft version
06th Mar 2020 Rishu Gupta 1.1
06th June 2020 Rishu Gupta 1.2 Checksum addition
th
08 March 2021 Gaurav Kale 1.3 Bene Lei Addition

Approvals
This document requires the following approvals:

Name Title Date of approval


Roshan Jha Senior Manager 06th June 2020
Table of Contents
Objective ...................................................................................................................................3
Format Available .......................................................................................................................3
HTTP Headers ...........................................................................................................................3
API Connect SubHeader ............................................................................................................3
1. Payment API ..........................................................................................................................4
Security Considerations ..........................................................................................................13
Sample Encryption Decryption code and Checksum Logic .....................................................14
Objective
The objective of this document is to list the specification APIs to be used for banking service.

Format Available
JSON

HTTP Headers
The following header parameters must be sent in each request.

Fields Mandatory Description

Content-Type Y Content type of request body. i.e., application/json for JSON


type

X-IBM-Client-Id Y Unique for each client. It will be provided by Axis bank

X-IBM-Client-Secret Y Unique for each client. It will be provided by Axis bank

API Connect SubHeader


API Connect SubHeader is the common identifier and audit parameter used for all the services built
in API Connect. SubHeader structure is same for both request and response bodies of an API Connect
service.

Fields Length Mandatory Description

requestUUID 40 Y Unique alphanumeric ID (without special characters)


from the source system

serviceRequestId 30 Y Service request ID configured at API Connect for the


source system.

serviceRequestVersion 3 Y Service request version configured at API Connect for


the source system.

channelId 10 Y Channel ID configured at API Connect for the client.

Note: Channel ID is client specific which will be


configured on API Connect. It will be provided by API
Connect to all the clients. It will also be used for
decryption of the encrypted request body sent by the
client.
1. Payment API

a) Transfer (N/R/I/IMPS/CC/DD)

URL https://sakshamuat.axisbank.co.in/gateway/api/txb/v1/payments/transfer-payment

Method
POST

Non-encrypted request body fields

API Connect fields Type Repeating Mandatory Description


TransferPaymentRequest complex N Y Request root tag
TransferPaymentRequest complex N Y Request body tag
Body
channelId varchar(10) N Y Channel ID configured at API
Connect for the client.
corpCode varchar2(15) N Y Corporate Code to identify the
source
paymentDetails complex N N Payment related details
txnPaymode char(2) N Y Payment mode identification
RT – RTGS
NE – NEFT
PA - IMPS
FT - Fund Transfer (Axis to Axis)
CC – Corporate Cheques
DD – Demand Draft
custUniqRef varchar2(30) N Y Corporate unique reference no
for each transaction
corpAccNum varchar2(30) N Y Corporate Debit account no
valueDate date (yyyy-mm-dd) N Y Always be current date
txnAmount number(15,2) N Y Transaction amount

beneLEI number(20) N N Mandatory–for transactions INR


50 Crs and above. Can be blank
for Transaction below 50 Crs INR
beneName varchar2(100) N Y No Special characters allowed in
case of E-Payment (RTGS &
NEFT)
Bene_code varchar2(30) N Y Merchant / Customer /
Distributor / Internal Code
beneAccNum varchar2(30) N Y Mandatory for RTGS, NEFT and
FT, IMPS. Can be blank for rest
of the payment modes
beneAcType varchar2(2) N N Beneficiary AC Type
10 -SAVINGS BANK
11 -CURRENT ACCOUNT
13 -CASH CREDIT
40 -NRE
41 -NRO
beneAddr1 varchar2(100) N N Beneficiary Address 1

beneAddr2 varchar2(100) N N Beneficiary Address 2

beneAddr3 varchar2(100) N N Beneficiary Address 3

beneCity varchar2(25) N N Beneficiary CITY

beneState varchar2(25) N N Beneficiary State

benePincode varchar2(7) N N Beneficiary City Pin Code

beneIfscCode varchar2(30) N N Mandatory for RTGS, NEFT, IMPS


– input IFSC Code. Optional but
recommended For FT. Can be
blank for rest of the products (CC
& DD)

beneBankName varchar2(100) N N Beneficiary Bank Name

baseCode varchar2(15) N N Mandatory for MICR CHEQUE


PRINTING. Short Acc No / Alpha
code provided by the bank to
the Corporate
chequeNumber varchar2(20) N N Mandatory for MICR CHEQUE
PRINTING
Cheque series will provide by
the bank
chequeDate date (yyyy-mm-dd) N N Future Date - Max 30 calendar
date from current date
payableLocation varchar2(30) N N Cheque Payable Location

printLocation varchar2(30) N N Cheque Print location as per the


mapping provided
beneEmailAddr1 varchar2(250) N N Multiple email with semicolon
separator
beneMobileNo varchar2(54) N N Multiple Mobile with pipe
separator, Max 5 mobile no
productCode varchar2(10) N N Product Code provided by bank
to the corporate for multi layout
cheque printing
Txn_type varchar2(30) N N Nature of transaction or
Payment type
Default values for payment
modes: Fixed -
CUST - Customer Payment
MERC - Merchant Payment
DIST - Distributor Payment
INTN - Internal Payment
VEND - Vendor Payment
invoiceDetails complex N N Invoice details

invoiceAmount varchar2(30) N N Amount

invoiceNumber varchar2(50) N N Invoice Number

invoiceDate date (yyyy-mm-dd) N N Invoice Date

cashDiscount varchar2(18) N N Cash Discount

tax varchar2(18) N N Tax

netAmount varchar2(18) N N Net Amount

invoiceInfo1 varchar2(50) N N Additional Info 1

invoiceInfo2 varchar2(50) N N Additional Info 2

invoiceInfo3 varchar2(50) N N Additional Info 3

invoiceInfo4 varchar2(50) N N Additional Info 4

invoiceInfo5 varchar2(50) N N Additional Info 5

enrichment1 varchar2(100) N N For future purpose

enrichment2 varchar2(100) N N For future purpose

enrichment3 varchar2(100) N N For future purpose

enrichment4 varchar2(100) N N For future purpose

enrichment5 varchar2(100) N N For future purpose

senderToReceiverInfo varchar2(30) N N Sender To Receiver information

checksum varchar2(255) N Y A checksum is a value used to


verify the integrity of a file or a
data transfer. This is calculated
only on attributes within body.
Non-encrypted JSON request sample
{
"TransferPaymentRequest": {
"SubHeader": {
"requestUUID": "ABC123",
"serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentRequestBody": {
"channelId":"TXB",
"corpCode":"DEMOCORP11",
"paymentDetails":[{
"txnPaymode":"NE",
"custUniqRef":"338200641748800",
"corpAccNum":"248012910169",
"valueDate":"2020-03-06",
"txnAmount":"500.00",
"beneLEI": "12dfkj",
"beneName":"RANCO INDUSTRIES",
"beneCode":"RAI15235",
"beneAccNum":"914020013977038",
"beneAcType":"",
"beneAddr1":"",
"beneAddr2":"",
"beneAddr3":""
,"beneCity":"Mumbai",
"beneState":"Maharashtra",
"benePincode":"400101",
"beneIfscCode":"SBIN0007959",
"beneBankName":"STATE BANK OF INDIA",
"baseCode":"",
"chequeNumber":"",
"chequeDate":"",
"payableLocation":"",
"printLocation":"",
"beneEmailAddr1":"ranco@gmail.com",
"beneMobileNo":"7678429077",
"productCode":"",
"txnType":"",
"invoiceDetails":[
{
"invoiceAmount": "1888.00",
"invoiceNumber": "M713-DN",
"invoiceDate": "2018-11-21",
"cashDiscount": "0.00",
"tax": "0.00",
"netAmount": "0.00"
"invoiceInfo1": "slfj13",
"invoiceInfo2": "20384lskdjf",
"invoiceInfo3": "lsdjf2903",
"invoiceInfo4": "0234sjdlf",
"invoiceInfo5": "ls0w392sdfk"
}
],
"enrichment1":"",
"enrichment2":"",
"enrichment3":"",
"enrichment4":"",
"enrichment5":"",
"senderToReceiverInfo":""
}], "checksum": " e326c1ca326533f55d0aa93c1caffde30769a715"
}

}}
Encrypted request body fields

Field Type Repeating Mandatory Description

TransferPaymentRequest Complex N Y Request root tag

TransferPaymentRequestBodyEncrypted Complex N Y Encrypted request data

Encrypted JSON request sample


{
"TransferPaymentRequest": {
"SubHeader": {
"requestUUID": "ABC123",
"serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentRequestBodyEncrypted":
"r96ExEvpb2atQvw0llKHfT97mHq8UfVtG43cLbD8LzyCihVbS3Vm+4xaL+n4QCAhZraT3HpaSDB2i/U4l8
/iWCMetjTk2Xvt9eWLqNnAO7Wm1/edinEcCaE71F8GQZY70X4V/Qrd+/6L7oa6zRngLfZpjJk5nuEBm+U
9H3rEhG/70TsmVeRf8WqAtBRGfOrsHjbzxv8c0z+70IpHIAW83h0C9gOeVqDecvlPp5nRRpWI1zSyCZj/f
HU1aGEzQghniqgql8D72FWXHR7pFYSX/STs8heHyvVscANsVfFrU362ZuC/pAmEQTNpb+NEEYVxmIjcg
h7lSOhsM4sSqMR1j5vEdl1BXvXysbhJ+GLeB6ooWjomwVMAdMvU9cPJsCGPieldWoD/TkgE4vdQojYrD
oqUcn7lMYgA7LCb8HIsPFED/OtU2vqgGx2DWiZuBRDQQzTcEhSVF4hStLQmYZeZd4qdxWhlYbBLYDoE
eX4psZC2E/KGQ9OP/HMbkqpEyGeiSXUTf4QrkrHGy1x52dcSj6kbWkfEqIBqgaW/svJlNZSyqVd5tiCCzKG
FB8bUJ4yqsCzYa+r3o0ZnnHymCJpFH9jr9txKNEVIrkgkKMm+Ezy/0F5yzU7UCGzQfe97gyjQ2MNK4cSNq
+49wl6lMv/sIvwpRYn89mnZJNIdzkqXkUZtQGUD1RWx/jbzzFA3bJWRkjUOs/PbTDjLTY1w5owZurEwN3
uYczWZ4KNeI7evERckMIenzJ5rwLt88k5ygfhBeVsmUGDF7UH6IWJg7ujk1lLrmQmWsVbF6yYtNCFHM7
8zMswztnpCjfqztHol45h3lm2z7wHbTL2niziqFxSJZkQsndbukbcwGsKn6zuNlsT15v4MEVTVk0JgC52ZM
a2qGKa3409J917K3HrbmuRLtOuhNb8/Zih9nugvr04yshczISFnHJh3b3cluBF7KJXbr/plkRcqDI72x7jzVkG
ONBxcDsqX4mU9yKWdkziQ9oPW88MRbxpnnk/PAy75oK61LEyQWI966V9+SqrGl3K8S2a5RPI6PC22J4
G3IckQmkYbUXmDbYTicer0Fh4ub/NgUUQGuwWcIhKQFH6Y5S6K+FcAPoAa+eOXUfMxEIdOXTvTKptu
LqGbgpGCDh78TxzDFGzzXUifTd/FvSPYGZGGCIERQjaRQ2B1jdDWdm/SscZadSDB6IavJDmcMkWKTShX
iRieObAVOv8fX2drnHF7AvA7yEgc2z4bjffAp9yP5bmYx3iM+EFFN4+zQ003kZTYZ96p4bWFhlmQvFQO4
U4yS5HFF6V3zKvjxtw5dNtqoXQW0Wa+ePoLl99PZmYKpVVVm2hY7rYd/n1xm3n4M4UGnRLaceL0vSY
nlsM AwpJN2NBgPNNSoQ3PVPy//hCI6TS"
}
}
Non-encrypted response body fields

API Connect fields Type Repeating Mandatory Description

TransferPaymentResponse Complex N Y Response root tag

TransferPaymentResponseBody Complex N Y Response body tag

status N Y It indicates the status of the


response

data Complex N Y Actual data in response in


JSON format

message N Y Message as per the status

checksum varchar2(500) N Y A checksum is a value used


to verify the integrity of a file
or a data transfer. This is
calculated only on attributes
within data.

Non-encrypted JSON response sample


{
"TransferPaymentResponse": {
"SubHeader": {
"requestUUID": "ABC123",
"serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentResponseBody": {
"data": "",
"message": "Success"
"status": "S"
}
}
}
Encrypted response body fields

Field Type Repeating Mandatory Description

TransferPaymentResponse complex N Y Response root tag

TransferPaymentResponseBodyEncrypted complex N Y Encrypted response


data

Encrypted JSON response sample


{
"TransferPaymentResponse": {
"SubHeader": {
"requestUUID": "ABC123", "serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentResponseBodyEncrypted":
"dptYwdTIHqsH1NmpRjHLyfSL8BGVJ+JCqXYwpEuVp47CfJnuo+WdSxTMGZvnF3i8gr0iJV4YeFyrkrf7t8h
blg=="
}}
Non-encrypted JSON failure response samples

Checksum verification failed


{
"TransferPaymentResponse": {
"SubHeader": {
"requestUUID": "ABC123",
"serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentResponseBody": {
"data": "",
"message": "Checksum verification failed",
"status": "F"
}}

Invalid Corporate Code or Channel


{
"TransferPaymentResponse": {
"SubHeader": {
"requestUUID": "ABC123",
"serviceRequestId": "OpenAPI",
"serviceRequestVersion": "1.0",
"channelId": "TXB"
},
"TransferPaymentResponseBody": {
"data": "",
"message": "Corp ID not found",
"status": "F"
}

}
}
Security Considerations
Following are the security considerations which will need to be followed by the consumers for
successful connectivity with the application:
1. HTTPS and two way SSL
All consumers will be needed to invoke the application over HTTPS protocol. We also have two way
SSL established. This means that we would be validating the consumer certificate. Hence it is required
that the consumer has a certificate and the same is shared with us as a prerequisite.
2. IP whitelisting
We allow only select IP addresses to access our application over the internet. Hence as a consumer it
may be required to whitelist all the ip addresses that the consumer would be consuming the
application from. This step is a prerequisite to setup successful connectivity.
3. Symmetric encryption
The API to be invoked accepts the request body encrypted using encryption algorithm. The body
has to be encrypted using AES-128 encryption. The encryption key will be provided and will be
different for each consumer.
Sample Encryption Decryption code and Checksum Logic

import java.io.ByteArrayOutputStream;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.Cipher; import


javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import com.sun.org.apache.xml.internal.security.utils.Base64;

public class AESUtilImpl


{
private static final String ALGORITHM = "AES"; private static final String
CIPHER_ALGORITHAM = "AES/CBC/PKCS5PADDING"; private static final String
KEY = "29C1EB633ECAB0CA0F52B588AE92EA31";

//Encrypt request
public String aes128Encrypt(String plainText) throws Exception
{
byte[] iv = new byte[] { (byte) 0x8E, 0x12, 0x39, (byte) 0x9C, 0x07,
0x72, 0x6F, 0x5A, (byte) 0x8E, 0x12, 0x39, (byte) 0x9C, 0x07,
0x72, 0x6F, 0x5A };

AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);


/** Generate a secret key from the hex string as key */
SecretKeySpec skeySpec = getSecretKeySpecFromHexString(ALGORITHM, KEY);
/** Creating a cipher instance with the algorithm and padding */
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHAM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec);
/** generating the encrypted result */
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
// To add iv in encrypted string. byte[]
encryptedWithIV = copyIVAndCipher(encrypted, iv); String
encryptedResult = Base64.encode(encryptedWithIV);
return encryptedResult;
}

//Encrypt response
public String aes128Decrypt(String encryptedText) throws Exception
{
SecretKeySpec skeySpec = getSecretKeySpecFromHexString(ALGORITHM, KEY);
byte[] encryptedIVandTextAsBytes = Base64.decode(encryptedText);
/** First 16 bytes are always the IV */
byte[] iv = Arrays.copyOf(encryptedIVandTextAsBytes, 16);

byte[] ciphertextByte = Arrays.copyOfRange(encryptedIVandTextAsBytes, 16,


encryptedIVandTextAsBytes.length);
// Decrypt the message
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHAM);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv)); byte[]
decryptedTextBytes = cipher.doFinal(ciphertextByte); String
decryptedResult = new String(decryptedTextBytes, "UTF-8");
return decryptedResult;
}

private static SecretKeySpec getSecretKeySpecFromHexString(String algoCommonName,String hexString)


throws Exception {
byte [] encodedBytes = hexStrToByteArray(hexString) ;
return new SecretKeySpec(encodedBytes, algoCommonName);
}

private static byte[] hexStrToByteArray(String hex) {


ByteArrayOutputStream baos = new ByteArrayOutputStream(hex.length() / 2);

for (int i = 0; i < hex.length(); i += 2) {


String output = hex.substring(i, i + 2);
int decimal = Integer.parseInt(output, 16);
baos.write(decimal);
}
return baos.toByteArray();
}

public static byte[] copyIVAndCipher(byte[] encryptedText, byte[] iv) throws Exception {


ByteArrayOutputStream os = new
ByteArrayOutputStream(); os.write(iv);
os.write(encryptedText);
return os.toByteArray();
}

}
Checksum Logic

Sample Request:
{
“data”:{
attr1: val1,
attr2 : val2,
.
.
attrN : valN
}
}
Checksum string = val1+val2+…+valN; public
static Object validateInfo(String value) {
return StringUtils.isNotEmpty(value) && "null" != value ? value : StringUtils.EMPTY;
}

Attribute Value extractor


//To retrieve the checksum string, convert JSON object into map of request of data attribute. Only Body part
of request to be considered.
public String generateCheckSum(LinkedHashMap<String, Object> requestMap) throws Exception {
StringBuilder finalChkSum = new StringBuilder();
StringBuilder keys = new StringBuilder(); try {
if(null==requestMap) {
return null;
}

for(Map.Entry<String, Object> entry: requestMap.entrySet()) {


if(!entry.getKey().equals("checksum")) { if(entry.getValue()
instanceof List) {
List<Object> tempLst=((List)entry.getValue());
if(!CollectionUtils.isEmpty(tempLst) && (tempLst.get(0) instanceof Map)) {
List<? extends Map<String, Object>> innerObjectMap
= (List<? extends Map<String, Object>>) entry.getValue();

for(Map<String ,Object> innerMap : innerObjectMap) {


for(Entry<? extends String, ? extends Object> entryInn :
innerMap.entrySet()) {
keys.append(entryInn.getKey());

finalChkSum.append(
getInnerLevel2Map(
entryInn.getValue(),finalChkSum));
}
}
}else if(!CollectionUtils.isEmpty(tempLst)) {
for(Object strValues : tempLst) {
finalChkSum.append(
validateInfo(
String.valueOf(strValues)));
}
}

} else if(entry.getValue() instanceof Map){


Map<? extends String, ? extends Object> innerObjectMap2
= (Map<? extends String, ? extends Object>) entry.getValue();
for(Entry<? extends String, ? extends Object> entryInn :
innerObjectMap2.entrySet()) {
keys.append(entryInn.getKey());
finalChkSum.append(
validateInfo(
String.valueOf(entryInn.getValue())));
}
}else {
finalChkSum.append(
validateInfo(
String.valueOf(entry.getValue())));
}
}
}
} catch (Exception e) {
logger.error(e);
}
return String.valueOf(
encodeCheckSumWithSHA256(
finalChkSum.toString().trim()));
}
private String getInnerLevel2Map(Object entryInnLvl2,StringBuilder finalChkSum123) {
StringBuilder finalChkSum = new StringBuilder();
StringBuilder keys = new StringBuilder();
if(entryInnLvl2 instanceof List) {
List<Object> tempLst=((List)entryInnLvl2);
if(!CollectionUtils.isEmpty(tempLst) && (tempLst.get(0) instanceof Map)) {

List<? extends Map<String, Object>> innerObjectMap =


(List<? extends Map<String, Object>>) entryInnLvl2;
for(Map<String ,Object> innerMap : innerObjectMap) {
for(Entry<? extends String, ? extends Object> entryInn : innerMap.entrySet()) {
keys.append(entryInn.getKey());
finalChkSum.append(
validateInfo(String.valueOf(entryInn.getValue())));
}
}
}else if(!CollectionUtils.isEmpty(tempLst)) {
for(Object strValues : tempLst) {
finalChkSum.append(
validateInfo(
String.valueOf(strValues)));
}
}
} else if(entryInnLvl2 instanceof Map){
Map<? extends String, ? extends Object> innerObjectMap2 =
(Map<? extends String, ? extends Object>) entryInnLvl2; for(Entry<? extends
String, ? extends Object> entryInn : innerObjectMap2.entrySet()) {
keys.append(entryInn.getKey());

finalChkSum.append(
validateInfo(
String.valueOf(entryInn.getValue())
));
}
}else {
finalChkSum.append(
validateInfo(
String.valueOf(entryInnLvl2)));
}
return finalChkSum.toString();
}

Hashing Algorithm
//Based on the final value of
string, checksum will be generated using MD5 algorithm.
public static String encodeCheckSumWithSHA256(String data) {
MessageDigest md;
StringBuilder sb = new StringBuilder();
String response = null;
try {
md = MessageDigest.getInstance(“MD5”);
md.update(data.getBytes(StandardCharsets.UTF_8));
// Get the hashbytes byte[]
hashBytes = md.digest(); // Convert
hash bytes to hex format for (byte
b : hashBytes) {
sb.append(String.format("%02x", b));
}
response = sb.toString();
}catch (Exception e) {
throw new RuntimeException("Internal server error");
}
return response;
}}}

You might also like