npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

whish-pay

v1.0.3

Published

Whish Money payment gateway SDK for Node.js - Simple, type-safe, zero dependencies

Readme

whish-pay

Whish Money Payment Gateway SDK for Node.js - Simple, type-safe, zero dependencies

npm version npm downloads TypeScript License: MIT

A lightweight, framework-agnostic SDK for integrating Whish Money payments into your Node.js application. Works with Next.js, Express, Fastify, Hono, or any other Node.js backend.

Features

  • Zero Dependencies - No external runtime dependencies
  • Type-Safe - Full TypeScript support with comprehensive type definitions
  • Framework Agnostic - Works with any Node.js backend
  • Secure - Server-side only, secrets never exposed to client
  • Simple API - Single client class with intuitive methods
  • Multi-Currency - Supports USD, LBP, and AED currencies

Installation

npm install whish-pay
yarn add whish-pay
pnpm add whish-pay

Quick Start

import { WhishClient } from 'whish-pay';

// Initialize the client
const whish = new WhishClient({
  channel: process.env.WHISH_CHANNEL!,
  secret: process.env.WHISH_SECRET!,
  websiteUrl: process.env.WEBSITE_URL!,
});

// Create a payment
const { collectUrl } = await whish.createPayment({
  amount: 100.00,
  currency: 'USD',
  invoice: 'Order #12345',
  externalId: whish.generateExternalId(),
  successCallbackUrl: 'https://yourdomain.com/api/whish/callback/success',
  failureCallbackUrl: 'https://yourdomain.com/api/whish/callback/failure',
  successRedirectUrl: 'https://yourdomain.com/checkout/success',
  failureRedirectUrl: 'https://yourdomain.com/checkout/failure',
});

// Redirect user to payment page
// collectUrl: "https://whish.money/pay/abc123"

Configuration

Environment Variables

# Required
WHISH_CHANNEL=your_channel_id      # Provided by Whish
WHISH_SECRET=your_secret_key       # Provided by Whish (keep secure!)
WEBSITE_URL=https://yourdomain.com # Your registered website URL

# Optional
NODE_ENV=production                # Auto-switches to production API

Client Options

const whish = new WhishClient({
  // Required
  channel: string,      // Channel ID from Whish
  secret: string,       // Secret key from Whish
  websiteUrl: string,   // Your website URL

  // Optional
  environment?: 'sandbox' | 'production', // Default: auto-detect from NODE_ENV
  timeout?: number,     // Request timeout in ms (default: 30000)
});

API Reference

createPayment(request)

Creates a new payment and returns the payment URL.

const result = await whish.createPayment({
  amount: 100,                    // Payment amount
  currency: 'USD',                // 'USD' | 'LBP' | 'AED'
  invoice: 'Order #123',          // Description shown to user
  externalId: whish.generateExternalId(), // Unique transaction ID
  successCallbackUrl: '...',      // Whish calls this on success (server-to-server)
  failureCallbackUrl: '...',      // Whish calls this on failure (server-to-server)
  successRedirectUrl: '...',      // User redirected here after success
  failureRedirectUrl: '...',      // User redirected here after failure
});

if (result.success) {
  // Redirect user to result.collectUrl
} else {
  // Handle error: result.code, result.dialog?.message
}

getPaymentStatus(currency, externalId)

Verifies the status of a payment. Use this in your callback handlers.

const status = await whish.getPaymentStatus('USD', externalId);

// status.collectStatus: 'success' | 'failed' | 'pending'
// status.amount: number (if available)
// status.currency: string (if available)

getRate(amount, currency)

Gets the current rate/fees for payments.

const { rate } = await whish.getRate(100, 'USD');
// rate: 0.01 (1% fee)
const fee = amount * rate; // $1 fee on $100

getBalance()

Gets your Whish account balance.

const { balanceDetails } = await whish.getBalance();
// balanceDetails.balance: number

generateExternalId()

Generates a cryptographically secure unique ID for payments.

const externalId = whish.generateExternalId();
// Returns a unique numeric ID

