laravel-vitepay maintained by ibracilinks
Laravel VitePay
Accept Orange Money (and other mobile money) payments in your Laravel app through VitePay.
- Creates payments and redirects customers to the VitePay checkout
- Registers the callback route and verifies VitePay's
authenticitysignature - Dispatches
PaymentSucceeded/PaymentFailedevents for you to update your orders - Laravel 10 – 13, PHP 8.1+
Installation
composer require ibracilinks/laravel-vitepay
Add your credentials (VitePay dashboard → Paramètres → Kit d'intégration) to .env:
VITEPAY_API_KEY=your-api-key
VITEPAY_API_SECRET=your-api-secret
VITEPAY_MODE=sandbox # "prod" for live payments
VITEPAY_RETURN_URL=/orders/thanks
VITEPAY_DECLINE_URL=/orders/failed # optional, defaults to return URL
VITEPAY_CANCEL_URL=/cart # optional, defaults to return URL
Optionally publish the config file:
php artisan vendor:publish --tag=vitepay-config
Creating a payment
use Ibracilinks\LaravelVitepay\Facades\Vitepay;
public function checkout(Order $order)
{
return Vitepay::payment($order->id, $order->total) // amount in XOF, e.g. 12500
->email($order->customer_email)
->description('Hébergement Web')
->buyerIp(request()->ip())
->redirect(); // or ->url() to get the checkout URL
}
The amount is given in major units and multiplied by 100 for you (12500 XOF → amount_100 = 1250000).
If you already have the ×100 value, use ->amount100(1250000).
Every default from the config can be overridden per payment:
->currency(), ->country(), ->language('en'), ->paymentType(), ->returnUrl(), ->declineUrl(), ->cancelUrl(), ->callbackUrl().
Order IDs must be unique: VitePay rejects duplicates.
Failures (network error, VitePay error response, unexpected body, missing credentials) throw
Ibracilinks\LaravelVitepay\Exceptions\VitepayException.
Handling the callback
The package registers POST /vitepay/callback (named vitepay.callback) and sends its URL to VitePay automatically.
The route is outside the web middleware group, so no CSRF exclusion is needed.
When VitePay calls it, the package checks the authenticity signature, rejecting invalid calls with
{"status": "0"}, then dispatches an event and answers {"status": "1"}.
Listen for the events to update your orders:
use Ibracilinks\LaravelVitepay\Events\PaymentFailed;
use Ibracilinks\LaravelVitepay\Events\PaymentSucceeded;
use Illuminate\Support\Facades\Event;
Event::listen(function (PaymentSucceeded $event) {
$order = Order::findOrFail($event->callback->orderId);
// Always check the amount and that the order is still open
if ($order->isPaid() || (int) round($order->total * 100) !== $event->callback->amount100) {
return;
}
$order->markAsPaid();
});
Event::listen(function (PaymentFailed $event) {
Order::find($event->callback->orderId)?->markAsFailed();
});
$event->callback exposes orderId, amount100, amount(), currencyCode, success, sandbox and the raw payload.
To handle the callback yourself instead, set vitepay.route.enabled to false and use
Vitepay::verifyCallback($request->all()) in your own controller.
If your app sits behind a proxy or the generated URL is not publicly reachable, set VITEPAY_CALLBACK_URL.
Testing in sandbox
With VITEPAY_MODE=sandbox, use these phone numbers on the checkout page:
| Number | Result |
|---|---|
77000001 |
payment confirmed |
77000009 |
payment cancelled |
VitePay requires at least one successful sandbox payment before you can go to production.
Running the package tests
composer install
composer test
Contributing
Contributions are welcome! To propose a change:
- Fork the repository and create a branch from
main. - Install dependencies with
composer install. - Make your changes and add tests covering them.
- Make sure the test suite passes with
composer test. - Open a pull request describing what you changed and why.
Please report bugs and suggest features through GitHub issues. If you find a security vulnerability, do not open a public issue: contact the maintainers privately instead.
License
MIT