Switch to dark theme

Switch to light theme

KYC Methods: IDFC Bank


We have partnered with the IDFC Bank to provide the KYC services to the fintechs. The IDFC Bank enables the fintech to complete the KYC of the account holder using either of the following methods-

  • Minimal KYC
  • Aadhaar OTP KYC

Minimal KYC


Step 1: Details’ verification

In minimal KYC, the fintech shall verify the contact number, generally done via one-time passwords(OTP), and the identification proof, i.e. officially valid documents that can be a passport, driving licence, voters’ ID card, PAN card, and job card issued by NREGA signed by a State Government official.

Step 2: Create Application

Fintech requests creation of application using /newindividual API Fusion checks for an already existing account holder on the contact number with the IFI, in this case, IDFC Bank.

Note: An applicant may sign up with multiple Fintechs under the same issuer. Zeta system maintains a single identity of an Account Holder per issuer. This is in line with the compliance requirements of the bank and the regulator. This means that if an applicant signs up with multiple fintech’s working with Fusion on the same issuer, there would only be one Account Holder entity.

You can refer to Creating Application for Account Holder creation to understand how the application to create an account holder is sent.


Aadhaar OTP KYC

A self-serve mode of KYC where the user punches the Aadhaar number and OTP is delivered to the mobile number that is registered against the Aadhaar number. The OTP is verified and the application data is validated against the Aadhaar details to complete the KYC verification.


EKYC service

The KYC service is provided by Fusion on behalf of the Issuers (IFI) to the Fintechs. The service is exposed in the form of a callable Web view that can be embedded in the callee’s web app or the mobile app.

The web view takes the applicants through a series of steps to capture application data required to make the applicant KYC compliant.

EKYC Setup

Because the connection to the webview needs to be authenticated, we use a public/private key encryption to ascertain the identity of the callee. The way this works is as follows:

  1. You generate the public/private key pair using ECDSA. If you want to understand how this algorithm functions, we recommend going through the details in this primer. It is similar to RSA but more difficult to break and uses an elliptical curve to generate the public and private key.
  2. The payload that needs to be signed must be in a prescribed format
  3. You create a short fingerprint for your prescribed payload by using the key pair generated above and creating a signature.
  4. This signature is Base64 encoded before transmitting over the wire. Add the signature to the header before invoking the EKYC service.

The public key generated through ECDSA needs to be shared with us along with your vboId at Fusion Support.

Step 1: Generate ECDSA Key Pair

In the section below, we provide the sample java code that would allow you to generate the ECDSA key pair.

Key pair generation
Switch Theme
Expand More
Copy
package in.zeta.KeyPairGenerator;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

public class GenerateKeyPair {

        public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException {
            KeyPair keyPair = generateKeyPair("EC");
            System.out.println("private key: " + getPrivateKey(keyPair));
            System.out.println("public key: " + getPublicKey(keyPair));
        }
}
Code Copied
Key pair generation
Switch Theme
Expand More
Copy
from fastecdsa.encoding.der import DEREncoder
from fastecdsa.encoding.pem import PEMEncoder
from fastecdsa.curve import P256
from fastecdsa import keys, ecdsa
import base64

    private_key = keys.gen_private_key(P256)
    public_key = keys.get_public_key(private_key, P256)
Code Copied

Step 2: Format Payload

Before signing the payload, the payload must be formatted to ensure proper serialization. For the purpose of signing, the whole payload is broken down into key-value pairs. These key values are converted into a string separated by =. Post that all these strings are sorted and joined into a single string separated by \n.

Objects must be formatted in the above format before signing it with the library. Still the final signature is not ready.

Examples are as below:

Example #1

Sample request
Switch Theme
Expand More
Copy
{
      "vboTransactionId":"test6_58f27c1a-601c-455d-ac29-956b834f8836_1590353353188","customerName": "test ets",
      "bundleId": null,
      "ifiId": 140827,
      "kycType": "AADHAAR_OTP",
      "vectorType": "p",
      "vectorValue": "+918368799223",
      "attrs": {}
}
Code Copied
Formatted request
Switch Theme
Expand More
Copy
"bundleId=null
 customerName=test ets
 ifiId=140827
 kycType=AADHAAR_OTP
 vboTransactionId=test6_58f27c1a-601c-455d-ac29-956b834f8836_1590353353188
 vectorType=p
 vectorValue=+918368799223"
