PHP code example of digitaltunnel / jeelpay

1. Go to this page and download the library: Download digitaltunnel/jeelpay 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/ */

    

digitaltunnel / jeelpay example snippets


use DigitalTunnel\JeelPay\Facades\JeelPay;
use DigitalTunnel\JeelPay\Requests\ItemsCheckoutRequest;
use DigitalTunnel\JeelPay\ValueObjects\Buyer;
use DigitalTunnel\JeelPay\ValueObjects\Item;
use DigitalTunnel\JeelPay\ValueObjects\Urls;

$result = JeelPay::checkouts()->createItems(
    ItemsCheckoutRequest::make()
        ->buyer(Buyer::make(
            firstName: 'Essa',
            lastName: 'Alshammari',
            mobileNumber: '512345678',          // Saudi format, 9 digits, starts with 5
            email: '[email protected]',
            nationalId: '1234567890',            // 10 digits, starts with 1 or 2
        ))
        ->addItem(Item::make(
            name: 'Data Science Diploma',
            quantity: 1,
            totalCost: 3500.00,
            referenceId: 'course_456',
            unitPrice: 3500.00,
            entityId: 'uuid-of-entity',          // 

use DigitalTunnel\JeelPay\Requests\SchoolingCheckoutRequest;
use DigitalTunnel\JeelPay\ValueObjects\Student;

// Get the active educational year IDs (auth handled for you)
$years = JeelPay::public()->educationalYears();

$result = JeelPay::checkouts()->createSchooling(
    SchoolingCheckoutRequest::make()
        ->buyer(Buyer::make('Zayed', 'Al-Abbad', '512345678'))
        ->addStudent(Student::make(
            name: 'Nasser Al-jbreen',
            nationalId: '2098765432',
            entityId: 'uuid-of-school-entity',
            educationalYearId: $years[0]->id,
            cost: 8500.00,
            referenceId: 'student_grade5_001',
        ))
        ->urls(Urls::make(
            redirectUrl: route('checkout.return'),
            notificationUrl: route('jeelpay.webhook'),
        ))
        ->referenceId('enrollment_2026_0012')
        ->metadata(['grade' => '5', 'academic_year' => '2026-2027']),
);

return redirect($result->redirectUrl);

$key = (string) Str::uuid();
// save $key to your order record FIRST so retries can find it

try {
    $result = JeelPay::checkouts()->createItems($request, idempotencyKey: $key);
} catch (\DigitalTunnel\JeelPay\Exceptions\ConnectionException) {
    // Retry with the same key — JeelPay returns the cached response, no duplicate.
    $result = JeelPay::checkouts()->createItems($request, idempotencyKey: $key);
}

use DigitalTunnel\JeelPay\Enums\RefundStatus;

$status = JeelPay::checkouts()->find('checkout-uuid');

if ($status->isPaid()) {
    // SUCCEEDED — buyer paid down payment, installment plan created
}

// Submit a refund (plan withdrawal). Only SUCCEEDED checkouts can be refunded.
// amount + reason are  {
    // PENDING — under review; poll later
}

// Poll status later by the withdrawal id ($refund->id)
$refund = JeelPay::refunds()->find($refund->id);

if ($refund->isRejected()) {
    Log::warning('Refund rejected', ['reason' => $refund->rejectionReason]);
}

use DigitalTunnel\JeelPay\Events\CheckoutSucceeded;
use DigitalTunnel\JeelPay\Events\CheckoutRejected;
use DigitalTunnel\JeelPay\Events\CheckoutExpired;

Event::listen(CheckoutSucceeded::class, function (CheckoutSucceeded $event) {
    // $event->payload is a DigitalTunnel\JeelPay\DTOs\WebhookPayload
    $order = Order::firstWhere('jeelpay_checkout_id', $event->payload->checkoutId);
    $order->markPaid();
});

Route::post('my-custom-path', \DigitalTunnel\JeelPay\Http\Controllers\WebhookController::class)
    ->middleware([\DigitalTunnel\JeelPay\Http\Middleware\VerifyWebhookSignature::class])
    ->name('my.webhook');

use DigitalTunnel\JeelPay\Models\JeelPayCheckout;

$checkout = JeelPayCheckout::query()->where('checkout_id', $id)->first();
$checkout->payable()->associate($order)->save();
$checkout->statusEnum();        // CheckoutStatus::Succeeded
$checkout->isPaid();

JeelPay::auth()->token();      // returns DTOs\AccessToken
JeelPay::auth()->refresh();    // force re-mint (after a 401)
JeelPay::auth()->forget();     // clear cache + memoised

use DigitalTunnel\JeelPay\Exceptions\ValidationException;
use DigitalTunnel\JeelPay\Exceptions\AuthenticationException;
use DigitalTunnel\JeelPay\Exceptions\IdempotencyConflictException;
use DigitalTunnel\JeelPay\Exceptions\ConnectionException;

try {
    JeelPay::checkouts()->createItems($request);
} catch (ValidationException $e) {
    // 400 — JeelPay-native errors:  $e->errors()  /  $e->firstErrorMessage()
    Log::warning('JeelPay validation', [
        'tx_id' => $e->txId(),
        'errors' => $e->errors(),
    ]);
} catch (IdempotencyConflictException $e) {
    // IDEMPOTENCY-001 — concurrent duplicate; wait and retry
} catch (AuthenticationException $e) {
    // 401 — credentials issue
} catch (ConnectionException $e) {
    // network/timeout — safe to retry with the same idempotency key
}

use DigitalTunnel\JeelPay\Testing\JeelPayFake;

it('creates an items checkout', function () {
    JeelPayFake::fakeAuth();
    JeelPayFake::fakeItemsCheckoutCreated();

    $this->post('/orders', [...])->assertRedirect();

    JeelPayFake::assertSentTo('https://api.sandbox.jeel.co/v3/checkout');
});

it('processes a refund', function () {
    JeelPayFake::fakeAuth();
    JeelPayFake::fakeRefundSubmitted(status: 'DONE');

    $refund = JeelPay::refunds()->submit('chk_x', 3500.00, 'Cancelled');

    expect($refund->isDone())->toBeTrue();
});

it('handles a SUCCEEDED webhook', function () {
    $signed = JeelPayFake::signedWebhook(
        secret: config('jeelpay.client_secret'),
        checkoutId: 'chk_x',
        status: 'SUCCEEDED',
    );

    $this->call(
        method: 'POST',
        uri: route('jeelpay.webhook'),
        server: $this->transformHeadersToServerVars($signed['headers']),
        content: $signed['body'],
    )->assertNoContent();
});
bash
php artisan vendor:publish --tag=jeelpay-config
bash
php artisan vendor:publish --tag=jeelpay-migrations
php artisan migrate
bash
php artisan route:list --name=jeelpay.webhook
# POST  webhooks/jeelpay ... VerifyWebhookSignature