serenity_technologies/gtbghana-partner-api

1.4.0 2025-10-04 01:03 UTC

README

Latest Version on Packagist Total Downloads

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 either test or live (default: test)
  • GTB_PARTNER_SECRET_KEY: Your secret key for generating secure hashes
  • GTB_PARTNER_MERCHANT_ID: Your merchant ID for API authentication
  • GTB_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
ParameterRequiredDetails
PartnerTransIdYESUnique Id or reference for request
Type: Numeric
Max length 20.
ServiceNameYESService Name of the service being accessed. (Found in response of the services endpoint)
ServiceNumberYESThe account number / identifier of service being verified
Eg. Bank account Number, Mobile Money Wallet Number, Student ID.
SecondaryServiceNumberNORequired 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:

ParameterRequiredDetails
PartnerTransIdYESUnique Id or reference for request
Type: Numeric
Max length 20.
CallbackURLYESa URI the API will send response payload to on completion of request
SecureHashYESAn 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.
ServiceNameYESService Name of the service being accessed. (Found in response of the services endpoint)
ServiceNumberYESThe account number / identifier of service.
Eg. Bank account Number, Mobile Money Wallet Number, Student ID.
SecondaryServiceNumberNORequired 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
AmountYESAmount to be paid
RemarksYESNarration/Remarks of transaction
PaidByYESName of Person making the transaction
PayeeNameNOName 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

MethodDescription
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:

MethodDescription
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:

  1. Airtime

    • Service Name: airtime
    • Description: Airtime Topup
  2. 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
  3. Investment/Pensions

    • Service Name: mfund - DATABANK MFUND
    • Service Name: epack - DATABANK EPACK
    • Service Name: bfund - DATABANK BFUND
  4. Education

    • Service Name: sltf - STUDENT LOAN TRUST FUND
  5. Transfers

    • Service Name: banktrf - Bank Transfer
    • Service Name: CREDITWALLET - Credit Wallet
    • Service Name: DEBITWALLET - Debit Wallet

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

  1. Account/Wallet Lookup: The system first queries the API to verify the account exists
  2. Name Comparison: If an expected name is provided, it's compared with the returned name
  3. 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 results
  • verifyWallet() - Caches wallet verification results
  • verifyAccount() in BankTransferService - Caches bank transfer verification results
  • Wallet verification in CreditWalletService and DebitWalletService

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:

  1. BaseCallbackHandler: Abstract base class for all callback handlers
  2. PaymentCallbackHandler: Handles general payment callbacks
  3. BankTransferCallbackHandler: Handles bank transfer specific callbacks
  4. WalletCallbackHandler: Handles wallet operation callbacks
  5. CallbackManager: Routes callbacks to appropriate handlers
  6. 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.