PHP code example of paynexus / laravel-paynexus

1. Go to this page and download the library: Download paynexus/laravel-paynexus library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

paynexus / laravel-paynexus example snippets


use PayNexus\Facades\PayNexus;

// 1. Initiate an M-Pesa STK Push payment
$result = PayNexus::initiatePayment([
    'amount'      => 1500,
    'phone'       => '254712345678',
    'description' => 'Order #1001 - Wireless Headphones',
]);

if ($result['success']) {
    $checkoutRequestId = $result['data']['checkout_request_id'];
    $reference         = $result['data']['reference'];
    echo "STK Push sent! Reference: {$reference}";
}

// 2. Check status immediately
$status = PayNexus::getPaymentByCheckoutId($checkoutRequestId);
echo $status['data']['status']; // 'pending', 'completed', 'failed'

// 3. Or poll until completion (blocks up to 120s by default)
$final = PayNexus::pollStatus($checkoutRequestId);
if ($final['data']['status'] === 'completed') {
    echo 'Payment completed!';
}

// Get merchant details
$merchant = PayNexus::getMerchant();
// Returns: { success: true, data: { id, business_name, status, subscription_status, … } }

// List merchant businesses
$businesses = PayNexus::getBusinesses();
// Returns: { success: true, data: [{ id, business_name, business_email, status, … }] }

// List all payment accounts
$accounts = PayNexus::getPaymentAccounts();
// Returns: { success: true, data: [{ id, provider, type, account_name, till_number, … }] }

// Option A: Generic payment initiation (recommended)
// payment_account_id is auto-resolved from the API if not provided
$result = PayNexus::initiatePayment([
    'amount'      => 500,
    'phone'       => '254712345678',
    'description' => 'Invoice #42',
]);

// Option B: M-Pesa-specific endpoint (esult = PayNexus::initiatePayment(['payment_account_id' => 2, ...]);

$result = PayNexus::initiatePayment([
    'amount'      => 500,
    'phone'       => '254712345678',
    'description' => 'Invoice #42',
    'idempotency_key' => 'inv-42-unique-key',  // Optional but recommended
]);

// By PayNexus reference
$status = PayNexus::getPaymentByReference('PNXABCD1234');

// By PayNexus payment ID
$status = PayNexus::getPaymentById(42);

// By M-Pesa checkout request ID (also syncs local record)
$status = PayNexus::getPaymentByCheckoutId('ws_CO_...');

// Real-time M-Pesa query via Daraja (most accurate, also syncs local record)
$status = PayNexus::checkMpesaStatus('ws_CO_...');

$result = PayNexus::pollStatus(
    checkoutRequestId: 'ws_CO_...',
    intervalSeconds: 3,    // check every 3 seconds (default)
    timeoutSeconds: 120,   // give up after 2 minutes (default)
);

if ($result['data']['status'] === 'completed') {
    // Payment is done
}

$payments = PayNexus::listPayments([
    'status'         => 'completed',
    'payment_method' => 'mpesa',
    'from_date'      => '2026-01-01',
    'to_date'        => '2026-12-31',
    'per_page'       => 50,
]);

$validation = PayNexus::validatePhone('0712345678');
// { success: true, data: { valid: true, normalized: '254712345678' } }

// Register your webhook endpoint with PayNexus
PayNexus::registerWebhook(
    name: 'My App',
    url: 'https://myapp.com/paynexus/webhook',
    events: ['payment.completed', 'payment.failed']
);

// List webhooks
$webhooks = PayNexus::listWebhooks();

// Update a webhook
PayNexus::updateWebhook(1, ['active' => false]);

// Delete a webhook
PayNexus::deleteWebhook(1);

use PayNexus\Events\WebhookProcessingFailed;

protected $listen = [
    WebhookProcessingFailed::class => [
        \App\Listeners\HandleWebhookFailure::class,
    ],
];

use PayNexus\Events\PaymentCompleted;
use PayNexus\Events\PaymentFailed;

protected $listen = [
    PaymentCompleted::class => [
        \App\Listeners\HandlePaymentSuccess::class,
    ],
    PaymentFailed::class => [
        \App\Listeners\HandlePaymentFailure::class,
    ],
];

use PayNexus\Models\PaynexusPayment;

// Find by reference
$payment = PaynexusPayment::where('reference', 'PNXABCD1234')->first();

// Find by checkout request ID
$payment = PaynexusPayment::where('checkout_request_id', 'ws_CO_...')->first();

