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

lokipay-sdk

v2.4.2

Published

Official SDK for LokiPay VFM - Mobile Money Payment Verification System

Downloads

1,696

Readme

LokiPay SDK

LokiPay npm version TypeScript License: MIT

Official JavaScript/TypeScript SDK for LokiPay VFM

Automated Mobile Money Payment Verification for Ghana 🇬🇭

Getting StartedAPI ReferenceExamplesWebhooks


🌟 Features

  • Easy Integration - Simple, intuitive API for payment processing
  • TypeScript Support - Full type definitions included
  • Automatic Verification - Real-time SMS-based payment matching
  • Multi-Provider - Works with MTN MoMo, Telecel Cash, AirtelTigo Money
  • Polling Support - Built-in waitForPayment() method
  • Zero Dependencies - Lightweight, uses native fetch
  • ESM & CJS - Works with any JavaScript environment

📦 Installation

npm install lokipay-sdk
yarn add lokipay-sdk
pnpm add lokipay-sdk

🚀 Quick Start

import { LokiPay } from 'lokipay-sdk';

// Initialize with your secret key from the LokiPay Dashboard
const lokipay = new LokiPay({
  secretKey: 'sk_live_your_secret_key'  // Get this from your dashboard
});

// Create a payment order
const result = await lokipay.createOrder({
  phone: '0241234567',
  amount: 150.00,
  description: 'Order #12345 - Electronics Store'
});

console.log('Order created:', result.order.orderId);
console.log('Tell customer to pay with reference:', result.order.vfmReference);

// Wait for payment (polls automatically)
const status = await lokipay.waitForPayment(result.order.orderId, {
  intervalMs: 5000,  // Check every 5 seconds
  timeoutMs: 600000, // Wait up to 10 minutes
  onStatusChange: (status) => {
    console.log('Status:', status.status);
  }
});

if (status.status === 'confirmed') {
  console.log('✅ Payment confirmed!');
} else {
  console.log('❌ Payment not received:', status.status);
}

⚛️ React Component

The SDK exports a pre-built LokiPayCheckout component that handles the entire payment flow.

import { LokiPay } from 'lokipay-sdk';
import { LokiPayCheckout } from 'lokipay-sdk/react';

const lokipay = new LokiPay({
  secretKey: 'sk_live_...'
});

export default function Payment() {
  return (
    <div className="flex justify-center p-12">
      <LokiPayCheckout
        client={lokipay}
        amount={150.00}
        description="Premium Plan"
        onSuccess={(order) => {
          console.log('Payment Verified:', order);
          alert('Payment successful!');
        }}
        darkMode={false} // Toggle dark mode
        color="#30D158"  // Custom accent color
      />
    </div>
  );
}

⚙️ Configuration

API Keys

You get two API keys from your LokiPay Dashboard:

| Key Type | Format | Usage | |----------|--------|-------| | Secret Key | sk_live_... | Server-side only. Full access. Keep this private! | | Public Key | pk_live_... | Can be used client-side for limited operations |

⚠️ Important: Never expose your secret key in frontend code or public repositories.

// Recommended: Use secret key on your backend
const lokipay = new LokiPay({
  secretKey: 'sk_live_your_secret_key'  // From dashboard Settings > API Keys
});

// Alternative: Use public key for client-side (limited access)
const lokipay = new LokiPay({
  secretKey: 'pk_live_your_public_key'  // Less sensitive operations only
});

Advanced Options

const lokipay = new LokiPay({
  // Your API key (required)
  secretKey: 'sk_live_your_secret_key',
  
  // Custom API URL (for self-hosted deployments)
  apiUrl: 'https://your-api.com/api/vfm',
  
  // Request timeout in milliseconds (default: 30000)
  timeout: 60000,
  
  // Merchant configuration for payment instructions
  merchant: {
    mtnMerchantCode: '190638',
    mtnPaymentNumber: '0592353232'
  }
});

📖 API Reference

createOrder(options)

Create a new payment order.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | phone | string | ✅ | Customer phone number | | amount | number | ✅ | Payment amount in GHS (e.g., 50.00) | | description | string | ❌ | Description of the payment/order | | email | string | ❌ | Customer email for notifications | | telegramChatId | string | ❌ | Telegram chat ID for notifications |

