MFCentral - API Integration Document - CAS v2.2
MFCentral - API Integration Document - CAS v2.2
2|Page
API Specification and Integration Document
1. What is MFcentral?
MFcentral is application that allows users to seamlessly navigate, search, analyze, invest in MF trading
platform for all funds serviced by RTA’s. It lets you execute orders in real time, manage user portfolios
and place any Non-Financial and Financial Transactions request across all Mutual Funds.
2. Getting Started
This application provides a single unified portal for the user to access information regarding
investments made across mutual funds . This Walkthrough goes over the basics of the authentication
process as it applies to the MFCentral API using Json Web Tokens (JWT ).
Above illustration explained w.r.t GetCASDocument API, the invoking flow remains the same for
other APIs too.
To access MFcentral APIs, you will need the client Id and Client secret to generate the token.
You may contact a MFcentral representative for generating Client Id and secret.
Once you have the credentials, connecting to our API is easy. You can proceed with generating the
token, which should be passed in the header. Please refer to section 3.1
The following steps walk you through the basics to get started using the API.
1|Page
3.1 Get Client ID and Client Secret.
You can get the client ID and secret, through an Offline process.
If you think the key has been compromised, contact immediately to generate a new Client Secret
Below details will be shared by MFCentral during on-boarding
To generate a token that will be used for authorizing all subsequent APIs, pass the Client ID, Client
Secret and in the Authorization header.
Token generation involves passing Headers and Body together to the URL. Refer to the below
Postman screenshot on how to generate token.
Every token object will have an expiry time mentioned in seconds. The limit is set for 30 days.
Ensure that you are creating a new token object if the existing token object is expired.
Sample:
2|Page
Endpoint: https://uatservices.mfcentral.com/oauth/token
Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic dGVzdC1jbGllbnQxOnNzcGwkMTIzNA==
Body:
username: mfc-client1
password: Cams$1234
grant_type: password
Response:
{
"access_token": "dd33510a-f161-4818-8d35-65a64f617516",
"token_type": "bearer",
"refresh_token": "a0f749fa-2f97-44fd-be93-a5da24a22ca0",
"expires_in": 2591999,
"scope": "read write trust"
}
{
"clientRefNo": "testing12345",
"pan": "AANPE5444K",
"pekrn": "",
"mobile": "+919550755111",
"email": ""
}
Note: clientRefNo should be unique across different unique requests from client for
tracking purpose
3|Page
3.3.2) Encrypt the above request:
The above request should be encrypted using SHA 256 hash logic
To encrypt/decrypt data, use the below details.
During Encryption: Final value should be base 64 encoded value from the encrypted
result.
Take SHA-256 hash of the shared key and use the first 32 byte of the hash as your secret
key for both encryption and decryption.
Reference
Use CryptUtils.encryptDecrypt() for decryption
Sample Usage for Encryption :CryptUtils.encryptDecrypt("ENCRYPT",
payload, encryptionKey);
Generate a signature which should passed along with the request. The signed value is
a JWS (JSON WEB SIGNATURE) based value. Use the below detail to generate a JWS.
Reference :
Use generateSignature function
Sample Usage: generateSignature(encryptedText, privateKey);
4|Page
sample process – for JAVA based Users:
// Inputs to the request
String casRequestUrl =
"https://uatservices.mfcentral.com/api/client/V1/submitcassummaryrequest";
JSONObject response = submitRequestToMFCentral(
casRequestUrl,
token,
clientId,
encryptionDecryptionKey,
privateKey, publicKey, request);
Once you have generated the signature, submit your request in the below request
format.
Content-Type: application/json
ClientId: test-client1
Authorization: Bearer dd33510a-f161-4818-8d35-65a64f617516
Method: POST
5|Page
Reference
MFCentral returns response payload along with the digital signature. Verify the
signature before processing the response.
Reference:
Reference
Use CryptUtils.encryptDecrypt() for decryption
Sample Usage:
CryptUtils.encryptDecrypt("DECRYPT", response, encryptionKey);
6|Page
3.4 Submitting Investor consent to MFCentral (Validating OTP):
Upon successful authentication, you shall request for user OTP validation.
Once the User enters the OTP, MFcentral will validate and if validation is successful, shall allow to
proceed with the next step, else return error as OTP validation failed.
URL: https://uatservices.mfcentral.com/api/client/V1/investorconsent
Headers:
Content-Type: application/json
ClientId: test-client1
Authorization: Bearer dd33510a-f161-4818-8d35-65a64f617516
{
"reqId": 56475,
"otpRef": "9b69c14e-76f5-4ccb-9cd1-22e20793c4e9",
"userSubjectReference": "",
"clientRefNo": " testing12345",
"enteredOtp": "973947"
}
reqId – generated from response – step 3.3.6
otpRef – generated from response – step 3.3.6
perform steps 3.3.2 to 3.3.6 for the payload to be sent and to get the
response
String otpValidationUrl =
"https://uatservices.mfcentral.com/api/client/V1/investorconsent";
JSONObject otpRequest = new
JSONObject("{\"reqId\":55718,\"otpRef\":\"35979fc2-e2c8-4faa-b6dc-
ab6505a4612e\",\"userSubjectReference\":\"\",\"clientRefNo\":\"testing12345
\"}");
otpRequest.put("enteredOtp", "574224"); // otp entered by user
submitRequestToMFCentral(
otpValidationUrl, token, clientId, encryptionDecryptionKey,
privateKey,publicKey, otpRequest.toString());
Response:
7|Page
3.5 Submit request to get Response <CAS document>:
Upon successful OTP validation, you can invoke the MFcentral APIs. The API response structure
are provided in section 4
Below sample is provided for get CAS document, likewise you may use the respective service
endpoints.
Endpoint: https://uatservices.mfcentral.com/api/client/V1/getcasdocument
Headers:
Content-Type: application/json
ClientId: test-client1
Authorization: Bearer dd33510a-f161-4818-8d35-65a64f617516
Use the reqId and clientRefNo sent in the previous request 3.4.1
{"reqId":56475,"clientRefNo":"testing12345"}
perform steps 3.3.2 to 3.3.6 for the payload to be sent and get the response
String casDocumentUrl =
"https://uatservices.mfcentral.com/api/client/V1/getcasdocument";
JSONObject casDocument = submitRequestToMFCentral(
casDocumentUrl, token,clientId,
encryptionDecryptionKey, privateKey, publicKey,
otpRequest.toString());
Note: As this is asynchronous call, There might be a slight delay in fetching the
response and you might get the interim response as below:
Code: 422 – represents that the JSON is not yet ready as it might take some time
to get response from all 4 different entities. Therefore, a slight delay is
expected.
However, you can retry with the same request to get the successful response.
8|Page
422 Unprocessable Invalid Input or Request Format
Entity (WebDAV)
Sample error Response:
{
"code": "400",
"message": "Error message",
}
Description: The MFCentral CAS API retrieves PAN + Mobile/email data of the Investor( The folios
which are linked to the given Mobile/email only shall be fetched). Upon accepting the request with
PAN + Mobile/email, post validating the Mobile/email via OTP authentication
REQUEST:
{
"clientRefNo": "",
"reqId": "15043487",
"pan": " AXXPXXXXXN ",
"pekrn": "",
"email": "",
"mobile": "+919940615334",
}
RESPONSE:
{
"reqId": "15043487",
"pan": "AXXPXXXXXN",
"pekrn": "",
"mobile": "+919940615334",
"email": "",
"data": [
{
"portfolio": [
{
"currentMktValue": "21349.86",
"costValue": "16150.37",
"gainLoss": "5199.49",
"gainLossPercentage": "32.19",
"isDemat": "N"
},
{
"currentMktValue": "1130.72",
9|Page
"costValue": "1000.00",
"gainLoss": "130.72",
"gainLossPercentage": "13.07",
"isDemat": "Y"
}
],
"summary": [
{
10 | P a g e
5. CAS Statement API - Detailed
Description: The MFCentral CAS API retrieves PAN level data of the Investor. Upon accepting the
request with PAN and post validating the Mobile/email via OTP authentication, the service returns the
data segmented into Static information, Summary level and Transaction level information. Retrieves
data based on the transactions executed within the data range - from date and to date.
URL: https://uatservices.mfcentral.com/api/client/V1/submitcasdetailrequest
Request:
REQUEST:
{
"clientRefNo": "",
"reqId": "0111-0001",
"pan": "AXXPXXXXXN",
"pekrn": "",
"email": "",
"mobile": "",
"fromDate": "01-Jan-2021",
"toDate": "07-Jan-2021"
}
RESPONSE:
{
"reqId": "19686169",
"pan": "AXXPXXXXXN",
"pekrn": "",
"email": "",
"mobile": "",
"fromDate": "01-Apr-2022",
"toDate": "19-Jul-2022",
"data": [
{
"dtTransaction": [
{
"email": "[email protected]",
"amcName": "SBI Mutual Fund",
"folio": "25433715",
"trxnDate": "25-MAY-2022",
"postedDate": "25-MAY-2022",
"scheme": "8920",
"schemeName": "SBI Gold Fund - Direct Plan",
"trxnDesc": "Purchase",
11 | P a g e
"trxnAmount": "20000",
"trxnUnits": "1326.0050",
"purchasePrice": "15.0829",
"sttTax": "0",
"tax": "0",
"totalTax": "0",
"trxnMode": "N",
"stampDuty": "1",
"trxnCharge": "0"
}
],
"dtSummary": [
{
"email": "[email protected]",
"amcName": "SBI Mutual Fund",
"folio": "25433715",
"scheme": "D246G",
"schemeName": "SBI Gold Fund - Direct Plan - Growth ",
"kycStatus": "",
"brokerCode": "INZ000031633",
"brokerName": "INZ000031633",
"decimalUnits": "3",
"decimalAmount": "2",
"decimalNav": "4",
"lastTrxnDate": "25-MAY-2022",
"openingBal": "6534.3940",
"marketValue": "754693.773051",
"nav": "16.2842",
"closingBalance": "46345.1550",
"lastNavDate": "25-MAY-2022",
"isDemat": "Y",
"assetType": "DEBT",
"isin": "INF200K01RP8",
"nomineeStatus": "Y"
}
],
"investorDetails": {
"address": {
"address1": "16 STREET",
"address2": "IPURAM",
"address3": "CHRO",
"city": "CHENNAI",
"district": "",
"state": "Tamil Nadu",
"pincode": "600044",
"country": "India"
},
"email": "[email protected]",
"mobile": "8015933245",
"investorFirstName": "Kumar",
"investorMiddleName": "",
"investorLastName": ""
},
"statementHoldingFilter": null
}
]
12 | P a g e
}
7. Appendix
ThirdPartyUtils.java code
package com.sspl.sample.filter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Formatter;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.StringUtils;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwx.HeaderParameterNames;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
14 | P a g e
String pan = "";
String pekrn = "";
String mobile = "";
String email = "";
String clientReferenceNumber = "";
String casRequestUrl =
"https://devservices.mfcentral.com/api/client/V1/submitcassummaryrequest";
JSONObject response = submitRequestToMFCentral(casRequestUrl, token,
clientId, encryptionDecryptionKey, privateKey, publicKey, request);
String otpValidationUrl =
"https://devservices.mfcentral.com/api/client/V1/investorconsent";
JSONObject otpRequest = new
JSONObject("{\"reqId\":55718,\"otpRef\":\"35979fc2-e2c8-4faa-b6dc-
ab6505a4612e\",\"userSubjectReference\":\"\",\"clientRefNo\":\"testing12345\"}");
otpRequest.put("enteredOtp", "574224");
try {
RsaJsonWebKey rsaJsonWebKey = getPrivateKey(privateKey);
JsonWebSignature jws = new JsonWebSignature();
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
15 | P a g e
jws.getHeaders().setObjectHeaderValue(HeaderParameterNames.BASE64URL_ENCODE_P
AYLOAD, false);
jws.setPayload(payload);
jws.setKey(rsaJsonWebKey.getPrivateKey());
return output.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
try {
RsaJsonWebKey rsaJsonWebKey = getPublicKey(publicKey);
return false;
}
16 | P a g e
public static String getToken(String tokenGenerationUrl, String clientId, String clientSecret,
String userName, String password) {
if( ! isVerified ) {
return null;
}
18 | P a g e
System.out.println("Response from MFCentral: " + decryptedText);
class CryptUtils
{
public static String encryptDecrypt(String Mode, String cryptText, String passKey) throws
Exception {
byte[] decryptedVal = null;
String retText="";
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
byte[] bytehash = digest.digest(passKey.getBytes(StandardCharsets.UTF_8));
String strHash="";
Formatter formatter = new Formatter();
19 | P a g e
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_IVParamSpec = new IvParameterSpec(iv);
if (Mode.equals("ENCRYPT")){
_cipher.init(Cipher.ENCRYPT_MODE, _password, _IVParamSpec);
byte[] ciphertext = _cipher.doFinal(cryptText.getBytes(StandardCharsets.UTF_8));
byte[] decodedValue =
Base64.getDecoder().decode(cryptText.getBytes(StandardCharsets.UTF_8));
decryptedVal = _cipher.doFinal(decodedValue);
retText = new String(decryptedVal);
}
} catch (NoSuchAlgorithmException e) {
throw new Exception("Encryption error, No such algorithm ->" + ALGORITHM);
} catch (NoSuchPaddingException e) {
throw new Exception("Encryption error, No such padding PKCS7");
} catch (Exception e) {
throw new Exception("Encryption error:" + exceptionToString(e));
}
return retText;
}
20 | P a g e
}
}
ex.printStackTrace(printWriter);
return writer.toString();
}
return generatedString;
}
21 | P a g e
hexString.append(hex);
}
return hexString.toString();
}
22 | P a g e