// Query scopes
$pending   = PaynexusPayment::pending()->get();
$completed = PaynexusPayment::completed()->get();
$failed    = PaynexusPayment::failed()->get();

// Check state
$payment->isPending();   // true/false
$payment->isCompleted(); // true/false
$payment->isTerminal();  // completed, failed, or timeout
$payment->isVerified();  // true/false - if payment was verified with provider
$payment->isManuallyConfirmed(); // true/false - if manually confirmed by admin
$payment->canRetry();    // true/false - if failed payment can be retried

// Helper methods
$payment->markCompleted($transactionId, $providerReference);
$payment->markFailed($reason);
$payment->markVerified($verifiedAmount, $verifiedPhone, $verificationMethod);
$payment->markManuallyConfirmed('[email protected]');

// Link to your models via polymorphic relation
$payment->payable; // → App\Models\Order, App\Models\Invoice, etc.

$payment = PaynexusPayment::where('reference', 'PNXABCD1234')->first();

// Check if payment has been verified with provider
if ($payment->isVerified()) {
    echo "Verified on: " . $payment->verified_date->format('Y-m-d H:i:s');
    echo "Verified amount: " . $payment->verified_amount;
    echo "Verification method: " . $payment->verification_method;
}

// Manually mark as verified (e.g., after checking with bank)
$payment->markVerified(
    verifiedAmount: 1500.00,
    verifiedPhone: '254712345678',
    verificationMethod: 'bank_statement'
);

// Mark payment as manually confirmed by an admin
$payment->markManuallyConfirmed('[email protected]');

// Check if manually confirmed
if ($payment->isManuallyConfirmed()) {
    echo "Confirmed by: " . $payment->confirmed_by;
    echo "Confirmed at: " . $payment->confirmed_at->format('Y-m-d H:i:s');
}

// In your Order model
class Order extends Model
{
    public function payments()
    {
        return $this->morphMany(\PayNexus\Models\PaynexusPayment::class, 'payable');
    }
}

// When initiating payment, set payable after creation:
$result = PayNexus::initiatePayment([...]);

if ($result['success']) {
    $localPayment = PaynexusPayment::where('checkout_request_id', $result['data']['checkout_request_id'])->first();
    $localPayment->update([
        'payable_type' => Order::class,
        'payable_id'   => $order->id,
    ]);
}

// app/Models/Order.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use PayNexus\Models\PaynexusPayment;

class Order extends Model
{
    protected $fillable = [
        'user_id', 'order_number', 'total', 'currency', 'status',
        'customer_name', 'customer_email', 'customer_phone',
    ];

    public function payments()
    {
        return $this->morphMany(PaynexusPayment::class, 'payable');
    }

    public function latestPayment()
    {
        return $this->morphOne(PaynexusPayment::class, 'payable')->latestOfMany();
    }

    public function isPaid(): bool
    {
        return $this->payments()->completed()->exists();
    }

    public function markAsPaid(): void
    {
        $this->update(['status' => 'paid']);
    }
}

Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('order_number')->unique();
    $table->decimal('total', 14, 2);
    $table->string('currency', 10)->default('KES');
    $table->string('status')->default('pending'); // pending, paid, shipped, cancelled
    $table->string('customer_name');
    $table->string('customer_email')->nullable();
    $table->string('customer_phone');
    $table->timestamps();
});

// app/Http/Controllers/CheckoutController.php
namespace App\Http\Controllers;

use App\Models\Order;
use Illuminate\Http\Request;
use PayNexus\Facades\PayNexus;
use PayNexus\Models\PaynexusPayment;

class CheckoutController extends Controller
{
    /**
     * Step 1: Show checkout page with cart summary.
     */
    public function show(Request $request)
    {
        $cart = $request->user()->cart; // your cart logic
        return view('checkout', compact('cart'));
    }

    /**
     * Step 2: Create order and initiate M-Pesa payment.
     */
    public function pay(Request $request)
    {
        $request->validate([
            'phone' => 'der->order_number,
            'description'       => "Payment for {$order->order_number}",
            'metadata'          => ['order_id' => $order->id],
        ]);

        if (!$result['success']) {
            return back()->withErrors(['payment' => $result['message'] ?? 'Payment initiation failed.']);
        }

        // Link the local PaynexusPayment to the order
        $checkoutRequestId = $result['data']['checkout_request_id'];
        $localPayment = PaynexusPayment::where('checkout_request_id', $checkoutRequestId)->first();

        if ($localPayment) {
            $localPayment->update([
                'payable_type' => Order::class,
                'payable_id'   => $order->id,
            ]);
        }

        // Redirect to a page that polls for payment status
        return redirect()->route('checkout.status', [
            'order'               => $order->id,
            'checkout_request_id' => $checkoutRequestId,
        ]);
    }

