AePS Transaction API

One of the prime use cases of this API is Cash-out. Developers can create a solution around this where the amount can be withdrawn using a biometric device.

List of banks available with bank ids and bank codes is available in the following google excel sheet:

Header parameter request_hash generation process


First, the secret-key value which you have passed "d2fe1d99-6298-4af2-8cc5-d97dcf46df30"; is not a value of secret-key this is the key which is encoded to generate the secret-key and secret-key-timestamp.

Please generate the request hash properly. Please check the request hash generation code again. Before generating the request hash you need to generate a string which will be generated by concatenating some parameters in a particular manner only. You cannot change the sequence.

Sequence of concatenated string:

secret-key-timestamp + aadhaar + amount + user_code

Note : Unencrypted value of aadhaar number will be passed in the concatenated string and amount must be passed as 0 in case of balance inquiry / mini statement

After generating the concatenated string please follow the following procedure :

  1. Encode your authenticator password using the base 64. Authenticator password will be the key which you have used for the secret-key generation. Authenticator password for the staging server is "d2fe1d99-6298-4af2-8cc5-d97dcf46df30"

// Initializing key in some variable. You will receive this key from Eko via email
$key = "d2fe1d99-6298-4af2-8cc5-d97dcf46df30";
$encodedKey = base64_encode($key);

  1. After encoding the key, you need to hmac the concatenated string and encoded_key using hmac256.
    $signature_req_hash = hash_hmac('SHA256', $data, $encodedKey, true);
    In the $data you need to send the concatenated string.

  2. After hmac , you need to again encode the result using the base64.
    $request_hash = base64_encode($signature_req_hash);

Final result after encoding will be the request_hash.
Please make sure that you are generating the request_hash in this manner only.

Encryption process for aadhaar parameter:

  1. Decode public key using base64 encoding technique
  2. Compute RSA encrypted signature using decoded key and message.
  3. Encode encrypted signature with base64 encoding to send message on API

Public Key for UAT




  • If the agent is not onboarded on Eko's system is not allowed to do the transaction. They need to enroll themselves followed by the service activation. Kindly refer to the section Agent Management API.



Once the thorough testing is done from your end along with the sanity testing from our end on the staging (UAT) server, drop an email on [email protected] for the production public key for the aadhaar encryption

Only IP which is in India will be whitelisted while going on the production mode. IP which is present outside India will not be whitelisted as per compliance

Port 25002 and Port 25004 must be opened on your server in order to reach the requests from your server to our production and staging environment respectively and a connection must be made from your server. You can check if connection is being made from your server or not using the telnet command.

The command for staging environment which you have to use: telnet 25004.
The command for production environment which you have to use: telnet 25002.

