一键导入
knet-development
Build and work with KNET payment gateway integration, including payment initiation, callback handling, refunds, and event-driven payment flows.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Build and work with KNET payment gateway integration, including payment initiation, callback handling, refunds, and event-driven payment flows.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | knet-development |
| description | Build and work with KNET payment gateway integration, including payment initiation, callback handling, refunds, and event-driven payment flows. |
Use this skill when:
knet_transactions table or KnetTransaction modelasciisd/knet provides a fluent Laravel interface to Kuwait's KNET payment gateway. It handles AES-encrypted communication, payment initiation, callback verification, transaction inquiry, and refunds.
The package follows SOLID principles with focused interfaces:
CreatesPayments — payment creation and response handlingInquiresPayments — transaction status inquiryRefundsPayments — full and partial refundsTransactionRepository — data access abstractionEncryptsPayload — encryption abstraction (wraps AES-128-CBC)KnetPaymentService is a pure delegating facade that implements all three payment interfaces. Prefer depending on the narrower interface when only a subset of functionality is needed.
KNET_TRANSPORT_ID=your_transport_id
KNET_TRANSPORT_PASSWORD=your_password
KNET_RESOURCE_KEY=your_resource_key
KNET_REDIRECT_URL=/payment/success
KNET_CURRENCY=414
KNET_LANGUAGE=EN
KNET_DEBUG=false
Add HasKnet to any model that can make payments (typically User):
use Asciisd\Knet\HasKnet;
class User extends Authenticatable
{
use HasKnet;
}
This adds:
pay(float $amount, array $options = []): KnetTransaction — create a paymentpayWithKfast(float $amount, array $options = []): KnetTransaction — KFAST faster checkout (auto-generates 8-digit token)refund(KnetTransaction $transaction, ?float $amount = null): array — full or partial refundkfastToken(): string — overridable 8-digit numeric KFAST token generatorknetTransactions(): HasMany — relationship to all transactions$transaction = $user->pay(10.000, [
'udf1' => 'order_123',
'udf2' => 'product_subscription',
]);
return redirect($transaction->url);
use Asciisd\Knet\Services\KnetPaymentService;
public function checkout(KnetPaymentService $paymentService)
{
$transaction = $paymentService->createPayment(
user: auth()->user(),
amount: 25.500,
options: [
'udf1' => 'invoice_789',
'trackid' => 'custom-track-id', // optional, auto-generated if omitted
]
);
return redirect($transaction->url);
}
If you only need payment creation, type-hint the narrower interface:
use Asciisd\Knet\Contracts\CreatesPayments;
public function checkout(CreatesPayments $payments)
{
$transaction = $payments->createPayment(auth()->user(), 25.500);
return redirect($transaction->url);
}
// Auto-generates 8-digit token from user ID (e.g., user ID 42 → "00000042")
$transaction = $user->payWithKfast(25.500, [
'udf1' => 'order_id',
]);
return redirect($transaction->url);
// Or with a custom token override
$transaction = $user->payWithKfast(25.500, [
'udf3' => '99887766',
]);
// Or pass udf3 directly to pay()
$transaction = $user->pay(25.500, [
'udf3' => '12345678',
]);
Override the token strategy by implementing kfastToken() on your model:
class User extends Authenticatable
{
use HasKnet;
public function kfastToken(): string
{
return str_pad((string) $this->customer_number, 8, '0', STR_PAD_LEFT);
}
}
KFAST token rules:
PaymentRequest)10.000, 25.500, 0.250414 is the ISO code for Kuwaiti Dinarudf1–udf5) carry custom data through the full payment lifecycle$transaction->url contains the full KNET gateway URL to redirect the user to$user->pay() or KnetPaymentService::createPayment() — returns a KnetTransaction with a url$transaction->url (the KNET payment page)trandata to /knet/response — middleware decrypts once and passes payload via request attributesKnetPaymentSucceeded or KnetPaymentFailed is dispatchedKNET_REDIRECT_URL with the resultuse Asciisd\Knet\Events\KnetPaymentSucceeded;
use Asciisd\Knet\Events\KnetPaymentFailed;
use Illuminate\Support\Facades\Event;
// In a service provider or EventServiceProvider
Event::listen(KnetPaymentSucceeded::class, function ($event) {
$transaction = $event->transaction;
// Fulfill the order, send confirmation, etc.
});
Event::listen(KnetPaymentFailed::class, function ($event) {
$transaction = $event->transaction;
$error = $event->errorMessage;
// Notify user, log failure, etc.
});
| Event | Payload |
|---|---|
KnetPaymentSucceeded | KnetTransaction $transaction |
KnetPaymentFailed | KnetTransaction $transaction, ?string $errorMessage |
KnetRefundSucceeded | KnetTransaction $transaction, KnetTransaction $refundTransaction, float $amount |
KnetRefundFailed | KnetTransaction $transaction, KnetTransaction $refundTransaction, string $reason |
KnetResponseReceived | array $payload |
KnetResponseHandled | array $payload |
KnetTransactionCreated | KnetTransaction $transaction |
KnetTransactionUpdated | KnetTransaction $transaction |
KnetTransactionHasErrors | KnetTransaction $transaction |
KnetReceiptSeen | KnetTransaction $transaction |
use Asciisd\Knet\KnetTransaction;
// Check status
$transaction->isCaptured(); // true if result == 'CAPTURED'
$transaction->hasStatus(); // true if result is not empty
$transaction->isRefundable(); // true if captured and not yet refunded
$transaction->isRefunded(); // true if refunded
// Get amount
$transaction->rawAmount(); // float, e.g. 10.0
$transaction->formattedAmount(); // string, e.g. "10.000"
// Access relationship
$transaction->owner; // the User (or custom model) who made the payment
To find by track ID, use the repository:
use Asciisd\Knet\Contracts\TransactionRepository;
$repository = app(TransactionRepository::class);
$transaction = $repository->findByTrackId('track-123');
| Column | Type | Description |
|---|---|---|
trackid | string | Unique tracking identifier |
paymentid | string | KNET payment ID |
result | string | Payment result (CAPTURED, FAILED, etc.) |
amt | string | Payment amount |
auth | string | Authorization code |
ref | string | Reference number |
tranid | string | Transaction ID |
udf1–udf5 | string | User-defined fields |
paid | boolean | Whether payment was successful |
refunded | boolean | Whether transaction was refunded |
refund_amount | decimal | Refund amount (if partial) |
use Asciisd\Knet\Enums\PaymentStatus;
$status = PaymentStatus::from($transaction->result);
$status->isSuccessful(); // CAPTURED or SUCCESS
$status->isFailed(); // FAILED, ABANDONED, CANCELLED, DECLINED, etc.
$status->isPending(); // INITIATED, PENDING, UNKNOWN
$status->displayName(); // Human-readable name
For presentation (colors, images), use the presenter:
$presenter = $status->presenter();
$presenter->styleColor(); // 'success-status', 'info-status', 'danger-status'
$presenter->textColor(); // 'successText', 'infoText', 'dangerText'
$presenter->bgColor(); // 'successBG', 'infoBG', 'dangerBG'
$presenter->imageUrl(); // URL to status image
$presenter->toArray(); // Full presentation array
use Asciisd\Knet\Services\KnetPaymentService;
// Re-check transaction status with KNET gateway and update locally
$transaction = $paymentService->inquireAndUpdateTransaction($transaction);
// Raw inquiry (returns array)
$result = $paymentService->inquirePayment(10.000, 'track-123');
// Full refund
$result = $user->refund($transaction);
// Partial refund
$result = $user->refund($transaction, 5.000);
// Full refund
$result = $paymentService->refundPayment($transaction);
// Partial refund (5 KWD of a 10 KWD transaction)
$result = $paymentService->refundPayment($transaction, 5.000);
The service automatically validates before processing:
isRefundable())Throws KnetException on validation failure.
refunded = true, refunded_at is set, refund_amount is recordedKnetTransaction record is created for the refund (with action = 2 and original_transaction_id linking to the original)KnetRefundSucceeded event is dispatched on success; KnetRefundFailed on failureCAPTURED for success; any other value is a failureThe package auto-registers these routes (prefix configurable via KNET_PATH):
| Method | URI | Purpose |
|---|---|---|
| POST | /knet/response | KNET encrypted callback (with signature verification middleware) |
| POST | /knet/handle | Post-success redirect handler |
| GET/POST | /knet/error | Error callback handler |
Disable auto-registration with Knet::ignoreRoutes() in a service provider.
use Asciisd\Knet\KnetTransaction;
// In AppServiceProvider::boot()
KnetTransaction::useCustomerModel(\App\Models\Customer::class);
use Asciisd\Knet\Knet;
// In AppServiceProvider::register()
Knet::ignoreMigrations();
use Asciisd\Knet\Knet;
// In AppServiceProvider::register()
Knet::ignoreRoutes();
| Command | Purpose |
|---|---|
php artisan knet:install | Publish config, run migrations, validate setup |
php artisan knet:check | Validate credentials and configuration |
php artisan knet:publish | Publish config (--config) and/or migrations (--migrations) |
use Asciisd\Knet\Services\KnetPaymentService;
use Illuminate\Http\Request;
class CheckoutController extends Controller
{
public function __construct(
private readonly KnetPaymentService $paymentService
) {}
public function pay(Request $request)
{
$request->validate(['amount' => 'required|numeric|min:0.001']);
$transaction = $this->paymentService->createPayment(
$request->user(),
$request->amount,
['udf1' => $request->order_id]
);
return redirect($transaction->url);
}
}
use Asciisd\Knet\Events\KnetPaymentSucceeded;
class HandleSuccessfulPayment
{
public function handle(KnetPaymentSucceeded $event): void
{
$transaction = $event->transaction;
$orderId = $transaction->udf1;
Order::where('id', $orderId)->update(['status' => 'paid']);
}
}
This section documents the underlying KNET Payment Gateway protocol (doc K-064 v1.4) that the package abstracts.
| Environment | Portal | Transaction Pipe (RAW) |
|---|---|---|
| Test | https://www.kpaytest.com.kw/kpg/merchant.htm | https://www.kpaytest.com.kw/kpg/tranPipe.htm?param=tranInit& |
| Production | https://www.kpay.com.kw/portal/merchant.htm | https://www.kpay.com.kw/kpg/tranPipe.htm?param=tranInit& |
| Action | Code | Description |
|---|---|---|
| Purchase | 1 | Standard payment transaction |
| Refund (Credit) | 2 | Refund a captured transaction |
| Inquiry | 8 | Query transaction status |
The package uses RAW-based integration which requires:
KNET_TRANSPORT_ID) — unique terminal identifierKNET_TRANSPORT_PASSWORD) — terminal passwordKNET_RESOURCE_KEY) — 16-char AES-128-CBC key for encrypting/decrypting trandataRAW requests use Content-type: application/xml and send XML-formatted parameters to the tranPipe.htm endpoint.
| Variable | Type | Length | Required | Description |
|---|---|---|---|---|
| Tran Portal ID | STRING | 255 | Y | Unique terminal ID |
| Tran Portal Password | STRING | 15 | Y | Terminal password |
| Terminal Resource Key | STRING | 16 | Y | AES encryption key |
| Action | STRING | 1 | Y | 1 (purchase), 2 (refund), 8 (inquiry) |
| Amount | STRING | 10 | Y | 3 decimal places for KWD: 15.750, 10.000 |
| Currency Code | STRING | 3 | Y | 414 for KWD |
| Language | STRING | 3 | Y | EN or AR |
| Response URL | STRING | 255 | Y | URL for KNET to POST transaction response |
| Error URL | STRING | 255 | Y | URL for consumer redirect on error |
| Track ID | STRING | 40 | Y | Unique merchant-generated tracking ID (alphanumeric only) |
| Trans ID | STRING | 19 | Y (Refund/Inquiry) | Identifies the original transaction |
| UDF1–UDF4 | STRING | 255 | N | User-defined fields for custom data |
| UDF3 (KFAST) | STRING | 8 | N | 8-digit numeric customer token for KFAST faster checkout |
| UDF5 | STRING | 255 | N | Purchase: extra data, prefix with "ptlf" for bank reports (max 50 chars). Inquiry: identifier type — "TrackID", "PaymentID", "TransID", or "SeqNum" |
| Variable | Description |
|---|---|
| paymentid | Unique order ID from Payment Gateway |
| result | CAPTURED, NOT CAPTURED, CANCELED, HOST TIMEOUT |
| ref | Reference number from KNET |
| trackid | Merchant's original tracking ID |
| tranid | Transaction ID from Payment Gateway |
| postdate | Post date in MMDD format |
| auth | Authorization code from the bank |
| amt | Transaction amount (3 decimal places) |
| udf1–udf5 | User-defined fields echoed back |
| avr | Address verification response |
| authRespCode | Reason code for the transaction result |
| Error | Error code (if unsuccessful) |
| ErrorText | Error description (if unsuccessful) |
When KNET POSTs the response to the responseURL:
trandata parameter via URL-encoded POSTREDIRECT=<Merchant Receipt URL>REDIRECT= text| Result | Meaning | Context |
|---|---|---|
CAPTURED | Transaction approved | Purchase, Inquiry, Refund |
NOT CAPTURED | Transaction declined by bank | Purchase |
CANCELED | Customer canceled on payment page | Purchase |
HOST TIMEOUT | Bank did not respond in time | Purchase |
SUCCESS | Transaction available and captured | Inquiry |
FAILURE | Transaction failed | Inquiry |
SUSPECTED | Transaction suspected | Inquiry |
Inquiry uses action code 8. The udf5 parameter determines which identifier is used to locate the original transaction:
| Inquire by | transid value | udf5 value | amt | trackid |
|---|---|---|---|---|
| Transaction ID | Original TransId | Empty or "TransID" | Original Amount | Original TrackId |
| Track ID | Original TrackId | "TrackID" | Original Amount | Original TrackId |
| Payment ID | Original PaymentId | "PaymentID" | Original Amount | Original TrackId |
| Reference ID | Original RefId | "SeqNum" | Original Amount | Original TrackId |
Refund uses action code 2. When refunding by Track ID:
transid = original Track ID valuetrackid = original Track ID valueudf5 = "TrackID"CAPTURED; any other value is a failureKFAST allows registered cardholders to skip entering card details. To enable:
UDF3 that uniquely identifies the customerRestricted characters:
| Field | Forbidden Characters |
|---|---|
| UDF1–UDF5 | @, / |
| Track ID | -, =, [, ], /, ?, . |
Track ID must be alphanumeric, max 40 characters, unique per transaction.
https://www.kpaytest.com.kw/kpg/merchant.htm09/2021Error codes follow the pattern IPAY01xxxxx (validation/processing) and IPAY02xxxxx (system/database). Key codes:
| Code | Description |
|---|---|
| IPAY0100001 | Missing error URL |
| IPAY0100003 | Missing response URL |
| IPAY0100005 | Missing tranportal ID |
| IPAY0100008 | Terminal not enabled |
| IPAY0100013 | Invalid transaction data |
| IPAY0100015 | Invalid tranportal password |
| IPAY0100017 | Inactive terminal |
| IPAY0100018 | Terminal password expired |
| IPAY0100020 | Invalid action type |
| IPAY0100023 | Missing amount |
| IPAY0100024 | Invalid amount |
| IPAY0100027 | Invalid track id |
| IPAY0100033 | Terminal action not enabled |
| IPAY0100036 | UDF Mismatched |
| IPAY0100042 | Transaction time limit exceeded |
| IPAY0100045 | Denied by Risk |
| IPAY0100048 | Cancelled |
| IPAY0100050 | Invalid terminal key |
| IPAY0100158 | Host timeout |
| IPAY0100176 | Decrypting transaction data failed |
| IPAY0100249 | Merchant response URL is down |
| IPAY0100264 | Signature validation failed |
Full error code list: see K-064 Integration Manual Section 10.
src/Services/ and should implement the appropriate focused contractEncryptsPayload — do not use KPayClient static methods directlyTransactionRepository — do not use model static methods directlyKnetConfig singleton, not bare config() calls$config->isDebugMode(); only error-level logging should be unconditionalsrc/Events/ with Dispatchable and SerializesModels traitssrc/Exceptions/ extending KnetExceptionnumber_format($amount, 3, '.', '') for 3-decimal KWD formatting