serenity_technologies/ghana-payments

A payment gateway protocols for Ghanaian banks and payment systems

1.2.43 2025-08-12 15:38 UTC

This package is auto-updated.

Last update: 2025-10-02 23:55:25 UTC


README

myghpay.8f06666f.png

This package provides an Omnipay implementation for the MyGHPay Checkout payment gateway, allowing you to integrate Ghanaian payment methods into your Laravel application.

Features

  1. Authentication Management: The package automatically handles authentication with the MyGHPay API, including token caching for one hour to minimize authentication requests.
  2. Payment Session Creation: Create payment sessions with full support for itemized purchases.
  3. Payment Status Checking: Check the status of payment sessions at any time.
  4. Callback Handling: Process real-time payment status updates from MyGHPay.
  5. Environment Support: Works with both test and live environments.

Installation

Install the package via Composer:

composer require serenity_technologies/ghana-payments

Publish the configuration file:

php artisan vendor:publish --provider="SerenityTechnologies\GhanaPayments\GhanaPaymentsServiceProvider" --tag="config"

Configuration

Add the following environment variables to your .env file:

GHANA_PAY_MERCHANT_ID=your_merchant_username
GHANA_PAY_MERCHANT_KEY=your_merchant_password
GHANA_PAY_MERCHANT_SECRET=your_merchant_secret
GHANA_PAY_MERCHANT_URL=https://your-merchant-url.com
GHANA_PAY_CALLBACK_URL=https://your-merchant-url.com/callback

You can also configure multiple drivers by modifying the config/ghana-payments.php file:

   'default' => env('GHANA_PAY_DRIVER', 'myghpay'),
   'drivers' => [ 'myghpay' => [ 
                       'merchant_id' => env('GHANA_PAY_MERCHANT_ID'), 
                       'merchant_key' => env('GHANA_PAY_MERCHANT_KEY'), 
                       'merchant_secret' => env('GHANA_PAY_MERCHANT_SECRET'), 
                       'merchant_url' => env('GHANA_PAY_MERCHANT_URL'), 
                       'merchant_callback_url' => env('GHANA_PAY_CALLBACK_URL'), 
                       'test_mode' => env('GHANA_PAY_TEST_MODE', false), 
                   ],
                   'other_driver' => [
                       'api_key' => env('OTHER_DRIVER_API_KEY'),
                       'secret' => env('OTHER_DRIVER_SECRET'),
                       'test_mode' => env('OTHER_DRIVER_TEST_MODE', false),
                   ],
   ],

To switch between drivers, simply change the GHANA_PAY_DRIVER environment variable:

 GHANA_PAY_DRIVER=other_driver

Usage

Initialize the Gateway

use Omnipay\Omnipay;
use SerenityTechnologies\GhanaPayments\Drivers\GTBGhana\MyGHPayCheckout\MyGHPayCheckout;

$gateway = Omnipay::create(MyGHPayCheckout::class);
$gateway->setUsername(config('ghana-payments.merchant_id'));
$gateway->setPassword(config('ghana-payments.merchant_key'));
$gateway->setTestMode(true); // For testing environment

Or in Laravel, you can resolve it from the service container:

$gateway = app('ghana-payments');

Create a Payment Session

To initiate a payment, you need to create a purchase request:

$response = $gateway->purchase([
    'amount' => '100.00',
    'transactionReference' => uniqid(), // Unique transaction reference
    'callbackUrl' => route('payment.callback'), // URL for payment status updates
    'returnUrl' => route('payment.return'), // URL to redirect user after payment
    'description' => 'Order #12345', // Optional description
    'title' => 'Store Purchase', // Optional title
    'paymentItems' => [ // Optional itemized list
        [
            'name' => 'Product 1',
            'description' => 'Product 1 description',
            'amount' => '50.00',
            'quantity' => 1
        ],
        [
            'name' => 'Product 2',
            'description' => 'Product 2 description',
            'amount' => '50.00',
            'quantity' => 1
        ]
    ]
])->send();

