hansajith18/laravel-paycorp

Laravel integration for the Paycorp (Bancstac) payment gateway. Supports Hosted Page flow, Real-Time tokenised payments, and Refund/Void.

Maintainers

Package info

github.com/hansajith18/laravel-paycorp

pkg:composer/hansajith18/laravel-paycorp

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-06-26 18:30 UTC

This package is auto-updated.

Last update: 2026-06-26 18:30:56 UTC


README

Latest Version on Packagist PHP Version Laravel License: MIT Tests

Laravel integration for the Paycorp (Bancstac) payment gateway.

Supports the Sampath/Paycorp Paycenter Web 4.0 API — Hosted Page flow, Real-Time tokenised card payments, and Refund/Void operations — with full database audit logging and PCI DSS safe-handling baked in.

Features

  • Hosted Page flow — redirect payer to Paycorp-hosted card entry, receive callback
  • Real-Time flow — charge previously tokenised (saved) cards without redirecting
  • Refund & Void — session-authenticated back-office API with AES-256 encryption
  • HMAC-SHA256 request signing — every outgoing request is signed
  • Auto-registered log channelpaycorp-YYYY-MM-DD.log with zero config required
  • Sandbox mode — automatic amount normalisation for the Paycorp test environment
  • Full gateway audit log — all requests/responses written to payment_gateway_logs table
  • PCI DSS safe — never stores raw card numbers or CVVs; only masked card data persisted
  • Laravel 11 & 12 support

Requirements

  • PHP ^8.2
  • Laravel ^10.0, ^11.0, ^12.0, or ^13.0
  • ext-openssl

Installation

composer require hansajith18/laravel-paycorp

The service provider is auto-discovered. No manual registration required.

Publish config and migrations

php artisan paycorp:publish

Or publish individually:

# Config only
php artisan vendor:publish --tag=paycorp-config

# Migrations only
php artisan vendor:publish --tag=paycorp-migrations

Then run migrations:

php artisan migrate

Configuration

Add the following to your .env file:

# ── Required ──────────────────────────────────────────────────────────────────
PAYCORP_ENDPOINT=https://paycorp-smp.prod.aws.paycorp.lk/rest/service/proxy
PAYCORP_AUTH_TOKEN=your_auth_token
PAYCORP_HMAC_SECRET=your_hmac_secret

# ── Client IDs (provided by Paycorp per currency) ──────────────────────────────
PAYCORP_CLIENT_ID_LKR=your_lkr_client_id
PAYCORP_CLIENT_ID_USD=your_usd_client_id

# ── Tokenised payment client IDs (required for saved-card flow) ────────────────
PAYCORP_TOKEN_CLIENT_ID_LKR=your_tokenize_lkr_client_id
PAYCORP_TOKEN_CLIENT_ID_USD=your_tokenize_usd_client_id

# ── Return URL (Paycorp redirects here after card entry) ───────────────────────
PAYCORP_RETURN_URL="${APP_URL}/api/payments/paycorp/return"

# ── Optional ───────────────────────────────────────────────────────────────────
PAYCORP_DEFAULT_CURRENCY=LKR
PAYCORP_SANDBOX=false
PAYCORP_API_VERSION=1.04
PAYCORP_TIMEOUT=30
PAYCORP_CONNECT_TIMEOUT=10
PAYCORP_RETRY_TIMES=2
PAYCORP_RETRY_SLEEP_MS=500

# ── Refund / Void credentials (required only if using refund features) ─────────
PAYCORP_REFUND_ENDPOINT=https://paycorp-console.prod.aws.paycorp.lk
PAYCORP_REFUND_USERNAME=your_console_username
PAYCORP_REFUND_PASSWORD=your_console_password
PAYCORP_REFUND_IV_PHRASE=your_iv_phrase
PAYCORP_REFUND_AES_SECRET=your_aes_secret
PAYCORP_REFUND_DEVICE_ID=your_device_id

# ── Logging ────────────────────────────────────────────────────────────────────
PAYCORP_LOG_CHANNEL=paycorp
PAYCORP_LOG_LEVEL=debug
PAYCORP_LOG_DAYS=14

The package auto-registers a paycorp daily log channel — no changes to config/logging.php are needed. To redirect logs to an existing channel (e.g. stack), set PAYCORP_LOG_CHANNEL=stack.

Usage

Hosted Page Flow

1 — Initialize a payment

use Hansajith18\LaravelPaycorp\PaycorpClient;

$client = app(PaycorpClient::class);
// or: $client = app('paycorp');