public static String calculateRSA( String salt ) throws InvalidKeyException, Exception {

Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
byte[] secretMessageBytes = salt.getBytes("UTF-8");
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
String encodedMessage = Base64.encodeBase64String(encryptedMessageBytes);
return encodedMessage;
public static PublicKey getPublicKey() throws Exception {
String rawPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXa63O/UXt5S0Vi8DM/PWF4yugx2OcTVbcFPLfXmLm9ClEVJcRuBr7UDHjJ6gZgG/qcVez5r6AfsYl2PtKmYP3mQdbR/BjVOjnrRooXxwyio6DFk4hTTM8fqQGWWNm6XN5XsPK5+qD5Ic/L0vGrS5nMWDwjRt59gzgNMNMpjheBQIDAQAB";
byte[] keyBytes = Base64.decodeBase64(rawPublicKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);// generatePrivate(spec);
$curl = curl_init();

$aadhar_no = "123412341234";
$amount = "500";
$pdata = $_POST['pdata'];
$lat = "81";
$lon = "81";
$txn_date = date("Y/m/d");
$txn_time = date("H:i:s");
$timestamp = date("Y-m-s H:i:s");
$MerchantKey = $_SESSION['MerchantKey'];
$SessionToken = $_SESSION['SessionToken'];
$UserName = $_SESSION['UserName'];
$user_key = "20810200";

$key = "f74c50a1-f705-4634-9cda-30a477df91b7";
$encodedKey = base64_encode($key);
$secret_key_timestamp = round(microtime(true) * 1000);
$data = $secret_key_timestamp.$aadhar_no.$amount.$user_key;
$signature_secret_key = hash_hmac('SHA256', $secret_key_timestamp, $encodedKey, true);
$signature_req_hash = hash_hmac('SHA256', $data, $encodedKey, true);
$secret_key = base64_encode($signature_secret_key);
$request_hash = base64_encode($signature_req_hash);

$public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXa63O/UXt5S0Vi8DM/PWF4yugx2OcTVbcFPLfXmLm9ClEVJcRuBr7UDHjJ6gZgG/qcVez5r6AfsYl2PtKmYP3mQdbR/BjVOjnrRooXxwyio6DFk4hTTM8fqQGWWNm6XN5XsPK5+qD5Ic/L0vGrS5nMWDwjRt59gzgNMNMpjheBQIDAQAB';

$search = [
		"-----BEGIN PUBLIC KEY-----",
		"-----END PUBLIC KEY-----",
$public_key_resource = $search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];

openssl_public_encrypt($aadhar_no, $signature, $public_key_resource, OPENSSL_SSLV23_PADDING);
$encrypted_aadhar = base64_encode($signature);

echo $secret_key;
echo "<br />";
echo "<br />";
echo $secret_key_timestamp;
echo "<br />";
echo "<br />";
echo $request_hash;
echo "<br />";
echo "<br />";
echo $pdata;
echo "<br />";
echo "<br />";
echo "Encrypted Aadhar :";
echo "<br />";
echo $encrypted_aadhar;
echo "<br />";
echo "<br />";
echo "cURL Response :";
echo "<br />";
curl_setopt_array($curl, array(
  CURLOPT_URL => '',
    "service_type": "2",
    "initiator_id": "9962981729",
    "user_code": "20810200",
    "customer_id": "9999999999",
    "bank_code": "SBIN",
    "amount": "'.$amount.'",
    "client_ref_id": "AEPS1",
    "pipe": "0",
    "aadhar": "'.$encrypted_aadhar.'",
    "notify_customer": "0",
    "piddata": "<PidData>    <Data"
    'Content-Type: application/json',
    'developer_key: becbbce45f79c6f5109f848acd540567',
    'secret-key: '.$secret_key.'',
    'secret-key-timestamp: '.$secret_key_timestamp.'',
    'request_hash: '.$request_hash.''

$response = curl_exec($curl);

echo $response;

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System.Security.Cryptography;

 #region Aadhar Encryption Process
                            var keyBytes = Convert.FromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXa63O/UXt5S0Vi8DM/PWF4yugx2OcTVbcFPLfXmLm9ClEVJcRuBr7UDHjJ6gZgG/qcVez5r6AfsYl2PtKmYP3mQdbR/BjVOjnrRooXxwyio6DFk4hTTM8fqQGWWNm6XN5XsPK5+qD5Ic/L0vGrS5nMWDwjRt59gzgNMNMpjheBQIDAQAB
                            AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
                            RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
                            RSAParameters rsaParameters = new RSAParameters();
                            rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
                            rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
                            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

                            byte[] plaintext = Encoding.UTF8.GetBytes(ObjRequest.AadharNo);
                            byte[] ciphertext = rsa.Encrypt(plaintext, false);
                            string cipherresult = Convert.ToBase64String(ciphertext);
                            ObjRequestData.aadhar = cipherresult;
                        catch (Exception ex)
                        { }



Above mentioned codes are the sample and running codes provided by our partners, any changes done needs to checked from your end

 * Sample Function to capture fingerprint from RDService based biometric device in the browser (using JQuery).
 * @param {string} capture_url RDService URL to call for capture. Eg: or
 * @param {function} callbackFunction The function to call back on capture success or failure
 * @return {Object} response Object containing the response details.
 * @return {boolean} response.httpSuccess Whether AJAX request successful.
 * @return {boolean} response.captureSuccess Whether fingerprint capturing successful.
 * @return {number} response.captureQuality Quality of fingerprint scan if captureSuccess is true.
 * @return {number} response.errCode Error code returned by RDService if captureSuccess is false.
 * @return {string} response.errInfo Error details returned by RDService if captureSuccess is false.
 * @return {string} response.textStatus HTTP status if httpSuccess is false.
 * @return {string} response.errorThrown Error details if httpSuccess is false.
function capturefingerprint(capture_url, callbackFunction) {

	var doc = document.implementation.createDocument("", "", null);
	var pidOptionsElem = doc.createElement("PidOptions");
	var optsElem = doc.createElement("Opts");

	optsElem.setAttribute("fCount", 1);
	optsElem.setAttribute("fType", 2);
	optsElem.setAttribute("iCount", 0);
	optsElem.setAttribute("pCount", 0);
	optsElem.setAttribute("format", 0);
	optsElem.setAttribute("pidVer", "2.0");
	optsElem.setAttribute("timeout", 10000);
	optsElem.setAttribute("posh", "UNKNOWN");
	optsElem.setAttribute("env", "P");


		url: capture_url,
		type: 'CAPTURE',
		data: doc,
		processData: false,
		success: function (response) {
			var doc2;
			var result = {
				httpSuccess: true

			if (typeof response === 'string') {
				doc2 = (new DOMParser()).parseFromString(response, 'text/xml');
				result.pid_data = response;
			} else {
				doc2 = response;
				result.pid_data = (new XMLSerializer()).serializeToString(response);

			var resp = doc2.getElementsByTagName("Resp");
			result.errCode = resp[0].getAttribute('errCode');

			if (errCode != 0) {
				result.captureSuccess = false;
				result.errInfo = resp[0].getAttribute('errInfo');
			} else {
				result.captureSuccess = true;
				result.captureQuality = parseInt(resp[0].getAttribute('qScore'));


		error: function (jqXHR, textStatus, errorThrown) {
				httpSuccess: false,
				captureSuccess: false,
				textStatus: textStatus,
				errorThrown: errorThrown

Sample PidData after serialization

	<Data type=\\\"X\\\">MjAyMS0xMi0wNlQwNjo0ODoyM51MswAVy/PSZSqgXRudRMXTP356NsUJ4q4qItIZDjYZfOD4zwDpqlKT4aU927NvMJm6+IxgTTZEFngZ0TY+ibqUeQQiB7JEwj+8xeeO+7Y+G4yJmL7FjqNfQG7O/AgMP8AXWFS522iUeGmqkyf7InpXIj7VCiKlNDu+QNu+donxOQ6hRlNJ5J0kc082Fct4hvEr4iFVL9UrAx1+kR8yDbLAISxc+37RI7cxn577uNsazb/jy7O+tTk9zE6Ia3uPY0uqKfMNqNhSTomHMeJo5S0wuOW7uyRYrvz8Q4hUlCuqsup0ZmKA5su1F7HU60q6DHkO0eH+mk8Q/gA8ymaEHeBadkd+i/8tTZnxDyp/gw+z3vT+MPZNLKT4WAE5w2nhOoOOS+F9NPpJ2mn+FqwkRQ7VnEv09g0/bTyAZHCvmhUAy/NHYVYEPaycRpoSIzGuA3REoX++HaOetubgBx9vVVIl5ZKAR4hlwzuGJbcFlyJh6uxjQIK1bJh/jPJH/m+WyJpZwc99IArg9hnBkUFTO42ZeaHXj7+4BNDahs6vFtoquJGFXHYkZUZ866itGA6Dh8iJCjIjd8f6IEah1U+SKX0mkAzh4IM91lw6sIeNpykMwk99FTDJ33vkW+ao1mf/LK8yWV3hisEGqQtCAhn3S71lpf/pJk4TOVLIJKwqnlcsin6mWcLr3Ve8xkWvJW8dRVfZ+KbQTpdOU4oQs3iv4jl0ORbuJJhVC2IEOGpUfpQyS8OO0x8D7RTvl+L3FmtKIXNZ7qlfkYdxKnH3a0QSvFY8KFpxOhUKcQXqIWU/Yuhtldgjb6D2Ys2QvgR99kRhDF7449fbqkQnnNF8uIGX3MIailsw/JFcTiko22s6in6gzPuv7AoPl1XIfDURnvQQnxlGb3MArO2rD48SVmNpwYGBnGTTyV1OYl9EbrJ1NPVcoXFCt6tcDDXwnhB09iJK7PWmKuIe5wP8dGWK/kgdYuEYRmsso+niYg2zUwdt41JGFPVJR0eCwNCOcmQ2uocPGmukB3h0h6dR1mMCTYBPUyNIxQznMxGAj72N0yHXwCS5FR6Qih8sYTDA/x1OOnuANK/m7CuCJ6H+tv48PU6vubtQAfxKCXQMiUZp0qbc</Data>
	<DeviceInfo dc=\\\"79bfab62-5fd1-4ea1-bf5c-00cc714ae571\\\" dpId=\\\"MANTRA.MSIPL\\\" mc=\\\"MIIEGjCCAwKgAwIBAgIGAX0iDKcNMA0GCSqGSIb3DQEBCwUAMIHqMSowKAYDVQQDEyFEUyBNYW50cmEgU29mdGVjaCBJbmRpYSBQdnQgTHRkIDcxQzBBBgNVBDMTOkIgMjAzIFNoYXBhdGggSGV4YSBvcHBvc2l0ZSBHdWphcmF0IEhpZ2ggQ291cnQgUyBHIEhpZ2h3YXkxEjAQBgNVBAkTCUFobWVkYWJhZDEQMA4GA1UECBMHR3VqYXJhdDEdMBsGA1UECxMUVGVjaG5pY2FsIERlcGFydG1lbnQxJTAjBgNVBAoTHE1hbnRyYSBTb2Z0ZWNoIEluZGlhIFB2dCBMdGQxCzAJBgNVBAYTAklOMB4XDTIxMTEyNTEyMjEzNVoXDTIxMTIxNTA1MjMxMlowgbAxJTAjBgNVBAMTHE1hbnRyYSBTb2Z0ZWNoIEluZGlhIFB2dCBMdGQxHjAcBgNVBAsTFUJpb21ldHJpYyBNYW51ZmFjdHVyZTEOMAwGA1UEChMFTVNJUEwxEjAQBgNVBAcTCUFITUVEQUJBRDEQMA4GA1UECBMHR1VKQVJBVDELMAkGA1UEBhMCSU4xJDAiBgkqhkiG9w0BCQEWFXN1cHBvcnRAbWFudHJhdGVjLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwP8kOTVlcHl1sOaXo3e1DLJJMRdrfrVOsAsgkrZQNnppVB8c9hY0OPP9ncWNl7SMobrrA6k2lSI0RDd1/4vd11ZUlic/IaHkNJQ6XJHE+Cwl8r2zVlAIO/cyibm7oPZRuf6TFzwrxltxuRL9J81lT/bm53injV8Six7Zg0pYqoJ1kwXqxF3ql+T3SCDp9zUfohwC60X3lFnqxOLgrIH430exaSsRl1UjnaDbU71ihme1yXDeVkKaQNIlTXbj1RJNXeHJpJMEpDyld54oHTmvSIsZip/QmT8rzUHcRjuois71J4ZLV836AyncYBvWqfdr4ETJ3DpSIA1gLw8w8lpw8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAG+TPUnji6Ziyge9bIr9fEQ/4rnB2JaJXrnUxkuL3WG/vpCHBwWuSw67nHo4CzQx7XUgrA8sWZPnL1JFViWaFN1kKy/4veUtuMF12gBDwAs9egUDqb1jijcg7V9gv6aegftq0cXH6mU6qhUCtDm8Q5jMBn2v3FpQBXcTNZa4jWUDy2TkrKwssMlBFB3Jz+k2rMe1jsFc0ZoFyCmAqU7Vb80tRO0/RC4zjmO3YQXpUYjxd6frh3LRSl6626P6Qpf/szX4bpZp3s4Kuf1J/M7wF2/pcQfcoypXPv3iDlaqOU3VbjOgNCj3OHmJjabmin0mFbwN08pFNthFGvv8Xxe6Hkw==\\\" mi=\\\"MFS100\\\" rdsId=\\\"MANTRA.AND.001\\\" rdsVer=\\\"1.0.5\\\">
			<Param name=\\\"srno\\\" value=\\\"2174371\\\"/>
			<Param name=\\\"sysid\\\" value=\\\"356922093643968\\\"/>
			<Param name=\\\"ts\\\" value=\\\"2021-12-06T06:48:25+05:30\\\"/>
	<Resp errCode=\\\"0\\\" errInfo=\\\"Capture Success\\\" fCount=\\\"1\\\" fType=\\\"0\\\" iCount=\\\"0\\\" iType=\\\"0\\\" nmPoints=\\\"35\\\" pCount=\\\"0\\\" pType=\\\"0\\\" qScore=\\\"83\\\"/>
	<Skey ci=\\\"20221021\\\">agdti+4wZR9bKRVEHGMknQRUqTiFbloF4HoY7ko1GoVTj7uDMklfgkS1C/NljxJgnYyPY3TRjpvBHtOOuYKxbN/nD1zZxKcGokwENOIyAU6Ac+jm+iqeuNA7AWS/l/fDNs+70pRNg5ZeVh5eDQ8p6mDnPxyu0V7YanOfyD8PDim3YgXiI2Isg4NFJAsY8vGAKBygp6+L7lg8vu9QPFS5vin1KE0eAUyruhrsoNl8r1a0O2tQUssra+JO4aqdjIlgtp+Xlgx9sot43UpCa7HVdF+ASJXojptQYaC6yAoZj9HgrBQm2SmV6U/5J5krcr/75LBxPKQumuiuh+3WktTdnQ==</Skey>


Things to consider for PidData

  • The PidData should contain Data type="X" (for XML). If this comes as P (for Protobuf), make sure you send pid format as 0 when sending a capture request.

  • The PidData should contain DeviceInfo with a mc parameter. The mc parameter is the device public key certificate signed by Device Provider Key (To verify your certificate, visit

  • For more details, refer Section 2.3 PID Creation – Signing and Encrypting Biometrics from UIDAI guidelines.


Update value of fType parameter from 0 to 2

As per the strict guidelines of NPCI on 'FIR-FMR single PID block implementation in Aadhar-based biometric authentication. We need to capture the fingerprint data of our end-user with an updated PID fType value. In order to do that Frontend code which is responsible to capture finger data, needs to pass value of fType = 2 rather than 0; this will return PID XML with the updated fingerprint data format and Same can be passed over in Eko's API. Please refer the updated sample code snippet of capture fingerprint code.

The list of banks are not live with the FMR+FIR and hence the value of fType =0 instead of 2 for the mentioned banks.


Transaction types

Following are the parameters for different transaction types:

  • service_type=2 (Cash Withdrawal)
  • service_type=3 (Balance Inquiry)
  • service_type=4 (Mini Statement)
  • service_type=5 (Aadhaar Pay)


AePS two factor authentication process

Banks have added a two step process for merchant verification and authentication to prevent fraud and misuse.

We are adding two more service type parameter in existing AePS Transaction API payload
service_type=6 (Two Factor Registration)
service_type=7 (Two Factor Authentication)