if ($response->isSuccessful()) {
    // Payment session created successfully
    echo "Transaction ID: " . $response->getTransactionReference() . "\n";
} elseif ($response->isRedirect()) {
    // Redirect to offsite payment gateway
    $response->redirect();
} else {
    // Payment failed
    echo "Error: " . $response->getMessage();
}

You can also use the facade

 use SerenityTechnologies\GhanaPayments\Facades\GhanaPayments;
$response = GhanaPayments::purchase([
    'amount' => '100.00', 
    'transactionReference' => uniqid(), 
    'callbackUrl' => route('payment.callback'), 
    'returnUrl' => route('payment.return'), 
    'description' => 'Order #12345', // Optional description
    'title' => 'Store Purchase', // Optional title
    'paymentItems' => [ // Optional itemized list
        [
            'name' => 'Product 1',
            'description' => 'Product 1 description',
            'amount' => '50.00',
            'quantity' => 1
        ],
        [
            'name' => 'Product 2',
            'description' => 'Product 2 description',
            'amount' => '50.00',
            'quantity' => 1
        ]
    ]
    ])->send();
    
    if ($response->isSuccessful()) {
    // Payment session created successfully
    echo "Transaction ID: " . $response->getTransactionReference() . "\n";
} elseif ($response->isRedirect()) {
    // Redirect to offsite payment gateway
    $response->redirect();
} else {
    // Payment failed
    echo "Error: " . $response->getMessage();
}

Handle Callbacks

MyGHPay will send callbacks to your callbackUrl to notify you of payment status changes. You can handle these in your callback controller:

use SerenityTechnologies\GhanaPayments\Drivers\GTBGhana\MyGHPayCheckout\Messages\MyGHPayNotification;

public function handleCallback(Request $request)
{
    $notification = new MyGHPayNotification($request);
    
    $transactionReference = $notification->getTransactionReference();
    $status = $notification->getTransactionStatus();
    $message = $notification->getMessage();
    
    switch ($status) {
        case \Omnipay\Common\Message\NotificationInterface::STATUS_COMPLETED:
            // Payment was successful
            // Update your order status
            break;
        case \Omnipay\Common\Message\NotificationInterface::STATUS_PENDING:
            // Payment is pending
            // Wait for another callback
            break;
        case \Omnipay\Common\Message\NotificationInterface::STATUS_FAILED:
            // Payment failed or was cancelled
            // Update your order status accordingly
            break;
    }
    
    // Always return a 200 response to acknowledge the callback
    return response('OK', 200);
}

Check Payment Status

You can manually check the status of a payment session:

$response = $gateway->completePurchase([
    'sessionCode' => $transactionReference, // The session code from the purchase response
])->send();

if ($response->isSuccessful()) {
    // Payment completed successfully
    echo "Payment successful!";
} elseif ($response->isPending()) {
    // Payment is still pending
    echo "Payment pending";
} elseif ($response->isCancelled()) {
    // Payment was cancelled or failed
    echo "Payment failed or cancelled";
}

Testing

For testing, set the gateway to test mode:

$gateway->setTestMode(true);

The package includes a test suite that you can run to verify the functionality of the package. To run the tests, execute the following command in your terminal: php vendor/bin/phpunit

This will use the test endpoint: https://testbed.gtbghana.com/MyghpayCheckoutApi/api For production, ensure test mode is disabled (default):

$gateway->setTestMode(false);

This will use the live endpoint: https://client.myghpay.com/myghpaycheckoutapi/api

Adding a New Driver