$response = $client->initPayment(
    amountCents: 50000,          // 500.00 LKR
    clientRef:   'ORDER-' . $orderId,
    returnUrl:   route('payments.callback'),
    currency:    'LKR',
);

// Redirect the user to the Paycorp-hosted payment page
return redirect($response->paymentPageUrl);

2 — Complete the payment (callback route)

use Hansajith18\LaravelPaycorp\PaycorpClient;

$client = app(PaycorpClient::class);

$reqId = $request->query('reqid');

$response = $client->completePayment($reqId, 'LKR');

if ($response->isApproved()) {
    $txnRef = $response->txnReference;
    $last4  = $response->cardLast4();  // e.g. "4564"
    // fulfil the order…
} else {
    // $response->responseCode, $response->responseText
}

Tokenization (Save a Card)

To save a card during payment, pass tokenize: true to the service-level initializePayment:

use Hansajith18\LaravelPaycorp\Services\PaycenterPaymentService;
use Hansajith18\LaravelPaycorp\Enums\PaymentPurposeEnum;

$service = app(PaycenterPaymentService::class);

$payment = $service->initializePayment(
    userId:      auth()->id(),
    amountCents: 100,   // small verification charge — auto-voided after card saved
    purpose:     PaymentPurposeEnum::CARD_REGISTRATION,
    currency:    'LKR',
    tokenize:    true,
);

return redirect($payment->payment_page_url);

After the callback, the token is stored in saved_payments. The verification charge is automatically voided by the VoidTokenizationCharge queued job.

Real-Time Charge (Saved Card)

use Hansajith18\LaravelPaycorp\Models\SavedPayment;
use Hansajith18\LaravelPaycorp\Services\PaycenterPaymentService;
use Hansajith18\LaravelPaycorp\Enums\PaymentPurposeEnum;

$savedPayment = SavedPayment::where('user_id', auth()->id())->firstOrFail();
$service      = app(PaycenterPaymentService::class);

$payment = $service->chargeWithSavedPayment(
    userId:       auth()->id(),
    amountCents:  50000,
    purpose:      PaymentPurposeEnum::RIDE_PAYMENT,
    savedPayment: $savedPayment,
    currency:     'LKR',
);

// $payment->status === GatewayPaymentStatusEnum::COMPLETED on success

Refund

$response = $client->refund(
    originalTxnReference: $txnReference,
    amountCents:          50000,
    clientRef:            'REFUND-' . $refundId,
    currency:             'LKR',
    comment:              'Customer request',
);

if ($response->isApproved()) {
    // refund successful
}

Events

Listen to payment outcomes in your EventServiceProvider:

use Hansajith18\LaravelPaycorp\Events\PaymentSucceeded;
use Hansajith18\LaravelPaycorp\Events\PaymentFailed;

Event::listen(PaymentSucceeded::class, function ($event) {
    $payment = $event->payment;
    // fulfil order, send receipt, etc.
});

Event::listen(PaymentFailed::class, function ($event) {
    // notify user, release reservation, etc.
});

Payable Status Auto-Update (Optional)

If you want the package to automatically update a payment_status column on a related payable model when a payment completes or fails, list the model class base-names in config/paycorp.php:

// config/paycorp.php
'payable_status_classes' => ['Order', 'Booking'],

Leave the array empty (default) and handle status updates in your own event listeners instead.

Database Tables

Table Purpose
payments One row per payment attempt; tracks status, masked card info, gateway references
payment_gateway_logs Full request/response audit trail per gateway operation
saved_payments Tokenised cards per user (for Real-Time flow)

Sandbox Mode

Set PAYCORP_SANDBOX=true when using the Paycorp test environment. The package automatically:

  • Strips sub-unit cents (e.g. 5389.20 LKR → 5389.00 LKR)
  • Enforces a minimum amount of 200 cents (2.00 LKR)

No code changes needed between sandbox and production.

Testing

composer test

Or directly:

./vendor/bin/phpunit

Quality Tooling

# Code style (Laravel Pint)
composer format

# Static analysis (PHPStan level 5)
composer analyse

Security

  • All API requests are signed with HMAC-SHA256
  • TLS verification enforced (verify: true) — HTTP connections always use TLS
  • Card numbers and CVVs are never stored — only masked card data persisted
  • toSafeArray() explicitly excludes cardholder name, raw expiry, and internal comments
  • Refund credentials are AES-256-CBC encrypted before transmission
  • Gateway audit logs sanitise all sensitive fields before writing to the database

Please see SECURITY.md for how to report a security vulnerability.

Changelog

See CHANGELOG.md for release history.

For maintainers: see docs/releases.md for the full release workflow guide.

License

The MIT License (MIT). See LICENSE for details.

Credits