Code Copied
The formatted payloads does not contain empty objects. Although null valued fields are still present.

Example #2

The nested fields are prefixed by their formatted parent’s field name and a dot. The field values with an ArrayList, appends a dot and index of the field as shown below:

Sample request
Switch Theme
Expand More
Copy
{
  "vboTransactionId": "test6_1c89a65a-8a95-44b4-ab67-74e7e1c0c4d4_1590360312294",
  "customerName": "test ets",
  "bundleId": null,
  "ifiId": 140827,
  "kycType": "AADHAAR_OTP",
  "vectorType": "p",
  "vectorValue": "+918368799223",
  "attrs": {
    "bncd": {
      "def": "ghi"
    },
    "efc": [
      "ancd",
      "cdef"
    ],
    "abcd": "def"
   } 
}
Code Copied
Formatted request
Switch Theme
Expand More
Copy
    attrs.abcd=def
    attrs.bncd.def=ghi
    attrs.efc.0=ancd
    attrs.efc.1=cdef
    bundleId=null
    customerName=test ets
    ifiId=140827
    kycType=AADHAAR_OTP
    vboTransactionId=test6_1c89a65a-8a95-44b4-ab67-74e7e1c0c4d4_1590360312294
    vectorType=p
    vectorValue=+918368799223 
Code Copied

Step 3: Create the signature

Use getSignableRepresentation method to convert the payload to a signable format as elucidated in Step 2: Format Payload.

For Java

Please use the getSignature method below to get the signature of the payload.

In the final payload, add the headers field containing the signature details. Check the request payload in the curl request above.

Create signature
Switch Theme
Expand More
Copy
static String getSignature(String privateKey, String publicKey, String data) throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
	Signature dsa = Signature.getInstance("SHA256withECDSA", Security.getProvider("SunEC"));
	dsa.initSign(loadPrivateKey(privateKey));
	dsa.update(data.getBytes());
	byte[] dsaSignature = dsa.sign();
	byte[] publicKeyIdentifierBytes = Base64.getDecoder().decode(generatePublicKeyIdentifier(publicKey));
	ByteBuffer bb = ByteBuffer.allocate(2 + publicKeyIdentifierBytes.length + dsaSignature.length);
	bb.putShort((short)1);
	bb.put(publicKeyIdentifierBytes);
	bb.put(dsaSignature);
	return Base64.getEncoder().encodeToString(bb.array());
}

public static String generatePublicKeyIdentifier(String publicKey) {
	return Base64.getEncoder().encodeToString(generatePublicKeyIdentifierBytes(publicKey));
}

public static byte[] generatePublicKeyIdentifierBytes(String publicKey) {
	try {
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(publicKey.getBytes(StandardCharsets.UTF_8));
		return Arrays.copyOfRange(md.digest(), 0, 3);
	} catch (NoSuchAlgorithmException var2) {
		throw new RuntimeException(var2);
	}
}

static PublicKey loadPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
	byte[] data = Base64.getDecoder().decode(key.getBytes());
	X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
	KeyFactory fact = KeyFactory.getInstance("EC");
	return fact.generatePublic(spec);
}

static PrivateKey loadPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
	byte[] clear = Base64.getDecoder().decode(key.getBytes());
	PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
	KeyFactory fact = KeyFactory.getInstance("EC");
	PrivateKey priv = fact.generatePrivate(keySpec);
	Arrays.fill(clear, (byte) 0);
	return priv;
}

static String signPayload(String data, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
	Signature signer = Signature.getInstance("SHA256withECDSA");
	signer.initSign(privateKey);
	signer.update(data.getBytes());
	return Base64.getEncoder().encodeToString(signer.sign());
}

