1. Introduction
Veri5Digital mSite Solution offers a mobile browser based solution that can be seamlessly integrated with clients business application to do the KYC processing of the user.
This document explains technical specification and steps to integrate mSite SDK with clients application. Sample code snippets are wherever applicable are available for reference.
2. Steps To Integrate mSite SDK
Clients should follow the below steps for integrating mSite SDK to client application.
Client should get on boarded or registered with Veri5Digital Platform and get client credentials and other parameters required for integration.
Health Status Check API - Clients can integrate health status check API to check whether UIDAI Website is up or down.
Client Application should integrate mSite SDK.
Integrate fetchKYCInfo API to retrieve the processed KYC Info
Veri5Digital Platform provides Sandbox Environment for Integration and Production Environment for actual production purposes.
Note :
We recommend to integrate the app in sandbox environment first and then move to production post testing and certification in Sandbox Environment.
It is recommended that clients invoke Health Status Check API to check the availability status before invoking SDK.
2.1 Client Registration
For a client to get access to SDK and do integration, client registration is mandatory.
As part of registration , Client has to obtain values for following params for both Sandbox and Production Environments.
Client Code (client_code) , that uniquely identify the client that is onboarded to Khosla Labs Platform.
API-Key (api_key ) , will be provided during onboarding and is used for managing subscription.
Salt ( salt), salt is for calculating hash of request payload and will be shared during onboarding. Each api_key will have its own salt.
SandBox URL
Production URL
Note :
Clients should get these details from Veri5Digital Onboarding Team.
It is recommended that client should first get on boarded in Sandbox environment to do technical integration and testing before moving to production.
2.2 Health Status Check API
Client application can invoke this API before initiating SDK to check the status of service availability.This is applicable for WeDo only.
Client application should handle the scenario in case , UIDAI Service is down. API details are given below.
API Name : isUidaiUp
Method : POST
SandBox URL : https://sandbox.veri5digital.com/assisted/isUidaiUp
Production URL : https://prod.veri5digital.com/assisted/isUidaiUp
Request :
There is no specific request body as it is a Status Check API.
Response :
Based on the status of UIDAI availability, following are the response scenarios.
- Success Scenario
{
"code": "000”,
"status": "SUCCESS",
"message": "UIDAI website is up"
}
- Failure Scenario
{
"code": "390008",
"status": "FAILED",
"message": "UIDAI website is down"
}
2.3 How to integrate SDK in Client’s Application
Client should have received the credential information mentioned in Section 2.1 before start integration.
Clients application should invoke mSite SDK using the _initWebVIKYC API whose details are given below.
API Name : _initWebVIKYC
Method : POST
SandBox URL : https://sandbox.veri5digital.com/video-id-kyc/_initWebVIKYC
Production URL : https://prod.veri5digital.com/video-id-kyc/_initWebVIKYC
Given below are the details of the Request Payload of _initWebVIKYC request. Sample request follows the same.
2.3.1 Initiation of Veri5Digital mSite SDK
Inside client application’s mSite SDK has to be initiated using _initWebVIKYC API. This API should invoked from a client application’s form request.
_initWebVIKYC API Request Details
Headers
Content-Type: application/x-www-form-urlencoded
Body Parameters
Reference Code is given below.
Table : _initWebVIKYC API Request Body Parameters
Field Name | Type | Comments | Example |
---|---|---|---|
client_code | String, Mandatory | Your client code received during onboarding | a1b2c3 |
request_id | String, Mandatory | Unique transaction identifier Client app has to generate the same.For each request it should be unique.This is used for uniquely identifying the transaction. | 12345678910111 |
api_key | String, Mandatory | Pre-shared api key controls the access to various Api’s. Api Key will be shared during onboarding.There will be separate api_key for SandBox and Production Environment. | 1A3b5c7D910111 |
redirect_url | String, Mandatory | This should be a valid callback url exposed by the calling app. SDK will redirect the response on this URL with the status of the transaction, once SDK completes its execution. | https://mydomain.com/status.html |
hash | String, Mandatory | This should be a SHA-256 value of Hash Sequence defined for _initWebVIKYC request. Purpose of this is to ensure the integrity of the request. Refer Appendix B for hash generation logic. | 9780cd0d2c e77eef8f649 42f54e0281 a0e220ff6bb cce0a03df27 a2b15575f58 |
stan | String, Mandatory | System Trace Number. This number is used to uniquely identify an api call initiated from the client.Stan is also generated by client. | 98765432100000 |
otp_required | String, Mandatory, Possible Values ( “Y'' or “N”) | Specifies whether Mobile Number validation is required or not. Possible values are “Y” or “N”. If ‘Y’ then Veri5Digital Platform will generate an OTP and send to the mobile number.Then in SDK user will be presented with a page where he/she should enter the OTP. otp_required : “Y” Mobile number to which OTP has to be delivered should be specified as value to parameter ‘mobile’ and user will be taken to OTP Enter Page in the SDK for. otp_required : “N” If value is ‘N’ user will proceed directly to KYC options screen. | Y |
mobile | String,Conditional | If otp_required field is set to ‘Y’, pass mobile number in this field and is mandatory. If otp_required field is set to ‘N’, this field is optional. | 8812345678 |
Sample Html Code for SDK Initiation
Below given code snippet demonstrates how to invoke the Veri5 Digital mSite SDK from a form in clients application.
<form method="post" action="<<SandBox URL>>">
<input type="text" name="client_code" value="<<Your Client Code>>" >
<input type="text" name="api_key" value="<<Your API Key>>" >
<input type="text" name="redirect_url" value="<<Callback Url>>" >
<input type="text" name="request_id" value="<<Unique Request Id>>" >
<input type="text" name="stan" value="<<Unique Stan>>" >
<input type="text" name="hash" value="<<sha256 hash value>>" >
<input type="text" name="mobile" value="<<registered mobile number value>>">
<input type="text" name="otp_required" value="<”Y” | ”N”>" >
<button type="submit">Proceed </button>
</form >
Points to Note
Action URL should be changed based on the environment whether its SandBox or Production.
Please ensure correct api_key, client_code,redirect url to be passed.
Ensure that no Spaces before or after the parameter values.
Https protocol is recommended.
2.3.2 SDK Response Processing
On completion of mSite SDK processing, SDK response will be sent to the callback URL passed in _initWebVIKYC request as a redirection.
As a result of SDK execution “uuid”, which is a unique identifier will be generated. ‘uuid’ will be required for fetching the processed KYC info of the user later.
- On Successful completion of the SDK, client application will get redirected to callback URL
<a href="https://<callbackUrl>?requestId=<requestId>&userId=<userId>&uuid=<uuid>&hash=<hash>&status=<SUCCESS>"></a>
where in :
callbackUrl : Client specific URL passed in _initWebVIKYC request
requestId : Unique request id passed by calling application in _initWebVIKYC request.
userId : Unique Identifier generated by the SDK which is required later for
fetching processed KYC Info.
uuid : Unique Transaction Identifier generated by the SDK for the option selected.
hash : Hash of Init API Response.Refer Appendix B to see how to calculate the hash.
status : SUCCESS
Eg:
- In case SDK execution is failed, client application will get redirected to:
<a href=https://<callbackUrl>?requestId=<requestId>&userId=<userId>&uuid=<uuid>&hash=<hash>&errCode=<error-code>&status=<FAIL>>
where in
callbackUrl : Client specific URL passed in _initWebVIKYC request
requestId : Unique request id passed by calling application in _initWebVIKYC request.
userId : Unique Identifier generated by the SDK which is required later for
fetching processed KYC Info.
uuid : Unique Transaction Identifier generated by the SDK for the option selected.
hash : Hash of Init API Response. Refer Appendix B to see for the hash logic.
errCode : Error Code that indicates the reason for failure.
status : FAIL
Eg:
Refer to Appendix A for Error Codes & Description
Points to Note
userId that is passed in response is required to fetch KYC Data (See next section).
Callback URL should handle the URL parameters correctly.
Https protocol is recommended.
Post successful execution of SDK, client should invoke fetchKyc Api to retrieve the processed Kyc info.
Once the transaction is initiated, fetchKYC should be invoked within 20 minutes to retrieve the processed Kyc data.
2.4 Fetch KYC Request
On successful response from SDK is received, client application should invoke fetchKYCInfo API to retrieve the processed KYC info.
API Name : fetchKYCInfo
Method : POST
Sandbox URL :
https://sandbox.veri5digital.com/video-id-kyc/api/1.0/fetchKYCInfo
Production URL :
https://prod.veri5digital.com/video-id-kyc/api/1.0/fetchKYCInfo
Refer Appendix D for sample Angular Code Snippet that demonstrated invocation of fetchKYCInfo API request.
2.4.1 fetchKYCInfo API Request Details
Calling application should form the Request Payload in the following Json format.
Kindly note: Here "header" is block inside request body, it is not https header.
JSON
{
"headers":{
"client_code":"<your client_code>",
"sub_client_code":"<should be same as client_code>",
"actor_type":"NA",
"channel_code":"MSITE",
"stan":"<System Trace Number>",
"user_handle_type":"<>",
"user_handle_value":"<>",
"location":"",
"transmission_datetime":"1533123525716",
"run_mode":"REAL",
"client_ip":"<your client_ip>",
"operation_mode":"SELF",
"channel_version":"0.0.1",
"function_code":"REVISED",
"function_sub_code":"DEFAULT"
},
"request":{
"user_id":"<received in redirect browser url>",
"api_key":"<api-key>",
"hash":"xxxxxxxx",
}
}
Table : fetchKYCInfo API Request Body Parameters
Field Name | Type | Comments | Example |
---|---|---|---|
client_code | String,Mandatory | Unique code assigned to a client.This will be assigned to the client during onboarding. | client123 |
sub_client_code | String, Not Mandatory | Its useful in case calling client needs any customization w.r.to different departments. | subclient123 |
actor_type | String, Not Mandatory | Type of user who is making the request from the application. | CUSTOMER or AGENT |
channel_code | String, Not Mandatory | Channel code used by the client to initiate request. | MSITE |
stan | String,Mandatory | A unique number generated per request by the client. It is used to uniquely identify a request from a client and can be used for troubleshooting.Max length can be 64 characters long. | 98321892319 |
user_handle_type | String, Not Mandatory | Indicates the type of the user identifier, who has initiated the request. Eg : UUID, MSISDN, EMAIL. | |
user_handle_value | String, Not Mandatory | Value of user_handle_type. If user_handle_type is EMAIL, then user_handle_value is actual email. | a@b.com |
location | String, Not Mandatory | Location of the device that initiated the request. Can be empty. | |
transmission_datetime | String,Not Mandatory | Time in System milli seconds at which request was initiated from client. | 1553255080298 |
run_mode | String,Not Mandatory | Execution Mode in which transaction is being done.Possible values are REAL or TRIAL. | REAL |
client_ip | String, Not Mandatory | IP Address of the client device. | |
operation_mode | String, Not Mandatory | The way in which the transaction is executed.Example values can be “SELF”,”ASSISTED”,”SYSTEM” etc. | SELF |
channel_version | String, Not Mandatory | It can be Android SDK Version | 3.1.7 |
function_code | String,Mandatory | Defines the behaviour of this api.Value should be ‘REVISED’ | REVISED |
function_sub_code | String,Mandatory | Indicates default behaviour for this api. If no customized behaviour requirements,then value will be “DEFAULT” | |
user_id | String,Mandatory | This is same as user_id passed on to client application as part of SDK response. | userid123 |
hash | String,Mandatory | Hash to be calculated by client to verify integrity of request. Refer Appendix B for hash generation logic. | |
api_key | String,Mandatory | api_key shared with client during onboarding. | samplekey123 |
Points to Note:
URL should be changed based on the environment whether its SandBox or Production.
Please ensure correct api_key, client_code,redirect url to be passed.
Ensure that no Spaces before or after the parameter values.
Https protocol is recommended.
Please make sure you invoke fetchKYCInfo within 20 minutes after completing SDK flow. Data will not be retained beyond this duration.
2.4.2 fetchKYCInfo API Response Details
fetchKYCInfo API Response Payload structure is given below :
Response Payload
Response Payload holds the following :
{
“response_status”:{
“status” : ”<<status of API Execution>>”,
“code” : ”<<status code of API Execution>>”,
“message” :”<<message based on the status and code>>”
},
“response_data”:{
“is_encrypted” :”<<YES|NO>>”,
“kyc_info” :”<<base64 encoded KYC info>>”,
“hash” : <<sha256 of hash sequence defined for fetch response>>
}
}
response_status block encapsulates the status of API invocation
- status : Possible values are SUCCESS or FAIL
- code : Response code, based on status.
If status is SUCCESS code value will be ‘000’
If status is FAIL, refer to Appendix A for error code values.
response_data block is a base64 encoded string comprised of:
- Processed KYC Info (kyc_info)
Refer "Detailed Structure of kyc_info block" for details. - encrypted flag ( is_encrypted ) with possible values “YES” or “NO” that indicates whether kyc info is encrypted or not. It depends on whether the client has explicitly chosen the provision for data encryption or not during onboarding. By default value will be ‘NO’
Computed response hash (hash). Refer Appendix B for hash generation logic.
Response Payload Example :
Below given is an example for a successful response.
{
"response_status": {
"status": "SUCCESS",
"code": "000",
"message": "Kyc data fetched successfully"
},
"response_data": {
"is_encrypted": "NO",
"kyc_info": "Base64 Encoded kyc_info block",
"hash": "5eea1888a2920b6fddf25f6c12ec2aba5e7ce2bff6d9391c18fd1b2749a4ba47"
}
}
2.4.2.1 Detailed Structure of kyc_info block
Details of kyc_info block of response payload is given below :
Case 1 : is_encrypted flag is “NO”
If encrypted is NO then kyc_info block is just base64 encoded. Client application should just decode the Base64 encoded kyc_info block to get the kyc data.By default value of is_encrypted flag will be ‘NO’.
Case 2 : is_encrypted flag is “YES”
This means client has chosen the option to have the kyc_info data to be encrypted.If encrypted is YES then base64 encoded kyc_info block is encrypted.
In this case client application should
First decrypt the kyc_info block. This will give the Base64 encoded kyc_info block.
Decode the Base64 encoded kyc_info block to get the kyc data.
Please refer to Data Decryption Sample Code to understand the requirements for decryption in case data encryption is chosen, ie if “is_encrypted” is “YES”.
kyc_info Data Structure
Structure of kyc_info block post decoding of Base64 encoded data is given below. Please refer the Json and table given below for more field level details.
There are mainly following blocks :
“original_kyc_info” block holds the KYC Info that is extracted as a result of source document scan.
“declared_kyc_info” block holds the KYC info that is edited/declared by the user post scanning of document.
“photo” block holds face image specific data.
“doc_image” block holds the document image details.
Points to Note :
Please note that below structure contains the exhaustive list of data elements that SDK can provide. For example passport_front or passport_back will be present in case doc_type is “PASSPORT”
Depending on the flow that is chosen few of the fields might not be present.
High level structure of the response remains the same.
Client application should handle the data elements they are interested in.
{
// original_kyc_info tag encapsulates info extracted from the Original ID Document through OCR
"original_kyc_info":{
"address":"<address>",
"gender":"M",
"dob":"17/12/1993",
"name":"John Doe",
“father_name”:””,
"mother_name":"",
"expiry_date":"",
"email":"",
// Value will be Input Mobile#, in case Mobile Validation flow is chosen and hash of input mobile# matches with hash of mobile present in UIDAI Aadhaar XML.
"mobile":"",
"doc_type":"AADHAAR",
"document_id":"XXXXXXXX7059",
"dist": "",
"house":"",
"loc":"" ,
"pc":"" ,
"po":"" ,
"state":"" ,
"street":"" ,
"subdist":"" ,
"vtc":"" ,
"country":"",
“verified_by”:”UIDAI”,
“verified_using”:”DIGITAL_SIGNATURE”,
“document_verification_status”:”SUCCESS|FAIL”
“document_verification_code”:””
“document_verification_message”:””
},
// This tag encapsulates info that is declared or edited by the user after reviewing data extracted from the Original ID Document
"declared_kyc_info":{
"address":"NULL",
"gender":"M",
"dob":"17/12/1993",
"name":"John Doe",
“father_name”:””,
"mother_name":"",
"expiry_date":"",
"Email":"",
// Value will be Input Mobile#, in case Mobile Validation flow is chosen.
"mobile":"",
"doc_type":"AADHAAR",
"document_id":"XXXXXXXX7059",
“Verified_by”:””,
“verified_using”:””,
“document_verification_status”:”SUCCESS|FAIL”
“document_verification_code”:””
“document_verification_message”:””
},
"photo":{
"match_rate":””,
"match_status":"SUCCESS|FAIL|UNCERTAIN",
"document_image":"<Base64 encoded image>",
"live_image":"<base64 encoded image>"
},
"doc_image":{
"pan":"<Base64 encoded image>",
"aadhaar_front":"<Base64 encoded image>",
"aadhaar_back":"<Base64 encoded image>",
"passport_front":"<Base64 encoded image>",
"passport_back":"<Base64 encoded image>"
}
}
Table : kyc_info Field Information
Field Name | Block Name | Comments |
---|---|---|
address | original_kyc_info | Address info extracted from document as a result of OCR. Address info consists of all address fields as a single string. |
gender | original_kyc_info | Gender Information extracted from document if available in document. |
dob | original_kyc_info | Date Of Birth information extracted from document if available in document. |
name | original_kyc_info | Name extracted from document if available in document. |
father_name | original_kyc_info | Father Name extracted from document if available in document. |
mother_name | original_kyc_info | Mother’s Name extracted from document if available in document. |
expiry_date | original_kyc_info | Expiry Date extracted from document if available in document. |
original_kyc_info | Email extracted from document if available in document. | |
mobile | original_kyc_info | Mobile number user input in client application. It’s an optional field. If no mobile number is given as input, value will be an empty string. Its present in original_kyc_block means hash of input Mobile# matches with mobile hash present in UIDAI Aadhaar XML in case document type is ‘AADHAAR’ |
doc_type | original_kyc_info | Specifies the type of the document. |
document_id | original_kyc_info | Is the unique Document Identifier extracted from the document. For example, if doc_type is PAN then it will be PAN#. If doc_type is Aadhaar, it will be Aadhaar Number with first 8 digits masked. |
dist | original_kyc_info | District info extracted from Address in case of Aadhaar XML. |
house | original_kyc_info | House Name field extracted from Address in Aadhaar XML. |
loc | original_kyc_info | Locality field extracted from Aadhaar XML. |
pc | original_kyc_info | Pincode field extracted from Address in Aadhaar XML. |
po | original_kyc_info | Post Office field extracted from Address in Aadhaar XML. |
state | original_kyc_info | State field extracted from Address in Aadhaar XML. |
street | original_kyc_info | Street field extracted from Address in Aadhaar XML. |
subdist | original_kyc_info | Sub District field extracted from Address in Aadhaar XML. |
vtc | original_kyc_info | Village/Town/City field extracted from Address in Aadhaar XML. |
country | original_kyc_info | Street field extracted from Address in Aadhaar XML. |
verified_by | original_kyc_info | This is applicable in case of Aadhaar XML. Value will be “UIDAI” in this case. |
verified_using | original_kyc_info | This is applicable in case of Aadhaar XML. Value will be “DIGITAL_SIGNATURE” in this case. |
document_verification_status | original_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status. Possible values are SUCCESS/FAIL. If this service is not opted value will be an Empty String. |
document_verification_code | original_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status. If this service is not opted value will be an Empty String. |
document_verification_message | original_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status. If this service is not opted value will be an Empty String. |
address | declared_kyc_info | Address info that is declared by the user after reviewing data extracted from the Original ID Document. There is a review page where user can edit the info. |
gender | declared_kyc_info | Gender Information info that is declared by the user after reviewing data extracted from the Original ID Document |
dob | declared_kyc_info | Date Of Birth information info that is declared by the user after reviewing data extracted from the Original ID Document. |
name | declared_kyc_info | Name info that is declared by the user after reviewing data extracted from the Original ID Document. |
father_name | declared_kyc_info | Father Name info that is declared by the user after reviewing data extracted from the Original ID Document |
mother_name | declared_kyc_info | Mother’s Name info that is declared by the user after reviewing data extracted from the Original ID Document |
expiry_date | declared_kyc_info | Expiry Date info that is declared by the user after reviewing data extracted from the Original ID Document |
declared_kyc_info | Email info that is declared by the user after reviewing data extracted from the Original ID Document | |
mobile | declared_kyc_info | Mobile number user input in client application. It’s an optional field. If no mobile number is given as input, value will be an empty string. Its present in declared_kyc_info means hash of input Mobile# does not match with mobile hash present in UIDAI Aadhaar XML in case document type is ‘AADHAAR’ |
doc_type | declared_kyc_info | Specifies the type of the document. |
document_id | declared_kyc_info | Is the unique Document Identifier info that is declared by the user after reviewing data extracted from the Original ID Document For example, if doc_type is PAN then it will be PAN#. If doc_type is Aadhaar, it will be Aadhaar Number . |
verified_by | declared_kyc_info | This is applicable in case of Aadhaar XML. Value will be “UIDAI” in this case. |
verified_using | declared_kyc_info | This is applicable in case of Aadhaar XML. Value will be “DIGITAL_SIGNATURE” in this case. |
document_verification_status | declared_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status based on declared info. Possible values are SUCCESS/FAIL. If this service is not opted value will be an Empty String. |
document_verification_code | declared_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status based on declared info. If this service is not opted value will be an Empty String. |
document_verification_message | declared_kyc_info | In case the client has opted for verification of the Id doc against government database, this indicates the document verification status based on declared info. If this service is not opted value will be an Empty String. |
match_rate | photo | Face Match Confidence Percentage. |
match_status | photo | Possible values are SUCCESS/FAIL/UNCERTAIN. If face match confidence rate is above True Positive (TP) threshold rate configured, then status will be SUCCESS. If face match confidence rate is below True Negative (TN) threshold rate configured, then status will be FAIL. If face match confidence rate is between True Positive (TP) Threshold and True Negative (TN) Threshold, then status will be UNCERTAIN. |
document_image | photo | Base64 Encoded String of face image of the user that is extracted from document captured by SDK. |
live_image | photo | Base64 Encoded String of Live Face captured by SDK for liveness check. |
pan | doc_image | Base64 Encoded String of PAN Document captured by SDK. |
aadhaar_front | doc_image | Base64 Encoded String of Aadhaar Front Document captured by SDK. |
aadhaar_back | doc_image | Base64 Encoded String of Aadhaar Back Document captured by SDK. |
passport_front | doc_image | Base64 Encoded String of Passport Front Page Document captured by SDK. |
passport_back | doc_image | Base64 Encoded String of Passport Back Page Document captured by SDK. |
Appendix A: Error Codes
Code | Scenario/API | Message |
---|---|---|
380118 | _initWebVIKYC | Mandatory data is missing |
360022 | _initWebVIKYC | None/More entry exists for a client |
360025 | _initWebVIKYC | Token does not exist for client |
380114 | _initWebVIKYC | Session does not exist |
380048 | _initWebVIKYC | Client doesn’t exist |
380116 | _initWebVIKYC | Transaction does not exist |
380117 | _initWebVIKYC | Invalid status |
380091 | _initWebVIKYC | Invalid hash |
360004 | _initWebVIKYC | Duplicate Request-id found |
360015 | _initWebVIKYC | Invalid Value for OTP required field |
380115 | _initWebVIKYC | Failed to find SDK ClientConfig ID |
360005 | _initWebVIKYC | Unable to create SDK Session Info entity |
380039 | _initWebVIKYC | Failed to create User Info |
240006 | _initWebVIKYC | Subscription Info not found |
380181 | _initWebVIKYC | You have exceeded your maximum OTP limit |
380182 | _initWebVIKYC | Unexpected Error occured |
380183 | _initWebVIKYC | UUID doesn’t exist. |
380024 | fetchKYC | user_id is mandatory |
380025 | fetchKYC | hash is mandatory |
380026 | fetchKYC | api_key is mandatory |
380048 | fetchKYC | Invalid api_key or client_code |
380049 | fetchKYC | Invalid api_key or client_code |
380091 | fetchKYC | Hash validation failed |
380076 | fetchKYC | No such user-id exists |
380114 | fetchKYC | Session does not exist. |
380116 | fetchKYC | Transaction does not exist. |
333 | fetchKYC | Unexpected Error Occured |
Appendix B: Hash Generation
It is essential that there is a definitive protocol to verify the integrity of all the communication between Khosla Labs and Client.Hence for every request coming to KL Platform, client have to supply a hash which we will use as the first step of verification.
In return, all responses will also contain hash supplied by KL. You should not entertain any request at your callbackUrl if the hash does not match.
- Hash should be calculated using the below method : hash=SHA256(Hash-Sequence)
Hash Sequence is specified as follows(no space, no commas, no single/double quotes). Hash sequence is defined for each request and response.
Init Api Request ( _initWebVIKYCRequest)
client_code
|request_id
|api_key
|salt
Init Api Response ( _initWebVIKYC Response)
client_code
|request_id
|uuid
|status
|api_key
|salt
KYC Fetch Request ( fetchKYCInfo Request)
client_code
|user_id
|api_key
|salt
KYC Fetch Response ( fetchKYCInfo Response )
client_code
|user_id
|kyc_info
|status
|api_key
|salt
Example(for _init request), If your
client_code=a1b2c3,
api_key=123,
requestId=1234567890101112,
salt=e1d2c3b4a,
then
Hash-Sequence=a1b2c3|1234567890101112|123|e1d2c3b4a
hash =SHA-256(Hash-Sequence)
For validation:
- Receiving end should calculate hash based on request parameters and match it against the received hash.
- If receivedHash=calculatedHash, then only you should proceed with your application logic.
- api_key and salt are the key parameters here. It is known only to the client and Khosla Labs.
- One api_key is mapped to one salt. This allows us to have multiple salts active at a time.
- api_key and hash need to be passed in each API call. Salt is never transmitted in any API call.
Appendix C: Customization Options
Following are the customization capabilities provided by the SDK.
User Details Page
SDK provide option to clients to configure whether they want to show User Details page ( Page where extracted Kyc data will be displayed ) as Last Page or not. You can inform the same to the Tech Support Team at the time of on-boarding, and flow will be configured for you accordingly.
Option Flow Customization
By default there are two options for the user :
- UIDAI_XML Do it for me
- UIDAI_XML I’ll do it myself
SDK provides the capability to customize the flow in such a way that user can enable either one of the options or both the option. By default both options will be enabled.
During onboarding and integration Client should inform Tech Support team the client's preference.
User Interface
The SDK provides capability to customize themes and styles pertaining to client requirements.Client has to give the following properties at the time of on-boarding for the customization requirements in the format as defined in the below JSON Text.
Web SDK also allows clients to configure color themes and styles as per below -
- Adding your Company Logo on Top
- Dynamic Font Size and Color Theme on app
- Background
- NAV Bar
- Resend Timer Color
- Button
- Input Box
- Card Heading (KYC Option) Text
- Primary Text
- Secondary Text
- Tertiary Text
- Note Text
You need to share JSON Structure with values for each parameter. In case Json is not provided following default Json will be applicable.
Default Json
{
"--background": "white",
"--nav-color": "white",
"--nav-font-size": "24px",
"--nav-background": "#D52736",
"--resend-timer-color": "#3169ea",
"--btn-background": "#d52736",
"--btn-text-color": "#fab60f",
"--btn-font-size": "14px",
"--input-box-text-color": "#DE140305",
"--input-error-code-color": "#ff5833",
"--input-error-text": "14px",
"--card-heading-text-color": "#d52736",
"--card-heading-text-font-size": "24px",
"--card-text": "#777777",
"--card-font-size": "16px",
"--upload-bg-color" : "#dddddd",
"--upload-text-color" : "#000000",
"--upload-text-size" : "20px",
"--primary-text": "#777777",
"--primary-font-size-normal": "24px",
"--primary-font-size-heading": "32px",
"--secondary-text": "#d52736",
"--secondary-font-size": "32px",
"--tertiary-text": "#000000",
"--tertiary-font-size": "16px",
"--note-text": "red",
"--note-font-size": "16px",
"--verify-image-background": "white",
"--verify-font-size": "18px",
"--verify-font-color": "white",
}
Refer Customization Guide ( Customization_Offlinekyc.pdf ) for more details.
Appendix D: Code Snippet for fetchKycInfoRequest
Below code snippet demonstrates the AngularJS Code Snippet to invoke _fetch API and handle the response.
angular.module("myApp").controller('FetchController', function($scope, $http,$rootScope,$location){
$scope.init=function(){
$scope.userId=$location.search().userId;
$scope.calculateHash=function(){
$scope.hash=Sha256.hash( $scope.clientCode+ "|"+ $scope.userId+ "|"+ $scope.apiKey+"|"+$scope.salt);
}
$scope.fetchKYC = function() {
$scope.clientCode="SAMS3184";
$scope.apiKey="api-key2";
$scope.calculateHash();
var request = {
"headers": {
"client_code": $scope.clientCode,
"sub_client_code" :'',
"channel_code" :'WEB_APP',
"channel_version":'0.0.1',
"stan" :(new Date().getTime().toString() + Math.random()).toString(),
"client_ip": 'NA',
"transmission_datetime": Date.now().toString(),
"operation_mode":'SELF',
"run_mode" :'TRIAL',
"actor_type": 'CLIENT',
"user_handle_type" :'',
"user_handle_value":'',
"location": 'NA',
"function_code": 'REVISED',
"function_sub_code" : 'DEFAULT'
},
"request": {
"user_id": $scope.userId,
"hash": $scope.hash,
"api_key": $scope.apiKey,
}
}
$http({
method: "POST",
url: "https://hostname/video-id-kyc/api/1.0/fetchKYCInfo",
data: request
})
.success(svcSuccessHandler)
.error(svcErrorHandler);
}
/**
Success Response Handler - Code that handles success response of fetchKycInfo
Request
*/
var svcSuccessHandler = function(data, status, headers, config) {
var kycData=JSON.parse(atob(data["response_data"]["kyc_info"]));
$scope.kycInfo=atob(data["response_data"]["kyc_info"]);
$scope.docImage=kycData.photo.document_image;
$scope.matchRate=kycData.photo.match_rate;
$scope.liveImage=kycData.photo.live_image;
$scope.matchStatus=kycData.photo.match_status;
$scope.name=kycData.original_kyc_info.name;
$scope.verifiedBy=kycData.original_kyc_info.verified_by;
$scope.address=kycData.original_kyc_info.address;
$scope.gender=kycData.original_kyc_info.gender;
$scope.mobileNo=kycData.original_kyc_info.mobile;
$scope.dob=kycData.original_kyc_info.dob;
$scope.docType=kycData.original_kyc_info.doc_type;
$scope.documentId=kycData.original_kyc_info.document_id;
$scope.verifiedUsing=kycData.original_kyc_info.verified_using;
}
/**
Success Response Handler - Code that handles success response of fetchKycInfo Request
*/
var svcErrorHandler = function(data, status, headers, config) {
}
}
})
Appendix E: Data Decryption Process
This section demonstrates the process and sample code for implementation of decrypting kyc response in case client has opted for encryption of response data. Client has to : - Generate the Key Pair that consists of Public and Private Keys - Implement decryption Logic
Key Pair Generation Process
If client has opted for kyc data encryption, client should create the public-private key pair that will be used for encryption and decryption. Generated public key should be shared with KL.
SDK will encrypt kyc_data using the public key shared with KL. Client application should decrypt the response using the private key. This section explains the steps to generate the public-private key pair.
Steps to generate a CSR file using OpenSSL.
Create private key with a validity
keytool -genkey -alias ALIAS_NAME -keyalg RSA -keystore COMP_NAME.jks -keysize 2048 -dname "CN=COMMON_NAME, EMAILADDRESS=sample@abc.com, C=IN OU=Khosla Labs, O=ORGANIZATION_NAME"
Note :
ALIAS_NAME can be replaced with any string of your choice.
COMP_NAME can be replaced by your company name..
CN : Should give a string value.This should be the same as the contact person’s name.
EMAILADDRESS :Should give a string value. This should be some valid email id.Eg sample@abc.com
ORG_UNIT: Value should be “Khosla Labs”
ORGANIZATION_NAME: This should be the same as the organization name.
Create CSR for above key
keytool -certreq -alias ALIAS_NAME -file COMP_NAME.csr -keystore COMP_NAME.jks
Convert jks store to p12
keytool -importkeystore -srckeystore COMP_NAME.jks -destkeystore COMP_NAME.p12 -srcstoretype jks -deststoretype pkcs12
Get private key from .p12 file
openssl pkcs12 -in COMP_NAME.p12 -nodes -out COMP_NAME.key -nocerts
Self sign .csr file using the private key to get .cer file
openssl x509 -req -in COMP_NAME.csr -signkey COMP_NAME.key -out COMP_NAME.cer
Provide us the .cer file (public key certificate) generated above using which KYC response will be encrypted and use .p12 (private key) for decryption.
Code Snippet : kyc_info Data Block Decryption
Below given is Java Code Snippet that can be used as a reference for decryption using your private key.
Snippet 1: Response Reading and Decryption
Below code will read the Base64 encoded response string returned by the API. First it will Base64 decoding and then followed by decryption using your private key.This uses few utility classes given in Snippet 2 and Snippet 3.
// byte array of the base64 decoded response
byte[] decodeResponse = <<base64_decode_response>>;
// open your p12 file
InputStream inputStream = new FileInputStream("<<your_p12_file>>.p12");
// your keystore credentials
char[] keystorePassword = "<<your_keystore_password>>".toCharArray();
char[] aliasPassword = "<<your_alias_password>>".toCharArray();
String alias = "<<your_alias>>";
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(inputStream, keystorePassword);
// get the private key
PrivateKey privateKey =
(PrivateKey) keyStore.getKey(alias, aliasPassword);
ResponseByteArraySpliter splitter =
new ResponseByteArraySpliter(decodeResponse);
// get the symmetric key
byte[] sKey =
DecryptionUtil.decryptUsingPrivateKey(
privateKey, splitter.getEncryptedSymmetricKey()
);
// byte array of the decrypted data
byte[] decryptedData =
DecryptionUtil.decryptUsingSymmetricKey(
sKey, splitter.getEncryptedData()
);
Snippet 2 : ResponseByteArraySplitter Class.
// ResponseByteArraySplitter class
// Note: Please alter the access modifiers according to your packaging
// strategy.
public class ResponseByteArraySplitter {
private static final int SYMMETRIC_KEY_SIZE = 256;
private final byte[] encryptedSymmetricKey;
private final byte[] encryptedData;
public ResponseByteArraySplitter(byte[] data) throws Exception {
int offset = 0;
encryptedSymmetricKey = new byte[SYMMETRIC_KEY_SIZE];
copyByteArray(
data,
offset,
encryptedSymmetricKey.length,
encryptedSymmetricKey
);
offset = offset + SYMMETRIC_KEY_SIZE;
encryptedData = new byte[data.length - offset];
copyByteArray(data, offset, encryptedData.length, encryptedData);
}
byte[] getEncryptedSymmetricKey() {
return encryptedSymmetricKey;
}
byte[] getEncryptedData() {
return encryptedData;
}
private void copyByteArray(byte[] src,
int offset,
int length,
byte[] dest) throws Exception {
try {
System.arraycopy(src, offset, dest, 0, length);
} catch (Exception e) {
throw new Exception("Decryption failed, Corrupted packet!", e);
}
}
}
Snippet 3 : Decryption Util Class.
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
public class DecryptionUtil {
private static final String ASYMMETRIC_ALGO =
"RSA/ECB/PKCS1Padding";
public static byte[] decryptUsingPrivateKey(
PrivateKeyprivateKey,
byte[] data)
throws IOException, GeneralSecurityException {
Cipher pkCipher = Cipher.getInstance(ASYMMETRIC_ALGO);
pkCipher.init(Cipher.DECRYPT_MODE, privateKey);
return pkCipher.doFinal(data);
}
public static byte[] decryptUsingSymmetricKey(
byte[] symmetricKey,
byte[] data)
throws InvalidCipherTextException {
PaddedBufferedBlockCipher cipher =
new PaddedBufferedBlockCipher(
new AESEngine(), new PKCS7Padding()
);
cipher.init(false, new KeyParameter(symmetricKey));
int outputSize = cipher.getOutputSize(data.length);
byte[] tempOP = new byte[outputSize];
int processLen = cipher.processBytes(
data,
0,
data.length,
tempOP,
0
);
int outputLen = cipher.doFinal(tempOP, processLen);
byte[] result = new byte[processLen + outputLen];
System.arraycopy(tempOP, 0, result, 0, result.length);
return result;
}
}
Appendix F : GitHub Link For Sample Integration
Below is the github repository link of codebase of sample App integrated to our SDK and implementation of API.