Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Knet Laravel Package

asciisd/knet

Laravel package for integrating KNET payments into PHP applications. It simplifies payment initiation, callback handling, and response verification, giving developers a straightforward way to accept Kuwaiti debit card payments.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The package is a thin, opinionated adapter: KnetPaymentService is a delegating facade over four narrow contracts (CreatesPayments, InquiresPayments, RefundsPayments, TransactionRepository) plus an EncryptsPayload abstraction for AES-128-CBC. That is a genuinely Laravel-native shape — service-container bindings, a HasKnet trait for the billable model, Eloquent-backed persistence, and event-driven post-payment hooks. It will slot into an existing Laravel monolith or modular domain without architectural surgery.
  • The integration model is redirect-based against KNET's RAW pipe (protocol K-064), so cardholder data never touches our servers. This keeps our PCI DSS surface at roughly SAQ A/D-oriented scope and moves the heavy cryptographic work to the gateway plus a single encrypted trandata payload. For a payments TPM this is the single most valuable property of the package.
  • Payment lifecycle is explicit and inspectable: a knet_transactions row per attempt, result/paid state, UDF1–UDF5 as a passthrough correlation channel, and a distinct refund row (action = 2, original_transaction_id) rather than mutating the original. That gives us an audit trail we can reconcile against the acquirer.
  • The abstraction depth is right-sized. There is no repository/unit-of-work ceremony to fight, no custom ORM, no opinionated workflow engine. It is a data-mapper plus a gateway client. Risk of "framework inside a framework" is low.

Integration feasibility

  • Day-one feasibility is high: composer require, php artisan knet:install, set six env vars, add the trait to User, and the routes are auto-registered. The knet:check command gives us a credential-validation gate before we write any business logic.
  • The hard dependency is non-technical: a KNET Tran Portal ID, password, and resource key issued by the acquiring bank, plus KFAST enablement on the terminal if we want faster checkout. That is a procurement/onboarding lead time, not an engineering one, and it is the critical path for any schedule we publish.
  • Sandbox exists (kpaytest.com.kw) and is reachable, but it is a bank-run environment with its own availability and behavior quirks. We should budget for test-harness friction — declined-card matrices, error-code coverage, and callback timing are not fully documented in the package.
  • Precision and locale constraints are real and must be encoded as invariants at the boundary: amounts are 3-decimal KWD (10.000), currency is fixed to 414, trackid must be unique per transaction, and KFAST tokens are exactly 8 numeric digits with uniqueness per customer. These are all silently wrong if violated, so they belong in our request validation, not in the package.