    /**
     * Step 3: Show payment status page (polls via AJAX or Livewire).
     */
    public function status(Request $request, Order $order)
    {
        return view('checkout.status', [
            'order'              => $order,
            'checkoutRequestId'  => $request->query('checkout_request_id'),
        ]);
    }

    /**
     * AJAX endpoint: check payment status from the browser.
     */
    public function checkStatus(Request $request)
    {
        $request->validate(['checkout_request_id' => '

// routes/web.php
Route::middleware('auth')->group(function () {
    Route::get('/checkout', [CheckoutController::class, 'show'])->name('checkout');
    Route::post('/checkout/pay', [CheckoutController::class, 'pay'])->name('checkout.pay');
    Route::get('/checkout/{order}/status', [CheckoutController::class, 'status'])->name('checkout.status');
    Route::post('/checkout/check-status', [CheckoutController::class, 'checkStatus'])->name('checkout.check-status');
});

// app/Livewire/PaymentStatus.php
namespace App\Livewire;

use Livewire\Component;
use PayNexus\Facades\PayNexus;
use PayNexus\Models\PaynexusPayment;

class PaymentStatus extends Component
{
    public string $checkoutRequestId;
    public string $status = 'pending';
    public ?string $transactionId = null;
    public ?string $reference = null;

    public function mount(string $checkoutRequestId)
    {
        $this->checkoutRequestId = $checkoutRequestId;
        $this->checkPaymentStatus();
    }

    public function checkPaymentStatus(): void
    {
        $result = PayNexus::getPaymentByCheckoutId($this->checkoutRequestId);

        $this->status = $result['data']['status'] ?? 'pending';
        $this->transactionId = $result['data']['provider_transaction_id'] ?? null;
        $this->reference = $result['data']['reference'] ?? null;

        if ($this->status === 'completed') {
            $local = PaynexusPayment::where('checkout_request_id', $this->checkoutRequestId)->first();
            if ($local && $local->payable && method_exists($local->payable, 'markAsPaid')) {
                $local->payable->markAsPaid();
            }
        }
    }

    public function render()
    {
        return view('livewire.payment-status');
    }
}

// app/Listeners/HandlePaymentSuccess.php
namespace App\Listeners;

use PayNexus\Events\PaymentCompleted;

class HandlePaymentSuccess
{
    public function handle(PaymentCompleted $event): void
    {
        $payment = $event->payment;

        // Update the linked order
        if ($payment->payable && method_exists($payment->payable, 'markAsPaid')) {
            $payment->payable->markAsPaid();
        }

        // Send confirmation email, SMS, etc.
        // Mail::to($payment->payable->customer_email)->send(new OrderConfirmation($payment->payable));
    }
}

// app/Listeners/HandlePaymentFailure.php
namespace App\Listeners;

use PayNexus\Events\PaymentFailed;

class HandlePaymentFailure
{
    public function handle(PaymentFailed $event): void
    {
        $payment = $event->payment;

        // Update order status
        if ($payment->payable) {
            $payment->payable->update(['status' => 'payment_failed']);
        }

        // Notify the customer
        // Notification::send($payment->payable->user, new PaymentFailedNotification($event->reason));
    }
}

// app/Models/Subscription.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use PayNexus\Models\PaynexusPayment;

class Subscription extends Model
{
    protected $fillable = [
        'user_id',
        'plan_id',
        'status',
        'expires_at',
    ];

    public function payments()
    {
        return $this->morphMany(PaynexusPayment::class, 'payable');
    }

    public function activate()
    {
        $this->update([
            'status' => 'active',
            'expires_at' => now()->addMonth(),
        ]);
    }
}

// app/Http/Controllers/SubscriptionController.php
public function renew(Request $request)
{
    $subscription = $request->user()->subscription;

    $result = PayNexus::initiatePayment([
        'amount' => 1000,
        'phone' => $request->user()->phone,
        'account_reference' => "SUB-{$subscription->id}",
        'description' => 'Subscription renewal',
    ]);

    if ($result['success']) {
        $payment = PaynexusPayment::where(
            'checkout_request_id',
            $result['data']['checkout_request_id']
        )->first();

        $payment->update([
            'payable_type' => Subscription::class,
            'payable_id' => $subscription->id,
        ]);
    }

    return back();
}

// app/Http/Controllers/Admin/PaymentController.php
public function verifyPayment(Request $request, $id)
{
    $payment = PaynexusPayment::findOrFail($id);

    $payment->markVerified(
        verifiedAmount: $request->verified_amount,
        verifiedPhone: $request->verified_phone,
        verificationMethod: 'manual_admin'
    );

    return back()->with('success', 'Payment verified successfully');
}

public function confirmPayment(Request $request, $id)
{
    $payment = PaynexusPayment::findOrFail($id);

    $payment->markManuallyConfirmed(auth()->user()->email);

    // Update linked order
    if ($payment->payable && method_exists($payment->payable, 'markAsPaid')) {
        $payment->payable->markAsPaid();
    }

    return back()->with('success', 'Payment confirmed successfully');
}

use PayNexus\Exceptions\PayNexusAuthException;
use PayNexus\Exceptions\PayNexusConnectionException;
use PayNexus\Exceptions\PayNexusApiException;

try {
    $result = PayNexus::initiatePayment([
        'amount' => 1000,
        'phone' => '254712345678',
        'account_reference' => 'TEST',
    ]);

    if (!$result['success']) {
        Log::error('Payment initiation failed', [
            'message' => $result['message'],
            'error' => $result['error'] ?? null,
        ]);
        return back()->with('error', 'Payment failed. Please try again.');
    }

} catch (PayNexusAuthException $e) {
    Log::error('Authentication error', ['message' => $e->getMessage()]);
    return back()->with('error', 'API authentication failed. Check your API keys.');

} catch (PayNexusConnectionException $e) {
    Log::error('Connection error', ['message' => $e->getMessage()]);
    return back()->with('error', 'Could not connect to payment gateway. Please try again.');

} catch (PayNexusApiException $e) {
    Log::error('API error', ['message' => $e->getMessage()]);
    return back()->with('error', 'Payment gateway error. Please try again.');
}

// tests/Feature/PaymentTest.php
use PayNexus\Facades\PayNexus;
use Illuminate\Support\Facades\Http;

test('payment can be initiated', function () {
    // Mock the HTTP client
    Http::fake([
        'paynexus.co.ke/*' => Http::response([
            'success' => true,
            'data' => [
                'payment_id' => 123,
                'reference' => 'PNXTEST',
                'checkout_request_id' => 'ws_CO_test',
            ],
        ]),
    ]);

    $result = PayNexus::initiatePayment([
        'amount' => 1000,
        'phone' => '254712345678',
        'account_reference' => 'TEST',
    ]);

    expect($result['success'])->toBeTrue();
    expect($result['data']['checkout_request_id'])->toBe('ws_CO_test');
});

// app/Http/Controllers/CustomWebhookController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use PayNexus\Facades\PayNexus;
use PayNexus\Models\PaynexusPayment;

class CustomWebhookController extends Controller
{
    public function handle(Request $request)
    {
        // Verify signature
        $signature = $request->header('X-PayNexus-Signature');
        $payload = $request->getContent();
        $secret = config('paynexus.webhook.secret');

        $expected = hash_hmac('sha256', $payload, $secret);

        if (!hash_equals($expected, $signature)) {
            return response()->json(['error' => 'Invalid signature'], 403);
        }

        $data = $request->all();
        $event = $data['event'] ?? 'unknown';

        // Find or create payment
        $payment = PaynexusPayment::where(
            'reference',
            $data['data']['reference'] ?? null
        )->first();

        if (!$payment) {
            $payment = PaynexusPayment::create([
                'reference' => $data['data']['reference'],
                'amount' => $data['data']['amount'],
                'status' => $event === 'payment.completed' ? 'completed' : 'failed',
            ]);
        }

        // Handle event
        if ($event === 'payment.completed') {
            $payment->markCompleted(
                $data['data']['transaction_id'] ?? null,
                $data['data']['provider_reference'] ?? null
            );
        }

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

// routes/web.php
Route::post('/webhooks/paynexus', [CustomWebhookController::class, 'handle'])
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

'channels' => [
    'paynexus' => [
        'driver' => 'daily',
        'path' => storage_path('logs/paynexus.log'),
        'level' => 'info',
    ],
],
bash
php artisan vendor:publish --tag=paynexus-config
php artisan vendor:publish --tag=paynexus-migrations
php artisan migrate