Returns: Promise<CreateOrderResponse>

const result = await lokipay.createOrder({
  phone: '0551234567',
  amount: 100.00,
  description: 'Invoice #INV-2025-001',
  email: '[email protected]'
});

// Response
{
  success: true,
  message: 'Order created. Use the reference code when making payment.',
  order: {
    orderId: 'LokiPayABCD',
    vfmReference: 'LokiPayABCD',
    recipientPhone: '0551234567',
    description: 'Invoice #INV-2025-001',
    expectedAmount: 100.00,
    status: 'pending',
    expiresAt: '2025-01-15T10:45:00Z',
    instructions: {
      step1: 'Copy the reference code below',
      step2: 'Send exactly GHS 100.00 via MoMo',
      step3: 'Use "LokiPayABCD" as the payment reference/description',
      step4: 'After payment, click "I have completed payment" button',
      note: 'Order expires in 30 minutes'
    }
  }
}

getOrderStatus(orderId)

Check the current status of an order.

Parameters:

  • orderId (string) - The order ID to check

Returns: Promise<OrderStatusResponse>

const status = await lokipay.getOrderStatus('LokiPayABCD');

console.log(status.status);
// 'pending' | 'matched' | 'confirmed' | 'expired' | 'failed'

| Status | Description | |--------|-------------| | pending | Waiting for payment | | matched | Payment detected, pending confirmation | | confirmed | Payment verified and confirmed | | expired | Order expired before payment | | failed | Payment verification failed |


verifyPayment(orderId)

Manually trigger payment verification.

Parameters:

  • orderId (string) - The order ID to verify

Returns: Promise<VerifyPaymentResponse>

const result = await lokipay.verifyPayment('LokiPayABCD');

if (result.success) {
  console.log('Payment verified!');
  console.log('Transaction:', result.transaction);
}

waitForPayment(orderId, options)

Poll for payment status until confirmed, expired, or timeout.

Parameters:

  • orderId (string) - The order ID to poll
  • options (object) - Polling configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | intervalMs | number | 5000 | Polling interval in ms | | timeoutMs | number | 300000 | Maximum wait time in ms | | onStatusChange | function | - | Callback on status change |

Returns: Promise<OrderStatusResponse>

try {
  const status = await lokipay.waitForPayment('LokiPayABCD', {
    intervalMs: 3000,    // Check every 3 seconds
    timeoutMs: 600000,   // Timeout after 10 minutes
    onStatusChange: (status) => {
      console.log(`Status changed to: ${status.status}`);
      
      // Update your UI here
      updatePaymentUI(status);
    }
  });

  if (status.status === 'confirmed') {
    // Process successful payment
    await fulfillOrder(status.orderId);
  }
} catch (error) {
  if (error.message === 'Payment polling timeout') {
    console.log('Customer did not complete payment in time');
  }
}

getConfig()

Get VFM service configuration.

Returns: Promise<VFMConfig>

const config = await lokipay.getConfig();

console.log(config);
// {
//   enabled: true,
//   minAmount: 1,
//   maxAmount: 10000,
//   orderExpiryMinutes: 30,
//   paymentMethods: [
//     { name: 'MTN MoMo', instructions: '...' },
//     { name: 'Telecel Cash', instructions: '...' },
//     { name: 'AirtelTigo Money', instructions: '...' }
//   ]
// }

LokiPay.formatPaymentInstructions(order)

Static helper to format payment instructions for display.

const instructions = LokiPay.formatPaymentInstructions(result.order);
console.log(instructions);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//   💰 PAYMENT INSTRUCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 
// 📝 Invoice #INV-2025-001
// 💵 Amount: GHS 100.00
// 🔑 Reference: LokiPayABCD
// ...

🔔 Webhook Integration

Receive real-time payment notifications in your backend:

import type { WebhookPayload } from 'lokipay-sdk';