static KeyPair generateKeyPair(String algo) throws NoSuchAlgorithmException {
	KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algo);
	keyPairGenerator.initialize(256);
	return keyPairGenerator.generateKeyPair();
}

static String getPrivateKey(KeyPair keyPair) {
	return Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
}

static String getPublicKey(KeyPair keyPair) {
	return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
}

public static String getSignableRepresentation(Object signablePayload) {
	return (String)toSignableRepresentationOfComplexObject("", signablePayload).sorted().collect(Collectors.joining("\n"));
}

private static Stream<String> toSignableRepresentationOfJson(Object fieldValue, String prefix, String fieldName) {
	JsonElement jsonElem = (JsonElement)fieldValue;
	if (jsonElem.isJsonNull()) {
		return toSignableRepresentation(prefix, (Class)null, fieldName, (Object)null);
	} else if (jsonElem.isJsonPrimitive()) {
		return toSignableRepresentation(prefix, (Class)null, fieldName, jsonElem.getAsString());
	} else {
		List<JsonElement> asList = (List) StreamSupport.stream(jsonElem.getAsJsonArray().spliterator(), false).collect(Collectors.toList());
		return toSignableRepresentation(prefix, List.class, fieldName, asList);
	}
}

private static Stream<String> toSignableRepresentationOfComplexObject(String prefix, Object object) {
	return StreamUtils.takeUntil(superClassStream(object), (aClass) -> {
		return aClass == Object.class;
	}).flatMap((aClass) -> {
		return Arrays.stream(aClass.getDeclaredFields()).flatMap((nestedField) -> {
			return fieldToSignableRepresentation(prefix, object, nestedField);
		});
	});
}

private static Stream<Class> superClassStream(Object object) {
	Stream<Class> superClassesStream = Stream.iterate(object.getClass(), Class::getSuperclass);
	return StreamUtils.takeUntil(superClassesStream, (aClass) -> {
		return aClass == null;
	});
}

private static Stream<String> fieldToSignableRepresentation(String prefix, Object obj, Field field) {
	try {
		int modifiers = field.getModifiers();
		if (!field.isSynthetic() && !Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
			field.setAccessible(true);
			Object fieldValue = obj == null ? null : field.get(obj);
			String fieldName = field.getName();
			Class<?> fieldType = fieldValue == null ? null : fieldValue.getClass();
			return toSignableRepresentation(prefix, fieldType, fieldName, fieldValue);
		} else {
			return Stream.empty();
		}
	} catch (IllegalAccessException var7) {
		throw new RuntimeException(var7);
	}
}

private static Stream<String> toSignableRepresentation(String prefix, Class<?> fieldType, String fieldName, Object fieldValue) {
	if (fieldType != null && !fieldType.isPrimitive() && !Character.class.isAssignableFrom(fieldType) && !Boolean.class.isAssignableFrom(fieldType) && !Number.class.isAssignableFrom(fieldType) && !String.class.isAssignableFrom(fieldType)) {
		if (Enum.class.isAssignableFrom(fieldType)) {
			Enum enumz = (Enum)fieldValue;
			return toSignableRepresentation(prefix, (Class)null, fieldName, enumz.name());
		} else if (!List.class.isAssignableFrom(fieldType) && !fieldType.isArray()) {
			if (Map.class.isAssignableFrom(fieldType)) {
				Set<Map.Entry> set = ((Map)fieldValue).entrySet();
				return set.stream().flatMap((entry) -> {
					Preconditions.checkState(String.class.isAssignableFrom(entry.getKey().getClass()), "Map keys have to be strings.");
					return entry.getValue() == null ? Stream.empty() : toSignableRepresentation(getPrefix(prefix, fieldName), entry.getValue().getClass(), entry.getKey().toString(), entry.getValue());
				});
			} else {
				return JsonElement.class.isAssignableFrom(fieldType) ? toSignableRepresentationOfJson(fieldValue, prefix, fieldName) : toSignableRepresentationOfComplexObject(getPrefix(prefix, fieldName), fieldValue);
			}
		} else {
			List list = fieldType.isArray() ? Arrays.asList((Object[])((Object[])fieldValue)) : (List)fieldValue;
			Stream.Builder<String> builder = Stream.builder();

			for(int i = 0; i < list.size(); ++i) {
				toSignableRepresentation(getPrefix(prefix, fieldName), list.get(i).getClass(), i + "", list.get(i)).forEach(builder::add);
			}

			return builder.build();
		}
	} else {
		return Stream.of(prefix + fieldName + "=" + fieldValue);
	}
}

