payplus-ipg

PayPlus Payment Gateway SDK for JavaScript/TypeScript — works with React, Next.js, Vue, Angular, and plain JS/Node
1,465
Install
npm install payplus-ipg
Latest Version:1.0.6
License:MIT
Last Updated:May 22, 2026
Links: npm
Maintainer: payplus-ipg

payplus-ipg

Official PayPlus Internet Payment Gateway (IPG) SDK for JavaScript & TypeScript

Integrate PayPlus payments into any JavaScript project with a single async function call. Zero dependencies, fully typed, works everywhere.

npm version license types


✅ Framework Support

Framework Support
⚛️ React / Vite ✅
▲ Next.js (App Router, Pages Router, Edge Runtime) ✅
🟢 Vue 3 / Nuxt ✅
🔴 Angular ✅
🟠 Svelte / SvelteKit ✅
🟦 Plain JavaScript / TypeScript ✅
🖥️ Node.js ≥ 16 ✅

How It Works

  1. Your server calls createPaymentSession() with the order and customer details
  2. PayPlus returns a hosted payment URL
  3. You redirect the customer to that URL
  4. The customer completes payment on the secure PayPlus page
  5. PayPlus notifies your server via webhook (notifyUrl) and redirects the customer back to your site (redirectUrl)
Your Server ──► createPaymentSession() ──► PayPlus API
                                               │
                                        paymentUrl returned
                                               │
Customer ◄─── redirect to paymentUrl ◄─────────┘
    │
    └──► Pays on PayPlus hosted page
              │
              ├──► POST webhook ──► your notifyUrl  (server-to-server)
              └──► redirect    ──► your redirectUrl (customer browser)

Installation

npm install payplus-ipg
# or
yarn add payplus-ipg
# or
pnpm add payplus-ipg

Quick Start

import { createPaymentSession } from 'payplus-ipg';

const result = await createPaymentSession({
  merchantId:     'YOUR_MERCHANT_ID',
  applicationKey: 'YOUR_APPLICATION_KEY',
  secret:         'YOUR_SECRET',

  amount:      1000,
  currency:    'LKR',
  orderId:     'ORD-00123',
  redirectUrl: 'https://myshop.com/thank-you',
  notifyUrl:   'https://myshop.com/api/payment-notify',
  description: 'Order #ORD-00123',

  customer: {
    firstname:   'John',
    lastname:    'Anderson',
    email:       'john@example.com',
    phoneNumber: '771234567',  // without dial code
    dialCode:    '+94',        // optional, defaults to '+94'
  },

  sandbox: false,  // true = sandbox (test payments) | false = live (real payments)
});

if (result.success && result.paymentUrl) {
  // Redirect the customer to the PayPlus hosted payment page
  window.location.href = result.paymentUrl;
} else {
  console.error('Payment session error:', result.error);
}

Integration Guide

Step 1 — Get Your Credentials

Log in to the PayPlus Merchant Dashboard and obtain:

  • Merchant ID
  • Application Key
  • Secret (used for HMAC-SHA256 request signing — keep this private)

Store them in environment variables — never hardcode them in your source code.

PAYPLUS_MERCHANT_ID=your_merchant_id
PAYPLUS_APP_KEY=your_application_key
PAYPLUS_SECRET=your_secret

Step 2 — Create a Payment Session (Server-Side)

⚠️ Always call createPaymentSession from your server (Next.js Server Action, API route, Express endpoint, etc.) so your secret is never exposed in the browser.

