xfix / xfix-pay
Unified PHP SDK for XfixPay - M-Pesa, PayPal, Banks, XfixPay
Requires
- php: ^7.4 || ^8.0
- ext-json: *
- ext-openssl: *
- guzzlehttp/guzzle: ^7.0
Requires (Dev)
- phpunit/phpunit: ^9.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A unified PHP SDK for integrating with multiple payment gateways through a consistent, extensible API.
XfixPay currently supports M-Pesa in Kenya, with additional payment providers planned, including PayPal, Stripe, bank transfers, and other payment services.
Features
- Unified interface for multiple payment gateways
- M-Pesa STK Push
- STK Push status queries
- C2B URL registration
- B2C payments
- Account balance inquiries
- Transaction reversals
- Automatic M-Pesa OAuth token management and caching
- Automatic encryption of Safaricom security credentials
- PSR-4 autoloading
- PSR-12 compatible codebase
- Extensible gateway architecture
Requirements
- PHP 7.4 or higher
- Composer
- GuzzleHTTP 7.x or higher
- OpenSSL PHP extension
- Safaricom Developer account for M-Pesa integrations
- Safaricom M-Pesa security certificate (
.cer) for B2C, Balance Inquiry, and Reversal APIs
Installation
Install XfixPay using Composer:
composer require xfix/xfixpay
Composer will automatically install the required dependencies.
Configuration
XfixPay uses a shared client configuration while allowing each gateway to define its own credentials and settings.
Global Configuration
use Xfix\XfixPay\XfixPayClient; $client = new XfixPayClient([ 'environment' => 'sandbox', // sandbox or live 'timeout' => 30, ]);
The global configuration can be shared across gateways.
M-Pesa Configuration
$mpesa = $client->mpesa([ 'consumer_key' => 'your_consumer_key', 'consumer_secret' => 'your_consumer_secret', 'passkey' => 'your_passkey', 'shortcode' => '174379', 'initiator' => 'apitest', 'initiator_password' => 'your_initiator_password', 'environment' => 'sandbox', 'cert_path' => '/path/to/safaricom.cer', ]);
Where:
| Configuration | Description |
|---|---|
consumer_key |
Safaricom Daraja consumer key |
consumer_secret |
Safaricom Daraja consumer secret |
passkey |
Lipa Na M-Pesa Online passkey |
shortcode |
PayBill or Till number |
initiator |
Initiator name for B2C, Balance, and Reversal |
initiator_password |
Initiator password |
environment |
sandbox or live |
cert_path |
Path to the Safaricom.cer certificate |
The cert_path is required only for:
- B2C payments
- Account Balance Inquiry
- Transaction Reversal
The certificate can also be configured after creating the gateway:
$mpesa->setCertificatePath('/path/to/safaricom.cer');
M-Pesa Usage
1. STK Push
Initiate a Lipa Na M-Pesa Online payment request.
$response = $mpesa->requestSTKPush( phoneNumber: '254722336262', amount: 1.00, accountReference: 'INV-001', transactionDesc: 'Payment', callbackUrl: 'https://your-server.com/mpesa/callback' );
The response contains the M-Pesa checkout request identifier.
$checkoutRequestId = $response['CheckoutRequestID'];
Store the CheckoutRequestID if you need to query the transaction status later.
Important Parameters
phoneNumber— Customer MSISDN in international formatamount— Payment amountaccountReference— Account or invoice referencetransactionDesc— Transaction descriptioncallbackUrl— URL that receives the STK callback
2. Query STK Push Status
Check the status of an STK Push transaction using its CheckoutRequestID.
$status = $mpesa->querySTKStatus($checkoutRequestId); if ($status['ResultCode'] === '0') { // Payment successful }
The returned response should be evaluated according to the M-Pesa API response codes.
3. Register C2B URLs
Register the validation and confirmation URLs used for Customer-to-Business payments.
$mpesa->registerC2BUrls( confirmationUrl: 'https://your-server.com/mpesa/confirm', validationUrl: 'https://your-server.com/mpesa/validate', responseType: 'Completed' );
Supported response types include:
'Completed'
or:
'Canceled'
The validation endpoint can be used to validate incoming transactions before confirmation.
4. B2C Payment
Send money from a business M-Pesa account to a customer's M-Pesa account.
$response = $mpesa->sendB2C( phoneNumber: '254722336262', amount: 100.00, command: 'SalaryPayment', remarks: 'Salary for July', occasion: 'Monthly salary' );
Supported commands include:
'SalaryPayment'
'BusinessPayment'
'PromotionPayment'
The occasion parameter is optional.
5. Account Balance Inquiry
Retrieve the balance of an M-Pesa shortcode.
$balance = $mpesa->balanceInquiry( partyA: null, identifierType: '4' );
When partyA is null, the configured shortcode is used.
Supported identifier types include:
| Type | Description |
|---|---|
1 |
MSISDN |
2 |
Till Number |
4 |
PayBill |
6. Transaction Reversal
Reverse a completed M-Pesa transaction using its M-Pesa receipt number.
$reversal = $mpesa->reversal( transactionId: 'LKXXXX1234', amount: 100.00, remarks: 'Reversal due to error' );
Use transaction reversals carefully and only when the transaction meets Safaricom's reversal requirements.
Security Certificate
Safaricom requires the initiator password used by the B2C, Balance Inquiry, and Reversal APIs to be encrypted using Safaricom's public certificate.
The certificate is normally provided as a .cer file.
Example:
$mpesa->setCertificatePath('/path/to/safaricom.cer');
XfixPay handles the following automatically:
- Loads the Safaricom certificate.
- Encrypts the initiator password.
- Reuses the encrypted credential for subsequent requests within the gateway instance.
The SDK does not bundle Safaricom certificates.
If the certificate path is missing, invalid, or unreadable, XfixPay throws an MpesaException with a descriptive error message.
Error Handling
M-Pesa operations may throw MpesaException for errors such as:
- Network failures
- Authentication failures
- Invalid configuration
- Missing certificates
- Invalid API responses
- M-Pesa API errors
Handle exceptions using try/catch:
use Xfix\XfixPay\Exception\MpesaException; try { $response = $mpesa->requestSTKPush( phoneNumber: '254722336262', amount: 1.00, accountReference: 'INV-001', transactionDesc: 'Payment', callbackUrl: 'https://your-server.com/mpesa/callback' ); } catch (MpesaException $e) { // Log the exception and handle the failure gracefully. }
Applications should log relevant error information without exposing credentials or other sensitive data.
Testing
Run the PHPUnit test suite with:
vendor/bin/phpunit
The SDK is designed to support HTTP client mocking, allowing unit tests to run without making real requests to payment providers.
Integration tests can be used separately for environments where real API credentials are available.
Gateway Architecture
XfixPay is designed around an extensible gateway architecture.
Each payment provider is implemented as an independent gateway while sharing common infrastructure through the main client.
Example:
$client = new XfixPayClient([ 'environment' => 'sandbox', ]); $mpesa = $client->mpesa($mpesaConfig);
Future gateways will follow the same pattern:
$paypal = $client->paypal($paypalConfig); $stripe = $client->stripe($stripeConfig); $bank = $client->bank($bankConfig);
This allows applications to integrate multiple payment providers without having to learn a completely different SDK structure for each provider.
Planned Gateways
The following gateways are planned for future releases:
- PayPal — REST API
- Stripe — Stripe API / Connect
- Bank Transfers — Equity, KCB, and other supported banks
- XfixPay — Stablecoin and digital-asset payments
Gateway availability depends on implementation status and the relevant provider's API requirements.
Project Structure
xfixpay/
├── composer.json
├── README.md
├── LICENSE
├── .gitignore
│
├── src/
│ ├── XfixPayClient.php
│ ├── GatewayInterface.php
│ ├── AbstractGateway.php
│ │
│ ├── Exception/
│ │ ├── XfixPayException.php
│ │ ├── MpesaException.php
│ │ ├── PayPalException.php
│ │ ├── BankException.php
│ │ ├── StripeException.php
│ │
│ ├── Mpesa/
│ │ ├── MpesaGateway.php
│ │ ├── MpesaConfig.php
│ │ └── MpesaAuth.php
│ │
│ ├── PayPal/
│ │ ├── PayPalGateway.php
│ │ ├── PayPalConfig.php
│ │ └── PayPalAuth.php
│ │
│ ├── Bank/
│ │ ├── BankGateway.php
│ │ └── BankConfig.php
│ │
│ ├── Stripe/
│ │ └── ...
│
├── tests/
│ ├── Unit/
│ │ ├── MpesaGatewayTest.php
│ │ ├── MpesaAuthTest.php
│ │ └── XfixPayClientTest.php
│ └── Integration/
│ └── MpesaLiveTest.php
│
├── examples/
│ ├── mpesa_stk_push.php
│ ├── mpesa_b2c.php
│ ├── mpesa_balance.php
│ └── mpesa_reversal.php
│
└── docs/
├── mpesa.md
└── contributing.md
Key Components
| Component | Purpose |
|---|---|
src/XfixPayClient.php |
Main SDK entry point and gateway factory |
src/GatewayInterface.php |
Common contract for payment gateways |
src/AbstractGateway.php |
Shared gateway functionality |
src/Mpesa/MpesaGateway.php |
M-Pesa API implementation |
src/Mpesa/MpesaAuth.php |
M-Pesa OAuth authentication and token caching |
src/Mpesa/MpesaConfig.php |
M-Pesa configuration container |
src/Exception/MpesaException.php |
M-Pesa-specific exception |
src/Mpesa/certs/ |
Optional certificate directory for local development |
examples/ |
Common integration examples |
tests/ |
Unit and integration tests |
docs/ |
Extended technical documentation |
Gateway Isolation
Each payment provider is kept within its own namespace and directory.
For example:
src/Mpesa/
src/PayPal/
src/Stripe/
src/Bank/
This keeps provider-specific authentication, configuration, exceptions, and API implementations isolated from one another.
Certificate Handling
The SDK does not include payment-provider certificates.
For local development, users may optionally place their own certificates under:
src/Mpesa/certs/
However, production applications should preferably store certificates outside the source repository and reference them through configuration or environment variables.
For example:
'cert_path' => getenv('MPESA_CERT_PATH'),
Never commit private credentials, certificates, API secrets, or production configuration to source control.
Contributing
Contributions are welcome.
Before submitting a pull request:
- Follow PSR-12 coding standards.
- Add or update tests for changed functionality.
- Ensure the PHPUnit test suite passes.
- Keep gateway-specific logic isolated within its gateway namespace.
- Do not commit credentials, certificates, tokens, or other secrets.
Please open an issue before making substantial architectural changes.
License
XfixPay is released under the MIT License.
See the LICENSE file for the full license text.