private static String getPrefix(String prefix, String fieldName) {
	return fieldName.equals("") ? "" : prefix + fieldName + ".";
  }
}
Code Copied

For Python

Assuming that the data has been converted to the right format as elucidated in Step 2: Format Payload (m=”abcd”), use the following code to sign the data

Create signature
Switch Theme
Expand More
Copy
m = "abcd"

r, s = ecdsa.sign(m, private_key)
encoded = DEREncoder.encode_signature(r, s)

print(PEMEncoder.encode_public_key(public_key))
print(base64.b64encode(encoded))
 
Code Copied

Step 4: Base64 Encode

The last step is to base64 encode the data and pass it in the header as a signature.

Once this step is done, you are good to create and hit the EKYC service to load the web view that would allow you to perform KYC for the applicant.

Interaction Flow

The interaction flow with the Fusion EKYC service is as elucidated above.

Step 1: Create Session

Payload must be signed through the private key corresponding to the public key that the Fintech is registered with.

The Fintech must sign the payload by removing headers from below request. Once the signature has been generated it needs to be added to the header as a separate task. The curl request for this API is given below:

Example

cURL Sample
Switch Theme
Expand More
Copy
curl -X POST \
  {{base_url}}/vbo/session \
  -H 'Content-Type: application/json' \
  -d '{
  "vboTransactionId": "test_615991b5-2709-4a1e-a3d3-f7e36ea94889_1589280997619",
  "customerName": "test test",
  "bundleId": null,
  "ifiId": 140827,
  "kycType": "AADHAAR_OTP",
  "vectorType": "p",
  "vectorValue": "+916000000000",
  "attrs": {},
  "headers": {
    "signatoryJID": "[email protected]",
    "signature": "XXXX"
   }
}'
Code Copied
JSON Sample
Switch Theme
Expand More
Copy
{
     "sessionId": "d29e8d2e-cf81-4223-9dec-38b6de421fa7"
}
Code Copied
  • base_url: It is the base URL for EKYC service. The values of base_url for different environment is given below:
  • vboTrsanctionId: It is the unique parameter for the VBO that they must pass to query the status of a particular request for tracking purpose in our system as well. vboTransactionId is split into three parts vboId_randomUUID_timestamp.
    • vboId: It is provided to VBOs when they are onboarded onto Fusion.
    • randomUUID: Any unique random string.
    • Timestamp: Current epoch value.
  • customerName: Full name of the customer who is initiating the Aadhaar OTP request.
  • bundleId: Scope of this will be defined later. For now keep the value Null.
  • ifiId: ID of the IFI under which Aadhaar OTP needs to be done. The value of idfc in different environments is given below:
    • Stage environment: 140827
    • Preprod environment: 140827
    • Production environment: 140827
  • kycType: Type of KYC verification performed. Examples: AAHDAAR_OTP or AADHAAR_BIOMETRIC.
  • vectorType: It is the kind of vector you are using for the customer. It can be either p or e. p stands for phone number and e for email ID.
  • vectorValue: It is value of vector. If the vectorType is phone number, you must also add country code.
  • attrs: Optional. It is a set of attributes. This is required only if the fintech wants to store any other attribute for the customer.
  • headers: This is required to identify which fintech is sending the request. This must be added after calculating the signature of the payload.
    • signatoryJID: This is JID format of the VBO/Finetch and should always have the value [email protected].
    • Signature: Signature of the payload.

Upon successful verification of the signature and the payload, Zeta EKYC Service would respond back with a Session Token.

Step 2: Open the web view