// Example: Next.js API route  (pages/api/pay.ts)
import type { NextApiRequest, NextApiResponse } from 'next';
import { createPaymentSession } from 'payplus-ipg';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') return res.status(405).end();

  const { orderId, amount, customer } = req.body;

  const result = await createPaymentSession({
    merchantId:     process.env.PAYPLUS_MERCHANT_ID!,
    applicationKey: process.env.PAYPLUS_APP_KEY!,
    secret:         process.env.PAYPLUS_SECRET!,

    amount,
    currency:    'LKR',
    orderId,
    redirectUrl: `${process.env.NEXT_PUBLIC_APP_URL}/thank-you?order=${orderId}`,
    notifyUrl:   `${process.env.NEXT_PUBLIC_APP_URL}/api/payment-notify`,
    description: `Order ${orderId}`,
    customer,

    sandbox: false, // switch to true for test payments
  });

  if (result.success) {
    res.status(200).json({ paymentUrl: result.paymentUrl });
  } else {
    res.status(500).json({ error: result.error });
  }
}

Step 3 — Redirect the Customer

Once you receive the paymentUrl, redirect the customer to it:

// Client-side
const res = await fetch('/api/pay', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ orderId, amount, customer }),
});
const { paymentUrl } = await res.json();

if (paymentUrl) {
  window.location.href = paymentUrl;
}

Step 4 — Handle the Webhook (notifyUrl)

PayPlus will POST a notification to your notifyUrl once payment is complete. Use this to fulfill the order in your database.

// Example: pages/api/payment-notify.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') return res.status(405).end();

  const notification = req.body;

  // TODO: Validate the notification signature from PayPlus
  // TODO: Check notification.status === 'SUCCESS' before fulfilling

  if (notification.status === 'SUCCESS') {
    const orderId = notification.orderId;
    // Mark order as paid in your database
    await markOrderPaid(orderId);
  }

  // Always respond 200 so PayPlus knows you received it
  res.status(200).json({ received: true });
}

Step 5 — Handle the Redirect (redirectUrl)

After payment, PayPlus redirects the customer back to your redirectUrl. Show them a confirmation page:

// Example: pages/thank-you.tsx
import { useRouter } from 'next/router';

export default function ThankYouPage() {
  const { query } = useRouter();
  return (
    <div>
      <h1>Thank you for your order!</h1>
      <p>Order ID: {query.order}</p>
    </div>
  );
}

Testing with Sandbox

Set sandbox: true to use the PayPlus sandbox gateway. Sandbox payments are test transactions — no real money is charged.

const result = await createPaymentSession({
  // ... your options
  sandbox: true,  // test payments — no real money charged
});

Switch to sandbox: false when you go live.


API Reference

createPaymentSession(options)

Returns Promise<PaymentSessionResult>

Options
Parameter Type Required Default Description
merchantId string ✅ — Your PayPlus Merchant ID
applicationKey string ✅ — Your PayPlus Application Key
secret string ✅ — Your secret key — used for HMAC-SHA256 signing. Never expose in the browser.
amount number ✅ — Payment amount (e.g. 1000 for LKR 1,000)
currency string ✅ — ISO 4217 currency code — e.g. 'LKR', 'USD'
orderId string ✅ — Unique order ID from your system
redirectUrl string ✅ — URL to redirect the customer after payment
notifyUrl string ✅ — Server webhook URL — PayPlus POSTs payment result here
customer object ✅ — Customer details — see CustomerInfo below
domain string — '' Your store domain
description string — '' Human-readable order description
paymentType string — 'ONE_TIME' 'ONE_TIME' or 'RECURRING'
source string — 'CUSTOM' Integration source identifier
pluginVersion string — '1.0.0' Your integration version string
sandbox boolean — false true = sandbox gateway (test payments), false = live gateway (real payments)
CustomerInfo
Parameter Type Required Default Description
firstname string ✅ — Customer first name
lastname string ✅ — Customer last name
email string ✅ — Customer email address
phoneNumber string ✅ — Phone number without dial code
dialCode string — '+94' International dial code
PaymentSessionResult
{
  success:     boolean;   // true if the session was created successfully
  paymentUrl?: string;    // redirect the customer to this URL
  sessionId?:  string;    // PayPlus session ID
  statusCode?: number;    // HTTP status code from the gateway
  raw?:        unknown;   // full raw response body from the gateway
  error?:      string;    // error message (present when success is false)
}

