njoguamos / laravel-jenga
A Laravel package for setting up and interacting with Jenga V3 API.
Requires
- php: ^8.0 | ^8.1 | ^8.2 | ^8.3
- guzzlehttp/guzzle: ^7.5
- illuminate/contracts: ^9.0 | ^10.0 | ^11.0
- spatie/crypto: ^2.0
- spatie/laravel-package-tools: ^1.13.0
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.0
- nunomaduro/collision: ^6.0 | ^v7.10 | ^v8.1
- orchestra/testbench: ^7.0 | ^8.0 | ^9.0
- pestphp/pest: ^1.21 | ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- spatie/pest-plugin-test-time: ^1.1 | ^2.1
README
Jenga API wrapper for Laravel 9+
1. Why use this package
- 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.
2. Documentation
2.1 Installation
Use the Composer package manager to install this package into your Laravel project
composer require njoguamos/laravel-jenga
2.2 Update your .env
variables
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
2.3 Initialising the Package
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
2.4 Generating Bearer Token
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
2.5 Generate Bearer Token
Frequently
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(); }
2.6 Clearing Expired Token
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(); }
2.7 Generate Private and Public Keys
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.
2.8 Ensure that you are subscribed to the API services
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
.
3. Usage
3.1 Generating signature
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 ..."
3.2 Payment Gateway Checkout
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
3.3 Account services
- 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" } ] } }
3.4 Send money
- 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
3.5 Send money - IMT
- IMT Within Equity Bank
- IMT to Mobile Wallets
- IMT Pesalink - To Bank Account
- IMT Pesalink - To Bank Mobile
3.6 Receive money
- Receive Payments - Bill Payments
- Receive Payments - Merchant Payments
- Bill Validation
3.6 Receive money queries
- Get All EazzyPay Merchants
- Query Transaction Details
- Get All Billers
3.8 Airtime
- Purchase Airtime
3.9 Forex rates
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
3.10 ID Search & Verification
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": "" } } } }
3.11 MPGS direct integration
- MPGS Validate Payment
- MPGS Authenticate Payment
- MPGS Authorize Payment
- MPGS Query Payment
- MPGS Refund Payment
4. Testing
composer test
5. Changelog
Please see RELEASES for more information what has changed recently.
6. Contributing
Please see CONTRIBUTING for details.
7. Security
If you discover any security related issues, please email njoguamos@gmail.com instead of using the issue tracker.
8. Credits
9. License
The MIT License (MIT). Please see License File for more information.