Search by

oktocode / sham-cash-laravel

abd2code

Laravel bridge for the ShamCash PHP SDK.

Package info

github.com/OkToCode-L-L-C/Sham-Cash-Laravel

pkg:composer/oktocode/sham-cash-laravel

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-10-05 09:19 UTC

This package is auto-updated.

Last update: 2026-10-05 09:24:43 UTC


README

CI Packagist version PHP version Packagist downloads MIT license

ShamCash for Laravel

Packagist  ·  GitHub  ·  ok2code.com

Create ShamCash bills, accept webhooks, refund payments, and list transactions from Laravel.

Laravel bridge for the ShamCash PHP SDK. Implemented by OkToCode.

The package publishes configuration, resolves one OkToCode\ShamCash\Client from the container, and accepts the ShamCash webhook. Your application owns the order. This package is not a store.

Install

composer require oktocode/sham-cash-laravel
php artisan vendor:publish --tag=shamcash-config

The SDK requires Guzzle 7. Laravel 13 also allows Guzzle 8, so Composer may downgrade guzzlehttp/guzzle to 7 when this package is installed.

Add the credentials to .env. Do not commit them.

SHAMCASH_AGENT_KEY=
SHAMCASH_SECRET_KEY=
SHAMCASH_BASE_URL=https://example.shamcash/services

SHAMCASH_SECRET_KEY is the Base64 form of 32 raw bytes.

Create a bill

Amounts are decimal strings with at most two places. Pass the idempotency key yourself on a refund, and send that same key again if the refund times out. The package does not invent a key and does not retry a money call.

use OkToCode\ShamCash\Enum\Currency;
use OkToCode\ShamCash\Laravel\Facades\ShamCash;

$bill = ShamCash::createBill(
    billNo: 'order-42',
    amount: '20.00',
    currency: Currency::Usd,
    note: 'Order 42',
    callbackUrl: route('shamcash.webhook'),
    redirectUrl: route('checkout.return'),
);

return redirect()->away($bill->paymentUrl);

Send the customer to paymentUrl in the system browser. An embedded web view breaks the ShamCash app deep link. Do not log paymentUrl: the query string contains the agent key.

Currency::Usd and Currency::Syp are the currencies ShamCash accepts. callbackUrl and redirectUrl can instead be set as SHAMCASH_CALLBACK_URL and SHAMCASH_REDIRECT_URL. A value passed to createBill() replaces the matching default. ShamCash still requires both URLs.

A dropped response can still store the bill. The next createBill() for that billNo throws OkToCode\ShamCash\Exception\ApiException with result OkToCode\ShamCash\Enum\ResultCode::BillNoAlreadyExists (1704). Load it with ShamCash::getBill($billNo).

You can also type-hint OkToCode\ShamCash\Client.

Webhook

ShamCash POSTs {"encData"} to POST /shamcash/webhook. The route is named shamcash.webhook and is registered outside the web middleware group, so the CSRF check does not apply. Set SHAMCASH_WEBHOOK_PATH to move it, or set shamcash.webhook_path to an empty string and register the route yourself.

The controller passes the raw body to parseWebhook(). A body that fails decryption or the token time check gets HTTP 400. A valid notice dispatches OkToCode\ShamCash\Laravel\Events\WebhookReceived and returns HTTP 200. ShamCash retries unless that response arrives within 10 seconds. Keep the listener in the request, make it idempotent for the same billNo and status, and return before slow work such as email. A queued listener stores the decrypted notice in the queue, and ShamCash will not retry a job that fails later.

use OkToCode\ShamCash\Enum\BillStatus;
use OkToCode\ShamCash\Laravel\Events\WebhookReceived;
use Illuminate\Support\Facades\Event;

Event::listen(function (WebhookReceived $event): void {
    $notice = $event->notification;
    if ($notice->status !== BillStatus::Paid || $notice->tranId === null) {
        return;
    }

    // Mark the order for $notice->billNo paid once. Store $notice->tranId.
});

BillStatus::Expired means the customer did not pay. Apply each billNo and status once, because ShamCash delivers the same notice again after a timeout.

Do not log $notice->raw, SHAMCASH_SECRET_KEY, or encData.

ShamCash cannot deliver a webhook to localhost. For a local checkout, when the customer returns, call ShamCash::getBill($billNo) once. Do not poll it.

Refund

ShamCash::refundBill(
    billNo: 'order-42',
    amount: '20.00',
    idempotencyKey: 'refund-order-42-0',
);

The idempotency key is 10 to 100 characters. Repeat a timed-out refund with the same key.

Transactions

Dates use yyyy-MM-dd. limit is from 10 to 2500, and the default is 500.

$page = ShamCash::listTransactions('2026-01-01', '2026-01-20', afterTranId: 0, limit: 500);

foreach (ShamCash::eachTransaction('2026-01-01', '2026-01-20') as $transaction) {
    // $transaction->tranId
}

eachTransaction() follows hasMore. getBill() and listTransactions() are safe to call again. The package does not poll.

Security

Report a vulnerability through the GitHub private advisory. Do not put SHAMCASH_SECRET_KEY, encData, a decrypted payload, or paymentUrl in a public issue.