LogoLogo
  • Welcome!
  • Integrating Klasha
    • Getting Started
    • Prerequisites
    • Integration Checklist
    • Wrap Up
  • Overview
    • Introduction
    • Parameters
    • Token Generation
    • Errors
    • Countries & Payment Methods
  • Accepting Payments
    • Test Payments
    • Payments API
      • Mobile money
      • USSD
    • Payment Link
      • Dashboard
      • Payment Link API
    • Klasha Inline
    • HTML Checkout
  • PLUGINS AND SDKS
    • Plugins
    • Mobile SDKs
    • Web SDKs
  • MISC
    • Transaction Status
    • Webhook
    • API Status
  • Features
    • One-time Payments
    • Recurrent Payment
  • Transfers
    • Payout
      • ZAR Payout(new encryption)
      • KES Payout(new encryption)
      • ZMW Payout(new encryption)
      • TZS Payout(new encryption)
      • CNY Payout(new encryption)
    • Klasha Wire API
    • Swap API
    • Currency Coverage
  • Bank Account Collection
    • Virtual Account Creation
    • VA balance and statement
    • Business Identification Service
Powered by GitBook
On this page
  • Summary
  • Integration step
  • Make a POST call to the Create Merchant Beneficiary API to create your beneficiary
  • Make a POST call to the Create Quote API to generate your quote
  • Make a POST call to the Initiate Payment API
  • Make a GET call to the Fetch All API
  • Fetch by reference API to retrieve all your previously initiated wire payments.
  1. Transfers

Klasha Wire API

PreviousCNY Payout(new encryption)NextSwap API

Last updated 6 months ago

Summary

Give merchants the ability to send out funds from their collection balance via API using our internal Klasha rates.

Coverage

See all available currencies

You can transfer money in four easy steps:

  1. Generate a bearer token

  2. Create a beneficiary

  3. Generate a quote for the beneficiary

  4. Initiate a payment

Before you begin!

  • to the Postman collection

  • Find your keys on the Klasha Dashboard → Settings → Generate API Keys ()

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.

public static String encryptCBC(String stringToEncrypt, String encryptionkey) {
    try {
        SecureRandom sr = new SecureRandom();
        byte[] salt = new byte[8];
        sr.nextBytes(salt);
        final byte[][] 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, new SecretKeySpec(keyAndIV[0], "AES"), new IvParameterSpec(keyAndIV[1]));
        byte[] encryptedData = cipher.doFinal(stringToEncrypt.getBytes(StandardCharsets.UTF_8));
        byte[] prefixAndSaltAndEncryptedData = new byte[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);
        return Base64.getEncoder().encodeToString(prefixAndSaltAndEncryptedData);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}




