-
Notifications
You must be signed in to change notification settings - Fork 9
Understanding Hosted Checkout
The Hosted Checkout process for JazzCash provides a secure and convenient method for merchants to accept online payments. This guide explains how the hosted checkout works and how to implement it using the JazzCash Laravel package.
Hosted Checkout redirects customers to JazzCash's secure payment page where they complete the payment. This method is ideal for merchants who want to avoid PCI DSS compliance requirements as card data is never handled on their servers.
1. Customer initiates payment on your website
↓
2. Your application creates payment request
↓
3. Generate secure hash
↓
4. Redirect customer to JazzCash payment page
↓
5. Customer completes payment on JazzCash
↓
6. JazzCash redirects back to your callback URL
↓
7. Verify payment and update order status
$amount = 1000.00; // Transaction amount
$billReference = 'ORDER-' . time(); // Unique order reference
$productDescription = 'Product Purchase'; // Product descriptionuse zfhassaan\JazzCash\JazzCash;
$jazzcash = new JazzCash();$jazzcash->setAmount($amount)
->setBillReference($billReference)
->setProductDescription($productDescription);return $jazzcash->sendRequest();The sendRequest() method:
- Validates payment data
- Builds payment parameters
- Generates secure hash
- Creates HTML form with auto-submit
- Returns response with form
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use zfhassaan\JazzCash\JazzCash;
class PaymentController extends Controller
{
/**
* Initiate payment
*/
public function initiatePayment(Request $request)
{
// Validate request
$request->validate([
'amount' => 'required|numeric|min:0.01',
'billref' => 'required|string|max:255',
'productDescription' => 'required|string|max:500',
]);
try {
// Create JazzCash instance
$jazzcash = new JazzCash();
// Set payment details
$jazzcash->setAmount($request->amount)
->setBillReference($request->billref)
->setProductDescription($request->productDescription);
// Send request - returns HTML form
return $jazzcash->sendRequest();
} catch (\InvalidArgumentException $e) {
return back()->withErrors(['payment' => $e->getMessage()]);
} catch (\RuntimeException $e) {
return back()->withErrors(['payment' => 'Configuration error: ' . $e->getMessage()]);
}
}
/**
* Handle payment callback
*/
public function handleCallback(Request $request)
{
// Get response data
$responseCode = $request->input('pp_ResponseCode');
$responseMessage = $request->input('pp_ResponseMessage');
$txnRefNo = $request->input('pp_TxnRefNo');
$amount = $request->input('pp_Amount');
$billReference = $request->input('pp_BillReference');
$secureHash = $request->input('pp_SecureHash');
// Verify hash (recommended for security)
if (!$this->verifyHash($request->all())) {
return view('payment.error', [
'message' => 'Invalid payment response',
]);
}
// Process based on response code
if ($responseCode === '000') {
// Payment successful
// Update order status
// Send confirmation email
// etc.
return view('payment.success', [
'transaction_id' => $txnRefNo,
'amount' => $amount / 100, // Convert from paisa
'bill_reference' => $billReference,
]);
} else {
// Payment failed
return view('payment.failure', [
'message' => $responseMessage,
'code' => $responseCode,
]);
}
}
/**
* Verify callback hash
*/
private function verifyHash(array $data): bool
{
// Rebuild hash array (same order as sent)
$hashArray = [
$data['pp_Amount'] ?? '',
$data['pp_BankID'] ?? '',
$data['pp_BillReference'] ?? '',
$data['pp_Description'] ?? '',
$data['pp_IsRegisteredCustomer'] ?? '',
$data['pp_Language'] ?? '',
$data['pp_MerchantID'] ?? '',
$data['pp_Password'] ?? '',
$data['pp_ProductID'] ?? '',
$data['pp_ReturnURL'] ?? '',
$data['pp_TxnCurrency'] ?? '',
$data['pp_TxnDateTime'] ?? '',
$data['pp_TxnExpiryDateTime'] ?? '',
$data['pp_TxnRefNo'] ?? '',
$data['pp_TxnType'] ?? '',
$data['pp_Version'] ?? '',
$data['ppmpf_1'] ?? '',
$data['ppmpf_2'] ?? '',
$data['ppmpf_3'] ?? '',
$data['ppmpf_4'] ?? '',
$data['ppmpf_5'] ?? '',
];
$sortedArray = config('jazzcash.hash_key');
foreach ($hashArray as $value) {
if ($value !== 'undefined' && $value !== null && $value !== '') {
$sortedArray .= '&' . $value;
}
}
$expectedHash = hash_hmac('sha256', $sortedArray, config('jazzcash.hash_key'));
return hash_equals($expectedHash, $data['pp_SecureHash'] ?? '');
}
}Add routes to routes/web.php:
Route::post('/payment/initiate', [PaymentController::class, 'initiatePayment']);
Route::get('/payment/callback', [PaymentController::class, 'handleCallback']);
Route::post('/payment/callback', [PaymentController::class, 'handleCallback']); // Some gateways use POSTThe package automatically generates the following parameters:
| Parameter | Description | Example |
|---|---|---|
pp_Version |
API version | 2.0 |
pp_Language |
Language | EN |
pp_MerchantID |
Merchant ID | From config |
pp_Password |
Password | From config |
pp_TxnRefNo |
Transaction reference | TR20250115120000123 |
pp_Amount |
Amount in paisa |
100000 (for 1000.00) |
pp_TxnCurrency |
Currency | PKR |
pp_TxnDateTime |
Transaction date/time | 20250115120000 |
pp_BillReference |
Bill reference | Your order ID |
pp_Description |
Description | Product description |
pp_IsRegisteredCustomer |
Registered customer | No |
pp_TxnExpiryDateTime |
Expiry date/time | 20250116120000 |
pp_ReturnURL |
Return URL | From config |
pp_SecureHash |
Secure hash | Generated hash |
JazzCash returns the following response codes:
| Code | Status | Description |
|---|---|---|
000 |
Success | Payment successful |
001 |
Failed | Payment failed |
002 |
Cancelled | Payment cancelled by user |
003 |
Pending | Payment pending |
- Always verify hash - Verify the secure hash in callback
- Use HTTPS - Ensure all payment URLs use HTTPS
- Validate all inputs - Sanitize and validate callback data
- Log transactions - Keep audit trail of all payment attempts
- Handle errors gracefully - Don't expose sensitive information
JAZZCASH_PAYMENTMODE=sandboxUse sandbox credentials for testing. Test cards and credentials are provided by JazzCash.
JAZZCASH_PAYMENTMODE=productionSwitch to production mode when ready. Ensure all credentials are correct.
- Generate unique bill references - Use order IDs or UUIDs
-
Store transaction references - Save
pp_TxnRefNofor tracking - Handle timeouts - Set appropriate expiry times
- Verify callbacks - Always verify hash on callback
- Update order status - Mark orders as paid/failed appropriately
- Check JavaScript is enabled
- Verify form HTML is correct
- Check browser console for errors
- Ensure hash key is correct
- Verify parameter order matches
- Check for empty/null values
- Verify credentials are correct
- Check API URLs are correct
- Ensure return URL is accessible
- API Reference - Complete API documentation
- Payment Flow - Payment flow diagram
- Troubleshooting - Common issues and solutions