serenity_technologies / gtbghana-partner-api
GTBGhana Partner API
Requires
- illuminate/cache: ^12.21
- illuminate/console: ^12.21
- illuminate/database: ^12.21
- illuminate/http: ^12.21
- illuminate/routing: ^12.21
- illuminate/support: ^12.21
Requires (Dev)
- phpunit/phpunit: ^12.3
README
A Laravel package to integrate with GTB Ghana's Partner API, allowing you to access various financial services like airtime topup, bill payments, bank transfers, and more.
Installation
You can install the package via composer:
composer require serenity_technologies/gtbghana-partner-api
Quick Setup
After installing the package, you can quickly publish all necessary files with the install command:
php artisan gtb-api:install
This command will publish:
- Configuration file to config/partner-api.php
- Migration files to
database/migrations/
- Bank model to
app/Models/
Manual Configuration
Alternatively, you can manually publish the files:
After installing the package, you need to publish the configuration file:
php artisan vendor:publish --provider="SerenityTechnologies\GtbGhana\PartnerApi\PartnerApiServiceProvider" --tag="config"
This will create a config/partner-api.php file. You can also set your configuration values in your .env
file:
GTB_PARTNER_API_ENV=live
GTB_PARTNER_SECRET_KEY=your_secret_key_here
GTB_PARTNER_MERCHANT_ID=your_merchant_id_here
GTB_PARTNER_MERCHANT_KEY=your_merchant_key_here
Database Setup
To use the bank database feature, you need to run the migrations:
php artisan vendor:publish --provider="SerenityTechnologies\GtbGhana\PartnerApi\PartnerApiServiceProvider" --tag="migrations"
php artisan migrate
If you want to customize the Bank model, you can publish it to your application:
php artisan vendor:publish --provider="SerenityTechnologies\GtbGhana\PartnerApi\PartnerApiServiceProvider" --tag="models"
Configuration Options
GTB_PARTNER_API_ENV
: Set to eithertest
orlive
(default:test
)GTB_PARTNER_SECRET_KEY
: Your secret key for generating secure hashesGTB_PARTNER_MERCHANT_ID
: Your merchant ID for API authenticationGTB_PARTNER_MERCHANT_KEY
: Your merchant key for API authentication
Usage
With Facade (Recommended)
First, make sure to import the facade:
use SerenityTechnologies\GtbGhana\PartnerApi\Facades\PartnerApi;
Get Available Services
This api call returns a list of services available on Partner API
To make a request to the Partner API, you can use the PartnerApi
facade:
Then, you can use the facade to make requests to the Partner API:
$response = PartnerApi::getServices('2022011800004');
or
$response = PartnerApi::getServices(uniquePartnerTransId());
or
$response = PartnerApi::getServices(timeBasedUniqueInt());
Query Customer Details
This api call allows you to lookup or verify customer details on a service on Partner API
To query customer details, you can use the PartnerApi
facade:
Query Definitions
Parameter | Required | Details |
---|---|---|
PartnerTransId | YES | Unique Id or reference for request Type: Numeric Max length 20. |
ServiceName | YES | Service Name of the service being accessed. (Found in response of the services endpoint) |
ServiceNumber | YES | The account number / identifier of service being verified Eg. Bank account Number, Mobile Money Wallet Number, Student ID. |
SecondaryServiceNumber | NO | Required for specific Services that need extra data for verification. eg. For Bank Transfer: ServiceNumber is the account number, SecondaryServiceNumber is the bank code as specified in the banks list ( to get banks list, use the services endpoint with banks as service name) |
$response = PartnerApi::query(
'2022011800007851', // PartnerTransId
'banktrf', // ServiceName
'0013014480189501', // ServiceNumber
'300312'
); // SecondaryServiceNumber (optional) );
Make a Payment
This api call allows you to pay for a service or complete a merchant transaction on Partner API
To make a payment, you can use the PartnerApi
facade:
Parameter | Required | Details |
---|---|---|
PartnerTransId | YES | Unique Id or reference for request Type: Numeric Max length 20. |
CallbackURL | YES | a URI the API will send response payload to on completion of request |
SecureHash | YES | An HMACSHA256 hash of some of the parameters in the request. Below are the required parameters and the order they should be concatenated. _ServiceName + ServiceNumber+ SecondaryServiceNumber+Amount+Remarks+PartnerTransId_ key for hashing will be provided as part of your credentials. |
ServiceName | YES | Service Name of the service being accessed. (Found in response of the services endpoint) |
ServiceNumber | YES | The account number / identifier of service. Eg. Bank account Number, Mobile Money Wallet Number, Student ID. |
SecondaryServiceNumber | NO | Required for specific Services that need extra data for payment. Eg. Bank Transfer using GIP and NRT require this field. NOTE Bank Transfer (GIP) uses the GIP bank code as specified in the banks list ( to get banks list, use the services endpoint with banks as service name). Bank Transfer (NRT) uses the bank sort codes provided by BOG. If GIP Code is provided for NRT transactions, the main sort code of the receiving bank is used. BOG Sort Codes |
Amount | YES | Amount to be paid |
Remarks | YES | Narration/Remarks of transaction |
PaidBy | YES | Name of Person making the transaction |
PayeeName | NO | Name of Person receiving the transaction |
$response = PartnerApi::pay(
'20220118000556', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'banktrf', // ServiceName
'201113000110', // ServiceNumber
'0.10', // Amount
'credit account', // Remarks
'Benedicta Ghansah', // PaidBy
'300322', // SecondaryServiceNumber (optional)
'Mary-Ann Edem Afeku' // PayeeName (optional)
);
Check Transaction Status
$response = PartnerApi::getStatus('202201140008');
Get List of Banks
To get a list of banks, you can use the PartnerApi
facade:
$response = PartnerApi::getBanks('2022011800004');
Verify Account Details
Before making transfers, you can verify account details to ensure they exist and match expected names:
// Verify bank account details
$verification = PartnerApi::verifyBankAccount(
'20220118000556', // PartnerTransId
'0013014480189501', // Account Number
'300312', // Bank Code
'John Doe' // Expected Account Name (optional)
);
if ($verification['verified']) {
echo "Account verified: " . $verification['account_name'];
} else {
echo "Verification failed: " . $verification['message'];
}
Without Facade
You can also resolve the service from the container:
$partnerApi = app('partner-api');
// Or using the service container directly
$partnerApi = app(SerenityTechnologies\GtbGhana\PartnerApi\PartnerAPI::class);
// Then use any of the methods
$response = $partnerApi->getServices('2022011800004');
Available Methods
Method | Description |
---|---|
getServices(string $partnerTransId) | Get a list of all available services |
query(string $partnerTransId, string $serviceName, string $serviceNumber, string $secondaryServiceNumber = '') | Query customer details for a specific service |
pay(string $partnerTransId, string $callbackUrl, string $serviceName, string $serviceNumber, string $amount, string $remarks, string $paidBy, string $secondaryServiceNumber = '', string $payeeName = '') | Make a payment for a service |
getStatus(string $partnerTransId) | Check the status of a transaction |
getBanks(string $partnerTransId) | Get a list of all supported banks |
bankTransfer(string $partnerTransId, string $callbackUrl, string $accountNumber, string $amount, string $remarks, string $paidBy, string $bankCode = '', string $payeeName = '') | Make a bank transfer |
creditWallet(string $partnerTransId, string $callbackUrl, string $walletNumber, string $amount, string $remarks, string $paidBy, string $payeeName = '') | Credit a wallet |
debitWallet(string $partnerTransId, string $callbackUrl, string $walletNumber, string $amount, string $remarks, string $paidBy, string $payeeName = '') | Debit a wallet |
verifyBankAccount(string $partnerTransId, string $accountNumber, string $bankCode, string $expectedAccountName = null) | Verify bank account details |
verifyWallet(string $partnerTransId, string $walletNumber, string $expectedAccountName = null) | Verify wallet details |
PaymentResponse Methods
When working with verified transactions, the PaymentResponse object includes additional methods for accessing verification data:
Method | Description |
---|---|
wasVerified() | Check if verification was performed |
isVerified() | Check if verification was successful |
getVerificationData() | Get the complete verification data array |
Wallet Services Details
Make a Bank Transfer
Bank Transfer (banktrf
)
- Used to transfer funds to a bank account
- Requires a bank code for the recipient's bank when using GIP
- Supports both GIP and NRT transfer methods
To make a bank transfer, you can use the bankTransfer
method:
// Standard bank transfer
$response = PartnerApi::bankTransfer(
'20220118000556', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'201113000110', // Account Number
'0.10', // Amount
'credit account', // Remarks
'Benedicta Ghansah', // PaidBy
'300322', // Bank Code (optional)
'Mary-Ann Edem Afeku' // PayeeName (optional)
);
// Verified bank transfer (automatically verifies account before transfer)
$response = PartnerApi::bankTransfer(
'20220118000556', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'201113000110', // Account Number
'0.10', // Amount
'credit account', // Remarks
'Benedicta Ghansah', // PaidBy
'300322', // Bank Code (required for verification)
'Mary-Ann Edem Afeku', // PayeeName (optional, used for name verification)
true // Verify account before transfer
);
// Access verification data from the response
if ($response->wasVerified()) {
if ($response->isVerified()) {
echo "Account verified: " . $response->getVerificationData()['account_name'];
} else {
echo "Verification failed: " . $response->getVerificationData()['message']; }
}
Credit a Wallet
Credit Wallet (CREDITWALLET
)
- Used to add funds to a mobile money wallet
- Typically used for customer refunds or top-ups
To credit a wallet, you can use the
creditWallet
method:
// Standard wallet credit
$response = PartnerApi::creditWallet(
'20220118000557', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'0241234567', // Wallet Number
'50.00', // Amount
'wallet credit', // Remarks
'John Doe', // PaidBy
'Jane Doe' // PayeeName (optional)
);
// Verified wallet credit (automatically verifies wallet before crediting)
$response = PartnerApi::creditWallet(
'20220118000557', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'0241234567', // Wallet Number
'50.00', // Amount
'wallet credit', // Remarks
'John Doe', // PaidBy
'Jane Doe', // PayeeName (optional, used for name verification)
true // Verify wallet before crediting
);
Debit a Wallet
Debit Wallet (DEBITWALLET
)
- Used to deduct funds from a mobile money wallet
- Typically used for payments or withdrawals
To debit a wallet, you can use the debitWallet
method:
// Standard wallet debit
$response = PartnerApi::debitWallet(
'20220118000558', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'0241234567', // Wallet Number
'25.00', // Amount
'wallet debit', // Remarks
'John Doe', // PaidBy
'Jane Doe' // PayeeName (optional)
);
// Verified wallet debit (automatically verifies wallet before debiting)
$response = PartnerApi::debitWallet(
'20220118000558', // PartnerTransId
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019', // CallbackURL
'0241234567', // Wallet Number
'25.00', // Amount
'wallet debit', // Remarks
'John Doe', // PaidBy
'Jane Doe', // PayeeName (optional, used for name verification)
true // Verify wallet before debiting
);
Working with Responses
All methods return response objects that provide helpful methods for working with the API responses:
// Get services
$response = PartnerApi::getServices('2022011800004');
// Check if request was successful
if ($response->isSuccessful()) {
// Get the services data
$services = $response->getServices();
// Find a specific service
$bankTransferService = $response->getServiceByName('banktrf');
}
// Make a payment
$paymentResponse = PartnerApi::bankTransfer(
'20220118000556',
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019',
'201113000110',
'0.10',
'credit account',
'Benedicta Ghansah',
'300322'
);
// Check payment status
if ($paymentResponse->isSuccessful()) {
echo "Transaction completed successfully";
} elseif ($paymentResponse->isPending()) {
echo "Transaction is pending";
} elseif ($paymentResponse->isFailed()) {
echo "Transaction failed: " . $paymentResponse->getMessage();
}
// Get transaction reference
$transactionRef = $paymentResponse->getTransactionReference();
Error Handling
The package will throw an Illuminate\Http\Client\ConnectionException
if there are network issues or if the API is unreachable. You should wrap your calls in try-catch blocks:
use Illuminate\Http\Client\ConnectionException;
use SerenityTechnologies\GtbGhana\PartnerApi\Facades\PartnerApi;
try {
$response = PartnerApi::getServices('2022011800004');
} catch (ConnectionException $e) {
// Handle connection error
Log::error('Failed to connect to GTB Partner API: ' . $e->getMessage());
}
For verification errors, the package will throw exceptions when using automatic verification:
use SerenityTechnologies\GtbGhana\PartnerApi\Facades\PartnerApi;
try {
// This will throw an exception if verification fails
$response = PartnerApi::bankTransfer(
'20220118000556',
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019',
'201113000110',
'0.10',
'credit account',
'Benedicta Ghansah',
'300322',
'Expected Name',
true // Enable verification
);
} catch (Exception $e) {
echo "Transfer failed: " . $e->getMessage();
}
Available Services
Based on the API documentation, the following services are available:
Airtime
- Service Name:
airtime
- Description: Airtime Topup
- Service Name:
Utilities
- Service Name:
dstv
- DSTV - Service Name:
gotv
- GOTV - Service Name:
gwcl
- Ghana Water Payment - Service Name:
ecg
- ECG Postpaid Payment - Service Name:
box_office
- BOX OFFICE
- Service Name:
Investment/Pensions
- Service Name:
mfund
- DATABANK MFUND - Service Name:
epack
- DATABANK EPACK - Service Name:
bfund
- DATABANK BFUND
- Service Name:
Education
- Service Name:
sltf
- STUDENT LOAN TRUST FUND
- Service Name:
Transfers
- Service Name:
banktrf
- Bank Transfer - Service Name:
CREDITWALLET
- Credit Wallet - Service Name:
DEBITWALLET
- Debit Wallet
- Service Name:
Account Verification
The package includes robust account verification features to help prevent sending money to incorrect accounts:
Name Matching
The verification system includes intelligent name matching that can handle:
- Case differences
- Extra whitespace
- Name abbreviations
- Minor spelling variations
- Partial name matches
Verification Process
- Account/Wallet Lookup: The system first queries the API to verify the account exists
- Name Comparison: If an expected name is provided, it's compared with the returned name
Match Analysis: The system uses multiple techniques to determine if names match:
- Direct comparison
- Partial matching
- Word-by-word comparison
- Levenshtein distance for minor character differences
Manual Verification
You can manually verify accounts before making transfers:
// Verify a bank account
$verification = PartnerApi::verifyBankAccount(
'20220118000556', // PartnerTransId
'0013014480189501', // Account Number
'300312', // Bank Code
'John Doe' // Expected Account Name
);
if ($verification['verified']) {
// Account is verified, proceed with transfer
$transfer = PartnerApi::bankTransfer(/* parameters */);
} else {
// Handle verification failure
echo "Verification failed: " . $verification['message'];
}
Automatic Verification
You can enable automatic verification during transfers by setting the verify parameter to true:
// This will automatically verify before transferring
$response = PartnerApi::bankTransfer(
'20220118000556',
'https://webhook.site/4c4d2ec6-542f-45fe-b555-6bfbc51fd019',
'201113000110',
'0.10',
'credit account',
'Benedicta Ghansah',
'300322', // Required for verification
'Expected Name', // Used for name verification
true // Enable automatic verification
);
Caching
This package now includes caching mechanisms to reduce the number of calls to the GTBank API, improving performance significantly.
Configuration
You can configure the cache TTL in your partner-api.php config file:
'cache_ttl' => 30 // Cache TTL in minutes
Cached Methods
verifyBankAccount()
- Caches bank account verification resultsverifyWallet()
- Caches wallet verification resultsverifyAccount()
inBankTransferService
- Caches bank transfer verification results- Wallet verification in
CreditWalletService
andDebitWalletService
Cache Management
You can clear specific caches using these methods:
clearBankVerificationCache(string $accountNumber, string $bankCode)
clearWalletVerificationCache(string $serviceName, string $walletNumber)
clearBankVerificationResultCache(string $accountNumber, string $bankCode, ?string $expectedAccountName = null)
clearWalletVerificationResultCache(string $serviceName, string $walletNumber, ?string $expectedAccountName = null)
To force a refresh of cached data, use the forceRefresh
parameter in verification methods.
Callback Handling
The package includes a comprehensive callback handling system to process incoming notifications from the GTB Ghana Partner API. These callbacks are sent to your application when transactions are completed, failed, or change status.
Setting up Callback Routes
To handle callbacks, you need to set up routes in your Laravel application. You can either use the provided controller or create your own:
// In routes/web.php or routes/api.php
use SerenityTechnologies\GtbGhana\PartnerApi\Http\Controllers\CallbackController;
Route::post('/gtb-api/callback', [CallbackController::class, 'handleCallback']);
Route::post('/gtb-api/callback/bank-transfer', [CallbackController::class, 'handleBankTransferCallback']);
Route::post('/gtb-api/callback/wallet', [CallbackController::class, 'handleWalletCallback']);
How Callbacks Work
When you initiate a transaction with the GTB API, you provide a CallbackURL. When the transaction status changes, GTB sends a POST request to this URL with details about the transaction. The callback payload typically looks like this:
{
"SecureHash": "47ff0d9b1e7bbdaa97ba3441e76d0a308d7d23aba38882a3277bc4bb0bc30585",
"GTBTransId": "1075202201140008",
"PartnerTransId": "202201140008",
"ProviderTransId": "",
"Status": "COMPLETED",
"Message": "Transaction Successful",
"Data": null
}
Processing Callbacks
The package provides several classes to help you process these callbacks:
- BaseCallbackHandler: Abstract base class for all callback handlers
- PaymentCallbackHandler: Handles general payment callbacks
- BankTransferCallbackHandler: Handles bank transfer specific callbacks
- WalletCallbackHandler: Handles wallet operation callbacks
- CallbackManager: Routes callbacks to appropriate handlers
- CallbackController: Laravel controller for handling HTTP callbacks
Customizing Callback Handling
You can customize how callbacks are processed by extending the provided handlers:
// Create a custom handler
use SerenityTechnologies\GtbGhana\PartnerApi\Callbacks\BankTransferCallbackHandler;
class CustomBankTransferHandler extends BankTransferCallbackHandler
{
protected function handleCompletedPayment(PaymentResponse $response): array
{
// Call parent implementation
$result = parent::handleCompletedPayment($response);
// Add your custom logic here
// For example, send notification to user
// Update your database
// Trigger other business processes
return $result;
}
}
// Register your custom handler
$callbackManager = new CallbackManager();
$callbackManager->registerHandler('banktrf', CustomBankTransferHandler::class);
To register a custom callback handler in your Laravel application, you have several options: In a Service Provider (Recommended approach):
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use SerenityTechnologies\GtbGhana\PartnerApi\Services\CallbackHandlers\CallbackManager;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// Register custom callback handler
$this->app->resolving(CallbackManager::class, function ($callbackManager) {
// Register a custom handler for a specific service
$callbackManager->registerHandler('custom_service', \App\Custom\CustomCallbackHandler::class);
// Or override an existing handler
$callbackManager->registerHandler('banktrf', \App\Custom\CustomBankTransferHandler::class);
});
}
}
Callback Security
For production applications, you should verify that callbacks are genuinely coming from GTB. While the GTB API documentation doesn't specify a signature mechanism, you can implement your own verification:
// In your custom handler
protected function verifySignature(Request $request): bool
{
// Implement your signature verification logic here
// This might involve checking a shared secret or certificate
return true; // Return true if signature is valid
}
Testing Callbacks
You can test your callback handling by sending test requests to your endpoints:
curl -X POST https://yourdomain.com/gtb-api/callback \
-H "Content-Type: application/json" \
-d '{
"SecureHash": "test-hash",
"GTBTransId": "12345",
"PartnerTransId": "67890",
"Status": "COMPLETED",
"Message": "Test transaction"
}'
Testing
To run the tests:
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The GNU AFFERO GENERAL PUBLIC LICENSE. Please see License File for more information.