- To provide a way of generating jenga api
access_token
after a give period e.g every 15 minutes - To provide a fluent way of generating jenga api key pair of
private key
andpublic key
- To automate generation of jenga api
Bearer Token
- Offer a seamless gateway to interacting with Jenga API
Info Ready to get started? I have prepared a playground which you can clone and get started. It will help you test your crendentials while showinf you how to integrate this package with your laravel application.
Use the Composer package manager to install this package into your Laravel project
composer require njoguamos/laravel-jenga
This package assumes that you have a JengaHQ account, and that you have Api Key
, Merchant Code
and Consumer Secret
(from Jenga)(https://developer.jengaapi.io/docs/developer-quickstart).
Copy the respective keys and place them in the .env
as show in the example below.
JENGA_LIVE_MODE=false
JENGA_MERCHANT_CODE=
JENGA_API_KEY=
JENGA_CONSUMER_SECRET=
# Optional
JENGA_DEFAULT_ACC=
JENGA_DEFAULT_WALLET=
JENGA_COUNTRY_CODE=
Note For
JENGA_LIVE_MODE
usefalse
when testing andtrue
when running live transactions
You must run install command that will publish the jenga.php
config file and create_jenga_tokens
migration
php artisan jenga:install
Note For security reasons,
access_token
andrefresh_token
will be encrypted using youapplication key
. You can learn more about encryption from Laravel documentation
You can go ahead and migrate the database.
php artisan migrate
Once you have valid credentials, run the following command.
php artisan jenga:auth
This command will get an access_token
token from Jenga API and add them into a new record on jenga
table.
This command may fail:
- When you are not connected to the internet
- When
Api Key
orConsumer Secret
orMerchant
is/are invalid - There is a problem with jenga api endpoint
The generated access_token
expires after a particular period usually after one hour
. To generate a new access_token
automatically, schedule the jenga:auth
command in the console kernel. The schedule time should be less than 15 minutes.
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
# ...
$schedule->command(command: 'jenga:auth')->everyThirtyMinutes();
}
To periodically deleted expired Bearer Token
, schedule model:prune
command in the console kernel.
// app/Console/Kernel.php
use NjoguAmos\Jenga\Models\JengaToken;
protected function schedule(Schedule $schedule)
{
# ...
$schedule->command(command: 'model:prune', parameters: [
'--model' => [JengaToken::class],
])->everyFiveMinutes();
}
To generate a key pair of private and public key, run the following command.
php artisan jenga:keys
This command will create a jenga.key
and jenga.pub.key
file in your laravel application storage folder. You can customise the directory using JENGA_KEYS_PATH
variable.
# ./yourapplication/storage/jenga.key
-----BEGIN PRIVATE KEY-----
<private key here>
-----END RSA PRIVATE KEY-----
# ./yourapplication/storage/jenga.pub.key
-----BEGIN PUBLIC KEY-----
<public key here>
-----END PUBLIC KEY-----
You may use --force
flag to replace existing keys. The default key size is 4096
Warning The generated keys files SHOULD NEVER be kept in source control. Make sure you add them to you gitignore file.
Note Extensions like
bcmath
,gmp
,libsodium
andopenssl
are required when generating they keys.
If you attempt to access the API and you get Not Authorized to access the API
, confirm that your account has subscribed to the respective service you are trying to access. You can do so by going to the JengaAPI Settings -> Subscriptions, then subscribe
or unsubscribe
.
To generate a signature manually, call `getSignature` method in `JengaSignature` class using the data you want to sign.
Info The data is signed in the order it is passed.
use NjoguAmos\Jenga\JengaSignature;
$data = [
"accountId" => "0011547896523",
"countryCode" => "KE",
"date" => "2022-01-01"
];
$signature = (new JengaSignature(data: $data))->getSignature();
// This will return signature for "0011547896523KE2022-01-01'
// "NCgbapJwPIt+203eyADfPSvPX6uWPPVwMbFdrW+3XoT7oQC2+IaS6srFIGGdMrwrTH ..."
To use the payment gateway, prepare the data using the backend and pass to the browser form.
<?php
use NjoguAmos\Jenga\Models\JengaToken;
return view(view: 'check-out', data: [
'token' => JengaToken::query()->latest()->first()?->access_token, // Token generated via auth API
'checkOutUrl' => config(key: 'jenga.checkout'), // Check our url. Don't modify
'merchantCode' => config(key: 'jenga.merchant'), // The merchant code provided at registration.
'wallet' => config(key: 'jenga.wallet'), // The wallet to be used for the transaction
'orderAmount' => '', // The value of the transaction
'orderReference' => '', // The merchant order reference. Min8 characters and It has to be alphanumeric
'productType' => '', // Product category
'productDescription' => '' // A brief summary of the product. Max 200 characters. Alphanumeric only.,
'customerFirstName' => '', // The customer's First Name
'customerLastName' => '', // The customer's Last Name
'customerEmail' => '', // Customer email
'customerPhone' => '', // Customer phone number e.g 700325008
'countryCode' => config(key: 'jenga.country'), // Country code
'customerPostalCodeZip' => '', // Customer’s postal code
'customerAddress' => '', // Customer’s address
'callbackUrl' => '' // Merchant callback url
'extraData' => '', // This data will be echoed back during callback url
]);
Configure your frontend form.
<form id="submitcheckout" action="{{ $checkOutUrl }}" method="POST">
@csrf
<input type="hidden" id="token" name="token" value="{{ $token }}">
<input type="hidden" id="merchantCode" name="merchantCode" value="{{ $merchantCode }}">
<input type="hidden" id="wallet" name="wallet" value="{{ $wallet }}">
<input type="hidden" id="orderAmount" name="orderAmount" autofocus value="{{ $orderAmount }}">
<input type="hidden" id="orderReference" name="orderReference" value="{{ $orderReference }}">
<input type="hidden" id="productType" name="productType" value="{{ $productType }}">
<input type="hidden" id="productDescription" name="productDescription" value="{{ $productDescription }}">
<input type="hidden" id="customerFirstName" name="customerFirstName" value="{{ $customerFirstName }}">
<input type="hidden" id="customerLastName" name="customerLastName" value="{{ $customerLastName }}">
<input type="hidden" id="customerEmail" name="customerEmail" value="{{ $customerEmail }}">
<input type="hidden" id="customerPhone" name="customerPhone" value="{{ $customerPhone }}">
<input type="hidden" id="countryCode" name="countryCode" value="{{ $countryCode }}">
<input type="hidden" id="customerPostalCodeZip" name="customerPostalCodeZip" value="{{ $customerPostalCodeZip }}">
<input type="hidden" id="customerAddress" name="customerAddress" value="{{ $customerAddress }}">
<input type="hidden" id="callbackUrl" name="callbackUrl" value="{{ $callbackUrl }}">
<input type="hidden" id="extraData" name="extraData" value="{{ $extraData }}">
<button type="submit">Subscribe</button>
</form>
A successful response should look like like this.
{
"responseStatus": "true",
"transactionStatus": "SUCCESS",
"orderReference": "226151",
"extraData": "pmQgkBuepzSaiNdRh1rghq2ldPzdq0gQ",
"transactionReference": "RBF2PJILMC",
"transactionDate": "Wed Feb 15 2023",
"transactionAmount": "1",
"transactionCurrency": "KES",
"message": "Transaction completed successfully",
"paymentChannel": "MOBILE",
"orderItems": "undefined",
"secureResponse": "320396408033f540f6c9bcc426d6e3d1206d584984d72da4017cace6337e4e10d1729ed98ee326d5d0c403c298c789a9YhubIYK7B+WE0Bij2XWxn3iOL+MAyfWU3RruohGTfdB9t5j9lmNTqcmIeY8RL5M\/xenV+hIKvdweVIyzqX333PFgFGd4wV3+LwQpx9LGCxDsj0NFC+ouRdFZ0VADWbnCbZbHlBSO8kxIP8urAXuP1JM21DhTPqzbs8TB763IYmqVHCicmalkDdegDwo+BDQ0HJaf0ia3FektL2v\/Hj3nM9RkmNyA59VH0p5gUhRUhioMxNdFjai9TKZ3CwOZ6O75h5sc7L+Z8w3ucpvYOtuaTV5fxKIfSPkfi3mIvuGQEw7QDJeu3333BRDHt3XobtxZv9GW9\/eey1dRnNW9zplMBxQupJAn98fSKSC0VkSByqt5KKibQFAZxCOYjcvIJ0kea8MkBRwA\/z1YRdeQ+TmQmdLFoe3V3jWyE5SsN6EPU4k="
}
A customer should also receive an sms like this.
Your transaction of Kshs. 1.00 has successfully been
credited to Finserve Africa Limited-E Commerce Collection
Account with Ref. Number INVDRT and MPESA Tran Ref
RBF2PJILMC. Thank you
- Account Balance
- Account MINI Statement
- Account Full Statement
- Opening and Closing Account Balance
3.3.5 Account Inquiry - Bank Accounts
To get account details, call the AccountInquiry
and pass the account number and country code. If no parameters passed, the default account and country configured in config will be used
use NjoguAmos\Jenga\Api\AccountInquiry;
$search = (new AccountInquiry())
->search(
countryCode: $data['countryCode'],
accountNumber: $data['accountNumber']
);
The response should look like this
{
"status": true,
"code": 0,
"message": "success",
"data": {
"account": {
"branchCode": "145",
"number": "1450160649886",
"currency": "KES",
"status": "Active"
},
"customer": [
{
"name": "CATHERINE MURANDITSI MUKABWA",
"id": "54307789658",
"type": "Retail"
}
]
}
}
- Within Equity Bank
- To Mobile Wallets
- Real Time Gross Settlement (RTGS)
- Society for Worldwide Interbank Financial Telecommunication (SWIFT)
- Pesalink - To Bank Account
- Pesalink - To Mobile Number
- IMT Within Equity Bank
- IMT to Mobile Wallets
- IMT Pesalink - To Bank Account
- IMT Pesalink - To Bank Mobile
- Receive Payments - Bill Payments
- Receive Payments - Merchant Payments
- Bill Validation
- Get All EazzyPay Merchants
- Query Transaction Details
- Get All Billers
- Purchase Airtime
Get the Equity Bank daily currency conversion rate for major currencies.
use NjoguAmos\Jenga\Api\ForexExchangeRates;
use NjoguAmos\Jenga\Dto\ExchangeRatesDto;
// Convert 1042 USD into KES using Equity Bank Kenya rate.
$data = new ExchangeRatesDto(
amount: 1042,
currencyCode: "USD",
toCurrency: "KES",
accountNumber: '1450160649886',
countryCode: 'KE'
);
$rates = (new ForexExchangeRates())->convert($data);
Example success response
{
"status": true,
"code": 0,
"message": "success",
"data": {
"convertedAmount": 127749.2,
"rate": 122.6,
"fromAmount": 1042,
"rateCode": "TTB"
}
}
Refer to Forex API Reference
Supported currencies
Code | Name |
---|---|
KES | Kenyan Shilling |
YNG | Korean Yang |
SSP | South Sudanese Pound |
RWF | Rwandan Franc |
JPY | Japanese Yen |
USD | US Dollar |
GBP | British Pound Sterling |
EURO | European Union (EU) |
ZAR | South African Rand |
RUP | Russian Ruble |
Query the various registrar of persons in the various countries in East Africa.
use NjoguAmos\Jenga\Api\IDVerification;
use NjoguAmos\Jenga\Dto\IDVerificationDto;
$data = new IDVerificationDto(
documentNumber: '555555',
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '20 June 1985',
documentType: 'ID',
countryCode: 'KE',
);
$search = (new IDVerification())->search($data);
Example success response
{
"status": true,
"code": 0,
"message": "success",
"data": {
"identity": {
"customer": {
"firstName": "JOHN",
"lastName": "DOE",
"occupation": "",
"gender": "M",
"nationality": "Kenyan",
"deathDate": "",
"fullName": "JOHN JOHN DOE DOE",
"middlename": "JOHN DOE",
"ShortName": "JOHN",
"birthCityName": "",
"birthDate": "1985-06-20T12:00:00",
"faceImage": ""
},
"documentType": "NATIONAL ID",
"documentNumber": "555555",
"documentSerialNumber": "55555555555",
"documentIssueDate": "2011-12-08T12:00:00",
"documentExpirationDate": "",
"IssuedBy": "REPUBLIC OF KENYA",
"additionalIdentityDetails": [
{
"documentType": "",
"documentNumber": "",
"issuedBy": ""
}
],
"address": {
"locationName": "",
"districtName": "",
"subLocationName": "",
"provinceName": "",
"villageName": ""
}
}
}
}
- MPGS Validate Payment
- MPGS Authenticate Payment
- MPGS Authorize Payment
- MPGS Query Payment
- MPGS Refund Payment
composer test
Please see RELEASES for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email njoguamos@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.