After this, the Fintech needs to open the frontend URL with query params: vboId and vboTransactionId which were generated by the create session API using the sessionId which was returned in the response.

Frontend URL in different environments is as given below:

Step 3: Redirection of URL

After successful verification of Aadhar OTP, frontend will redirect to the above URL with query parameters such as name, dob and applicationID of the customer.

The redirection URL will look like this — sample redirecting URL.

  • applicationID: ID of the application of the Account Holder, on which Fintech needs to confirm whether to create an Account Holder for this application through Fusion APIs.
  • name: This is the name of the user as on Aadhaar card.
  • dob: This is the date of birth of the user as on Aadhaar card.

Step 4: Update Application

After redirection, Fintechs can take any necessary actions such as doing a DOB check, performing a name check, and so on at their end and then trigger the below API to mark the data capture complete for the application ID obtained in the above step.

The important point to note here is that the Fintech would need to call the appropriate Spool in order to update the application status.

  • For preprod spool IDs are as below:

    • Create Account Holder: c24add25-7cc5-4b38-85fd-82c482f010dd
    • Existing Account Holder: 29fd2457-4d18-477b-a11b-75e54d697680
  • For production spool IDs are as below:

    • Create Account Holder: c24add25-7cc5-4b38-85fd-82c482f010dd
    • Existing Account Holder: 29fd2457-4d18-477b-a11b-75e54d697680

The Fintech can use the following API to understand if an Account Holder with the provided phone number already exists in the system or not:

cURL sample
Switch Theme
Expand More
Copy
  curl --location --request GET 'https://fusion.gw.zetapay.in/api/v1/ifi/304851/individualByVector/p/+919988776655' \
  --header 'Content-Type: application/json'
Code Copied

This API returns the existing Account Holder if it already exists in the system. In an alternate case, it returns the following error:

Error response
Switch Theme
Expand More
Copy
  {
    "code": "ACCOUNT_HOLDER_VECTOR_NOT_FOUND",
    "message": "Get AccountHolderVector failed for type: p value : +919988776654 ifiID : 304851",
    "details": {
        "errorCode": "ACCOUNT_HOLDER_VECTOR_NOT_FOUND"
    }
  }
Code Copied

In the latter case, the Fintech must use the Create Account Holder spool whereas in the former, the Fintech must use the Existing Account Holder spool.

Once the spool is finalized the Fintech goes ahead and marks the data capture stage of the respective application in the spool as COMPLETE.

cURL Sample
Switch Theme
Expand More
Copy
  curl --location --request POST 'https://cosmos-ahp.preprod.zeta.in/api/v1/ifi/140827/spool/{{spoolID}}/application/{{applicationID}}/stage/DATA_CAPTURE/complete' \
  --header 'Content-Type: {{application/json}}' \
  --header 'X-Zeta-AuthToken: {{token}}' \
Code Copied

Step 5: Provision the Account Holder

After the data capture is completed Fusion processes the application and starts the Account Holder provisioning. Fintechs can listen on the topic tenant_{{ifiID}}_Application-V1 for the event APPLICATION-V1_UPDATED. This event ensures that all the processing for the application is done and the Account Holder provisioning is done successfully.

Ekyc Application Event Details

  1. Create Account holder Events and payloads

Event: APPLICATION-V1_CREATED
State: COMPLETED