// Express.js example
app.post('/webhooks/lokipay', express.json(), (req, res) => {
  const payload: WebhookPayload = req.body;
  
  console.log('Received webhook:', payload.event);
  
  switch (payload.event) {
    case 'payment.matched':
      // Payment detected but not yet confirmed
      console.log(`Payment matched for order ${payload.orderId}`);
      break;
      
    case 'payment.confirmed':
      // Payment fully verified
      console.log(`✅ Order ${payload.orderId} paid!`);
      await fulfillOrder(payload.orderId, payload.transaction);
      break;
      
    case 'order.expired':
      // Order expired without payment
      console.log(`Order ${payload.orderId} expired`);
      await cancelOrder(payload.orderId);
      break;
  }
  
  res.status(200).send('OK');
});

Webhook Payload Structure:

interface WebhookPayload {
  event: 'payment.matched' | 'payment.confirmed' | 'order.expired';
  orderId: string;
  vfmReference: string;
  amount: number;
  status: OrderStatus;
  timestamp: string;
  transaction?: {
    id: string;
    sender: string;
    reference: string;
  };
}

⚠️ Error Handling

import { LokiPay, LokiPayError } from 'lokipay-sdk';

try {
  const result = await lokipay.createOrder({ 
    phone: '0241234567',
    amount: 100
  });
} catch (error) {
  if (error instanceof LokiPayError) {
    console.error(`LokiPay Error [${error.statusCode}]: ${error.message}`);
    
    switch (error.statusCode) {
      case 400:
        console.log('Invalid request - check your parameters');
        break;
      case 404:
        console.log('Order not found');
        break;
      case 408:
        console.log('Request timeout - try again');
        break;
      case 500:
        console.log('Server error - contact support');
        break;
    }
  } else {
    console.error('Unexpected error:', error);
  }
}

📋 Examples

E-commerce Checkout

async function processCheckout(cart: Cart, customer: Customer) {
  const lokipay = new LokiPay();
  
  // Create payment order
  const result = await lokipay.createOrder({
    phone: customer.phone,
    amount: cart.total,
    description: `Order #${cart.id} - ${cart.items.length} items`,
    email: customer.email
  });
  
  // Show payment instructions to customer
  showPaymentModal({
    amount: result.order.expectedAmount,
    reference: result.order.vfmReference,
    instructions: result.order.instructions,
    expiresAt: result.order.expiresAt
  });
  
  // Wait for payment
  const status = await lokipay.waitForPayment(result.order.orderId, {
    onStatusChange: (status) => updatePaymentStatus(status.status)
  });
  
  if (status.status === 'confirmed') {
    closePaymentModal();
    showSuccessMessage('Payment received! Your order is being processed.');
    await createShipment(cart, customer);
  } else {
    showErrorMessage('Payment was not completed. Please try again.');
  }
}

React Hook

import { useState, useCallback } from 'react';
import { LokiPay, type Order, type OrderStatus } from 'lokipay-sdk';

const lokipay = new LokiPay();

export function usePayment() {
  const [order, setOrder] = useState<Order | null>(null);
  const [status, setStatus] = useState<OrderStatus | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const createPayment = useCallback(async (
    phone: string,
    amount: number, 
    description: string
  ) => {
    setLoading(true);
    setError(null);
    
    try {
      const result = await lokipay.createOrder({ phone, amount, description });
      setOrder(result.order);
      setStatus('pending');
      
      // Start polling
      const finalStatus = await lokipay.waitForPayment(result.order.orderId, {
        onStatusChange: (s) => setStatus(s.status)
      });
      
      return finalStatus;
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Payment failed');
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  return { order, status, loading, error, createPayment };
}

🔧 TypeScript Support

All types are exported for use in your TypeScript projects:

import type {
  LokiPayConfig,
  MerchantConfig,
  CustomInstructionsConfig,
  NetworkInstructionOverride,
  Order,
  OrderStatus,
  PaymentMethod,
  PaymentInstructions,
  CreateOrderRequest,
  CreateOrderResponse,
  OrderStatusResponse,
  VerifyPaymentResponse,
  VFMConfig,
  WebhookPayload,
  LokiPayErrorType,
  APIResponse
} from 'lokipay-sdk';

import type { LokiPayCheckoutProps } from 'lokipay-sdk/react';

📄 License

MIT © LokiPay


Made with ❤️ in Ghana 🇬🇭

WebsiteDocumentationSupport