PHPackages                             amzad/apple-pay-knet - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. amzad/apple-pay-knet

ActiveLibrary[Payment Processing](/categories/payments)

amzad/apple-pay-knet
====================

Apple Pay on the Web + KNET Direct integration for Laravel and plain PHP

v1.1.0(1mo ago)023MITPHPPHP ^7.4|^8.0

Since May 2Pushed 1mo agoCompare

[ Source](https://github.com/amzad78692/apple-pay-knet)[ Packagist](https://packagist.org/packages/amzad/apple-pay-knet)[ RSS](/packages/amzad-apple-pay-knet/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (5)Versions (12)Used By (0)

amzad/apple-pay-knet
====================

[](#amzadapple-pay-knet)

Apple Pay on the Web + KNET Direct integration for Laravel.
Designed for Kuwaiti merchants who want to accept Apple Pay payments through the KNET payment gateway with minimal setup.

[![Latest Version on Packagist](https://camo.githubusercontent.com/e370ef11c8effea157b6c443b63e22d9c1a32081c9fe17676b84d39d14b33272/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616d7a61642f6170706c652d7061792d6b6e65742e737667)](https://packagist.org/packages/amzad/apple-pay-knet)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/c1c8f654d0526154782e2945335470fe0c6e6cb40a8e069a04d7098726478c26/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545372e34253743253545382e302d626c7565)](composer.json)

---

Table of Contents
-----------------

[](#table-of-contents)

1. [Requirements](#requirements)
2. [Installation](#installation)
3. [Apple Pay Setup](#apple-pay-setup)
4. [Configuration](#configuration)
5. [Database Migration](#database-migration)
6. [Publishing Assets](#publishing-assets)
7. [Environment Variables](#environment-variables)
8. [Frontend Integration](#frontend-integration)
9. [Handling the Callback](#handling-the-callback)
10. [Using the Facade](#using-the-facade)
11. [API Endpoints](#api-endpoints)
12. [Transaction Model](#transaction-model)
13. [Exception Handling](#exception-handling)
14. [Sandbox vs Production](#sandbox-vs-production)
15. [Troubleshooting](#troubleshooting)

---

Requirements
------------

[](#requirements)

- PHP `^7.4` or `^8.0`
- Laravel `^8.0` | `^9.0` | `^10.0` | `^11.0` | `^12.0`
- PHP extensions: `curl`, `openssl`, `json`
- An **Apple Developer account** with Apple Pay enabled
- An **Apple Pay Merchant Identity Certificate** (`.pem`)
- A **KNET merchant account** with API credentials
- Your site must be served over **HTTPS** with a **registered Apple Pay domain**

---

Installation
------------

[](#installation)

### Step 1 — Install the package via Composer

[](#step-1--install-the-package-via-composer)

```
composer require amzad/apple-pay-knet
```

### Step 2 — Auto-discovery (Laravel 8+)

[](#step-2--auto-discovery-laravel-8)

Laravel will automatically register the service provider and facade via package auto-discovery. No manual registration is required.

If you have disabled auto-discovery, add the following to your `config/app.php`:

```
'providers' => [
    // ...
    Amzad\ApplePayKnet\ApplePayKnetServiceProvider::class,
],

'aliases' => [
    // ...
    'ApplePayKnet' => Amzad\ApplePayKnet\Facades\ApplePayKnet::class,
],
```

---

Apple Pay Setup
---------------

[](#apple-pay-setup)

Before any code runs, you must complete the Apple Pay merchant setup. These steps are **required** and must be done in order.

### Step 1 — Enroll in the Apple Developer Program

[](#step-1--enroll-in-the-apple-developer-program)

Go to [developer.apple.com](https://developer.apple.com) and ensure you have an active paid developer account.

### Step 2 — Create a Merchant ID

[](#step-2--create-a-merchant-id)

1. In the Apple Developer portal, go to **Certificates, Identifiers &amp; Profiles → Identifiers**.
2. Click **+** and select **Merchant IDs**.
3. Enter a description and identifier (e.g. `merchant.com.yourstore`).
4. Click **Register**.

### Step 3 — Register your domain

[](#step-3--register-your-domain)

1. In the Apple Developer portal, open your Merchant ID.
2. Under **Apple Pay on the Web**, click **Add Domain**.
3. Download the domain verification file Apple provides.
4. Place it at this exact path on your server:

```
https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association

```

5. Click **Verify** in the developer portal.

> The file must be accessible without redirect or authentication.

### Step 4 — Create a Merchant Identity Certificate

[](#step-4--create-a-merchant-identity-certificate)

1. In the Apple Developer portal, open your Merchant ID.
2. Under **Merchant Identity Certificate**, click **Create Certificate**.
3. Generate a CSR (Certificate Signing Request) on your server:

```
openssl req -new -newkey rsa:2048 -nodes \
  -keyout merchant.key \
  -out merchant.csr \
  -subj "/CN=merchant.com.yourstore"
```

4. Upload the `.csr` file to Apple and download the resulting `.cer` file.

### Step 5 — Convert the certificate to PEM format

[](#step-5--convert-the-certificate-to-pem-format)

Apple issues `.cer` files in DER format. Convert it:

```
openssl x509 -inform DER -in merchant_id.cer -out merchant.pem
```

### Step 6 — Store certificates securely

[](#step-6--store-certificates-securely)

- Store `merchant.pem` and `merchant.key` **outside your web root** (e.g. `/etc/ssl/apple-pay/`).
- Set restrictive permissions:

```
chmod 600 /etc/ssl/apple-pay/merchant.pem
chmod 600 /etc/ssl/apple-pay/merchant.key
```

---

Configuration
-------------

[](#configuration)

### Step 1 — Publish the config file

[](#step-1--publish-the-config-file)

```
php artisan vendor:publish --tag=apple-pay-knet-config
```

This creates `config/apple-pay-knet.php`.

### Step 2 — Review the config file

[](#step-2--review-the-config-file)

```
// config/apple-pay-knet.php

return [

    // Apple Pay display name shown on the payment sheet
    'display_name' => env('APPLE_PAY_DISPLAY_NAME', ''),

    // Absolute path to the merchant identity certificate (.pem file)
    'certificate_path' => env('APPLE_PAY_CERTIFICATE_PATH', ''),

    // Absolute path to the certificate private key (.pem file)
    'certificate_key_path' => env('APPLE_PAY_CERTIFICATE_KEY_PATH', ''),

    // Password used when encrypting the private key (leave empty if none)
    'certificate_key_password' => env('APPLE_PAY_CERTIFICATE_KEY_PASSWORD', ''),

    // Apple Pay merchant validation URL (do not change unless Apple updates it)
    'validation_url' => env('APPLE_PAY_VALIDATION_URL', 'https://apple-pay-gateway-cert.apple.com/paymentservices/startSession'),

    'initiative' => 'web',

    'knet' => [
        // KNET payment endpoint (use sandbox during development)
        'endpoint' => env('KNET_ENDPOINT', 'https://www.kpaytest.com.kw/kpg/tranPipe.htm?param=tranInit&'),

        'id'           => env('KNET_ID', ''),
        'password'     => env('KNET_PASSWORD', ''),

        // URL where KNET will POST the successful payment response
        'response_url' => env('KNET_RESPONSE_URL', ''),

        // URL where KNET will redirect on payment error
        'error_url'    => env('KNET_ERROR_URL', ''),
    ],

    // URL prefix for all package routes
    'route_prefix' => env('APPLE_PAY_ROUTE_PREFIX', 'apple-pay'),

    // Middleware applied to all package routes
    'route_middleware' => ['web'],

    // Log every charge attempt to the apple_pay_transactions table
    'log_transactions' => env('APPLE_PAY_LOG_TRANSACTIONS', true),
];
```

---

Database Migration
------------------

[](#database-migration)

### Step 1 — Publish the migration

[](#step-1--publish-the-migration)

```
php artisan vendor:publish --tag=apple-pay-knet-migrations
```

### Step 2 — Run the migration

[](#step-2--run-the-migration)

```
php artisan migrate
```

This creates the `apple_pay_transactions` table with the following columns:

ColumnTypeDescription`id`bigintAuto-increment primary key`order_id`stringYour order/reference ID`amount`stringKWD amount as decimal string (e.g. `"5.250"`)`currency`stringISO 4217 numeric code (`414` = KWD)`apple_transaction_id`string (nullable)Apple Pay transaction identifier`knet_transaction_id`string (nullable)KNET transaction ID`status`enum`pending`, `authorized`, `captured`, `failed``response_code`string (nullable)KNET result code`auth_code`string (nullable)KNET authorization code`raw_response`json (nullable)Full KNET response payload`created_at` / `updated_at`timestampsLaravel timestamps> Skip this step if you set `'log_transactions' => false` in your config.

---

Publishing Assets
-----------------

[](#publishing-assets)

### Publish the JavaScript handler

[](#publish-the-javascript-handler)

```
php artisan vendor:publish --tag=apple-pay-knet-assets
```

This copies `apple-pay-handler.js` to `public/vendor/apple-pay-knet/js/`. The Blade component references it automatically.

### Publish the Blade views (optional)

[](#publish-the-blade-views-optional)

```
php artisan vendor:publish --tag=apple-pay-knet-views
```

This copies the views to `resources/views/vendor/apple-pay-knet/` so you can customise them.

---

Environment Variables
---------------------

[](#environment-variables)

Add the following to your `.env` file:

```
# ── Apple Pay ─────────────────────────────────────────────────────────────
APPLE_PAY_DISPLAY_NAME="Your Store Name"
APPLE_PAY_CERTIFICATE_PATH=/etc/ssl/apple-pay/merchant.pem
APPLE_PAY_CERTIFICATE_KEY_PATH=/etc/ssl/apple-pay/merchant.key
APPLE_PAY_CERTIFICATE_KEY_PASSWORD=         # leave blank if no password
APPLE_PAY_ROUTE_PREFIX=apple-pay
APPLE_PAY_LOG_TRANSACTIONS=true

# ── KNET ──────────────────────────────────────────────────────────────────
KNET_ENDPOINT=https://www.kpaytest.com.kw/kpg/tranPipe.htm?param=tranInit&
KNET_ID=your_knet_merchant_id
KNET_PASSWORD=your_knet_password
KNET_RESPONSE_URL=https://yourdomain.com/payment/callback
KNET_ERROR_URL=https://yourdomain.com/payment/error
```

> Replace `KNET_ENDPOINT` with the production URL when going live (provided by your bank).

---

Frontend Integration
--------------------

[](#frontend-integration)

### Option A — Blade Component (Recommended)

[](#option-a--blade-component-recommended)

#### Step 1 — Publish the JS asset

[](#step-1--publish-the-js-asset)

```
php artisan vendor:publish --tag=apple-pay-knet-assets
```

#### Step 2 — Add the component to your Blade view

[](#step-2--add-the-component-to-your-blade-view)

```

```

The component automatically:

- Loads the Apple Pay SDK and the `apple-pay-handler.js` script (once per page)
- Shows/hides the button based on device support
- Handles merchant validation and payment processing

#### Available Component Props

[](#available-component-props)

PropRequiredDefaultDescription`amount`Yes—Payment amount as a string (e.g. `"5.250"`)`reference`Yes—Your unique order/reference ID`callbackUrl`Yes—URL to POST the KNET response to after payment`label`No`config('apple-pay-knet.display_name')`Label shown on the payment sheet`currencyCode`No`KWD`ISO 4217 currency code`countryCode`No`KW`ISO 3166 country code`paymentGateway`No`KNET`Payment gateway identifier`onSuccess`No`null`JavaScript callback function on success`onError`No`null`JavaScript callback function on error`onCancel`No`null`JavaScript callback function on cancel#### Custom JS Callbacks Example

[](#custom-js-callbacks-example)

```

```

---

### Option B — Manual JavaScript Integration

[](#option-b--manual-javascript-integration)

If you prefer not to use the Blade component, include the scripts manually and initialise `ApplePayKnet` directly.

#### Step 1 — Include the scripts

[](#step-1--include-the-scripts)

```

```

#### Step 2 — Add the Apple Pay button element

[](#step-2--add-the-apple-pay-button-element)

```

```

#### Step 3 — Initialise the handler

[](#step-3--initialise-the-handler)

```
window.ApplePayKnet.init({
  validateMerchantUrl: "/apple-pay/validate-merchant",
  processPaymentUrl: "/apple-pay/process-payment",
  amount: "5.250",
  reference: "ORD-001",
  callbackUrl: "/payment/callback",
  csrfToken: document.querySelector('meta[name="csrf-token"]').content,

  // Optional callbacks
  onSuccess: function (knetResponse) {
    console.log("Payment authorized", knetResponse);
  },
  onError: function (error) {
    console.error("Payment error", error);
  },
  onCancel: function () {
    console.log("Payment cancelled by user");
  },
});
```

#### Full init options

[](#full-init-options)

OptionRequiredDefaultDescription`validateMerchantUrl`Yes—Route to the package's validate-merchant endpoint`processPaymentUrl`Yes—Route to the package's process-payment endpoint`amount`Yes—Payment amount string`reference`Yes—Unique order reference`callbackUrl`Yes—Your callback URL that receives the KNET response`csrfToken`Yes—Laravel CSRF token`label`No`"Your card will be charged"`Label on the payment sheet total line`applePayVersion`No`3`Apple Pay JS API version`countryCode`No`"KW"`ISO 3166 country code`currencyCode`No`"KWD"`ISO 4217 currency code`merchantCapabilities`No`["supports3DS"]`Array of merchant capabilities`supportedNetworks`No`["visa", "masterCard", "amex", "discover"]`Array of supported card networks`paymentGateway`No`"KNET"`Gateway identifier sent to the server`onSuccess`No`null`JS function called on successful authorization`onError`No`null`JS function called on any error`onCancel`No`null`JS function called when the user cancels---

Handling the Callback
---------------------

[](#handling-the-callback)

After a successful payment, the package auto-submits a hidden form that POSTs the KNET response fields to your `callbackUrl`. Create a route and controller action to handle this:

### Step 1 — Define the route

[](#step-1--define-the-route)

```
// routes/web.php
Route::post('/payment/callback', [PaymentController::class, 'callback'])->name('payment.callback');
Route::get('/payment/error',     [PaymentController::class, 'error'])->name('payment.error');
```

### Step 2 — Handle the callback

[](#step-2--handle-the-callback)

```