Payload
Switch Theme
Expand More
Copy
{
  "payload": {
    "topic": "_tenant_140827_APPLICATION-V1",
    "name": "APPLICATION-V1_CREATED",
    "eventID": "214bfd3e-380a-4f13-a9bf-9b3512494d46",
    "source": {
      "uri": "APPLICATION-V1://140827/ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
      "tags": [
        "tag://spool-id/6ddd8d56-0d71-4124-b192-f6c34344e192",
        "tag://vbo-id/4fa18593-d2d9-4bf3-bea7-7f6deb9f2ca4"
      ],
      "state": "DATA_CAPTURE_INITIATED"
    },
    "origin": {
      "instance": "instance://default/cosmos-application/2724",
      "time": 1608817398664,
      "flowID": "16c31f6e-944c-45f0-9eda-0bcd5c5bf7b8"
    },
    "data": {
      "id": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
      "requestId": "965f8c84-352c-4c18-b54f-66c563d8d13e",
      "spoolId": "6ddd8d56-0d71-4124-b192-f6c34344e192",
      "status": "DATA_CAPTURE_INITIATED",
      "ifiId": 140827,
      "sections": {
        "Personal": {
          "id": "a87b7497-5e22-4314-8253-218c31221e98",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "Personal",
          "type": "CreateRealAccountHolder",
          "details": {
            "PersonalDetails": {
              "lastName": "",
              "firstName": "Noushad",
              "individualType": "REAL",
              "applicationType": "CREATE_ACCOUNT_HOLDER"
            }
          },
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 833876000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 833876000
            }
          }
        },
        "Vectors": {
          "id": "690ab60b-1e5b-4630-9580-11a2ecef7469",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "Vectors",
          "type": "CreateRealAccountHolder",
          "details": {
            "VectorDetails": [
              {
                "type": "p",
                "value": "+919597921270",
                "isVerified": true
              }
            ]
          },
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 883975000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 883975000
            }
          }
        }
      },
      "vectors": [],
      "tags": [
        {
          "type": "spool-id",
          "value": "6ddd8d56-0d71-4124-b192-f6c34344e192",
          "attributes": {}
        },
        {
          "type": "vbo-id",
          "value": "4fa18593-d2d9-4bf3-bea7-7f6deb9f2ca4",
          "attributes": {}
        }
      ],
      "stages": [
        {
          "id": "716a89b9-e85b-4f50-ba8e-a7a26179203e",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "ASSESSMENT",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 984771000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 984771000
            }
          }
        },
        {
          "id": "94eb37c3-2e15-4d91-b137-e5405bad9841",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "DATA_CAPTURE",
          "status": "INITIATED",
          "result": {
            "validationPassed": {
              "validation": "successful"
            }
          },
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 946344000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 18,
              "nano": 529303000
            }
          }
        },
        {
          "id": "2713108d-93d7-475e-9c12-2aea02201ee8",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "ENRICHMENT",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 948759000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 948759000
            }
          }
        },
        {
          "id": "03707d30-42f2-46f5-b868-6fa0b300d34d",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "PROVISIONING",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 986961000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 986961000
            }
          }
        },
        {
          "id": "7cbfd1e1-5cae-40b3-a60d-4cdb6cd6d2a4",
          "ifiId": 140827,
          "applicationId": "ff0c79e5-c3c7-4d92-a65b-d99df8f398e3",
          "name": "REVIEW",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 988139000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 13,
              "minute": 43,
              "second": 17,
              "nano": 988139000
            }
          }
        }
      ],
      "createdAt": {
        "date": {
          "year": 2020,
          "month": 12,
          "day": 24
        },
        "time": {
          "hour": 13,
          "minute": 43,
          "second": 17,
          "nano": 788283000
        }
      },
      "updatedAt": {
        "date": {
          "year": 2020,
          "month": 12,
          "day": 24
        },
        "time": {
          "hour": 13,
          "minute": 43,
          "second": 18,
          "nano": 436837000
        }
      }
    },
    "publisher": {
      "appDomain": "services.olympus",
      "serviceName": "cosmos-application",
      "nodeId": "2724"
    }
  },
  "topic": "_tenant_140827_APPLICATION-V1",
  "pType": "olympus.pubsub.model.PubSubEvent",
  "emitterType": "EVENT",
  "publisher": {
    "appDomain": "services.olympus",
    "serviceName": "cosmos-application",
    "nodeId": "2724"
  },
  "publishTime": 1608817398664,
  "oid": "00000aa4-0000-977e-0000-000000000001",
  "flowId": "16c31f6e-944c-45f0-9eda-0bcd5c5bf7b8",
  "from": {
    "appDomain": "services.olympus",
    "serviceName": "cosmos-application",
    "nodeId": "2724"
  }
}
Code Copied
  1. Existing account holder Events and payloads

