Skip to content

Laravel

Official Laravel integration for ZevPay Checkout. Provides a service provider, facade, webhook handling with signature verification, and event dispatching.

Installation

bash
composer require zevpay/laravel

The package uses Laravel auto-discovery — no manual provider registration needed.

Publish the config file:

bash
php artisan vendor:publish --tag=zevpay-config

Requires PHP 8.1+ and Laravel 10, 11, or 12.

Configuration

Add your API keys to .env:

env
ZEVPAY_SECRET_KEY=sk_live_your_secret_key
ZEVPAY_PUBLIC_KEY=pk_live_your_public_key
ZEVPAY_WEBHOOK_SECRET=whsec_your_webhook_secret

Get your keys from the ZevPay Dashboard.

The published config file (config/zevpay.php) supports these options:

VariableDefaultDescription
ZEVPAY_SECRET_KEYYour sk_live_* or sk_test_* key
ZEVPAY_PUBLIC_KEYYour pk_live_* or pk_test_* key (optional, for frontend)
ZEVPAY_WEBHOOK_SECRETWebhook signing secret from Dashboard
ZEVPAY_WEBHOOK_PATHwebhooks/zevpayWebhook endpoint path
ZEVPAY_BASE_URLhttps://api.zevpaycheckout.comAPI base URL
ZEVPAY_TIMEOUT30Request timeout in seconds
ZEVPAY_MAX_RETRIES2Retries on 5xx errors

Usage

Facade

php
use ZevPay\Laravel\Facades\ZevPay;

// Initialize a checkout session
$session = ZevPay::checkout()->initialize([
    'amount' => 500000, // ₦5,000 in kobo
    'email' => 'customer@example.com',
    'reference' => 'ORDER-123',
    'callback_url' => 'https://yoursite.com/callback',
]);

return redirect($session['checkout_url']);

Dependency injection

php
use ZevPay\ZevPay;

class PaymentController extends Controller
{
    public function checkout(ZevPay $zevpay)
    {
        $session = $zevpay->checkout->initialize([
            'amount' => 500000,
            'email' => 'customer@example.com',
        ]);

        return redirect($session['checkout_url']);
    }
}

Available resources

ResourceFacadeMethods
CheckoutZevPay::checkout()initialize, verify, get, selectPaymentMethod
TransfersZevPay::transfers()create, list, get, verify, listBanks, resolveAccount, calculateCharges, getBalance
InvoicesZevPay::invoices()create, list, get, update, send, cancel
Static PayIDZevPay::staticPayId()create, list, get, update, deactivate, reactivate
Dynamic PayIDZevPay::dynamicPayId()create, list, get, deactivate
Virtual AccountsZevPay::virtualAccounts()create, list, get
WalletZevPay::wallet()get, update, listMembers, addMember, removeMember, updateMember

Webhooks

The package registers a webhook route at POST /webhooks/zevpay with automatic HMAC-SHA256 signature verification.

Setup

  1. Copy the webhook URL: https://yoursite.com/webhooks/zevpay
  2. Go to your ZevPay Dashboard webhook settings
  3. Paste the URL and save
  4. Copy the webhook secret and add it to .env as ZEVPAY_WEBHOOK_SECRET

Always configure webhooks

Webhooks provide reliable server-to-server payment confirmation. Client-side callbacks may fail if the customer closes their browser.

Listening to events

Register listeners in your EventServiceProvider or use closures:

php
use ZevPay\Laravel\Events\ChargeSuccess;
use ZevPay\Laravel\Events\WebhookReceived;

// Listen to a specific event
class HandleChargeSuccess
{
    public function handle(ChargeSuccess $event): void
    {
        $reference = $event->payload['data']['reference'];
        $amount = $event->payload['data']['amount'];

        // Update your order, send receipt, etc.
        Order::where('reference', $reference)->update([
            'status' => 'paid',
        ]);
    }
}

// Or listen to all webhook events
class LogAllWebhooks
{
    public function handle(WebhookReceived $event): void
    {
        logger()->info("ZevPay: {$event->eventType}", $event->payload);
    }
}

Available events

Event classWebhook type
ChargeSuccesscharge.success
TransferSuccesstransfer.success
TransferFailedtransfer.failed
TransferReversedtransfer.reversed
InvoiceCreatedinvoice.created
InvoiceSentinvoice.sent
InvoicePaymentReceivedinvoice.payment_received
InvoicePaidinvoice.paid
InvoiceOverdueinvoice.overdue
InvoiceCancelledinvoice.cancelled
WebhookReceivedAll events (generic catch-all)

All specific event classes extend WebhookEvent and have a $payload property containing the raw webhook data.

Custom webhook path

env
ZEVPAY_WEBHOOK_PATH=api/webhooks/zevpay

CSRF exemption

The webhook route uses VerifyWebhookSignature middleware instead of CSRF. For Laravel 10 and older, add the path to your VerifyCsrfToken middleware $except array:

php
protected $except = [
    'webhooks/zevpay',
];

Laravel 11+ handles this automatically.

Artisan commands

Verify API keys

bash
php artisan zevpay:verify-keys

Checks that your keys are configured, have valid format (sk_*, pk_*), and tests API connectivity.

Test webhook

bash
php artisan zevpay:webhook-test
php artisan zevpay:webhook-test transfer.success

Sends a signed test webhook payload to your local endpoint. Useful for testing your event listeners during development.

Error handling

The package uses the PHP SDK exception hierarchy:

php
use ZevPay\Laravel\Facades\ZevPay;
use ZevPay\Exceptions\ValidationException;
use ZevPay\Exceptions\AuthenticationException;
use ZevPay\Exceptions\NotFoundException;
use ZevPay\Exceptions\RateLimitException;

try {
    $session = ZevPay::checkout()->initialize([
        'amount' => 500000,
        'email' => 'customer@example.com',
    ]);
} catch (ValidationException $e) {
    // $e->details contains field-level errors
    // e.g. ['email' => 'Email is required']
} catch (AuthenticationException $e) {
    // Invalid API key
} catch (NotFoundException $e) {
    // Resource not found
} catch (RateLimitException $e) {
    // $e->retryAfter — seconds to wait
}

Resources

ZevPay Checkout Developer Documentation