Find your keys on the Klasha Dashboard → Settings → Generate API Keys (here)
Encryption Algorithm
You need to encrypt the entire create transfer payload that we specify on the previous point (here). In order to encrypt the body correctly, you’d need the encryptionKey (that you can obtain following this guide here). We also provided an example in Java of the encryption algorithm in order to help you.
publicstaticStringencryptCBC(String stringToEncrypt,String encryptionkey) {try {SecureRandom sr =newSecureRandom();byte[] salt =newbyte[8];sr.nextBytes(salt);finalbyte[][] keyAndIV =GenerateKeyAndIV(32,16,1, salt,password.getBytes(StandardCharsets.UTF_8),MessageDigest.getInstance("MD5"));Cipher cipher =Cipher.getInstance("AES/CBC/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(keyAndIV[0],"AES"),newIvParameterSpec(keyAndIV[1]));byte[] encryptedData =cipher.doFinal(stringToEncrypt.getBytes(StandardCharsets.UTF_8));byte[] prefixAndSaltAndEncryptedData =newbyte[16+encryptedData.length];// Copy prefix (0-th to 7-th bytes)System.arraycopy("Salted__".getBytes(StandardCharsets.UTF_8),0, prefixAndSaltAndEncryptedData,0,8);// Copy salt (8-th to 15-th bytes)System.arraycopy(salt,0, prefixAndSaltAndEncryptedData,8,8);// Copy encrypted data (16-th byte and onwards)System.arraycopy(encryptedData,0, prefixAndSaltAndEncryptedData,16,encryptedData.length);returnBase64.getEncoder().encodeToString(prefixAndSaltAndEncryptedData); } catch (Exception e) {thrownewRuntimeException(e); }}publicstaticbyte[][] GenerateKeyAndIV(int keyLength,int ivLength,int iterations,byte[] salt,byte[] password,MessageDigest md) {int digestLength =md.getDigestLength();int requiredLength = (keyLength + ivLength + digestLength -1) / digestLength * digestLength;byte[] generatedData =newbyte[requiredLength];int generatedLength =0;try {md.reset();// Repeat process until sufficient data has been generatedwhile (generatedLength < keyLength + ivLength) {// Digest data (last digest if available, password data, salt if available)if (generatedLength >0)md.update(generatedData, generatedLength - digestLength, digestLength);md.update(password);if (salt !=null)md.update(salt,0,8);md.digest(generatedData, generatedLength, digestLength);// additional roundsfor (int i =1; i < iterations; i++) {md.update(generatedData, generatedLength, digestLength);md.digest(generatedData, generatedLength, digestLength); } generatedLength += digestLength; }// Copy key and IV into separate byte arraysbyte[][] result =newbyte[2][]; result[0] =Arrays.copyOfRange(generatedData,0, keyLength);if (ivLength >0) result[1] =Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);return result; } catch (DigestException e) {thrownewRuntimeException(e); } finally {// Clean out temporary dataArrays.fill(generatedData, (byte) 0); }}
Integration step
Generate a bearer token
Using the Token endpoint on the Postman collection, the token can be obtained from the headers under the header name: token
POST{{env_url}}/auth/account/v2/login
Request Body
Name
Type
Description
username*
username
password*
password
{"message":"success","error":null,"data": {"token":"This is your token" }}
Create a beneficiary
Make a POST call to the Create Merchant Beneficiary API to create your beneficiary
Make a POST call to the Create Merchant Beneficiary API to create your beneficiary. See an example of the payload you need to encrypt and send in order to create a beneficiary
The encrypted JSON body for the request can be found in the Postman link.
You’d need to pass, as header the x-auth-token. This can be obtained from your merchant dashboard → Settings → Generate API keys → Merchant public key.
Make a POST call to the Create Quote API to generate your quote
POST{{env_url}}/wallet/wire/generate/quote
Make a POST call to the Create Quote API to generate your quote. See an example of the payload you need to encrypt and send in order to generate your quote.
The encrypted JSON body for the request can be found in the Postman link as well as other APIs.
You’d need to pass, as header the x-auth-token. This can be obtained from your merchant dashboard → Settings → Generate API keys → Merchant public key.
Make a POST call to the Initiate Payment API to convert your quote into an initialised payment.
See an example of the payload you need to encrypt and send in order to generate your quote.
The encrypted JSON body for the request can be found in the Postman link as well as other APIs
You’d need to pass, as header the x-auth-token. This can be obtained from your merchant dashboard → Settings → Generate API keys → Merchant public key.
Make a GET call to the Fetch All API to retrieve all your previously initiated wire payments.
The URL can be found in the Postman link well as other APIs
You’d need to pass, as header the x-auth-token. This can be obtained from your merchant dashboard → Settings → Generate API keys → Merchant public key.
Make a GET call to the Fetch by reference API to retrieve all your previously initiated wire payments.
The URL can be found in the Postman link well as other APIs
You’d need to pass the transactionReference you obtained when you initiated the payment, as a path variable.
You’d need to pass, as header the x-auth-token. This can be obtained from your merchant dashboard → Settings → Generate API keys → Merchant public key.
When you generate a quote and initiate a payment, one of the field in the response body is klashaWireStatus, here you can find all the possible cases and explanation:
PENDING: this is the status when a payment just get initialised through the API. This is not a final status.
PROCESSING: this is when Klasha is actually processing the payment itself. This is not a final status.
SUCCESSFUL: the klasha wire payment was executed successfully. Final status.
CANCELLED: The payment has been cancelled from the Klasha finance/operation team, in result of previous communication with the merchant. Final status.
FAILED: the initiated wire payments failed to be executed. Final status.
Quote expiry logic
After you proceeded generating your quote, you can now convert that quote into an initiated payment.
The initiation would be successful if the quote is NOT expired.
A quote does not expire because of time but just if the rate in our system changed.
Example
If you generate a quote on 1st Oct at 11am and at 3pm the rate changes, you can convert your quote into a initiated payment until 2:59:59pm. Right after, then the rate get updated at 3pm, you won’t be able to initiate a payment with that quote and you’d have to generate a new quote.
In case you try to initiate a payment with an expired quote, you’d have a Bad Request response with the the following body:
{"message":"Quote has expired or does not exist!","error":"QuoteNotFoundException","data":null}