Technical risk

  • Maintainer concentration. 14 stars and a recent-but-single release (2025-03-19) implies a small bus factor. MIT licensing means we can fork and vendor it, which materially de-risks abandonment, but we should plan for "we own this code" as a realistic contingency.
  • Callback authenticity. The docs state the response middleware "decrypts once" and passes the payload via request attributes, and that /knet/response sits behind signature-verification middleware. We must verify exactly what is verified — decryption success is not the same as origin authentication or replay protection. If the resource key is symmetric and shared, a captured payload is replayable; idempotency must be enforced by us on trackid and paymentid.
  • Event-driven fulfillment is fire-and-forget. KnetPaymentSucceeded is dispatched inside the callback request cycle. If our listener throws, we lose fulfillment while the user is being redirected. Anything financially material (order state, entitlements, ledger entries) must be idempotent and re-drivable, ideally via a queued listener plus an inquireAndUpdateTransaction reconciliation job.
  • Shared table for refunds. Refund records live in knet_transactions with action = 2. Every downstream query, report, and finance export must filter on action or it will double-count. That is an easy, expensive mistake.
  • Route namespace exposure. Auto-registered public POST routes under /knet/* can collide with application routing and must be reviewed for CSRF exemption, rate limiting, and WAF allowlisting. Knet::ignoreRoutes() exists but then we own the wiring.

Key questions

  1. Which Laravel and PHP versions are actually in the support matrix, and is there CI proving it, or is the constraint inferred?
  2. Does the response middleware verify any MAC/signature beyond AES decryption, and is there replay protection or timestamp validation?
  3. Is trackid uniqueness enforced by a database unique index in the shipped migration, or only by convention?
  4. Do refunds and inquiries retry on gateway timeouts, or fail fast? What is the error taxonomy surfaced through KnetException?
  5. Is there any published test suite or fixture set we can run against the sandbox, or do we build our own contract tests?
  6. Can the acquirer issue separate terminals for staging vs. production, so we are not testing against live credentials?

Integration Approach

Stack fit

  • Laravel-native throughout: service provider registration, config publishing, migrations, artisan commands, Eloquent model, events, contracts bound in the container. It assumes a standard User-as-billable model but supports KnetTransaction::useCustomerModel() for a custom payer entity — relevant if we bill organizations or accounts rather than users.
  • Queue compatibility is implicit rather than built in. We should add our own queued listeners and a scheduled reconciliation command that calls inquireAndUpdateTransaction for any transaction stuck in INITIATED/PENDING past a threshold.
  • The TransactionRepository contract is our seam for read paths; keeping reporting and finance queries behind it prevents them from coupling to knet_transactions columns directly.

Migration path

  • New capability, not a replacement, so there is no data migration. We add one table and one trait. If we already run a payment orchestration layer or a generic payments table, we introduce KnetTransaction as a provider-specific detail and project it into our canonical ledger via the events — do not let KNET column names (amt, auth, ref, tranid, result) leak into the domain model.
  • If we later add a second gateway, the narrow interfaces (CreatesPayments) let us swap or decorate without touching controllers. We should type-hint the narrowest interface we need from day one to keep that door open.

Compatibility

  • Config surface is small and env-driven (KNET_TRANSPORT_ID, KNET_TRANSPORT_PASSWORD, KNET_RESOURCE_KEY, KNET_REDIRECT_URL, KNET_CURRENCY, KNET_LANGUAGE, KNET_DEBUG, plus KNET_PATH). All must live in secrets management, not .env in the repo, and must be rotated on a schedule with a documented procedure.
  • Currency is hard-coded to KWD in practice (414) and amounts are 3-decimal. Any multi-currency ambition requires a separate gateway decision; treat this package as Kuwait-only and say so in the product spec.
  • KFAST requires acquirer-side enablement. If it is not enabled on our terminal, payWithKfast will fail at the gateway, not in the package. Gate the feature behind a config flag and a business decision, not a code path.

Sequencing

  1. Credential gate: acquire terminal ID/password/resource key and sandbox access. This runs in parallel from week one; everything else waits on it.
  2. Spike: install into a throwaway branch, run knet:install, exercise a full sandbox payment and callback end-to-end, capture the real request/response payloads, and document actual gateway behavior against the docs.
  3. Contract test suite: encode invariants (3-decimal amounts, unique trackid, 8-digit KFAST token, currency 414) and build fixtures for success/decline/abandon/refund/inquiry.
  4. Domain wiring: canonical order/payment state machine, queued KnetPaymentSucceeded/KnetPaymentFailed listeners, idempotency keys on trackid + paymentid.
  5. Refund and inquiry paths: implement partial refunds with an explicit accounting rule, and the scheduled reconciliation job for stuck transactions.
  6. KFAST: enable only after terminal confirmation and a token-strategy decision (default is zero-padded user ID — we likely want customer_number or a stable external ID).
  7. Observability and cutover: instrument KnetResponseReceived/KnetResponseHandled/KnetTransactionHasErrors, define alerting on failed callbacks, then production terminal switch with a small canary cohort.

Operational Impact

Maintenance

  • Ongoing maintenance is modest but nonzero: pin the version, watch the upstream repo for releases, and keep a fork ready. Because the package is small and MIT, the practical worst case is forking and owning roughly a few thousand lines — acceptable, but it must be an explicit line item, not an assumption.
  • Config and secrets rotation is the main recurring chore. AES-128-CBC with a shared resource key means key rotation requires coordination with the acquirer and a window where old and new payloads may both arrive.
  • Schema evolution risk is low but real: the package owns a migration. If we need extra columns (e.g., our order ID, a replay nonce, an idempotency hash), we add them in our own migration and keep the package's migration untouched.

Support

  • No commercial support tier. Escalation runs two ways: package-level bugs to the maintainer (slow, community-paced) and gateway/protocol issues through the acquiring bank's merchant support (process-heavy, Kuwait business hours). We should establish the bank relationship and a named contact before launch — that channel is our real production support line, not GitHub.
  • Internally, designate one owner for the payment domain. The package is simple enough that a mid-level Laravel engineer can hold it, but the KNET-specific failure semantics (result codes, RAW action codes, refund windows) need a documented runbook.

Scaling

  • Server-side load is trivial: one row insert per attempt, one redirect, one callback. The bottleneck is the gateway, not us.
  • knet_transactions grows monotonically and is never pruned by the package. Plan indexes on trackid (unique), paymentid, result, paid, and created_at, and a retention/archival policy — finance and audit typically want multi-year retention, so archive to cold storage rather than delete.
  • Callback concurrency is the real scaling concern: the same trackid can legitimately arrive more than once. Enforce idempotency with a database-level constraint and an upsert-style handler, not a read-then-write check.

Failure modes

  • Lost callback: user completes payment, our endpoint never sees it. Mitigation: scheduled inquiry reconciliation over pending transactions and a user-initiated "check status" path.
  • Listener exception during callback: payment captured, fulfillment lost. Mitigation: queue the listener, make handlers idempotent, and re-drive from the reconciliation job.
  • Duplicate/replayed callback: double fulfillment. Mitigation: unique constraint on trackid/paymentid plus a state-machine guard that only transitions from a pending state.
  • Refund double-counting: refunds stored in the same table as payments. Mitigation: mandatory action filtering in every report and a ledger projection that separates debits from credits.
  • Precision and currency errors: 2-decimal amounts or a non-414 currency reaching the gateway. Mitigation: validation at the boundary plus a lint-style test.
  • KFAST token collision: two customers sharing a token. Mitigation: enforce uniqueness in the token strategy and validate before submission.
  • Stuck pending transactions: gateway timeouts leave INITIATED rows indefinitely. Mitigation: age-based alerting and an operator runbook to force inquiry.

Ramp-up

  • Engineering ramp-up is short — a Laravel developer is productive in a day given the docs, trait, and service API. The long pole is domain onboarding: KNET result-code semantics, refund eligibility rules, KFAST terminal prerequisites, and the acquirer's dispute process.
  • Allocate time for sandbox discovery. Expect the gateway's real behavior (error payloads, timing, redirect handling) to differ in small ways from the documentation, and capture that delta in our own integration notes rather than assuming the package normalizes it.
  • Recommend a written runbook covering: credential rotation, callback failure triage, manual refund procedure, reconciliation job operation, and the bank escalation contact. That runbook, not the package, is what determines whether this is operationally boring in year two.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log