To add a new payment driver to this package, follow these steps:

  1. Create the Driver Class

    Create a new driver class that extends SerenityTechnologies\GhanaPayments\Drivers\AbstractDriver:

         <?php 
         namespace YourNamespace\YourDriver;
         use SerenityTechnologies\GhanaPayments\Drivers\AbstractDriver; 
         use YourNamespace\YourDriver\Messages\PurchaseRequest; 
         use YourNamespace\YourDriver\Messages\CompletePurchaseRequest; 
         use YourNamespace\YourDriver\Messages\YourDriverNotification; 
            
         class YourDriverName extends AbstractDriver {
          public function getName(): string 
          { 
             return 'YourDriverName';
          } 
          public function getDefaultParameters(): array 
          { 
             return [
              'apiKey' => '', 
              'secret' => '', 
              'testMode' => false, 
              ]; 
          } 
             
          public function purchase(array $options = []): \Omnipay\Common\Message\RequestInterface 
          {
             return $this->createRequest(PurchaseRequest::class, $options);
          }
           public function completePurchase(array $options = []): \Omnipay\Common\Message\RequestInterface 
           {
             return $this->createRequest(CompletePurchaseRequest::class, $options); 
          }
          public function acceptNotification(array $options = []): \Omnipay\Common\Message\NotificationInterface 
          {
             return new YourDriverNotification();
          } 
          // Add other required methods like setUsername(), setPassword(), etc. depending on your driver's authentication requirements
         }
    
  2. Create Request Classes

    Create request classes for your driver in a Messages subdirectory:

       <?php 
       namespace YourNamespace\YourDriver\Messages; 
       use SerenityTechnologies\GhanaPayments\Drivers\AbstractRequest; 
       
       class PurchaseRequest extends AbstractRequest {
            public function getData() {
               $this->validate('amount', 'transactionReference');
               return [ 
                    'amount' => $this->getAmount(),
                     'transactionReference' => $this->getTransactionReference(),
                    // Add other required fields 
                ]; 
           }
           public function sendData($data): \Omnipay\Common\Message\ResponseInterface { 
           // Implement your API call logic here 
           $response = $this->httpClient->request('POST', $this->getEndpoint().'/payment',[
                    'Authorization' => 'Bearer ' . $this->getApiKey(), 
                    'Content-Type' => 'application/json',
                 ], json_encode($data));
           
            $responseData = json_decode((string) $response->getBody(), true);
            return $this->response = new PurchaseResponse($this, $responseData);
           }
            public function getApiKey() { 
                return $this->getParameter('apiKey');
            } 
           public function setApiKey($value) { 
                return $this->setParameter('apiKey', $value);
           }
       }
    
  3. Create Response Classes

    Create response classes for handling API responses:

         <?php 
         namespace YourNamespace\YourDriver\Messages; 
         use Omnipay\Common\Message\AbstractResponse; 
         use Omnipay\Common\Message\RedirectResponseInterface; 
            
         class PurchaseResponse extends AbstractResponse implements RedirectResponseInterface {
          public function isSuccessful(): bool 
          { 
             return isset($this->data['status']) && $this->data['status'] === 'success'; 
          }
          public function isRedirect(): bool 
          { 
             return isset($this->data['redirectUrl']); 
          }
          public function getRedirectUrl(): ?string 
          { 
             if ($this->isRedirect()) {
               return $this->data['redirectUrl'];
             }
              return null; 
          } 
          public function getTransactionReference(): ?string 
          { 
             return $this->data['transactionId'] ?? null; 
          } 
             
          public function getMessage(): ?string 
          { 
             return $this->data['message'] ?? null; 
          } 
             
          public function getRedirectMethod(): string 
          { 
             return 'GET'; 
          }
           public function getRedirectData(): ?array 
           { 
             return null; 
           } 
       }
    
  4. Create Notification Class

    Create a notification class to handle callbacks from your payment provider:

    <?php 
    namespace YourNamespace\YourDriver\Messages; 
    use Omnipay\Common\Message\AbstractRequest; 
    use Omnipay\Common\Message\NotificationInterface; 
    use Illuminate\Http\Request as HttpRequest; 
       
    class YourDriverNotification implements NotificationInterface { 
    protected mixed $data;
     protected HttpRequest $httpRequest;
    
     /**
      * Constructor
      */
     public function __construct(HttpRequest $request = null)
     {
         $this->httpRequest = $request ?: HttpRequest::createFromGlobals();
         $this->data = json_decode($this->httpRequest->getContent(), true);
     }
       
    public function getData(): mixed 
    { 
         return $this->data; 
    } 
       
    public function sendData($data): static 
    { 
         return $this; 
    } 
       
    public function getTransactionReference(): ?string 
    { 
         return $this->data['transactionId'] ?? null; 
    } 
       
    public function getTransactionStatus() {
     if (isset($this->data['status'])) {
      switch ($this->data['status']) {
          case 'completed': 
             return NotificationInterface::STATUS_COMPLETED; 
         case 'pending':
             return NotificationInterface::STATUS_PENDING; 
         case 'failed': 
             return NotificationInterface::STATUS_FAILED; 
         }
     } 
       
     return null; 
    } 
       
    public function getMessage(): ?string 
    { 
         return $this->data['message'] ?? null; 
    }
       
    }
    
  5. Update the Service Provider

    Update the GhanaPaymentsServiceProvider to register your new driver:

     public function register(): void { $this->app->singleton('ghana-payments', function ($app) { $driver = config('ghana-payments.default', 'myghpay'); $config = config('ghana-payments.drivers.' . $driver, []);
     $gateway = match($driver) {
         'myghpay' => Omnipay::create(MyGHPayCheckout::class),
         'your_driver' => Omnipay::create(YourDriver::class), // Add this line
         default => Omnipay::create(MyGHPayCheckout::class),
     };
    
     // Apply configuration to the gateway
     if ($gateway instanceof \SerenityTechnologies\GhanaPayments\Drivers\DriverInterface) {
         $gateway->setConfig($config);
     } else if ($driver === 'myghpay') {
         $gateway->setUsername($config['merchant_id'] ?? config('ghana-payments.merchant_id'));
         $gateway->setPassword($config['merchant_key'] ?? config('ghana-payments.merchant_key'));
     }
     // Add similar configuration for your driver
    
     return $gateway;
     });
     }
    
  6. Update Configuration

    Add your driver configuration to the config/ghana-payments.php file:

    'drivers' => [ 'myghpay' => [ // ... existing configuration ],
     'your_driver' => [
     'api_key' => env('YOUR_DRIVER_API_KEY'),
     'secret' => env('YOUR_DRIVER_SECRET'),
     'test_mode' => env('YOUR_DRIVER_TEST_MODE', false),
     ],
     ],
    
  7. Add Environment Variables

    Add your driver's environment variables to your .env file:

    YOUR_DRIVER_API_KEY=your_api_key
    YOUR_DRIVER_SECRET=your_secret
    YOUR_DRIVER_TEST_MODE=true
    

    Users can now switch to your driver by setting:

    GHANA_PAY_DRIVER=your_driver
    

Using the Facade

This package includes a Laravel facade for easier access to the payment gateway. You can use the facade in two ways:

  1. Automatic Aliasing (Laravel 5.5+): The package automatically registers the facade alias, so you can use it directly:

          use SerenityTechnologies\GhanaPayments\Facades\GhanaPayments;
          // Create a payment 
          $response = GhanaPayments::purchase([ 
             'amount' => '50.00', 
             'transactionReference' => uniqid(), 
             'callbackUrl' => route('payment.callback'), 
             'returnUrl' => route('payment.return'), 
             ])->send();
          // Check payment status 
          $response = GhanaPayments::completePurchase([ 'sessionCode' => $sessionCode, ])->send();
          // Handle notifications 
          $notification = GhanaPayments::acceptNotification();
          
    
  2. Manual Aliasing:

  'aliases' => [ // ... other aliases
  'GhanaPayments' => SerenityTechnologies\GhanaPayments\Facades\GhanaPayments::class, 
  ];

If you prefer to manually register the facade alias, add it to the aliases array in your config/app.php:

The facade provides access to all methods available on the payment gateway, making it easy to process payments:

Security

  • Authentication tokens are cached securely using Laravel's cache system
  • Tokens are automatically refreshed when they expire
  • All communication with the MyGHPay API is done over HTTPS
  • Sensitive configuration values should be stored in environment variables

Troubleshooting

If you encounter issues:

  1. Ensure your merchant credentials are correct
  2. Check that your callback URL is publicly accessible
  3. Verify that your server can make outbound HTTPS requests
  4. Confirm that your cache system is working properly For any authentication issues, the package will automatically attempt to re-authenticate and obtain a new token.