validateAmount(received, expected, currency, tolerance?)

Validates payment amounts match within tolerance.

// Default tolerance: USD/AED = 0.02, LBP = 100
const isValid = whish.validateAmount(99.99, 100, 'USD'); // true
const isValid = whish.validateAmount(99.97, 100, 'USD'); // false

// Custom tolerance
const isValid = whish.validateAmount(99, 100, 'USD', 1); // true

Framework Examples

Next.js (App Router)

Create Payment API Route:

// app/api/whish/payment/route.ts
import { WhishClient } from 'whish-pay';
import { NextResponse } from 'next/server';

const whish = new WhishClient({
  channel: process.env.WHISH_CHANNEL!,
  secret: process.env.WHISH_SECRET!,
  websiteUrl: process.env.WEBSITE_URL!,
});

export async function POST(request: Request) {
  const { amount, currency, orderId, invoice } = await request.json();

  try {
    const externalId = whish.generateExternalId();

    const result = await whish.createPayment({
      amount,
      currency,
      invoice,
      externalId,
      successCallbackUrl: `${process.env.WEBSITE_URL}/api/whish/callback/success`,
      failureCallbackUrl: `${process.env.WEBSITE_URL}/api/whish/callback/failure`,
      successRedirectUrl: `${process.env.WEBSITE_URL}/checkout/success?orderId=${orderId}`,
      failureRedirectUrl: `${process.env.WEBSITE_URL}/checkout/failure?orderId=${orderId}`,
    });

    if (!result.success) {
      return NextResponse.json(
        { error: result.dialog?.message || 'Payment creation failed' },
        { status: 400 }
      );
    }

    // Save externalId to your order for later verification
    // await updateOrder(orderId, { externalId, status: 'awaiting_payment' });

    return NextResponse.json({ collectUrl: result.collectUrl, externalId });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to create payment' },
      { status: 500 }
    );
  }
}

Success Callback Handler:

// app/api/whish/callback/success/route.ts
import { WhishClient, parseCallbackUrl } from 'whish-pay';
import { NextResponse } from 'next/server';

const whish = new WhishClient({
  channel: process.env.WHISH_CHANNEL!,
  secret: process.env.WHISH_SECRET!,
  websiteUrl: process.env.WEBSITE_URL!,
});

export async function GET(request: Request) {
  const { externalId, currency } = parseCallbackUrl(request.url);

  if (!externalId || !currency) {
    return NextResponse.json({ error: 'Missing parameters' }, { status: 400 });
  }

  try {
    // Verify payment with Whish
    const status = await whish.getPaymentStatus(currency, externalId);

    if (status.collectStatus === 'success') {
      // Update your order status
      // await updateOrder(externalId, { status: 'paid' });

      return NextResponse.json({ success: true, externalId });
    }

    return NextResponse.json(
      { success: false, status: status.collectStatus },
      { status: 400 }
    );
  } catch (error) {
    return NextResponse.json(
      { error: 'Payment verification failed' },
      { status: 500 }
    );
  }
}

Express.js

import express from 'express';
import { WhishClient, parseCallbackUrl } from 'whish-pay';

const app = express();
app.use(express.json());

const whish = new WhishClient({
  channel: process.env.WHISH_CHANNEL!,
  secret: process.env.WHISH_SECRET!,
  websiteUrl: process.env.WEBSITE_URL!,
});

// Create payment
app.post('/api/whish/payment', async (req, res) => {
  const { amount, currency, orderId, invoice } = req.body;

  try {
    const externalId = whish.generateExternalId();

    const result = await whish.createPayment({
      amount,
      currency,
      invoice,
      externalId,
      successCallbackUrl: `${process.env.WEBSITE_URL}/api/whish/callback/success`,
      failureCallbackUrl: `${process.env.WEBSITE_URL}/api/whish/callback/failure`,
      successRedirectUrl: `${process.env.WEBSITE_URL}/checkout/success`,
      failureRedirectUrl: `${process.env.WEBSITE_URL}/checkout/failure`,
    });

    if (!result.success) {
      return res.status(400).json({ error: result.dialog?.message });
    }

    res.json({ collectUrl: result.collectUrl, externalId });
  } catch (error) {
    res.status(500).json({ error: 'Failed to create payment' });
  }
});

