hyprdev / usimpay-laravel
Framework-agnostic PHP and Laravel SDK for USIMPay
Requires
- php: ^8.2
- ext-curl: *
- ext-json: *
- illuminate/contracts: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
Requires (Dev)
- orchestra/testbench: ^9.0 || ^10.0
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A small PHP 8.2+ SDK for the USIMPay API. The core client is framework-independent; Laravel package discovery, configuration, and a facade are included.
Installation
composer require hyprdev/usimpay-laravel
Laravel discovers the service provider automatically. Publish its configuration:
php artisan vendor:publish --tag=usimpay-config
Configure credentials in .env (never commit real keys):
USIMPAY_ENVIRONMENT=sandbox USIMPAY_API_KEY=usim_test_... USIMPAY_SECRET_KEY=... USIMPAY_WEBHOOK_SIGNING_KEY=whsec_test_...
The optional USIMPAY_SANDBOX_BASE_URL and USIMPAY_PRODUCTION_BASE_URL variables override the API hosts.
By default, the SDK uses https://sandbox-api.usimpay.com.my/v1 for Sandbox and https://api.usimpay.com.my/v1 for Production. Overrides may contain either the API origin or the full /v1 API base.
Laravel usage
Type-hint the client in a controller or service:
use Hyprdev\UsimPay\UsimPayClient; public function store(UsimPayClient $usimPay) { $payment = $usimPay->createPayment([ 'reference' => 'ORD-10001', 'amount' => '150.00', 'currency' => 'MYR', 'description' => 'Order ORD-10001', 'customer' => [ 'name' => 'Ahmad Ali', 'email' => 'ahmad@example.com', ], ], 'order-10001-attempt-1'); return redirect()->away($payment['data']['payment_url']); }
The UsimPay facade is also auto-discovered. Other methods are ping(), getPayment(), listBanks(), listCollections(), createCollection(), getCollection(), updateCollection(), and deactivateCollection().
Standalone PHP usage
use Hyprdev\UsimPay\UsimPayClient; use Hyprdev\UsimPay\UsimPayConfig; $config = new UsimPayConfig('sandbox', $_ENV['USIMPAY_API_KEY'], $_ENV['USIMPAY_SECRET_KEY']); $client = new UsimPayClient($config); $banks = $client->listBanks('b2c'); $availableB2cBanks = $banks['data']['b2c'];
Failed HTTP responses throw ApiException, transport failures throw TransportException, and invalid local input throws ValidationException.
Verify webhooks
Always verify the exact raw request bytes before decoding JSON:
use Hyprdev\UsimPay\WebhookVerifier; $payload = $request->getContent(); $timestamp = (string) $request->header('X-USIMPay-Timestamp'); $signature = (string) $request->header('X-USIMPay-Signature'); $verifier = new WebhookVerifier(config('usimpay.webhook_signing_key')); if (!$verifier->verify($payload, $timestamp, $signature, toleranceSeconds: 300)) { abort(401, 'Invalid webhook signature'); } $event = json_decode($payload, true, flags: JSON_THROW_ON_ERROR);
Store processed event_id values to make webhook handling idempotent. A timestamp tolerance helps reject replayed deliveries.
USIMPay sends merchant webhooks only for verified terminal PayNet decisions: payment.success, payment.failed, and payment.cancelled. Use getPayment() when reconciliation is required.
Development
composer install
composer test