Event: APPLICATION-V1_UPDATED
State: COMPLETED

Payload
Switch Theme
Expand More
Copy
{
  "payload": {
    "topic": "_tenant_140827_APPLICATION-V1",
    "name": "APPLICATION-V1_UPDATED",
    "eventID": "8963bbc2-43e7-442c-8c5e-88d665a6f0a7",
    "source": {
      "uri": "APPLICATION-V1://140827/8b76723b-f0ae-4d0e-92db-4c62570a5182",
      "tags": [
        "tag://spool-id/6ddd8d56-0d71-4124-b192-f6c34344e192",
        "tag://vbo-id/4fa18593-d2d9-4bf3-bea7-7f6deb9f2ca4"
      ],
      "state": "DATA_CAPTURE_INITIATED"
    },
    "origin": {
      "instance": "instance://default/cosmos-application/2724",
      "time": 1608822385678,
      "flowID": "d6ded90c-8158-4f69-8f10-7ead3a96abc9"
    },
    "data": {
      "id": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
      "requestId": "b6e1528d-2c63-4ab9-ac92-c50e0f31b9b9",
      "spoolId": "6ddd8d56-0d71-4124-b192-f6c34344e192",
      "status": "DATA_CAPTURE_INITIATED",
      "ifiId": 140827,
      "sections": {
        "Personal": {
          "id": "624c1339-4665-4957-af11-857cf3f22df8",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "Personal",
          "type": "CreateRealAccountHolder",
          "details": {
            "PersonalDetails": {
              "lastName": "",
              "firstName": "Noushad",
              "individualType": "REAL",
              "applicationType": "CREATE_ACCOUNT_HOLDER"
            }
          },
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 875807000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 875807000
            }
          }
        },
        "Vectors": {
          "id": "7ff89c13-2e90-4261-a220-7990c7018879",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "Vectors",
          "type": "CreateRealAccountHolder",
          "details": {
            "VectorDetails": [
              {
                "type": "p",
                "value": "+919597921278",
                "isVerified": true
              }
            ]
          },
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 912588000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 912588000
            }
          }
        },
        "KYCStatus": {
          "id": "a114d8ad-21ae-43b9-9cb7-c4c186b86ccc",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "KYCStatus",
          "type": "CreateRealAccountHolder",
          "details": {
            "KYCStatusDetails": {
              "ifiID": "140827",
              "kycStatus": "AADHAAR_OTP",
              "attributes": {
                "dob": "28-10-1992",
                "name": "Mohamed Noushad Mohamed Nasar",
                "AADHAAR": "fba396593478e76d0e1f85315334443024ee2c882b23689467550b720d1c991bf903e916e6f48b0c6aa7d51905b23947",
                "kycType": "AADHAAR_OTP",
                "authType": "AADHAAR"
              },
              "expiryTime": {
                "date": {
                  "day": 24,
                  "year": 2021,
                  "month": 12
                },
                "time": {
                  "hour": 15,
                  "nano": 892000000,
                  "minute": 6,
                  "second": 26
                }
              },
              "updateTime": {
                "date": {
                  "day": 24,
                  "year": 2020,
                  "month": 12
                },
                "time": {
                  "hour": 15,
                  "nano": 892000000,
                  "minute": 6,
                  "second": 26
                }
              }
            }
          },
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 6,
              "second": 25,
              "nano": 646234000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 6,
              "second": 25,
              "nano": 646234000
            }
          }
        }
      },
      "vectors": [],
      "tags": [
        {
          "type": "spool-id",
          "value": "6ddd8d56-0d71-4124-b192-f6c34344e192",
          "attributes": {}
        },
        {
          "type": "vbo-id",
          "value": "4fa18593-d2d9-4bf3-bea7-7f6deb9f2ca4",
          "attributes": {}
        }
      ],
      "stages": [
        {
          "id": "8f0d234d-0dd3-4ef3-8822-cb59cfeb7bfd",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "ASSESSMENT",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 996992000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 996992000
            }
          }
        },
        {
          "id": "c27c5a04-87ac-45b5-9969-6f37ab50d77e",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "DATA_CAPTURE",
          "status": "INITIATED",
          "result": {
            "validationPassed": {
              "validation": "successful"
            }
          },
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 973029000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 22,
              "nano": 447265000
            }
          }
        },
        {
          "id": "5d49cb53-0830-45d0-91c2-89b6d2f58e56",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "ENRICHMENT",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 972496000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 972496000
            }
          }
        },
        {
          "id": "a3e3c7fe-fc96-4e7c-a9fb-7240ed40a07e",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "PROVISIONING",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 22,
              "nano": 55668000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 22,
              "nano": 55668000
            }
          }
        },
        {
          "id": "965ab4e5-dac5-4b1e-9358-8aa1dbe39ee4",
          "ifiId": 140827,
          "applicationId": "8b76723b-f0ae-4d0e-92db-4c62570a5182",
          "name": "REVIEW",
          "status": "NOT_INITIATED",
          "result": {},
          "details": {},
          "createdAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 998042000
            }
          },
          "updatedAt": {
            "date": {
              "year": 2020,
              "month": 12,
              "day": 24
            },
            "time": {
              "hour": 15,
              "minute": 2,
              "second": 21,
              "nano": 998042000
            }
          }
        }
      ],
      "createdAt": {
        "date": {
          "year": 2020,
          "month": 12,
          "day": 24
        },
        "time": {
          "hour": 15,
          "minute": 2,
          "second": 21,
          "nano": 843047000
        }
      },
      "updatedAt": {
        "date": {
          "year": 2020,
          "month": 12,
          "day": 24
        },
        "time": {
          "hour": 15,
          "minute": 2,
          "second": 22,
          "nano": 368611000
        }
      }
    },
    "publisher": {
      "appDomain": "services.olympus",
      "serviceName": "cosmos-application",
      "nodeId": "2724"
    }
  },
  "topic": "_tenant_140827_APPLICATION-V1",
  "pType": "olympus.pubsub.model.PubSubEvent",
  "emitterType": "EVENT",
  "publisher": {
    "appDomain": "services.olympus",
    "serviceName": "cosmos-application",
    "nodeId": "2724"
  },
  "publishTime": 1608822385678,
  "oid": "00000aa4-0000-9a32-0000-000000000001",
  "flowId": "d6ded90c-8158-4f69-8f10-7ead3a96abc9",
  "from": {
    "appDomain": "services.olympus",
    "serviceName": "cosmos-application",
    "nodeId": "2724"
  }
}
Code Copied