public static byte[][] 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 = new byte[requiredLength];
    int generatedLength = 0;

    try {
        md.reset();

        // Repeat process until sufficient data has been generated
        while (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 rounds
            for (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 arrays
        byte[][] result = new byte[2][];
        result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);
        if (ivLength > 0)
            result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);

        return result;

    } catch (DigestException e) {
        throw new RuntimeException(e);

    } finally {
        // Clean out temporary data
        Arrays.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

POST {{env_url}}/merchant/merchantbeneficiary/create

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

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.

Headers

Name
Value

Authorization*

Bearer {{token}}

x-auth-token

MERCHANT PUBLIC KEY

Request Body

Name
Type
Description

accountNumber*

1234567890

bankName*

Bank Name

bankAddress*

Bank Address

beneficiaryName*

Beneficiary Name

beneficiaryAddress*

Beneficiary Address

country*

Country Name

countryCode*

US

currency*

USD

phone*

phone number

swiftCode*

SWFT1234

narration*

clothes

email*

your.email@example.com

routingNumber*

12345

iban*

045

{
  "message": "encrypted request"
}
Response
{
    "message": "success",
    "error": null,
    "data": {
        "accountNumber": "1234567890",
        "bankName": "Bank Name",
        "token": "d95a6930-233f-4699-a11f-0d1337a34cce",
        "beneficiaryName": "Beneficiary Name",
        "id": 345
    }
}

Generate a quote

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.

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.

Headers

Name
Value

Authorization

Bearer {{token}}

x-auth-token

MERCHANT PUBLIC KEY

Request Body

Name
Type
Description

sourceCurrency*

NGN

destinationCurrency*

USD

beneficiary*

beneficiar87954c4f-736a-4e09-b588-76ab9c13bafeyId

destinationAmount*

1000.00

{
  "message": "encrypted request"
}
Response
{
    "message": "success",
    "error": null,
    "data": {
        "id": 1,
        "sourceCurrency": "NGN",
        "sourceAmount": 575338.5,
        "destinationCurrency": "USD",
        "destinationAmount": 1000,
        "destinationFees": 27.5,
        "sourceFees": 15821.808749999998,
        "rate": 575.3385,
        "klashaWireStatus": "PENDING",
        "merchantBeneficiary": "87954c4f-736a-4e09-b588-76ab9c13bafe",
        "quoteToken": "842dcd42-8f95-4a3b-a5f3-07a3d0416119",
        "createdAt": "2023-10-09T13:11:29.478",
        "updatedAt": "2023-10-09T13:11:29.478"
    }
}

Initiate a payment

Make a POST call to the Initiate Payment API

POST {{env_url}}/wallet/wire/initiate

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.

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.

Headers

Name
Value

Authorization

Bearer {{token}}

x-auth-token

MERCHANT PUBLIC KEY

Request Body

Name
Type
Description

quoteToken*

842dcd42-8f95-4a3b-a5f3-07a3d0416119

beneficiary*

87954c4f-736a-4e09-b588-76ab9c13bafe

narration*

School fees

invoiceUrl*

www.invoiceURL.com

{
  "message": "encrypted request"
}
Response
{
    "message": "success",
    "error": null,
    "data": {
        "id": 5,
        "sourceCurrency": "NGN",
        "sourceAmount": 575338.5,
        "destinationCurrency": "USD",
        "destinationAmount": 1000,
        "narration": "School fees",
        "destinationFees": 27.5,
        "sourceFees": 15821.81,
        "rate": 575.3385,
        "klashaWireStatus": "PENDING",
        "transactionReference": "KWire-32f1d4c6-4560-4033-8cf6-713d405ec10d",
        "merchantBeneficiary": "7ed8d2e3-8709-4202-8842-7757946ee194",
        "quoteToken": "1c8eaf0d-3490-4774-ae86-7443e4f93557",
        "createdAt": "2023-10-26T12:44:37.355",
        "updatedAt": "2023-10-26T12:45:27.243"
    }
}

Fetch all your payments

Make a GET call to the Fetch All API

GET {{env_url}}/wallet/wire/fetch/all

Make a GET call to the Fetch All API to retrieve all your previously initiated wire payments.

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.

Headers

Name
Value

Authorization

Bearer {{token}}

x-auth-token

MERCHANT PUBLIC KEY

Response
{
    "message": "success",
    "error": null,
    "data": [
         {
            "id": 46,
            "sourceCurrency": "NGN",
            "sourceAmount": 1628664.50,
            "destinationCurrency": "USD",
            "destinationAmount": 1000.00,
            "narration": "Test",
            "destinationFees": 27.50,
            "sourceFees": 44788.27,
            "rate": 0.000614,
            "klashaWireStatus": "PENDING",
            "transactionReference": "KWire-296aac06-f425-4d43-9e4c-611247959a88",
            "merchantBeneficiary": "e0595f0b-16b4-4b62-a317-fa00af40a7ec",
            "quoteToken": "71a6aff6-5c23-41e3-8b85-6918cf92ead6",
            "createdAt": "2024-07-09T19:00:52.218",
            "updatedAt": "2024-07-09T19:02:14.863"
        },
        {
            "id": 60,
            "sourceCurrency": "NGN",
            "sourceAmount": 1631321.37,
            "destinationCurrency": "USD",
            "destinationAmount": 1000.00,
            "narration": "Test",
            "destinationFees": 27.50,
            "sourceFees": 44861.34,
            "rate": 0.000613,
            "klashaWireStatus": "PENDING",
            "transactionReference": "KWire-bae3f6dc-aaec-4e6a-a963-cffe1a3899c5",
            "merchantBeneficiary": "633b70a6-da15-4bc5-b0ec-1eda041245e2",
            "quoteToken": "dbd4e976-ad5e-4555-aee5-d4afa59849c5",
            "createdAt": "2024-07-11T14:40:11.91",
            "updatedAt": "2024-07-11T14:41:29.237"
        }
     ...
    ]
}

Fetch a single payment by reference

Fetch by reference API to retrieve all your previously initiated wire payments.

GET {{env_url}}/wallet/wire/fetch/by/reference/<ref>

Make a GET call to the Fetch by reference API to retrieve all your previously initiated wire payments.

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.

Headers

Name
Value

Authorization

Bearer {{token}}

x-auth-token

MERCHANT PUBLIC KEY

Response
{
    "message": "success",
    "error": null,
    "data": {
            "id": 46,
            "sourceCurrency": "NGN",
            "sourceAmount": 1628664.50,
            "destinationCurrency": "USD",
            "destinationAmount": 1000.00,
            "narration": "Test",
            "destinationFees": 27.50,
            "sourceFees": 44788.27,
            "rate": 0.000614,
            "klashaWireStatus": "PENDING",
            "transactionReference": "KWire-296aac06-f425-4d43-9e4c-611247959a88",
            "merchantBeneficiary": "e0595f0b-16b4-4b62-a317-fa00af40a7ec",
            "quoteToken": "71a6aff6-5c23-41e3-8b85-6918cf92ead6",
            "createdAt": "2024-07-09T19:00:52.218",
            "updatedAt": "2024-07-09T19:02:14.863"
    }
}

Notes

Klasha Wire Statuses

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
}

The encrypted JSON body for the request can be found in the Postman .

The encrypted JSON body for the request can be found in the Postman as well as other APIs.

The encrypted JSON body for the request can be found in the Postman as well as other APIs

The URL can be found in the Postman well as other APIs

The URL can be found in the Postman well as other APIs

link
link
link
link
link
here
Link
here