Framework Examples

⚛️ React

import { useState } from 'react';
import { createPaymentSession } from 'payplus-ipg';

function CheckoutButton({ order }) {
  const [loading, setLoading] = useState(false);

  const handlePay = async () => {
    setLoading(true);

    // ⚠️ Call your backend API — do NOT call createPaymentSession directly
    //    from the browser with your real secret
    const res = await fetch('/api/pay', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ orderId: order.id, amount: order.total, customer: order.customer }),
    });
    const { paymentUrl, error } = await res.json();

    if (paymentUrl) {
      window.location.href = paymentUrl;
    } else {
      alert(`Payment error: ${error}`);
      setLoading(false);
    }
  };

  return (
    <button onClick={handlePay} disabled={loading}>
      {loading ? 'Redirecting...' : 'Pay Now'}
    </button>
  );
}

▲ Next.js — App Router (Server Action)

// app/actions/payment.ts
'use server';
import { createPaymentSession } from 'payplus-ipg';

export async function initiatePayment(orderId: string, amount: number, customer: object) {
  return createPaymentSession({
    merchantId:     process.env.PAYPLUS_MERCHANT_ID!,
    applicationKey: process.env.PAYPLUS_APP_KEY!,
    secret:         process.env.PAYPLUS_SECRET!,
    amount,
    currency:    'LKR',
    orderId,
    redirectUrl: `${process.env.NEXT_PUBLIC_APP_URL}/thank-you`,
    notifyUrl:   `${process.env.NEXT_PUBLIC_APP_URL}/api/payment-notify`,
    customer,
    sandbox: false,
  });
}
// app/checkout/page.tsx
'use client';
import { initiatePayment } from '../actions/payment';

export default function CheckoutPage() {
  const handlePay = async () => {
    const result = await initiatePayment('ORD-001', 1500, {
      firstname: 'John', lastname: 'Anderson',
      email: 'john@example.com', phoneNumber: '771234567',
    });
    if (result.success && result.paymentUrl) {
      window.location.href = result.paymentUrl;
    }
  };
  return <button onClick={handlePay}>Pay Now</button>;
}

▲ Next.js — Pages Router (API Route)

// pages/api/create-payment.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { createPaymentSession } from 'payplus-ipg';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') return res.status(405).end();

  const result = await createPaymentSession({
    merchantId:     process.env.PAYPLUS_MERCHANT_ID!,
    applicationKey: process.env.PAYPLUS_APP_KEY!,
    secret:         process.env.PAYPLUS_SECRET!,
    ...req.body,
  });

  res.status(result.success ? 200 : 500).json(result);
}

🟢 Vue 3 / Nuxt

<script setup lang="ts">
import { ref } from 'vue';
import { createPaymentSession } from 'payplus-ipg';

const loading = ref(false);

// ⚠️ In production use a Nuxt server route — not direct client-side calls with your secret
async function pay() {
  loading.value = true;
  const result = await createPaymentSession({
    merchantId:     import.meta.env.VITE_PAYPLUS_MERCHANT_ID,
    applicationKey: import.meta.env.VITE_PAYPLUS_APP_KEY,
    secret:         import.meta.env.VITE_PAYPLUS_SECRET,
    amount:      2500,
    currency:    'LKR',
    orderId:     'ORD-456',
    redirectUrl: `${window.location.origin}/thank-you`,
    notifyUrl:   'https://myshop.com/api/payment-notify',
    customer: {
      firstname: 'Nimal', lastname: 'Silva',
      email: 'nimal@example.com', phoneNumber: '779876543',
    },
    sandbox: false,
  });

  if (result.success && result.paymentUrl) {
    window.location.href = result.paymentUrl;
  } else {
    alert(result.error);
    loading.value = false;
  }
}
</script>

<template>
  <button @click="pay" :disabled="loading">
    {{ loading ? 'Redirecting…' : 'Pay Now' }}
  </button>
</template>

🔴 Angular