Error Codes

List of errors codes thrown by the Zeta EKYC service:

Error Codes Http Status Code Error Messages
001 INTERNAL_SERVER_ERROR Internal Technical Glitch (Mostly timeout from bank APIs)
003 FORBIDDEN Session Expired - Session expiry is 30 mins.
004 BAD_REQUEST Invalid input signature
005 NOT_FOUND Error while fetching KYC Details. Error if the provided account holder is not present.
007 INTERNAL_SERVER_ERROR Generate OTP has got failed.
008 INTERNAL_SERVER_ERROR Verify OTP has got failed.
010 BAD_REQUEST Technical Error while verifying signature in create session api.
011 INTERNAL_SERVER_ERROR Technical Error.
015 FORBIDDEN Aadhaar OTP already processed and closed.
022 NOT_FOUND OVD Hash generated has not yet created challenge (generate OTP) and trying to verify it.
023 CONFLICT Account already exists and KYCed
024 INTERNAL_SERVER_ERROR UID not found trying to modify.
025 INTERNAL_SERVER_ERROR Deplicate request for aadhaar otp kyc.
027 BAD_REQUEST Input IFI Id is not valid.
030 INTERNAL_SERVER_ERROR Error while creating application.
031 INTERNAL_SERVER_ERROR Error while adding kyc section in application.
033 BAD_REQUEST Input data is invalid and non-parsable data.

You can refer to the error codes thrown by the downstream services (UIDAI and NSDL errors) here.



Related articles