// Success callback
app.get('/api/whish/callback/success', async (req, res) => {
  const { externalId, currency } = req.query;

  try {
    const status = await whish.getPaymentStatus(
      currency as 'USD' | 'LBP',
      Number(externalId)
    );

    if (status.collectStatus === 'success') {
      // Update order status...
      res.json({ success: true });
    } else {
      res.status(400).json({ success: false });
    }
  } catch (error) {
    res.status(500).json({ error: 'Verification failed' });
  }
});

// Failure callback
app.get('/api/whish/callback/failure', async (req, res) => {
  const { externalId, errorCode, errorMessage } = req.query;
  // Handle failure, restore inventory, etc.
  res.json({ success: false, errorCode, errorMessage });
});

app.listen(3000);

Error Handling

The SDK provides specific error classes for different failure scenarios:

import {
  WhishError,
  WhishConfigError,
  WhishApiError,
  WhishNetworkError,
  WhishValidationError,
} from 'whish-pay';

try {
  const result = await whish.createPayment(request);
} catch (error) {
  if (error instanceof WhishConfigError) {
    // Invalid configuration
    console.error('Config error:', error.message);
  } else if (error instanceof WhishValidationError) {
    // Request validation failed
    console.error('Validation error:', error.message, 'Field:', error.field);
  } else if (error instanceof WhishApiError) {
    // Whish API returned an error
    console.error('API error:', error.code, error.dialog?.message);
  } else if (error instanceof WhishNetworkError) {
    // Network request failed
    console.error('Network error:', error.message);
  }
}

Payment Flow

  1. Create Order - Create an order in your database with status awaiting_payment
  2. Create Payment - Call whish.createPayment() with order details
  3. Save External ID - Store the externalId with your order for later verification
  4. Redirect User - Send user to the collectUrl to complete payment
  5. Handle Callback - Whish calls your callback URL after payment
  6. Verify Payment - Call whish.getPaymentStatus() to verify
  7. Update Order - Update order status based on payment result
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Your App   │────▶│ Whish API   │────▶│ Whish Page  │
│             │     │             │     │  (Payment)  │
└─────────────┘     └─────────────┘     └──────┬──────┘
       ▲                                        │
       │            ┌─────────────┐             │
       └────────────│  Callback   │◀────────────┘
                    │  Handler    │
                    └─────────────┘

Security Best Practices

  1. Keep secrets secure - Never expose WHISH_SECRET to the client
  2. Validate callbacks - Always verify payment status with getPaymentStatus()
  3. Use HTTPS - All callback URLs must use HTTPS in production
  4. Validate amounts - Use validateAmount() to prevent amount manipulation
  5. Idempotency - Handle duplicate callbacks gracefully
  6. Unique external IDs - Use generateExternalId() for collision-free IDs

Testing

Use the sandbox environment for testing:

const whish = new WhishClient({
  channel: process.env.WHISH_CHANNEL!,
  secret: process.env.WHISH_SECRET!,
  websiteUrl: process.env.WEBSITE_URL!,
  environment: 'sandbox', // Explicitly use sandbox
});

Or set NODE_ENV=development to auto-select sandbox.

API Environments

| Environment | Base URL | |-------------|----------| | Sandbox | https://lb.sandbox.whish.money/itel-service/api | | Production | https://whish.money/itel-service/api |

TypeScript Support

Full TypeScript support with exported types:

import type {
  WhishConfig,
  PaymentRequest,
  PaymentResponse,
  StatusResponse,
  WhishCurrency,
  PaymentStatus,
} from 'whish-pay';

License

MIT License - see LICENSE for details.

Support

  • Issues: GitHub Issues
  • Whish Support: Contact Whish Money for API credentials and merchant support

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a PR.

Made with ❤️ by Zaytoun Solutions www.zaytounsolutions.com