You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中集成KNET Payment Gateway

Next.js中集成KNET Payment Gateway

Hey there! I’ve worked with KNET integrations a few times, so let me break down how to get this set up in your Next.js app—since official JS-specific docs are pretty hard to find, this step-by-step should help you get started.

First off, make sure you have your KNET merchant credentials handy: you’ll need a Merchant ID, Terminal ID, and Secret Key (you can get these from your KNET merchant dashboard).


1. Frontend: Add a Payment Trigger Component

In Next.js, you’ll create a client-side component to handle the payment initiation. This component will call your backend API to generate KNET payment parameters, then auto-submit a hidden form to redirect users to the KNET payment page.

Here’s a sample component:

'use client';

import { useState } from 'react';

export default function KnetPaymentButton() {
  const [isLoading, setIsLoading] = useState(false);

  const handlePayment = async () => {
    setIsLoading(true);
    try {
      // Call your backend API to get KNET payment details
      const res = await fetch('/api/knet/initiate-payment', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          amount: '1000', // Remember: KNET uses fils (1KD = 1000 fils)
          orderId: `ORDER-${Date.now()}`, // Unique order ID for every payment
          returnUrl: `${window.location.origin}/api/knet/callback`,
        }),
      });

      const data = await res.json();
      if (data.success) {
        // Create a hidden form to submit to KNET
        const paymentForm = document.createElement('form');
        paymentForm.method = 'POST';
        paymentForm.action = data.paymentUrl;

        // Add all required KNET parameters as hidden inputs
        Object.entries(data.paymentParams).forEach(([key, value]) => {
          const input = document.createElement('input');
          input.type = 'hidden';
          input.name = key;
          input.value = value;
          paymentForm.appendChild(input);
        });

        document.body.appendChild(paymentForm);
        paymentForm.submit();
      }
    } catch (err) {
      console.error('Failed to start payment:', err);
      alert('Oops, something went wrong. Please try again later.');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <button 
      onClick={handlePayment} 
      disabled={isLoading}
      className="px-6 py-3 bg-blue-600 text-white rounded"
    >
      {isLoading ? 'Processing...' : 'Pay with KNET'}
    </button>
  );
}

2. Backend: Initiate Payment API Route

Create an API route (/api/knet/initiate-payment/route.js) to generate the signed KNET payment parameters. This is critical because you never want to expose your secret key on the frontend.

import crypto from 'crypto';

export async function POST(request) {
  try {
    const { amount, orderId, returnUrl } = await request.json();

    // Load KNET credentials from environment variables (never hardcode these!)
    const merchantId = process.env.KNET_MERCHANT_ID;
    const terminalId = process.env.KNET_TERMINAL_ID;
    const secretKey = process.env.KNET_SECRET_KEY;
    const knetPaymentUrl = process.env.KNET_PAYMENT_URL; // Test: https://testpay.knet.com.kw/PaymentHTTP.htm | Production: https://pay.knet.com.kw/PaymentHTTP.htm

    // Build required KNET parameters
    const paymentParams = {
      MerchantID: merchantId,
      TerminalID: terminalId,
      Amount: amount,
      OrderID: orderId,
      ReturnURL: returnUrl,
      ErrorURL: returnUrl, // Can use the same URL as return, or a separate error page
      Language: 'ENG', // Use 'ARB' for Arabic
      CurrencyCode: '414', // Currency code for KD; adjust if using other currencies
    };

    // Generate the secure hash (follow KNET's exact parameter order!)
    const signatureString = `${paymentParams.MerchantID}${paymentParams.TerminalID}${paymentParams.OrderID}${paymentParams.Amount}${paymentParams.CurrencyCode}`;
    const secureHash = crypto.createHmac('sha256', secretKey)
      .update(signatureString)
      .digest('hex')
      .toUpperCase();

    paymentParams.SecureHash = secureHash;

    return new Response(
      JSON.stringify({
        success: true,
        paymentUrl: knetPaymentUrl,
        paymentParams,
      }),
      { status: 200 }
    );
  } catch (err) {
    return new Response(
      JSON.stringify({ success: false, error: err.message }),
      { status: 500 }
    );
  }
}

3. Backend: Handle KNET Callback

KNET will send a POST request to your specified returnUrl once the payment is complete. Create another API route (/api/knet/callback/route.js) to verify the payment and update your order status.

import crypto from 'crypto';
import { redirect } from 'next/navigation';

export async function POST(request) {
  try {
    const formData = await request.formData();
    const callbackData = Object.fromEntries(formData.entries());

    // Extract key callback parameters
    const {
      MerchantID,
      TerminalID,
      OrderID,
      Amount,
      CurrencyCode,
      ResponseCode,
      TrackID,
      SecureHash,
    } = callbackData;

    const secretKey = process.env.KNET_SECRET_KEY;

    // Verify the secure hash to ensure the callback is legitimate
    const verifyString = `${MerchantID}${TerminalID}${OrderID}${ResponseCode}${TrackID}${Amount}${CurrencyCode}`;
    const calculatedHash = crypto.createHmac('sha256', secretKey)
      .update(verifyString)
      .digest('hex')
      .toUpperCase();

    if (calculatedHash !== SecureHash) {
      console.error('KNET callback signature verification failed');
      return redirect('/payment/failed');
    }

    // Process payment result
    if (ResponseCode === '000') {
      // ✅ Payment succeeded: Update your database (mark order as paid, save TrackID, etc.)
      console.log(`Payment successful for order ${OrderID} | TrackID: ${TrackID}`);
      return redirect(`/payment/success?orderId=${OrderID}`);
    } else {
      // ❌ Payment failed: Log the error and redirect to failure page
      console.log(`Payment failed for order ${OrderID} | Response Code: ${ResponseCode}`);
      return redirect(`/payment/failed?orderId=${OrderID}`);
    }
  } catch (err) {
    console.error('Error handling KNET callback:', err);
    return redirect('/payment/failed');
  }
}

Key Things to Remember

  • Environment Variables: Store all KNET credentials in .env.local (e.g., KNET_MERCHANT_ID=xxx) to keep them secure.
  • Test First: Use KNET’s test environment to debug before switching to production. You can get test cards from your merchant dashboard.
  • Parameter Order: The secure hash generation relies on a strict parameter order—double-check KNET’s docs to make sure you’re using the right sequence (I’ve included the standard ones here, but confirm with your KNET rep).
  • Amount Format: Always use fils for the amount (no decimals!). For example, 2.5 KD becomes 2500.
  • Error Handling: Add proper error messages for users and log all payment events for debugging.

备注:内容来源于stack exchange,提问作者Samiur Akif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 15:32:37