Laravel integration

Accept payments in a Laravel application using the official Watenga PHP SDK, Blade views, and signed webhooks.

Installation

Install the Watenga PHP package from Composer. The package name is watenga/watenga-php and it wraps the same REST API as the Node SDK.

bash
composer require watenga/watenga-php

Add your API credentials to .env. Use sandbox keys while developing; switch to live keys only after KYC approval and a live API app in the dashboard.

bash
WATENGA_SECRET_KEY=sk_test_...
WATENGA_PUBLIC_KEY=pk_test_...
WATENGA_WEBHOOK_SECRET=whsec_...

Register the keys in config/services.php so controllers and service providers can resolve them with config().

php
'watenga' => [
    'secret_key' => env('WATENGA_SECRET_KEY'),
    'public_key' => env('WATENGA_PUBLIC_KEY'),
    'webhook_secret' => env('WATENGA_WEBHOOK_SECRET'),
],

Service provider (recommended)

For larger applications, bind Watenga\Watenga as a singleton so you can inject it into controllers instead of instantiating the client in every action.

php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Watenga\Watenga;

class WatengaServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Watenga::class, function () {
            return new Watenga(config('services.watenga.secret_key'));
        });
    }
}

Register the provider in your application configuration.

php
// config/app.php — add to the providers array:
App\Providers\WatengaServiceProvider::class,

After registration, type-hint Watenga in any controller constructor and Laravel will resolve the configured client automatically.

Accepting a payment

Create a checkout session on the server when the customer starts checkout. Return the checkout_id and payment_url to your frontend, or embed Watenga.js with your public key for an on-page widget.

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Watenga\Watenga;

class PaymentController extends Controller
{
    public function __construct(private Watenga $watenga) {}

    public function createCheckout(Request $request): JsonResponse
    {
        $checkout = $this->watenga->checkout->create([
            'amount' => $request->input('amount'),
            'currency' => $request->input('currency'),
            'merchantTransactionId' => 'INV-' . $request->input('order_id'),
            'returnUrl' => route('payment.success'),
            'notificationUrl' => route('webhooks.watenga'),
            'customerName' => $request->user()?->name,
            'customerEmail' => $request->user()?->email,
        ]);

        return response()->json([
            'checkout_id' => $checkout['checkoutId'],
            'payment_url' => $checkout['paymentUrl'],
        ]);
    }
}

In your Blade template, load Watenga.js and mount the widget using the public key from configuration. Never put the secret key in views or JavaScript.

php
{{-- resources/views/checkout.blade.php --}}
<div id="watenga-payment"></div>

<script src="https://js.watenga.africa/v1/watenga.js"></script>
<script>
  const w = Watenga(@json(config('services.watenga.public_key')));
  w.mount('#watenga-payment', {
    amount: {{ $amount }},
    currency: @json($currency),
    reference: @json($orderReference),
    onSuccess: function (txn) {
      window.location.href = @json(route('payment.success'));
    },
  });
</script>

Handling webhooks

Watenga notifies your application when a payment completes or fails. Verify every payload with Watenga::constructEvent() before updating orders or inventory.

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Watenga\Watenga;

class WatengaWebhookController extends Controller
{
    public function handle(Request $request): JsonResponse
    {
        $rawBody = $request->getContent();
        $signature = $request->header('Watenga-Signature');

        $event = Watenga::constructEvent(
            $rawBody,
            $signature,
            config('services.watenga.webhook_secret')
        );

        if ($event['type'] === 'payment.capture.completed') {
            // Mark order paid using $event['data']
        }

        if ($event['type'] === 'payment.capture.declined') {
            // Notify customer or release inventory
        }

        return response()->json(['received' => true], 200);
    }
}

Register a POST route for the webhook endpoint.

php
// routes/api.php
Route::post('/webhooks/watenga', [WatengaWebhookController::class, 'handle'])
    ->name('webhooks.watenga');

CSRF exemption required

Exclude the Watenga webhook route from Laravel's CSRF protection. Add it to the $except array in app/Http/Middleware/VerifyCsrfToken.php.
php
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'api/webhooks/watenga',
];

WooCommerce and WHMCS

If your Laravel app uses the Watenga WooCommerce or WHMCS plugin, you do not need this guide — the plugins handle checkout, webhooks, and reconciliation automatically.

Get notified when InnBucks and OneMoney go live.