// payment.service.ts
import { Injectable } from '@angular/core';
import { createPaymentSession, CreatePaymentSessionOptions } from 'payplus-ipg';
import { environment } from '../environments/environment';

@Injectable({ providedIn: 'root' })
export class PaymentService {
  initiatePayment(options: Omit<CreatePaymentSessionOptions, 'merchantId' | 'applicationKey' | 'secret'>) {
    return createPaymentSession({
      ...options,
      merchantId:     environment.payplusMerchantId,
      applicationKey: environment.payplusAppKey,
      secret:         environment.payplusSecret,
    });
  }
}
// checkout.component.ts
import { Component } from '@angular/core';
import { PaymentService } from './payment.service';

@Component({
  selector: 'app-checkout',
  template: `<button (click)="pay()" [disabled]="loading">
    {{ loading ? 'Redirecting...' : 'Pay Now' }}
  </button>`
})
export class CheckoutComponent {
  loading = false;
  constructor(private paymentService: PaymentService) {}

  async pay() {
    this.loading = true;
    const result = await this.paymentService.initiatePayment({
      amount:      1000,
      currency:    'LKR',
      orderId:     'ORD-789',
      redirectUrl: 'https://myshop.com/thank-you',
      notifyUrl:   'https://myshop.com/api/payment-notify',
      customer: {
        firstname: 'Sunil', lastname: 'Fernando',
        email: 'sunil@example.com', phoneNumber: '712345678',
      },
      sandbox: false,
    });

    if (result.success && result.paymentUrl) {
      window.location.href = result.paymentUrl;
    } else {
      alert(result.error);
      this.loading = false;
    }
  }
}

🖥️ Node.js

import { createPaymentSession } from 'payplus-ipg';

const result = await createPaymentSession({
  merchantId:     process.env.PAYPLUS_MERCHANT_ID!,
  applicationKey: process.env.PAYPLUS_APP_KEY!,
  secret:         process.env.PAYPLUS_SECRET!,
  amount:      500,
  currency:    'LKR',
  orderId:     'ORD-001',
  redirectUrl: 'https://myshop.com/thank-you',
  notifyUrl:   'https://myshop.com/api/payment-notify',
  customer: {
    firstname: 'John', lastname: 'Doe',
    email: 'john@example.com', phoneNumber: '771234567',
  },
  sandbox: true, // switch to false for live payments
});

if (result.success) {
  console.log('Payment URL:', result.paymentUrl);
} else {
  console.error('Error:', result.error);
}

Security Best Practices

  • Never expose your secret in client-side code. Always call createPaymentSession from a server (API route, Server Action, Express endpoint).
  • Store all credentials in environment variables — never commit them to source control.
  • Validate webhook payloads from PayPlus before fulfilling orders.
  • Use HTTPS for both your redirectUrl and notifyUrl in production.

TypeScript Support

Full TypeScript support is built in — no @types package needed.

import {
  createPaymentSession,
  CreatePaymentSessionOptions,
  CustomerInfo,
  PaymentSessionResult,
} from 'payplus-ipg';

Requirements

  • Node.js ≥ 16 (uses native Web Crypto API or built-in crypto module — no extra dependencies)
  • Browser — any modern browser (Chrome 37+, Firefox 34+, Safari 11+, Edge 79+)

License

MIT © PayPlus

Related Packages

@discoverworthy/deploy

Deploy static sites to DiscoverWorthy hosting

3,281
@xcodleox/devinspector

SDK de monitoramento e auditoria de erros em tempo real | Dev Inspector

7,360
@coderefine/cli

CodeRefine — Multi-framework tech debt scanner CLI for React, Vue, Svelte, and A...

2,313
rasedi-sdk

Universal Rasedi Payment Gateway SDK for React, Vue, Angular, React Native, and...

965

Version History

Version Released License
1.0.6 MIT
1.0.5 ISC
1.0.3 ISC
1.0.2 ISC
1.0.1 ISC